Search code examples
javascripttestingpromisemocha.jses6-promise

Mocha - How to test for unsettled promise?


I am testing a function that returns a promise. I want to assert that, in certain conditions, the returned promise would never settle (doesn't resolve nor reject).

How can I test this with Mocha?


If I run the following:

describe('under certain conditions', function () {
  let promise;
  beforeEach(function () {
    promise = new Promise((resolve, reject) => {});
  });
  it('should hang forever', function () {
    return promise;
  });
});

I get the following error:

Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves

Solution

  • robertklep's answer works, but you'd have to wait for 5 seconds before the test completes. For unit tests, 5 seconds is simply too long.

    As you've suggested, you can integrate the lolex library into robertklep's solution, to avoid the wait.

    (I am also using a Symbol instead of the string 'timeout', in case your promise resolves, by coincidence, also resolves with the string 'timeout')

    import { install } from 'lolex';
    
    describe('A promise', function () {
      let clock;
      before(function () { clock = install() });
      after(function () { clock.uninstall() });
    
      describe('under certain conditions', function () {
        const resolvedIndicator = Symbol('resolvedIndicator');
        const forever = 600000; // Defining 'forever' as 10 minutes
        let promise;
        beforeEach(function () {
          promise = Promise.race([
            new Promise(() => {}), // Hanging promise
            new Promise(resolve => setTimeout(resolve, forever, resolvedIndicator)),
          ]);
        });
        it('should hang forever', function () {
          clock.tick(forever);
          return promise.then((val) => {
            if (val !== resolvedIndicator) {
              throw Error('Promise should not have resolved');
            }
          }, () => {
            throw Error('Promise should not have rejected');
          });
        });
      });
    });