Jest react testing: Check state after delay
JavascriptReactjsUnit TestingJestjsJavascript Problem Overview
I'm really confused trying to create test with the help of Jest documentation https://facebook.github.io/jest/docs/timer-mocks.html#content
I'm trying to check a state when container mounts and then few seconds later, after I have manually set values in the state (using setTimeout()).
I have a function inside Main's componentDidMount like this:
componentDidMount() {
this.setStateAfterDelay();
}
And what the function does is:
setStateAfterDelay = () => {
setTimeout(() => {
this.setState({ fruits: ['banana', 'apple', 'orange', 'vodka', 'kiwi'] });
}, 1500);
}
I achieved the first part with:
const component = mount(<Main />);
expect(component.state().fruits).toEqual(null);
But I have no clue how to check the state again after, lets say 2000ms?
Any help is appreciated :)
Javascript Solutions
Solution 1 - Javascript
while jest can run async code easily, you can use promise and setTimeout combination to wait a bit. For example this code will wait for 2 seconds:
await new Promise((r) => setTimeout(r, 2000));
Full sample test. Don't forget to add async
flag before the callback function:
test('some test title', async () => {
const foo = true;
await new Promise((r) => setTimeout(r, 2000));
expect(foo).toBeDefined();
});
Also, keep in mind that default "timeout" is 5 seconds (5000ms). If your test may run longer, you can add jest.setTimeout(30000);
above the test()
. 30000 will make sure to not timeout for 30 seconds. You can add any number you need. Full example with setTimeout:
jest.setTimeout(30000);
test('some test title', async () => {
const foo = true;
await new Promise((r) => setTimeout(r, 2000));
expect(foo).toBeDefined();
});
Solution 2 - Javascript
I haven't really tested this code. But, something similar to this should work I think.
const fruits = ['banana', 'apple', 'orange', 'vodka', 'kiwi'];
it('mock setTimeout test', () => {
jest.useFakeTimers();
setTimeout(() => {
expect(component.state().fruits).toEqual(fruits);
}, 1500);
jest.runAllTimers();
});
Solution 3 - Javascript
You don't need to delay your tests, simply calling jest.runAllTimers()
before asserting, will work.
const fruits = ['banana', 'apple', 'orange', 'vodka', 'kiwi'];
it('initializes the fruits state', () => {
jest.useFakeTimers();
jest.runAllTimers();
expect(component.state().fruits).toEqual(fruits);
});
You could also call useFakeTimers()
in a beforeEach
if you are going to test multiple times and also runAllTimers()
could be inside another beforeEach
so you don't repeat yourself.
Solution 4 - Javascript
I know this is question about how to check something after 20 seconds. But this might be also an indicator that you don't want to test 20 seconds, since what's important sometimes is whether certain action has been performed with the right inputs. In this case, you could restructure your code a bit so that you can pass in a dispatch function. For instance
function abc() {
return dispatch => {
return Promise.then(res => {}) // this would take 20 seconds
}
}
Because dispatch
is passed in, therefore you can easily use the following in the testing code.
const dispatch = Jest.fn()
abc(dispatch)
expect(dispatch).toBeCalled()
Of course the assumption is that you do not care about if it's 20 seconds, instead you care more about the workflow process.