How do I properly test for a rejected promise using Jest?
Solution 1
You should do something like this:
it('rejects...', () => {
const Container = createUserContainer(CreateUser);
const wrapper = shallow(<Container />);
return expect(wrapper.instance().handleFormSubmit()).rejects.toEqual('error');
});
I think it is cleaner this way. You can see this approach in the official docs.
Solution 2
The test fails because it's not aware that the subject is asynchronous. It can be fixed by using a done
param or making the test function async
.
Note it's also necessary to set the number of expected assertions so that the test will fail even if the catch branch is not taken.
async
/await
style:
it('rejects...', async () => {
expect.assertions(1);
const Container = createUserContainer(CreateUser);
const wrapper = shallow(<Container />);
await wrapper.instance().handleFormSubmit()
.catch(e => {
console.log("State: ", wrapper.state());
expect(e).toEqual('error');
});
});
Older style done
param:
it('rejects...', done => {
expect.assertions(1);
const Container = createUserContainer(CreateUser);
const wrapper = shallow(<Container />);
wrapper.instance().handleFormSubmit()
.catch(e => {
console.log("State: ", wrapper.state());
expect(e).toEqual('error');
done();
});
});
Asynchronous Testing Reference
Solution 3
Your code looks correct. Why do you say that it doesn't wait for the Promise to reject? The only difference I would make would be to make use of Jest's mocking capability, so change
Mock
export const createUser = function() {
return new Promise((resolve, reject) => {
reject('error');
});
};
to
Test
jest.mock('../services');
const services = require('../services');
const createUser = jest.spyOn(services, "createUser");
createUser.mockRejectedValue("error");
...
it('rejects...', () => {
There's no need to have a separate Mock file
coding123
Updated on August 23, 2022Comments
-
coding123 over 1 year
Code
import { createUser } from '../services'; ... ... handleFormSubmit = () => { this.setState({ loading: true }); createUser() .then(() => { this.setState({ loading: false, }); }) .catch(e => { this.setState({ error: e, }); }); };
Test
it('rejects...', () => { const Container = createUserContainer(CreateUser); const wrapper = shallow(<Container />); return wrapper.instance().handleFormSubmit() .catch(e => { console.log("State: ", wrapper.state()); expect(e).toEqual('error'); }); });
Mock
export const createUser = function() { return new Promise((resolve, reject) => { reject('error'); }); };
The test does force the code to go into the catch in the method. So the state does get set to 'error'.
But in my test, it doesn't do what I expect and wait for the Promise to reject before it tests for the state change. I'm not sure what to try here, should I be using async/await?
So it's the
createUser
method I want to wait for but I'm not sure my implementation allows for this. -
coding123 almost 6 yearsthis didn't solve the issue. The code still goes into the catch, but the test still does not wait for the promise to fulfill before running the expects
-
Hriday Modi almost 6 yearsMy bad, Have updated the answer with documentation link. It will surely solve your problem
-
Shiraz almost 5 yearsNote that your test can also confirm that state.loading is still set to true
-
BenjiFB over 4 yearsThis was VERY helpful to me. The ".catch" style was exactly what I needed. Thanks!
-
oyalhi over 4 yearswouldn't this test give false positive if the function didn't throw?
-
A F about 4 years@oyalhi no, it won't give a false positive. The line
expect.assertions(1)
tells jest that there will be an assertion so if thecatch
isn't triggered, jest will complain about the missing assertion -
Brian Sterling almost 4 yearsWhat if the target code of the test needed to use "new services" thus you needed to do jest.doMock with a requireActual and override just a single function?
-
Technotronic about 3 yearsThis is the official way to check async errors. This should be the accepted answer.
-
Ahmed-Anas over 2 yearsNote: should probably make the method async and add await before expect (see linked official docs)
-
Andres Gardiol over 2 years@Ahmed-Anas see the first example in the link. The one that starts with
t('tests error with rejects', () => {
not the other. -
Jordi over 2 yearsI had to make make a slight variation to make this work:
expect(wrapper.instance().handleFormSubmit()).rejects.toEqual(Error('error));
-
Andres Gardiol over 2 years@Jordi that depends on what your tested method returns
-
Dave Amphlett about 2 yearsI've had success with using the syntax:
expect(wrapper.instance().handleFormSubmit()).rejects.toThrow('error text')