I need to do multiple async calls in before() hook in mocha. I need to delete a user, then signup , verify email and finally login to get token to authenticate all other test cases. Here is my code snippet :
const userInfo = {
"password": "pass123",
"email": "[email protected]",
};
var token = '' , userId = '';
before((done) => {
// Delete the user if already exists
User.remove({
email: userInfo.email
}).then((res) => {
// console.log(res.result);
})
.end(done);
done();
});
before((done) => {
request(app)
.post('/api/users')
.send(userInfo)
.expect(200)
.expect((res) => {
})
.end(done);
});
before((done) => {
User.findOne({
email: userInfo.email
}).then((res) => {
userId = res._id;
request(app)
.post('/api/users/verify-email')
.send({'token' : userId})
.expect(200)
.expect((res) => {
})
.end(done);
})
.end(done);
done();
});
Here these calls are not executing in sequence. I need to fetch userId before verifying the email, but I am getting below error:
POST /api/users/verify-email 401 4.082 ms - 45
1) "before all" hook
First of all, yes, mocha allows multiple before hooks and guarantees that they are called in the right order. To make sure of this you could run this snippet.
'use strict';
const results = [];
const assert = require('assert');
before(done => {
setTimeout(() => {
console.log(`First 'before'`);
results.push(1);
done(); //Will be called last
}, 1000)
});
before(done => {
setTimeout(() => {
console.log(`Second 'before'`);
results.push(2); //Will be called second
done();
}, 300)
});
before(done => {
setTimeout(() => {
console.log(`Third 'before'`);
results.push(3); //Will be called first
done();
}, 100)
});
describe('Before hooks order', () => {
it('should before hooks sequentially', () => {
//Check if the hooks were called in the right order anyway
assert.deepEqual(results, [1, 2, 3]);
});
});
//Output is:
// First 'before'
// Second 'before'
// Third 'before'
But to make this happen you need to call done() only when all the async operations are done to let mocha know that the hook is completed and it should run the next one.
Also there is a rule that any Node.js callback must be called only once. So here are a couple of fixes:
before((done) => {
// Delete the user if already exists
User
.remove({
email: userInfo.email
})
.then((res) => {
// console.log(res.result);
})
.end(done);
//Do not call done here() because User.remove have only started
//We need to wait until it finishes. Done will be called in .end method
// done();
});
before((done) => {
//All good here
request(app)
.post('/api/users')
.send(userInfo)
.expect(200)
.expect((res) => {
})
.end(done);
});
before((done) => {
User.findOne({
email: userInfo.email
}).then((res) => {
userId = res._id;
//You need a return statement here so the outer promise waits
//Until the internal call finishes
return request(app)
.post('/api/users/verify-email')
.send({'token': userId})
.expect(200)
.expect((res) => {
});
//We must not call callback multiple times, so remove this.
// .end(done);
})
//Now this 'end' will happen only after both calls finish
.end(done);
//Remove this please, for the same reason as with the first 'before'
// done();
});
Please check it out. I'm not able to run your code (don't have your api), so please let me know of any problems.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With