Mocha tests using superagent + promises timeout rather than fail with 'expect'
Asked Answered
S

2

1

I'm using mocha to run a number of integration tests against an external web service. I use superagent-promise for the request/response handling, and I'm using expect as my assertion library.

For some of these tests I need to chain a large number of requests together, so the promises have been very helpful. However I'm noticing that my tests are now failing with a timeout (and no error message) rather than with the error message itself. As a simple example:

  it('[MESSAGES-1] cannot be posted without an auth token', function(done) {
    agent.post(config.webRoot + '/rooms/ABC/messages').send({
      content: 'This is a test!'
    }).end().then(function(res) {
      // Not expected
    }, function(err) {
      expect(err.status).toBe(401)
      done()
    })
  })

Works as expected and passes:

  Messages
    ✓ [MESSAGES-1] cannot be posted without an auth token

However if I alter my assertion to expect a different status code:

expect(err.status).toBe(200) // This should fail

Then the test fails with a timeout!

  1) Messages [MESSAGES-1] cannot be posted without an auth token:
     Error: timeout of 1000ms exceeded. Ensure the done() callback is being called in this test.

Is this a common problem? Is there a workaround or tweak I can make? I don't want to lose the ability to use promises.

Swetiana answered 12/11, 2016 at 13:46 Comment(0)
C
3

Is this a known issue?

This is actually not an issue.

The problem is that expect(err.status).toBe(200) throws an error that is swallowed inside the .then and which causes the code to never reach done(). You should restructure you code to the following:

it('[MESSAGES-1] cannot be posted without an auth token', function(done) {
    agent.post(config.webRoot + '/rooms/ABC/messages').send({
      content: 'This is a test!'
    }).end()

    .then(function(res) {
      // Not expected
    }, function(err) {
      expect(err.status).toBe(401)
      done()
    })
    .catch(function(err) {
        done(err); //report error thrown in .then
    })
  })

This way you catch and report the error thrown by expect(err.status).toBe(200).

Chattanooga answered 12/11, 2016 at 13:59 Comment(1)
That was it! I'm new to promises in JavaScript - I wasn't aware of the catch(), but that works perfectly.Swetiana
P
2

In your case the timeout happens becouse the done callback is never called, either because the http request didnt fail, or the expectation failed so it threw an assertation error.

Mocha handles proper (promise returning) asynchronous tests, so don't use the done callback, it causes confusion when mixed with promises. Return the promise instead:

it('[MESSAGES-1] cannot be posted without an auth token', function() {
  return agent.post(config.webRoot + '/rooms/ABC/messages').send({
    content: 'This is a test!'
  }).end().then(function(res) {
    // here you must throw an error, because if the post didnt fail somehow, the test would be green because of no assertations and no promise rejection.
    throw new Error("Not expected");
  }, function(err) {
    expect(err.status).toBe(401);
  });
});
Pomona answered 12/11, 2016 at 14:8 Comment(3)
"...either because the http request didnt fail ..." OP explicitly states that the only change he makes to the code is changing expect(err.status).toBe(401) to expect(err.status).toBe(200). Based on this premise the problem is that the thrown assertion error halts the execution of the code inside the .then promise - an error which in OP's code is swallowed by the promise (as stated in my answer).Chattanooga
@Chattanooga that's why you shouldn't use done when working with promises, and let Mocha handle them properly.Ruddie
@Ruddie : agreedChattanooga

© 2022 - 2024 — McMap. All rights reserved.