Mocha, promises and testing rejections

How to test Promise.reject()

Mocha is a great testing framework for Node.js. It supports everything you need to be able to exercise your code.

In other languages testing asynchronous code is usually quite problematic. Either you need to depend on fragile delays or setup complicated harness. Sometimes you just give up and test your code in non-asynchronous environment.

Not in Mocha.

It has asynchronous code testing built in. It’s not a surprise. It would be quite hard to imagine a JavaScript testing framework without it.

Of course, support for promises is also built in. The only thing you need to do is to return them from your test case and the framework will handle the rest.

Testing promise rejection is not that intuitive. The culprit is the way in which promises and assertions interact with each other. To explain that look at the code below:

it('returns rejected promise', () => {
  return something()
  .then(() => assert(false))
  .catch(() => assert(true));

It looks reasonable. As a matter of fact, if something() returns rejected promise it will pass.

But what will happen if something() returns resolved promise?

It would seem that it should hit assert(false) and report a test failure. Unfortunately, that’s not what is going to happen.

First, as expected, it does reach assert(false). Then instead of reporting an error the exception from assert the following .catch() takes over it and because it contains assert(true) it passes. From the point of view of the test framework, everything is OK.

There’s one simple solution. Something which most of the tutorials and guides about promises tell you not to do. It’s to add the rejection handler as the second argument to .then().

it('returns rejected promise', () => {
  return something()
  .then(() => assert(false), () => assert(true));

That way any exception from the first function will bubble up. It will be visible to Mocha and will report it as a test failure.

As I mentioned before the proper error handling when using promises is tricky. One needs to be extra careful when dealing with it.

One piece of advice which did help me a lot is to always make sure you can see your test case failing. Otherwise, you may have a bit of test code which will give you a false sense of security.