Search code examples
javascriptjestjsnode.js-got

JEST Received function did not throw, but HTTPError is thrown


I am testing an endpoint with JEST and Got. I expect 403 Forbidden error. The following code prints the error from catch block AND fails that the identical call does not throw an error. Why?

    try {
        response = await api(`verify/${profile.auth.verifyToken}`, {method: 'POST'}).json();
    } catch (e) {
        console.log(e);
    }
    expect(async () => {
        response = await api(`verify/${profile.auth.verifyToken}`, {method: 'POST'}).json();
    }).toThrow();

Output:

console.log test/api.int.test.js:112
HTTPError: Response code 403 (Forbidden)
    at EventEmitter.<anonymous> (C:\dev\mezinamiridici\infrastructure\node_modules\got\dist\source\as-promise.js:118:31)
    at processTicksAndRejections (internal/process/task_queues.js:97:5) {
  name: 'HTTPError'
}


Error: expect(received).toThrow()
Received function did not throw

This variant does not work either:

expect(() => api(`verify/${profile.auth.verifyToken}`, {method: 'POST'})).toThrow();

Btw when the HTTPError is thrown and not catched, there is no stacktrace and I do not see where the error was thrown. If there are other error I exactly see which test line was responsible. Why?


Solution

  • expect(...).toThrow() is for checking if an error is thrown from a function call. When calling an async function, it never throws an error; rather it returns a Promise which may eventually become "rejected." Although async functions use the same throw/catch terminology, the code required to detect a thrown error differs from what's required to detect a rejected Promise. This is why Jest needs a different assertion technique.

    Try expect(...).rejects.toThrow() instead:

    await expect(api(`verify/${profile.auth.verifyToken}`, {method: 'POST'}).json())
      .rejects.toThrow();
    

    Notice you have to await this assertion because Jest needs to wait until the Promise finalizes before seeing whether it resolved or rejected.