首页 > 解决方案 > 如何测试(断言)使用钩子的 React 组件的中间状态

问题描述

这个问题是关于:如何测试使用useEffect钩子和useState钩子的组件,使用react-testing-library.

我有以下组件:

function MyComponent() {
  const [state, setState] = useState(0);

  useEffect(() => {
     // 'request' is an async call which takes ~2seconds to complete
     request().then(() => {
        setState(1);
     });
  }, [state]);

  return <div>{state}</div>
}

当我渲染这个应用程序时,我看到的行为如下:

  1. 该应用程序最初呈现0
  2. 大约 2 秒后,应用程序呈现1

现在,我想使用 and 来测试和断言这种react-testing-library行为jest

这是我到目前为止所拥有的:

import {render, act} from '@testing-library/react';

// Ignoring the describe wrapper for the simplicity
test('MyComponent', async () => {
  let result;
  await act(async () => {
    result = render(<MyComponent />);
  });
  expect(result.container.firstChild.textContent).toBe(1);
})

测试通过。但是,我还想断言用户最初看到应用程序呈现的事实0(在12 秒后呈现之前)。

我怎么做?提前致谢。

标签: reactjsjestjsreact-hooksreact-testing-libraryuse-effect

解决方案


正如 Sunil Pai 在此博客中指出的那样:https ://github.com/threepointone/react-act-examples/blob/master/sync.md

这是我设法解决这个问题的方法:

import {request} from '../request';

jest.mock('../request');

test('MyComponent', async () => {
  let resolve;
  request.mockImplementation(() => new Promise(resolve => { 
    // Save the resolver to a local variable
    // so that we can trigger the resolve action later
    resolve = _resolve;
  }));

  let result;
  await act(async () => {
    result = render(<MyComponent />);
  });

  // Unlike the non-mocked example in the question, we see '0' as the result
  // This is because the value is not resolved yet
  expect(result.container.firstChild.textContent).toBe('0');

  // Now the setState will be called inside the useEffect hook
  await act(async () => resolve());

  // So now, the rendered value will be 1
  expect(result.container.firstChild.textContent).toBe('1');
})

推荐阅读