Search code examples
typescriptmocha.jschaichai-as-promised

Test async function to throw with mocha


I've got an async function which runs 2000ms and then it'll throw an exception. I am trying to test exactly this behaviour with Mocha / chai, but apparently I am doing it wrong.

That's what I've tried:

First:

expect(publisher.dispatchMessage<ExampleResponseMessage>(message, {}, 2 * 1000)).to.eventually.throw();

This marks the test as passed (52ms runtime) but throws an exception 2s later. So apparently it hasn't awaited the promise of that function at all.

Second:

expect(async () => {
      await publisher.dispatchMessage<ExampleResponseMessage>(message, {}, 2 * 1000);
    }).to.throw();

The test fails with: should reject a scheduled message after a predefined timeout: AssertionError: expected [Function] to throw an error at Context.mocha_1.it (test\integration\rpc-communication.spec.ts:75:16) at

Expected behaviour is that the test passed because an exception is thrown after 2000ms, which is within the given test case timeout of 4000ms.

Additional information:

This would work. The promise is rejected with an error (I can also change it to reject with a string). That should proove that dispatchMessage() is working as intended. The test case takes 2002ms and passes then.

    try {
      await publisher.dispatchMessage<ExampleResponseMessage>(message, {}, 2 * 1000);
    } catch (err) {
      expect(err).to.be.an('Error');
    }

Question:

How do I properly test if an async function throws an exception?


Solution

  • .to.throw() shouldn't work on async function because it doesn't throw an error, it returns rejected promise.

    The problem is specific to chai-as-promised. As explained in this issue, .to.eventually.throw() won't work as expected. It asserts that a promise resolves with a function that will throw error synchronously when called. This is likely not what happens in dispatchMessage.

    This depends on dispatchMessage but likely should be:

    expect(publisher.dispatchMessage<ExampleResponseMessage>(message, {}, 2 * 1000))
    .to.be.rejected;