Jest react testing: Check state after delay

JavascriptReactjsUnit TestingJestjs

Javascript 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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJack M.View Question on Stackoverflow
Solution 1 - JavascriptLukas LiesisView Answer on Stackoverflow
Solution 2 - JavascriptDinesh RamasamyView Answer on Stackoverflow
Solution 3 - JavascriptWaraoView Answer on Stackoverflow
Solution 4 - JavascriptwindmaomaoView Answer on Stackoverflow