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

React 18测试懒加载组件时消除act()警告的方法

React 18 懒加载组件测试中Suspended警告的解决方案

问题描述

参考React官方文档编写App组件测试用例,用act()包裹渲染逻辑后测试可正常通过,但当App包含React懒加载组件时,出现「Suspended资源加载完成事件未被act()包裹」的警告。尝试过await waitFor()、findBy()、移除act()等方案,均未解决,求React 18环境下的可行方案。

相关代码与环境

测试代码

import ReactDOM from 'react-dom/client';
import { act } from 'react-dom/test-utils';
import App from './App'
import { screen } from '@testing-library/react'

let container: HTMLElement;

beforeEach(() => {
  container = document.createElement('div');
  document.body.appendChild(container);
});

it('can render and update a counter', () => {
  act(() => {
    ReactDOM.createRoot(container).render(<App />);
  });
  const title = screen.getByText('My App');
  expect(title).toBeInTheDocument()
});

警告信息

Warning: A suspended resource finished loading inside a test, but the event was not wrapped in act(...).

When testing, code that resolves suspended data should be wrapped into act(...):

act(() => {
  /* finish loading suspended data */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act

setupTest.ts

import '@testing-library/jest-dom';

package.json依赖

"dependencies": {
    "@react-spring/web": "^9.4.5",
    "react": "^18.1.0",
    "react-dom": "^18.1.0",
    "styled-components": "^5.3.5"
 },
"devDependencies": {
    "@react-spring/types": "^9.4.5",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.2.0",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.5.1",
    "@types/react": "^18.0.9",
    "@types/react-dom": "^18.0.5",
    "@types/styled-components": "^5.1.25",
    "@typescript-eslint/eslint-plugin": "^5.36.1",
    "@typescript-eslint/parser": "^5.36.1",
    "eslint": "^8.23.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-import-resolver-typescript": "^3.5.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-prettier": "^4.2.1",
    "eslint-plugin-react": "^7.31.1",
    "eslint-plugin-react-hooks": "^4.6.0",
    "prettier": "^2.7.1",
    "react-scripts": "5.0.1",
    "typescript": "^4.6.4"
  }

环境信息

Node版本:16.16

解决方案

方案1:使用Testing Library内置render函数(推荐)

React Testing Library在React 18下已自动适配act()逻辑,包括懒加载组件的Suspend状态处理,无需手动包裹act():

import { render, screen } from '@testing-library/react'
import App from './App'

it('can render and update a counter', async () => {
  render(<App />);
  // 懒加载组件需异步加载,用findByText(异步查询)替代同步的getByText
  const title = await screen.findByText('My App');
  expect(title).toBeInTheDocument()
});

方案2:异步包裹act()处理Suspend状态

若必须手动使用ReactDOM.createRoot,需将渲染逻辑改为异步,等待Suspend资源加载完成:

import ReactDOM from 'react-dom/client';
import { act } from 'react-dom/test-utils';
import App from './App'
import { screen } from '@testing-library/react'

let container: HTMLElement;

beforeEach(() => {
  container = document.createElement('div');
  document.body.appendChild(container);
});

it('can render and update a counter', async () => {
  await act(async () => {
    ReactDOM.createRoot(container).render(<App />);
    // 等待Suspend资源加载完成的微任务执行
    await new Promise(resolve => setTimeout(resolve, 0));
  });
  const title = screen.getByText('My App');
  expect(title).toBeInTheDocument()
});

方案3:Mock懒加载组件(单元测试场景)

若测试仅关注App组件本身,可Mock懒加载组件避免触发Suspend状态:
假设App中使用const LazyComponent = React.lazy(() => import('./LazyComponent')),测试中Mock如下:

import { render, screen } from '@testing-library/react'
import App from './App'

// Mock懒加载组件
jest.mock('./LazyComponent', () => ({
  default: () => <div>Lazy Component Mock</div>
}));

it('can render and update a counter', () => {
  render(<App />);
  const title = screen.getByText('My App');
  expect(title).toBeInTheDocument()
});

关键原因说明

React 18中React.lazy加载组件会触发Suspend状态,手动同步act()无法覆盖异步加载完成后的状态更新。Testing Library的render和findBy*异步查询方法已适配React 18并发特性,能自动将所有UI变化包裹在act()中,解决警告问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 07:54:26