You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React 18.3测试中act警告问题的解决方式及版本变更咨询

React 18.3中ToggleButton测试的act警告解决方案及变更解析

手动包裹act不是正确解决方式

手动把userEvent.click再包一层act(...)只是临时屏蔽警告,并没有解决根本问题,甚至可能掩盖测试中未处理的异步更新逻辑,导致测试结果不可靠。

React 18.3的关键变更点

React 18.3对测试环境中的异步更新检测逻辑做了强化:

  • 之前版本中,React可能会忽略一些在userEvent操作完成后延迟执行的微任务/宏任务更新(比如组件内部Promise.resolve().then()、setTimeout里的状态变更)
  • 18.3版本会严格检测所有组件更新是否在act边界内,只要有更新发生在act包裹的操作之外,就会抛出警告,目的是确保测试能捕获到所有状态变更,避免测试结果出现假阳性。

更合理的测试调整方案

针对这个警告,核心是确保测试等待所有异步操作完成,而不是手动添加冗余的act包裹:

1. 必须await userEvent操作

userEvent.click是异步函数,即使它内部已经被act包裹,测试中也需要用await等待其完成,确保所有同步和异步更新都被React捕获:

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import ToggleButton from '../ToggleButton';

test('切换按钮文本正确变更', async () => {
  render(<ToggleButton />);
  const button = screen.getByText('Light Mode');
  
  // 等待点击操作及所有关联更新完成
  await userEvent.click(button);
  
  expect(screen.getByText('Dark Mode')).toBeInTheDocument();
});

2. 处理组件内的延迟更新

如果你的ToggleButton组件内部存在异步逻辑(比如useEffect里的Promise、setTimeout),需要用waitFor或findBy*查询来等待这些更新完成:

test('处理异步更新的按钮文本切换', async () => {
  render(<ToggleButton />);
  const button = screen.getByText('Light Mode');
  
  await userEvent.click(button);
  
  // 等待异步更新完成后再断言
  await waitFor(() => {
    expect(screen.getByText('Dark Mode')).toBeInTheDocument();
  });
  
  // 或者用findByText(本身就是waitFor的封装)
  // await screen.findByText('Dark Mode');
});

3. 检查组件是否存在未处理的异步逻辑

如果上述调整后仍有警告,需要排查组件代码:

  • 有没有在状态变更后触发延迟执行的逻辑(比如setTimeout、requestAnimationFrame)
  • 有没有第三方库的异步回调导致状态更新
  • 确保所有状态更新都在React的渲染周期内触发

内容的提问来源于stack exchange,提问作者Jacobdo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 05:02:16