act
是个测试辅助工具,用于在断言前应用待处理的 React 更新。
await act(async actFn)
要将组件准备好进行断言,请将渲染代码和执行更新的操作包裹在 await act()
中。这能让你的测试更接近 React 在浏览器中的实际工作方式。
参考
await act(async actFn)
在编写 UI 测试时,诸如渲染、用户事件或数据获取等操作都可以视为与用户界面的“交互单元”。React 提供了 act() 辅助工具,确保在进行任何断言之前,所有与这些“交互单元”相关的更新都已处理并应用到 DOM。
名称 act
来源于 Arrange-Act-Assert 模式。
it ('renders with button disabled', async () => {
await act(async () => {
root.render(<TestComponent />)
});
expect(container.querySelector('button')).toBeDisabled();
});
参数
async actFn
: 包裹被测组件渲染或交互的异步函数。在actFn
内触发的所有更新都会被加入内部 act 队列,随后统一执行以处理变更并应用到 DOM。由于是异步操作,React 还会执行跨越异步边界的代码,并刷新所有计划中的更新。
返回值
act
不返回任何值。
用法
测试组件时,可以使用 act
对其输出进行断言。
例如,假设我们有这个 Counter
组件,以下示例演示如何测试它:
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(prev => prev + 1);
}
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={handleClick}>
Click me
</button>
</div>
)
}
在测试中渲染组件
要测试组件的渲染输出,请将渲染操作包裹在 act()
中:
import {act} from 'react';
import ReactDOMClient from 'react-dom/client';
import Counter from './Counter';
it('can render and update a counter', async () => {
container = document.createElement('div');
document.body.appendChild(container);
// ✅ 在 act() 内渲染组件
await act(() => {
ReactDOMClient.createRoot(container).render(<Counter />);
});
const button = container.querySelector('button');
const label = container.querySelector('p');
expect(label.textContent).toBe('You clicked 0 times');
expect(document.title).toBe('You clicked 0 times');
});
这里我们创建容器元素并添加到文档中,然后在 act()
内渲染 Counter
组件。这确保了在断言前组件已完成渲染且副作用已应用。
使用 act
能保证所有更新在断言前已完成处理。
在测试中触发事件
要测试事件,请将事件触发操作包裹在 act()
中:
import {act} from 'react';
import ReactDOMClient from 'react-dom/client';
import Counter from './Counter';
it.only('can render and update a counter', async () => {
const container = document.createElement('div');
document.body.appendChild(container);
await act( async () => {
ReactDOMClient.createRoot(container).render(<Counter />);
});
// ✅ 在 act() 内触发事件
await act(async () => {
button.dispatchEvent(new MouseEvent('click', { bubbles: true }));
});
const button = container.querySelector('button');
const label = container.querySelector('p');
expect(label.textContent).toBe('You clicked 1 times');
expect(document.title).toBe('You clicked 1 times');
});
这里我们先用 act
渲染组件,然后在另一个 act()
内触发事件。这确保了事件引起的所有更新在断言前已完成处理。
疑难解答
出现错误 “The current testing environment is not configured to support act”(…)”
使用 act
需要在测试环境中设置 global.IS_REACT_ACT_ENVIRONMENT=true
。这是为了确保 act
仅在正确的环境中使用。
如果未设置该全局变量,将看到如下错误:
Console
Warning: The current testing environment is not configured to support act(…)
解决方法:在 React 测试的全局设置文件中添加:
global.IS_REACT_ACT_ENVIRONMENT=true