0

In my mocha.js test, I'm calling an async function that throws an error, but the test doesn't fail. It passes and there is an UnhandledPromiseRejectionWarning:

describe('async function', async function () {
    it('should fail', async function () {
        [1].forEach(async function () {
            throw new Error("Why can't I see this error?!");
        });
    });
});

Note, that a simpler case works as expected:

describe('async function', async function () {
    it('should fail', async function () {
        throw new Error('This one fails the test');
    });
});

How can I cause the test to fail due to an exception in an inner function?

(I've tried adding an unhandledRejection handler, but the test still passes)

GilZ
  • 6,418
  • 5
  • 30
  • 40
  • Check out the thread here: https://stackoverflow.com/questions/14879181/test-for-expected-failure-in-mocha – devadviser Oct 25 '17 at 16:37
  • 2
    @MihaiAndrici, I didn't mention it to keep the question and code short, but in the original code it's actually not a `throw` but a failed Chai assert. The result is the same (`expect.fail()` will not cause the test to fail). But thank anyway. – GilZ Oct 25 '17 at 16:40

2 Answers2

3

Your test case with .forEach cannot work like you want it to work. When it calls its async callback, the callback does create a promise, but .forEach does not do anything with it. The callback you pass to it is async too and it does return a promise, but the promise it returns is not connected to the promises that the callback to .forEach produces. That's why you get UnhandledPromiseRejectionWarning.

You can solve the issue by connecting the promises through Promise.all:

describe('async function', async function () {
    it('should fail', async function () {
        return Promise.all([1].map(async function () {
            throw new Error("Why can't I see this error?!");
        }));
    });
});

Using map makes it so that your array is turned into an array of promises, and then Promise.all waits for all the promises in the array to be resolved, or it rejects if any promise rejects. Returning the return value of the Promise.all call then allow Mocha to wait for the whole thing.

Louis
  • 146,715
  • 28
  • 274
  • 320
3

Louis' answer is spot on. As an alternative, you could avoid using an inner function and use a normal for loop instead:

const data = [1];
for (let i = 0; i < data.length; i++) {
  // await some more stuff here
  throw new Error('This one fails the test');
}
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143