Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async/ await toThrow is not working #1700

Closed
seeden opened this issue Sep 15, 2016 · 22 comments
Closed

async/ await toThrow is not working #1700

seeden opened this issue Sep 15, 2016 · 22 comments

Comments

@seeden
Copy link

seeden commented Sep 15, 2016

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)

@cpojer
Copy link
Member

cpojer commented Sep 15, 2016

Yes, this isn't supported currently. See #1377

@cpojer cpojer closed this as completed Sep 15, 2016
@tkrotoff
Copy link
Contributor

tkrotoff commented Apr 2, 2018

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...

@tkrotoff
Copy link
Contributor

tkrotoff commented Apr 2, 2018

You can also write:

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

@natterstefan
Copy link

natterstefan commented Apr 2, 2018

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

@mathiasose
Copy link

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);
  });

@SimenB
Copy link
Member

SimenB commented May 2, 2018

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

Should work as well

@vadivelkindhealth
Copy link

vadivelkindhealth commented May 2, 2018

await expect(check).rejects.toThrow(/DUPLICATES_DETECTED/);

is what I do.

@dasoncheng
Copy link

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]

@SimenB
Copy link
Member

SimenB commented Aug 10, 2018

You need to invoke it to give it the actual promise

@dasoncheng
Copy link

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

@dasoncheng
Copy link

I know it need a promise, but the case you're offering is not :)

@Marchelune
Copy link

Marchelune commented Oct 16, 2018

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.

@dozenne
Copy link

dozenne commented Oct 26, 2018

@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.

@Karabur
Copy link

Karabur commented Mar 28, 2019

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()`

@Sergeyshall
Copy link

@Karabur typo toBeThruthy should be toBeTruthy

tom-sherman added a commit to tom-sherman/grapesjs that referenced this issue Oct 21, 2019
Every time I did `await expect(...).rejects.toThrow(...)` jest would
throw. Error here:

https://travis-ci.org/artf/grapesjs/jobs/600715489#L1147

Many comments in the jest github issues (jestjs/jest#1700)
say that this syntax should work but I don't believe it does.
@furkanacaryes
Copy link

furkanacaryes commented Dec 2, 2019

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();
    });

@mahuzedada
Copy link

mahuzedada commented Apr 24, 2020

Hi @SimenB.
If I have this and it's working.

async function check() {
    // do something
}
await expect(check()).rejects.toThrow(InternalServerErrorException);

InternalServerErrorException is thrown with an object....

How can I also assert for properties on the error thrown? For example:

  • exception.message = 'ERROR'
  • exception.status = '500'

@David-Tennant
Copy link

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.

@furkanacaryes
Copy link

Hey @David-Tennant 🖐

Thanks for pointing out that. I was working on a Promise<notVoid> method at that time. I realized that I didn't share a common solution that is also valid for Promise<void>. I updated my answer with a comment says I made assumptions. I agree with you about the flow.

Thanks 💨

@David-Tennant
Copy link

David-Tennant commented Jun 3, 2020

Howdy @futuredayv 👋

Hey @David-Tennant 🖐

Thanks for pointing out that. I was working on a Promise<notVoid> method at that time. I realized that I didn't share a common solution that is also valid for Promise<void>. I updated my answer with a comment says I made assumptions. I agree with you about the flow.

Thanks 💨

The problem is that your test will still pass if the test does return void. Which should be a bug right?
Calling done() means "My test has passed in a way that is expected and I am ready to move onto my next test"

yourCoolAsyncMethod('yeah it is')
     // -- Lets say your method does not throw, and returns void instead
    .then(ok => { // Presumes not a Promise<void>
        expect(ok).toBeUndefined(); // -- At this point if it was void, this would pass
        done(); // -- Then your test would end and the catch would not be reached
        // -- Now you have unknown behavior passing a test where it's suppose to catch a fail
    })
    .catch(bad => {
        // -- This block does not run because done() is called above
        expect(bad).toBeDefined();
        expect(bad).toMatchInlineSnapshot(
            `Specifically serious error!`
        );

        done();
    });

Not sure what the solution would be for your use case. But I would start by not calling done() in the then or maybe throwing an error in the "then" to make sure the test fails,

yourCoolAsyncMethod('yeah it is')
    .then(ok => throw new Error("This block of code should not be reached")
    .catch(bad => {
        expect(bad).toBeDefined();
        expect(bad).toMatchInlineSnapshot(
            `Specifically serious error!`
        );

        done();
    });

@Jaimies
Copy link

Jaimies commented Oct 28, 2020

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()`

mhchia added a commit to zkopru-network/blind-find that referenced this issue Jan 11, 2021
@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests