如何测试(断言)使用钩子的 React 组件的中间状态

How to test(assert) intermediate states of a React Component which uses hooks

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

我有以下组件:

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

现在,我想使用 react-testing-libraryjest 测试并断言此行为。

这是我目前拥有的:

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(在 2 秒后渲染 1 之前)。

我该怎么做? 提前致谢。

正如 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');
})