我试图弄清楚是否有一种方法可以防止 Jest/testing-library 抛出“未包含在 act(...)”警告,当我在导致警告发生的状态更新后没有任何可断言的情况时,或者我是否应该忽略这个警告。
假设我有这个简单的组件:
import React, {useEffect, useState} from 'react';
import {getData} from 'services';
const MyComponent = () => {
const [arr, setArr] = useState([]);
useEffect(() => {
(async () => {
const {items} = await getData();
setArr(items);
})();
}, []);
return (
<div>
{!(arr.length > 0) && <p>no array items</p>}
{arr.length > 0 && (
<ul>
{arr.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
)}
</div>
);
};
export default MyComponent;
假设我想简单地测试该组件是否渲染正常,即使getData()
不为我返回任何数据。
所以我有一个这样的测试:
import React from 'react';
import {getData} from 'services';
import {render, screen} from 'testUtils';
import MyComponent from './MyComponent';
jest.mock('services', () => ({
getData: jest.fn(),
}));
it('renders', () => {
getData.mockResolvedValue({items: []});
render(<MyComponent />);
expect(screen.getByText('no array items')).toBeInTheDocument();
});
该测试将通过,但我会收到“未包含在 act(...)”警告,因为测试将在之前完成getData()
有机会完成。
在这种情况下,来自的响应getData()
sets arr
与我最初将其设置在组件顶部的值相同(空数组)。因此,异步函数完成后,我的 UI 不会发生变化——我仍然只是看一段“没有数组项”——所以我实际上没有任何可以断言等待状态更新的东西去完成。
I can expect(getData).toHaveBeenCalledTimes(1)
,但这不会等待函数调用后状态实际更新。
我尝试在测试中任意暂停以留出时间setArr(items)
即将发生:
it('renders', async () => {
getData.mockResolvedValue({items: []});
render(<MyComponent />);
expect(screen.getByText('no array items')).toBeInTheDocument();
await new Promise(resolve => setTimeout(resolve, 2000));
expect(screen.getByText('no array items')).toBeInTheDocument();
});
但这似乎没有帮助,老实说我也不知道为什么。
有没有办法通过仅修改测试来处理这种情况?
我确信我可以通过重构 MyComponent 来解决问题,例如,通过arr
到 MyComponent 作为 prop 并移动getData()
调用父组件,或者创建一些仅用于测试的自定义道具,这将跳过getData()
完全调用,但我不想纯粹为了避免测试中的警告而修改组件。
我在用测试库/反应 https://www.npmjs.com/package/@testing-library/react,v11.2.2。