最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Waiting for React component state to update before testing with Jest - Stack Overflow

programmeradmin3浏览0评论

I have a component with a handleAdd function. This function calls a library, which in turn calls axios and returns a promise. Once that's resolved, the handleAdd() method updates component state which in turns renders child(ren).

In other words, it checks with the server first to make sure the item is added before displaying it locally.

When testing with Jest, i have to await sleep for a few msec before the expect runs otherwise the shallow render isn't updated yet, even though I mock/overwrite the api call. There's some delay between the promise resolving, rerender and expect(). Here's what that kind of looks like:

it('adds a thing', async () => {
    ThingManager.default.addPlan = () => {
      const response = new Promise((resolve, reject) => { resolve() })
      return response;
    }

    const wrapper = shallow(<Home />)
    wrapper.find('button').simulate('click')
    const input = wrapper.find('#plan-title')
    input.simulate('change', { target: { value: 'TEST ITEM' } })

    await sleep(500) // without it, <Thing /> isn't rendered yet.

    expect(wrapper.find('Thing').length).toBe(1)
  });

What's the proper way of doing this?

I have a component with a handleAdd function. This function calls a library, which in turn calls axios and returns a promise. Once that's resolved, the handleAdd() method updates component state which in turns renders child(ren).

In other words, it checks with the server first to make sure the item is added before displaying it locally.

When testing with Jest, i have to await sleep for a few msec before the expect runs otherwise the shallow render isn't updated yet, even though I mock/overwrite the api call. There's some delay between the promise resolving, rerender and expect(). Here's what that kind of looks like:

it('adds a thing', async () => {
    ThingManager.default.addPlan = () => {
      const response = new Promise((resolve, reject) => { resolve() })
      return response;
    }

    const wrapper = shallow(<Home />)
    wrapper.find('button').simulate('click')
    const input = wrapper.find('#plan-title')
    input.simulate('change', { target: { value: 'TEST ITEM' } })

    await sleep(500) // without it, <Thing /> isn't rendered yet.

    expect(wrapper.find('Thing').length).toBe(1)
  });

What's the proper way of doing this?

Share Improve this question edited Aug 9, 2020 at 13:25 Estus Flask 222k78 gold badges469 silver badges605 bronze badges asked Aug 9, 2020 at 12:18 McDerpMcDerp 1571 gold badge2 silver badges16 bronze badges 1
  • The question is very specific to the lib you're using that seems to be Enzyme. Consider specifying this. – Estus Flask Commented Aug 9, 2020 at 13:26
Add a comment  | 

3 Answers 3

Reset to default 8

You can use act from test-utils. That is what the React docs recommend, but I have had more success with waitFor from testing-library.

Just wanted to throw it out there that I use simple setTimeout with the combination of jest's done().

EDIT

it('sample test case', (done) => {
        // initialize your component

        setTimeout(function () {
            // expect something that's available after the timeout
            done();
        }, 500);
    });

I'm not an enzyme user, but I do use jest. Here is how I do this with @testing-library/react. The recommendation is that you don't look at the state directly, but at the markup resulting from the state being set.

const view = render(<Thing />);
const input = await screen.findByTestId('input-test-id');
fireEvent.change(input, {
  target: {value: 'new value'},
});
// This element is then displayed as a result of the state getting set
// resulting from the change event. screen.findByTestId (or any screen.find*) waits for 
// the element to appear timing out if it does not.
expect(await screen.findByTestId('logo-image-test-id')).toBeDefined();
发布评论

评论列表(0)

  1. 暂无评论