jest: async/ await toThrow is not working

next test

async function check() {
  throw new Error('Test');
}

expect(async () => 
  await check()
).toThrow();

will fail and don’t catch error properly (I am using latest version of jest)

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 108
  • Comments: 22 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Instead of

expect(async () => await check()).toThrow()
// Jest error: "Expected the function to throw an error. But it didn't throw anything."

this works:

expect(check()).rejects.toEqual(new Error('Test'))

Yeah the syntax is awkward…

await expect(check).rejects.toThrow(SomeSpecificError);

Should work as well

You can also write:

let error;
try {
  await check();
} catch (e) {
  error = e;
}
expect(error).toEqual(new Error('Test'));

Yes, this isn’t supported currently. See https://github.com/facebook/jest/issues/1377

async function check() {
  throw new Error("Test");
}
await expect(check()).rejects.toThrow(Error);

Should work as well

it(`some test`, async () => {
  async function check() {
    try {
      return Promise.reject(await asyncMethod());
    } catch (error) {
      throw new Error("test");
    }
  }
  await expect(check()).rejects.toThrow(Error);
});

can work

version

  • jest: 23.4.2
  • ts-jest: 23.1.2
await expect(check).rejects.toThrow(/DUPLICATES_DETECTED/);

is what I do.

The following worked for me as well:


async function check() {
  throw new Error('Test');
}

expect(check()).rejects.toEqual(new Error('Test'))

See: https://facebook.github.io/jest/docs/en/tutorial-async.html#rejects

In case someone throw anything different from instance Error class and struggle to use advise from that thread (as I did). toThrow() will check what value thrown is the instance of Error class, and if it is not - throw will not be detected. This wasn’t obvious from the docs and common sense. This will fail, even though it clearly throws:

async function f() {throw 'aa'}
const res = await expect(f()).rejects.toThrow()`

but this will work (not sure if there is a better way):

async function f() {throw 'aa'}
const res = await expect(f()).rejects.toBeTruthy()`
async function check() {
  throw new Error("Test");
}
await expect(check).rejects.toThrow(Error);
expect(received).rejects.toThrow()

received value must be a Promise.
Received:
 function: [Function check]

Adding to the list of workarounds. If you like me want to catch a specific error type, and don’t care about the message:

async function check() {
  throw new SomeSpecificError('Whatever');
}

await check()
  .then(() => {
    throw new Error('Should go to .catch, not enter .then');
  })
  .catch((err) => {
    expect(err).toBeInstanceOf(SomeSpecificError);
  });

In case someone throw anything different from instance Error class and struggle to use advise from that thread (as I did). toThrow() will check what value thrown is the instance of Error class, and if it is not - throw will not be detected. This wasn’t obvious from the docs and common sense. This will fail, even though it clearly throws:

async function f() {throw 'aa'}
const res = await expect(f()).rejects.toThrow()`

but this will work (not sure if there is a better way):

async function f() {throw 'aa'}
const res = await expect(f()).rejects.toBeTruthy()`

A slightly better way is to use toBeDefined() instead of toBeTruthy():

async function f() {throw 'aa'}
const res = await expect(f()).rejects.toBeTruthy()`

Here’s an explicit test that assures it will definitely break if it does NOT throw and matches specific error.

yourCoolAsyncMethod('yeah it is')
    .then(ok => { // Presumes not a Promise<void>
        expect(ok).toBeUndefined();
        done();
    })
    .catch(bad => {
        expect(bad).toBeDefined();
        expect(bad).toMatchInlineSnapshot(
            `Specifically serious error!`
        );

        done();
    });

@Marchelune When you write class CustomErrorType extends Error {} you haven’t actually defined a new class. If you give CustomErrorType a body, even just a constructor that does nothing but call super(), it will work.

Hi ! I might be doing something wrong, but I still have an issue with custom errors in async calls. Consider the following:

class CustomErrorType {}
// ...
test('check throws custom error', async () => {            
    async function check() {
        throw new CustomErrorType();
    }
    await expect(check()).rejects.toThrow(CustomErrorType);
});

then the test fails with the following output:

Expected the function to throw an error of type: “CustomErrorType” But it didn’t throw anything.

So the test fails - whilst it works perfectly when the thrown class is Error. When I try to extend Error with

class CustomErrorType extends Error {}

then the error is

Expected the function to throw an error of type: “CustomErrorType” Instead, it threw: Error

Any clue on something what is wrong in that sample ? I’m using jest 23.4.2.

Here’s an explicit test that assures it will definitely break if it does NOT throw and matches specific error.

yourCoolAsyncMethod('yeah it is')
    .then(ok => {
        expect(ok).toBeUndefined();
        done();
    })
    .catch(bad => {
        expect(bad).toBeDefined();
        expect(bad).toMatchInlineSnapshot(
            `Specifically serious error!`
        );

        done();
    });

Problem about this is that your test will pass if the code never has errors.

So this test would not really offer much value as it’s expected results are varied based on whether the code it’s testing has an error or not.

Tests should have a negative flow or a positive flow and we should only test what is needed to test. This sort of randomness isn’t the greatest.

@Karabur typo toBeThruthy should be toBeTruthy

You need to invoke it to give it the actual promise