admin管理员组

文章数量:1127175

I'm writing an async test that expects the async function to throw like this:

it("expects to have failed", async () => {
  let getBadResults = async () => {
    await failingAsyncTest()
  }
  expect(await getBadResults()).toThrow()
})

But jest is just failing instead of passing the test:

 FAIL  src/failing-test.spec.js
  ● expects to have failed

    Failed: I should fail!

If I rewrite the test to looks like this:

expect(async () => {
  await failingAsyncTest()
}).toThrow()

I get this error instead of a passing test:

expect(function).toThrow(undefined)

Expected the function to throw an error.
But it didn't throw anything.

I'm writing an async test that expects the async function to throw like this:

it("expects to have failed", async () => {
  let getBadResults = async () => {
    await failingAsyncTest()
  }
  expect(await getBadResults()).toThrow()
})

But jest is just failing instead of passing the test:

 FAIL  src/failing-test.spec.js
  ● expects to have failed

    Failed: I should fail!

If I rewrite the test to looks like this:

expect(async () => {
  await failingAsyncTest()
}).toThrow()

I get this error instead of a passing test:

expect(function).toThrow(undefined)

Expected the function to throw an error.
But it didn't throw anything.
Share Improve this question edited Jun 29, 2021 at 10:14 Rufi 2,6451 gold badge23 silver badges45 bronze badges asked Nov 6, 2017 at 19:18 SeanSean 5,1042 gold badges13 silver badges12 bronze badges 0
Add a comment  | 

10 Answers 10

Reset to default 937

You can test your async function like this:

it('should test async errors', async () =>  {        
    await expect(failingAsyncTest())
    .rejects
    .toThrow('I should fail');
});

'I should fail' string will match any part of the error thrown.

I'd like to just add on to this and say that the function you're testing must throw an actual Error object throw new Error(...). Jest does not seem to recognize if you just throw an expression like throw 'An error occurred!'.

await expect(async () => { 
    await someAsyncFunction(someParams); 
}).rejects.toThrowError("Some error message");

We must wrap the code in a function to catch the error. Here we are expecting the Error message thrown from someAsyncFunction should be equal to "Some error message". We can call the exception handler also

await expect(async () => { 
    await someAsyncFunction(someParams); 
}).rejects.toThrowError(new InvalidArgumentError("Some error message"));

Read more https://jestjs.io/docs/expect#tothrowerror

Custom Error Class

The use of rejects.toThrow will not work for you. Instead, you can combine the rejects method with the toBeInstanceOf matcher to match the custom error that has been thrown.

Example

it("should test async errors", async () => {
  await expect(asyncFunctionWithCustomError()).rejects.toBeInstanceOf(
    CustomError
  )
})

To be able to make many tests conditions without having to resolve the promise every time, this will also work:

it('throws an error when it is not possible to create an user', async () => {
        const throwingFunction = () => createUser(createUserPayload)

        // This is what prevents the test to succeed when the promise is resolved and not rejected
        expect.assertions(3)

        await throwingFunction().catch(error => {
            expect(error).toBeInstanceOf(Error)
            expect(error.message).toMatch(new RegExp('Could not create user'))
            expect(error).toMatchObject({
                details: new RegExp('Invalid payload provided'),
            })
        })
    })

If you want to test that an async function does NOT throw:

it('async function does not throw', async () => {
    await expect(hopefullyDoesntThrow()).resolves.not.toThrow();
});

The above test will pass regardless of the value returned, even if undefined.

Keep in mind that if an async function throws an Error, its really coming back as a Promise Rejection in Node, not an error (thats why if you don't have try/catch blocks you will get an UnhandledPromiseRejectionWarning, slightly different than an error). So, like others have said, that is why you use either:

  1. .rejects and .resolves methods, or a
  2. try/catch block within your tests.

Reference: https://jestjs.io/docs/asynchronous#asyncawait

I've been testing for Firebase cloud functions and this is what I came up with:

test("It should test async on failing cloud functions calls", async () => {
    await expect(async ()=> {
        await failingCloudFunction(params)
    })
    .rejects
    .toThrow("Invalid type"); // This is the value for my specific error
  });

This is built on top of lisandro's answer.

This worked for me

it("expects to have failed", async () => {
  let getBadResults = async () => {
    await failingAsyncTest()
  }
  expect(getBadResults()).reject.toMatch('foo')
  // or in my case
  expect(getBadResults()).reject.toMatchObject({ message: 'foo' })
})

You can do like below if you want to use the try/catch method inside the test case.

test("some test case name with success", async () => {
 let response = null;
 let failure = null;
  // Before calling the method, make sure someAsyncFunction should be succeeded
 try {
  response = await someAsyncFunction();
 } catch(err) {
  error = err;
 }
expect(response).toEqual(SOME_MOCK_RESPONSE)
expect(error).toBeNull();
})

test("some test case name with failure", async () => {
 let response = null;
 let error = null;
 // Before calling the method, make sure someAsyncFunction should throw some error by mocking in proper way
 try {
  response = await someAsyncFunction();
 } catch(err) {
  error = err;
 }
expect(response).toBeNull();
expect(error).toEqual(YOUR_MOCK_ERROR)
})

Edit:

As my given solution is not taking the advantage of inbuilt jest tests with the throwing feature, please do follow the other solution suggested by @Lisandro https://stackoverflow.com/a/47887098/8988448

it('should test async errors', async () =>  {        
    await expect(failingAsyncTest())
    .rejects
    .toThrow('I should fail');
});

test("It should test async on failing cloud functions calls", async (done) => {
   failingCloudFunction(params).catch(e => {
    expect(e.message).toBe('Invalid type');
    done()
   })
  });

本文标签: javascriptCan you write async tests that expect toThrowStack Overflow