Reputation: 2999
I have a function (hostelService.book
) that returns a promise: return Promise.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
Upvotes: 59
Views: 93343
Reputation: 10604
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.
Upvotes: 101
Reputation: 1377
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).
Upvotes: 8
Reputation: 2077
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.
Upvotes: 10
Reputation: 2151
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
Upvotes: 2
Reputation: 779
Here action is function and you're not calling it from expect. I've also removed await from last line
Try this solution
const action = async () => {
await hostelService.book(id);
};
expect(action()).rejects.toThrow();
Upvotes: 1