Mocha added support for Promises back in version
1.18.0. Recently while testing asynchronous code written using Promises, I was using the built-in promise support instead of the old-fashioned callbacks oriented
done callback and I found my tests were resulting in false positives. So here I’m explaining what happened and how to avoid it.
It’s easy to see that there are four possible cases when testing Promises:
|Case||Expectation||Actual||Expected test status|
The test expects the promise to resolve and so it does. The snippet above shows that the test passes expectedly.
In the case when test expects the promise to resolve, but it doesn’t, Mocha gracefully fails the test. In the snippet above, the
then block was never executed and Mocha detected the error rejected by the code and failed the test.
The test expects the promise to be rejected and it is caught by the
catch block, which results in this test passing as expected.
In this case, the test expects the promise to be rejected and the catch block to execute but instead, it doesn’t. The promise resolves. Mocha doesn’t throw an error here!
So while doing Negative Testing, the built-in promises support doesn’t hold up well and can result in false positives. This is not a bug and the reason behind this behavior totally makes sense, once given a careful thought, but at the very least, it’s not intuitive and causes the tests to pass even when they shouldn’t.
The simplest way to avoid this situation is to always handle the rejection scenarios yourself, rather than asking Mocha to do it. Here’s how:
The above test will fail due to timeout as Mocha waits for
done to be called but it doesn’t, and times out eventually.
Another way to avoid this situation is to chain a
then block to the existing
catch block and assert that the catch was called.
If you know other elegant ways to avoid this behavior, please let me know in the comments!