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

Jest测试报错:LoginForm组件更新未包裹在act(...)中

解决测试中"更新未包裹在act(...)中"的警告

问题根源

这个警告源于组件的状态更新(比如setLoggedIn)、Toast提示这类异步操作,在测试执行时未被React测试渲染器正确追踪。你的测试里有两处容易触发该警告的场景:

  • 登录成功后的状态切换与Toast提示
  • 登出后的状态切换与Toast提示

修复步骤

1. 调整Axios Mock时序,确保登录请求同步完成

你当前是先点击登录按钮再设置Mock实现,这会导致登录请求的Promise处于pending状态后才被resolve,引发异步更新未被追踪。将Mock设置移到登录点击之前:

it("should remove accessToken from localStorage on logout", async () => {
  // 提前设置登录请求的Mock
  mockedAxios.post.mockImplementation(() =>
    Promise.resolve({
      status: 200,
      data: { accessToken: "eYagkaogk...", refreshToken: "eyAagga..." },
    })
  );

  render(<Login />);
  const email = await screen.findByRole("textbox");
  const password = await screen.findByPlaceholderText("Password");
  const loginBtn = await screen.findByRole("button", { name: /login/i });

  fireEvent.change(email, { target: { value: "email" } });
  fireEvent.change(password, { target: { value: "password" } });
  fireEvent.click(loginBtn);

  // 等待登录状态更新完成,确保Logout按钮渲染
  const logoutBtn = await screen.findByRole("button", { name: /logout/i });
  const removeItem = jest.spyOn(Storage.prototype, "removeItem");

  fireEvent.click(logoutBtn);

  // 等待登出后的所有异步更新完成
  await waitFor(() => {
    expect(removeItem).toHaveBeenCalledWith("accessToken");
    // 额外验证状态更新,确保组件渲染完成
    expect(screen.queryByRole("button", { name: /login/i })).toBeInTheDocument();
  });

  // 清理Mock,避免影响其他测试
  jest.restoreAllMocks();
});

2. 处理Toast组件的异步渲染

toast.success/toast.error是异步渲染的组件,即使状态更新完成,Toast的DOM操作可能仍在进行。可以在测试环境中禁用Toast的延迟或直接Mock Toast组件:

在测试文件顶部添加:

// Mock Toast组件,避免异步渲染引发警告
jest.mock('react-toastify', () => ({
  ...jest.requireActual('react-toastify'),
  toast: {
    success: jest.fn(),
    error: jest.fn(),
  },
  ToastContainer: () => null,
}));

3. 显式包裹复杂异步操作(可选)

如果上述步骤仍未解决问题,可尝试用act显式包裹触发状态更新的操作:

await act(async () => {
  fireEvent.click(logoutBtn);
});

注:React Testing Library的fireEvent和waitFor已内置act处理,大部分场景下无需手动包裹,但复杂异步场景可尝试该方案。

关键注意点

  • 始终先设置Mock,再触发依赖Mock的操作,避免异步时序问题
  • 用await screen.findBy*替代getBy*等待组件渲染完成,确保状态更新后再执行下一步
  • 测试完成后清理Mock,避免测试用例间的污染

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:15:27