Expect a function to throw an exception in Jest
Solution 1
Jest is throwing this error Matcher error: received value must be a promise
because in expect
you are just passing the function reference. Without ()
- action
is just a function reference it will not return anything.
To fix this issue you have to call the function in expect like action()
so it will return the promise object.
And the second part, you have to throw error like. Promise.reject(new Error('some error'));
in the reject so the tothrow
condition can be full filled.
Example:
function hostelService() {
return Promise.reject(new Error('some error'));
}
const action = async () => {
await hostelService();
};
it( "Should throw the error", async () => {
await expect(action()).rejects.toThrow('some error');
});
Hope this will be helpful.
Solution 2
Your test fails because you're awaiting the promise (and therefore, it is no longer a Promise when you call .rejects
on it). If you remove await
from the last statement, it should do the trick:
const action = async () => {
await hostelService.book(id);
};
expect(action()).rejects.toThrow();
Here is some rationale behind it. async
automatically wraps your return type into a Promise. However, when you call await
, it synchronously "unwraps" the value of a given Promise and therefore it can't call .rejects
on the result (unless you wrap a Promise into another Promise).
I've composed a small example to illustrate what I mean.
Solution 3
It seems you almost have it. I have created a codesandbox with a function that throws an error and a test that passes. You can run it with npm run test
in a terminal inside codesandbox. Here's the link:
https://codesandbox.io/s/musing-goodall-ssss4?fontsize=14&hidenavigation=1&theme=dark
But basically the code is this:
const action = async () => {
throw new Error("error!")
}
describe("func", () => {
it("should fail", async () => {
await expect(action()).rejects.toThrow()
})
})
The difference with the code you showed is the call in action()
that was missing, maybe that was the type error. I don't know if that was a mistake or it wasn't just code and you just meant to explain what you wanted. In the future, for better understanding and to help your future "helpers", you should post a snippet of your code (or modified to avoid property issues).
Solution 4
Unfortunately you can't test rejects directly with toThrow()
. Rejects it self is an error object so you can test for equality.
test('', () => {
// dont forget to call the action.
await expect(action()).rejects.toEqual(new Error())
});
You can find more workarounds here https://github.com/facebook/jest/issues/1700
Sandro Rey
Bendiciones y unos Nullpointers. y si no sabes la respuesta a mis preguntas que te den por el xxxx dos veces.
Updated on January 22, 2020Comments
-
Sandro Rey over 4 years
I have a function (
hostelService.book
) that returns a promise: returnPromise.resolve(response);
and I made this test:const action = async () => { await hostelService.book(id); }; await expect(action).rejects.toThrow();
but I have this error:
Matcher error: received value must be a promise
-
jonrsharpe over 4 yearsIt's only
toThrow
that calls the supplied value.rejects
requires it to already be a promise, not a function that returns one. I don't think.rejects.toThrow()
makes sense at all; you probably wantexpect(hostelService.book(id)).rejects.toEqual(someError)
. See jestjs.io/docs/en/tutorial-async.html#rejects.
-
-
JHH almost 3 yearsYour last comment is incorrect. You should not remove
await
from theexpect(...).rejects.toThrow('some message');
statement. It may or may not work depending on if it's the last statement of the test etc, but what you're essentially doing is finishing the test with async code still executing, which might mean you'd be calling tear down code mid-test. Always await asynchronous calls in your tests.