act
是一个测试助手,用于在做出断言之前应用待处理的 React 更新。
¥act
is a test helper to apply pending React updates before making assertions.
await act(async actFn)
要为断言准备组件,请封装代码以对其进行渲染并在 await act()
调用内执行更新。这会使你的测试运行更接近 React 在浏览器中的工作方式。
¥To prepare a component for assertions, wrap the code rendering it and performing updates inside an await act()
call. This makes your test run closer to how React works in the browser.
参考
¥Reference
await act(async actFn)
在编写 UI 测试时,渲染、用户事件或数据获取等任务可被视为与用户界面交互的“单元”。React 提供了一个名为 act()
的助手,它可以确保在做出任何断言之前,与这些“单元”相关的所有更新都已处理并应用于 DOM。
¥When writing UI tests, tasks like rendering, user events, or data fetching can be considered as “units” of interaction with a user interface. React provides a helper called act()
that makes sure all updates related to these “units” have been processed and applied to the DOM before you make any assertions.
act
这个名字来自 Arrange-Act-Assert 模式。
¥The name act
comes from the Arrange-Act-Assert pattern.
it ('renders with button disabled', async () => {
await act(async () => {
root.render(<TestComponent />)
});
expect(container.querySelector('button')).toBeDisabled();
});
参数
¥Parameters
-
async actFn
:一个异步函数,封装正在测试的组件的渲染或交互。在actFn
中触发的任何更新都会添加到内部动作队列中,然后将它们一起刷新以处理和应用对 DOM 的任何更改。由于它是异步的,React 还将运行任何跨越异步边界的代码,并刷新任何计划的更新。¥
async actFn
: An async function wrapping renders or interactions for components being tested. Any updates triggered within theactFn
, are added to an internal act queue, which are then flushed together to process and apply any changes to the DOM. Since it is async, React will also run any code that crosses an async boundary, and flush any updates scheduled.
返回
¥Returns
act
不返回任何东西。
¥act
does not return anything.
用法
¥Usage
测试组件时,你可以使用 act
对其输出做出断言。
¥When testing a component, you can use act
to make assertions about its output.
例如,假设我们有这个 Counter
组件,下面的使用示例展示了如何测试它:
¥For example, let’s say we have this Counter
component, the usage examples below show how to test it:
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>
)
}
在测试中渲染组件
¥Rendering components in tests
要测试组件的渲染输出,请将渲染封装在 act()
中:
¥To test the render output of a component, wrap the render inside 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);
// ✅ Render the component inside 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
组件。这可确保在做出断言之前渲染组件并应用其效果。
¥Here, we create a container, append it to the document, and render the Counter
component inside act()
. This ensures that the component is rendered and its effects are applied before making assertions.
使用 act
可确保在我们做出断言之前已应用所有更新。
¥Using act
ensures that all updates have been applied before we make assertions.
在测试中分派事件
¥Dispatching events in tests
要测试事件,请将事件调度封装在 act()
中:
¥To test events, wrap the event dispatch inside 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 />);
});
// ✅ 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()
内分派事件。这可确保在做出断言之前应用事件的所有更新。
¥Here, we render the component with act
, and then dispatch the event inside another act()
. This ensures that all updates from the event are applied before making assertions.
故障排除
¥Troubleshooting
我收到错误:“当前测试环境未配置为支持 act”(…)”
¥I’m getting an error: “The current testing environment is not configured to support act”(…)”
使用 act
需要在测试环境中设置 global.IS_REACT_ACT_ENVIRONMENT=true
。这是为了确保 act
仅在正确的环境中使用。
¥Using act
requires setting global.IS_REACT_ACT_ENVIRONMENT=true
in your test environment. This is to ensure that act
is only used in the correct environment.
如果你未设置全局变量,你将看到如下错误:
¥If you don’t set the global, you will see an error like this:
要修复,请将其添加到 React 测试的全局设置文件中:
¥To fix, add this to your global setup file for React tests:
global.IS_REACT_ACT_ENVIRONMENT=true