How do I test async code with mocha? I wanna use multiple await
inside mocha
var assert = require('assert');
async function callAsync1() {
// async stuff
}
async function callAsync2() {
return true;
}
describe('test', function () {
it('should resolve', async (done) => {
await callAsync1();
let res = await callAsync2();
assert.equal(res, true);
done();
});
});
This produces error below:
1) test
should resolve:
Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.
at Context.it (test.js:8:4)
If I remove done() I get:
1) test
should resolve:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/tmp/test/test.js)
async
/await
is nothing more than syntactic sugar built on top of Promises which Mocha natively supports.
Here's how it's done -s with full async
/await
syntax:
async function getFoo() {
return 'foo'
}
describe('#getFoo', () => {
it('returns foo', async () => {
const result = await getFoo()
assert.equal(result, 'foo')
})
})
As said, you can also use Promises.
You just have to return the Promise
to it()
's callback.
As simple as that.
Since async
functions always implicitly return a Promise
you can just do:
// technically returns a Promise which resolves with 'foo'
async function getFoo() {
return 'foo'
}
describe('#getFoo', () => {
it('resolves with foo', () => {
return getFoo().then(result => {
assert.equal(result, 'foo')
})
})
})
which effectively the exact same as this:
In either case, do not declare done
as a function argument. This is what's catching most people off-guard.
If you use any of the methods described above - which involve Promise
and async
/await
- you need to remove done
completely from your testing setup.
That includes passing it as an argument to it
s callback because that hints to Mocha that this isn't a Promise-based test but rather a done/callback-based test.
Mocha has 4 different types of tests. It's important to pick one style and roll with it all the way because Mocha makes assumptions about the type of test based on how you set it up.
it
callback and use then
/catch
handlers to perform assertions.it
callback as async
and use await
to perform assertions.done
: do asynchronous operations and assertions and when you're done, explicitly call done()
. This is a relic from the old days when we had to deal with callbacks, before Promise
or async
/await
came about. It still has some use cases, mainly testing callback-style code or events.If you return both a Promises and also declare done
as an argument, Mocha will start complaining:
Error: Resolution method is overspecified. Specify a callback or return a Promise; not both
Because it's conflicted as to which type of test you want to use.
The done
method is only used for testing callback-based or event-based code. You shouldn't use it if you're testing Promise-based or async/await functions. If you find yourself having to use both done
and Promise.then
/Promise.catch
semantics, you've probably misunderstood how Promises work and failing tests would be the least of your worries.