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.

注意

你可能会发现直接使用 act() 有点太冗长了。为了避免一些样板,你可以使用像 React 测试库 这样的库,它的助手用 act() 封装。

¥You might find using act() directly a bit too verbose. To avoid some of the boilerplate, you could use a library like React Testing Library, whose helpers are wrapped with act().


参考

¥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();
});

注意

我们建议将 actawaitasync 函数一起使用。尽管同步版本在许多情况下都有效,但它并非在所有情况下都有效,而且由于 React 内部安排更新的方式,很难预测何时可以使用同步版本。

¥We recommend using act with await and an async function. Although the sync version works in many cases, it doesn’t work in all cases and due to the way React schedules updates internally, it’s difficult to predict when you can use the sync version.

我们将在未来弃用并删除同步版本。

¥We will deprecate and remove the sync version in the future.

参数

¥Parameters

  • async actFn:一个异步函数,封装正在测试的组件的渲染或交互。在 actFn 中触发的任何更新都会添加到内部动作队列中,然后将它们一起刷新以处理和应用对 DOM 的任何更改。由于它是异步的,React 还将运行任何跨越异步边界的代码,并刷新任何计划的更新。

    ¥async actFn: An async function wrapping renders or interactions for components being tested. Any updates triggered within the actFn, 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.

易犯错误

不要忘记,只有将 DOM 容器添加到文档时,调度 DOM 事件才有效。你可以使用像 React 测试库 这样的库来减少样板代码。

¥Don’t forget that dispatching DOM events only works when the DOM container is added to the document. You can use a library like React Testing Library to reduce the boilerplate code.

故障排除

¥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:

Console

要修复,请将其添加到 React 测试的全局设置文件中:

¥To fix, add this to your global setup file for React tests:

global.IS_REACT_ACT_ENVIRONMENT=true

注意

在测试 React 测试库 等框架时,IS_REACT_ACT_ENVIRONMENT 已经为你设置好了。

¥In testing frameworks like React Testing Library, IS_REACT_ACT_ENVIRONMENT is already set for you.


React 中文网 - 粤ICP备13048890号