Reputation: 4477
I am practicing basic unit test cases with mocha
and a bit confused HOW and WHEN to use done() handler.
done()
?Below is my sample code where I am not able to use done
:
it('Testing insertDocumentWithIndex', async (done) => {
try{
var data = await db.insertDocumentWithIndex('inspections', {
"inspectorId" : 1,
"curStatus" : 1,
"lastUpdatedTS" : 1535222623216,
"entryTS" : 1535222623216,
"venueTypeId" : 1,
"location" : [
45.5891279,
-45.0446183
]
})
expect(data.result.n).to.equal(1);
expect(data.result.ok).to.equal(1);
}
catch(e){
logger.error(e);
done(e);
}
})
When I run, it fails and throws an error-
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
But done
should be called in case of failure only(Please correct me If I am missing something, I am a beginner😄), which I have done in catch
block and coming to the second point of returning a Promise, well that works fine. See below code
it('Testing insertDocumentWithIndex', async () => {
return new Promise(async (resolve, reject) => {
try{
var data = await db.insertDocumentWithIndex('inspections', {
"inspectorId" : 1,
"curStatus" : 1,
"lastUpdatedTS" : 1535222623216,
"entryTS" : 1535222623216,
"venueTypeId" : 1,
"location" : [
45.5891279,
-45.0446183
]
})
expect(data.result.n).to.equal(1);
expect(data.result.ok).to.equal(1);
resolve()
}
catch(e){
reject(e);
}
})
});
But this requires an additional Promise construction code which is antipattern. But it raises another question
done
should be used ?Any help or suggestion for a better approach for writing test cases with mocha
will help.
Upvotes: 17
Views: 14240
Reputation: 173
Your problem is not caused by where you use done
parameter, as @estus-flask told you, done
is not used with async/await pattern. Your problem is due the promise is taking more than the default 2000ms timeout for the test function; you have to increase that time. One way is using --timeout 5000
(more or less) in the command line when you call mocha, but the recommended way is to set it into each describe
function, or even into each it
function like this:
describe('Your description', function() {
this.timeout(7000);
// your tests
});
or
describe('Your description', function() {
it('Your test', async function())
this.timeout(7000);
// your tests with await
});
it('Another no-async test', function(done) {
// your not-async test
done();
});
});
Remember to not use arrow functions when you use the this
keyword:
describe('Your description', () => {
this.timeout(7000); // It will not work.
// your tests
});
Upvotes: 0
Reputation: 222875
The correct way is to not use done
with async..await
. Mocha supports promises and is able to chain a promise that is returned from it
, etc. functions. And async
function is syntactic sugar for a function that always returns a promise:
it('Testing insertDocumentWithIndex', async () => {
var data = await db.insertDocumentWithIndex('inspections', {
"inspectorId" : 1,
"curStatus" : 1,
"lastUpdatedTS" : 1535222623216,
"entryTS" : 1535222623216,
"venueTypeId" : 1,
"location" : [
45.5891279,
-45.0446183
]
})
expect(data.result.n).to.equal(1);
expect(data.result.ok).to.equal(1);
})
done
is needed only for testing asynchronous APIs than don't involve promises. Even then, converting to promises often results in cleaner control flow.
And this
it('Testing insertDocumentWithIndex', async () => {
return new Promise(async (resolve, reject) => {
...
is promise construction antipattern, which is even worse because of async
promise constructor callback.
These concerns also apply to other JS testing frameworks with similar API, Jest and Jasmine.
Upvotes: 17