Reputation: 91243
When using Mocha for unit testing, I have a situation like this that I need to test:
it('should assert true blah blah blah', function () {
return doSomething() // <-- returns a Promise
.then(function(value) {
return setTimeout(function() {
assert.equal(something, true);
},1000);
});
});
So I have a Promise that is returned from a function, and then I need to do an assert within an async setTimeout
after the Promise has been resolved. The above code appears to always pass the test no matter what. In fact, it seems like the setTimeout
never ever runs. If I put a console.log
in the setTimeout
it never prints out. Mocha finishes the unit test and moves on.
What is the proper way to test something like this? I see there is some sort of done()
method with Mocha but I'm not sure if that is something I should use with this or not. I don't fully understand it.
Upvotes: 1
Views: 2174
Reputation: 135425
Because Mocha will work intelligently with functions that return Promises, you could also use the new async
/await
syntax, which implicitly returns Promises!
import 'babel-polyfill';
it('should assert true blah blah blah', async function () {
// `doSomething` is a function that returns a Promise
// `something` will be the resolved value
let something = await doSomething();
assert.equal(something, true);
});
A little bit of setup is required, but I think it's worth it considering how nice and flat your testing code looks in the end. And it's super easy to write.
You'll probably want the following packages – es2015
and es2016
are optional here, but if you're transpiling your testing code, you might as well include these. You'll end up wanting them anyway. babel-register
is used for the require hook and babel-polyfill
is used for the regenerator runtime.
$ npm install --save-dev babel-cli \
babel-register \
babel-polyfill \
babel-preset-es2015 \
babel-preset-es2016 \
babel-preset-es2017
Your .babelrc
{
"presets": ["es2015", "es2016", "es2017"]
}
Your package.json
{
"scripts": {
"test": "mocha --compilers js:babel-register"
}
}
Upvotes: 0
Reputation: 58440
If you return a promise to Mocha, it will assume the test is complete when the promise resolves.
If you have some non-promise-based asynchronous function to test after the promise resolves, you can use a done
callback instead of returning a promise:
it('should assert true blah blah blah', function (done) {
doSomething()
.then(function(value) {
setTimeout(function() {
assert.equal(something, true);
done();
},1000);
})
.catch(done);
});
Note that you should also include a catch
so that any promise rejection is passed to the done
callback, as Mocha understands Node-style errors and will fail the test if it receives one.
Alternatively, you could use a completely promise-based approach and could create a Promise
to enclose your asynchronous function:
it('should assert true blah blah blah', function () {
return doSomething()
.then(function(value) {
return new Promise(function (resolve, reject) {
setTimeout(function() {
try {
assert.equal(something, true);
resolve();
} catch (error) {
reject(error);
}
},1000);
});
});
});
Upvotes: 1
Reputation: 444
You do not need to use setTimeout()
to "wait" the Promise to be resolved. In stead, when it the Promise is resolved, the .then()
will be call. You simply just use the value
or do some assert
there, that's it.
Upvotes: 0