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 ${this.state.count} times`;
}, [count]);
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={this.handleClick}>
Click me
</button>
</div>
)
}
在测试中渲染组件
要测试组件的渲染输出,请将渲染包装在 act()
中
import {act} from 'react';
import ReactDOM from 'react-dom/client';
import Counter from './Counter';
it('can render and update a counter', async () => {
container = document.createElement('div');
document.body.appendChild(container);
// ✅ Render the component inside act().
await act(() => {
ReactDOM.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 ReactDOM 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 />);
});
// ✅ Dispatch the event inside 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()
内部调度事件。这确保在进行断言之前应用来自事件的所有更新。
故障排除
我收到一个错误:“当前测试环境未配置为支持 act(…)"
使用 act
需要在您的测试环境中设置 global.IS_REACT_ACT_ENVIRONMENT=true
。这是为了确保 act
仅在正确的环境中使用。
如果您没有设置全局变量,您将看到如下错误
控制台
警告:当前测试环境未配置为支持 act(…)
要解决此问题,请将其添加到您的 React 测试全局设置文件中
global.IS_REACT_ACT_ENVIRONMENT=true