Getting a UnhandledPromiseRejectionWarning when testing using mocha/chai Getting a UnhandledPromiseRejectionWarning when testing using mocha/chai javascript javascript

Getting a UnhandledPromiseRejectionWarning when testing using mocha/chai


The issue is caused by this:

.catch((error) => {  assert.isNotOk(error,'Promise error');  done();});

If the assertion fails, it will throw an error. This error will cause done() never to get called, because the code errored out before it. That's what causes the timeout.

The "Unhandled promise rejection" is also caused by the failed assertion, because if an error is thrown in a catch() handler, and there isn't a subsequent catch() handler, the error will get swallowed (as explained in this article). The UnhandledPromiseRejectionWarning warning is alerting you to this fact.

In general, if you want to test promise-based code in Mocha, you should rely on the fact that Mocha itself can handle promises already. You shouldn't use done(), but instead, return a promise from your test. Mocha will then catch any errors itself.

Like this:

it('should transition with the correct event', () => {  ...  return new Promise((resolve, reject) => {    ...  }).then((state) => {    assert(state.action === 'DONE', 'should change state');  })  .catch((error) => {    assert.isNotOk(error,'Promise error');  });});


I got this error when stubbing with sinon.

The fix is to use npm package sinon-as-promised when resolving or rejecting promises with stubs.

Instead of ...

sinon.stub(Database, 'connect').returns(Promise.reject( Error('oops') ))

Use ...

require('sinon-as-promised');sinon.stub(Database, 'connect').rejects(Error('oops'));

There is also a resolves method (note the s on the end).

See http://clarkdave.net/2016/09/node-v6-6-and-asynchronously-handled-promise-rejections


The assertion libraries in Mocha work by throwing an error if the assertion was not correct. Throwing an error results in a rejected promise, even when thrown in the executor function provided to the catch method.

.catch((error) => {  assert.isNotOk(error,'Promise error');  done();});

In the above code the error objected evaluates to true so the assertion library throws an error... which is never caught. As a result of the error the done method is never called. Mocha's done callback accepts these errors, so you can simply end all promise chains in Mocha with .then(done,done). This ensures that the done method is always called and the error would be reported the same way as when Mocha catches the assertion's error in synchronous code.

it('should transition with the correct event', (done) => {  const cFSM = new CharacterFSM({}, emitter, transitions);  let timeout = null;  let resolved = false;  new Promise((resolve, reject) => {    emitter.once('action', resolve);    emitter.emit('done', {});    timeout = setTimeout(() => {      if (!resolved) {        reject('Timedout!');      }      clearTimeout(timeout);    }, 100);  }).then(((state) => {    resolved = true;    assert(state.action === 'DONE', 'should change state');  })).then(done,done);});

I give credit to this article for the idea of using .then(done,done) when testing promises in Mocha.