I'm building a node module and am trying to do my best to unit test the heck out of it. I've setup mocha and chai to do the test handling. I'm having a problem testing my async methods (methods that return promises).
In the following test I am testing a method on an "Upgrade" object.
it('Should return a list of versions for the default git repo', function (done) {
fs.writeFileSync(appSetup.CONFIG_FILENAME, JSON.stringify(appSetup.DEFAULT_CONFIG));
var upgrade = new Upgrade({
quiet: true
});
upgrade.getVersions().then(function (versions) {
assert(versions && versions.length > 0, 'Should have at least one version.');
assert.equal(1, 2); // this throws the exception which causes the test case not even exist
done();
}, done);
});
The getVersions()
call returns a promise as the method is async. When the promise resolves I want to test the value returned in the versions
variable.
The assert(versions && versions.length > 0, 'Should have at least one version.');
is the actual test. I added assert.equal(1, 2);
because I noticed that when the test should fail the test case wouldn't even show up in the test list.
I'm assuming that the assert call is throwing an exception that Mocha should pickup. However it is getting trapped in the promises then
handler function.
What is going on here? Why when the assert is going to fail in that method does it not show the test case in the list (it doesn't show as failed; like it doesn't exist)?
The core of the issue is that the code you have is essentially:
try {
var versions = upgrade.getVersions();
} catch (err){
return done(err);
}
assert(versions && versions.length > 0, 'Should have at least one version.');
assert.equal(1, 2); // this throws the exception which causes the test case not even exist
done();
Looking at that, it should be clear that if the assertions throw, then neither callback will run.
try {
var versions = upgrade.getVersions();
assert(versions && versions.length > 0, 'Should have at least one version.');
assert.equal(1, 2); // this throws the exception which causes the test case not even exist
done();
} catch (err){
return done(err);
}
is more like what you want, which would be:
upgrade.getVersions().then(function (versions) {
assert(versions && versions.length > 0, 'Should have at least one version.');
assert.equal(1, 2); // this throws the exception which causes the test case not even exist
}).then(done, done);
Node that this will execute the assertions and then move the callbacks into a secondary .then()
that will always handle the errors.
That said, it would be much easier to simply return the promise as
return upgrade.getVersions().then(function (versions) {
assert(versions && versions.length > 0, 'Should have at least one version.');
assert.equal(1, 2); // this throws the exception which causes the test case not even exist
});
to let Mocha monitor the promise itself without the callback.
The test doesn't show up in the list until you call the callback, which never happens if that assert fails. You would need to call .catch(done)
on the final promise to ensure done
is always called.
The test will show up if you give it a timeout value, which you should probably do.
All that said, mocha
understands promises. You don't need to deal with callbacks at all:
it('Should return a list of versions for the default git repo', function () {
fs.writeFileSync(appSetup.CONFIG_FILENAME, JSON.stringify(appSetup.DEFAULT_CONFIG));
var upgrade = new Upgrade({
quiet: true
});
return upgrade.getVersions().then(function (versions) {
assert(versions && versions.length > 0, 'Should have at least one version.');
assert.equal(1, 2);
});
});
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