6

Got the following failing test case and i'm not sure why:

foo.js

async function throws() {
  throw 'error';
}

async function foo() {
  try {
    await throws();
  } catch(e) {
    console.error(e);
    throw e;
  }
}

test.js

const foo = require('./foo');

describe('foo', () => {
  it('should log and rethrow', async () => {
    await expect(foo()).rejects.toThrow();
  });
});

I expect foo to throw but for some reason it just resolves and the test fails:

FAILED foo › should log and rethrow - Received function did not throw

Live example

Probably missing some basic detail of async await throw behavior.

Daniel
  • 6,194
  • 7
  • 33
  • 59
  • 1
    don't await it ... just `expect(foo()).rejects.toThrow();` = because all foo does is return a promise that rejects ... – Bravo Nov 15 '19 at 09:39
  • @Bravo that's just hiding the problem because the test doesn't wait for the result. – Daniel Nov 15 '19 at 09:41
  • yeah, I see that ... but wouldn't you expect( await foo()) instead? I'm getting dizzy :p – Bravo Nov 15 '19 at 09:44
  • @Bravo yeah it's quite confusing but that's the way to test a throwing async function :) [https://stackoverflow.com/a/47887098/4341456](https://stackoverflow.com/a/47887098/4341456) – Daniel Nov 15 '19 at 09:46

3 Answers3

8

I think what you need is to check the rejected error

const foo = require('./foo');
describe('foo', () => {
  it('should log and rethrow', async () => {
    await expect(foo()).rejects.toEqual('error');
  });
});
  • 1
    Thanks, not 100% sure it the same as testing for throwing but i guess it's the next best thing. Ended up going with `await expect(foo()).rejects.toBeTruthy();` – Daniel Nov 15 '19 at 10:26
  • 2
    You can also tweak your code to something like and should work: `async function throws() { throw new Error('error'); }` – lucoceano Nov 15 '19 at 10:40
  • thank you! for some reason throwing errors manually requires different syntax – fIwJlxSzApHEZIl Oct 19 '21 at 18:36
2

Seems like it's a known bug: https://github.com/facebook/jest/issues/1700

This works though:

describe('foo', () => {
  it('should log and rethrow', async () => {
    await expect(foo()).rejects.toEqual('error')
  });
});
Juviro
  • 180
  • 1
  • 7
0

I use this code when I don't want to use toEqual or toBe (like the other correct answers). Instead, I use toBeTruthy.

async foo() {
  throw "String error";
}

describe('foo', () => {
  it('should throw a statement', async () => {
    await expect(foo()).rejects.toBeTruthy();
  });
});
Guillem Puche
  • 1,199
  • 13
  • 16