开发者问题收集

如何测试异步 useEffect?

2021-01-08
24297

如何使用 react-testing-libs 测试异步 useEffect

我有:

// in other file
const getData = () => {
  return new Promsise(resolve => setTimeout(() => resolve([1, 2, 3]), 5000));
};

const MyComponent = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      const data = await getData();
      setData(data);
    };
    fetchData();
  }, []);

  return <div>{data.map(item => <span>{item}</span>)}</div>
};

如何测试此组件?

我现在的测试:

it('MyComponent test', async () => {
  await act( async () => {
    render(<MyComponent/>, container);
  });

  expect(container.innerHTML).toMatchSnapshot();
});

但是 act、render 不会等待 useEffect()。

为什么?

2个回答

react-testing-library 对此有一个干净的解决方案。您可以等待元素出现在 DOM 中,这意味着您的异步 useEffect 运行完毕。

它被称为 waitFor ,它会等待断言完成后再继续执行代码。您可以使用其他实用程序(如 getByText )来 expect

it('MyComponent test', async () => {
  await act( async () => {
    render(<MyComponent/>, container);
  });

  await waitFor(() => {
    // I'd look for a real text here that is renderer when the data loads
    expect(container.queryElement('span')).toBeDefined();
  })

  expect(container.innerHTML).toMatchSnapshot();

});
Obed Parlapiano
2021-01-08

请尝试以下操作:

test('My Test', async () => {
  const queries = render(<MyComponent/>, container);

  expect(await queries.findByText((content, element) => element.tagName.toLowerCase() === 'span')).toBeInTheDocument();

  expect(container.innerHTML).toMatchSnapshot();
})

我无法测试,因此如果有效请告诉我。

我阅读了 react-testing-library 问题上的此 评论 ,然后我查看了 此文档 。似乎有很多方法可以自定义此测试行为。

Ernesto Stifano
2021-01-08