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

Jest快照测试如何等待含异步请求的React组件渲染完成

异步请求React组件测试快照异常解决方案

问题场景

测试包含异步fetch逻辑的React组件时,快照始终捕获加载态内容,无法拿到接口返回后的最终渲染结果,同时控制台抛出act相关警告。

被测组件示例

export default function Page() {
    const [result, setResult] = useState();
    // 注意:原示例代码未声明isLoading状态,实际使用需自行补充加载态逻辑
    async function initialize() {
       const response = api.fetchData();
       setResult(response);
    }

    useEffect(() => {
        initialize();
    }, []);

    return (isLoading ? (
        <div>Fetching Data...</div>
    ) : (
        <div className="page-result-name">{result.name}</div>
    )
}

初始错误测试写法

test('Page rendering test.', async () => {
    jest.spyOn(api, 'fetchData').mockResolvedValue({ name: 'User 1'});

    const pageRendering = renderer.create(<Page />);
    // 缺失正确的异步等待逻辑,提前生成快照
    expect(pageRendering.toJSON()).toMatchSnapshot();
});

核心问题表现

  • 快照始终匹配Fetching Data...加载态,未捕获接口返回后的最终DOM结构
  • 控制台抛出警告:Warning: It looks like you're using the wrong act() around your test interactions

可行解决方案

方案1:使用react-test-renderer自带的异步act方法

react-test-renderer提供了异步act API,可包裹所有触发组件状态更新的操作,等待所有重渲染完成后再生成快照,不会触发act警告:

import renderer, { act } from 'react-test-renderer';
import Page from './Page';
import api from './api';

test('Page rendering test.', async () => {
    jest.spyOn(api, 'fetchData').mockResolvedValue({ name: 'User 1'});
    
    let pageRendering;
    // 将组件创建、异步更新逻辑全部包裹在act回调中
    await act(async () => {
        pageRendering = renderer.create(<Page />);
    });

    // 此时异步请求、状态更新、重渲染全部完成,生成最终快照
    expect(pageRendering.toJSON()).toMatchSnapshot();
});

注意:使用react-test-renderer创建的组件不会挂载到全局document对象上,不要尝试通过document.querySelector等全局API查找节点,会导致查询始终失败。

方案2:使用@testing-library/react工具链

如果习惯使用@testing-library/react的测试API,无需额外引入react-test-renderer,等待目标节点渲染完成后直接通过返回的container生成快照即可:

import { render, waitFor } from '@testing-library/react';
import Page from './Page';
import api from './api';

test('Page rendering test.', async () => {
    jest.spyOn(api, 'fetchData').mockResolvedValue({ name: 'User 1'});
    
    const { container } = render(<Page />);

    // 等待目标内容渲染完成,确认异步逻辑执行完毕
    await waitFor(() => {
        expect(container.querySelector('.page-result-name').textContent).toContain('User 1');
    });

    // 基于container生成快照
    expect(container.firstChild).toMatchSnapshot();
});

常见踩坑点

  • 不要在异步逻辑执行完成前调用toJSON()或生成快照,否则只能捕获到初始加载态
  • 所有触发组件状态更新的操作(初始化触发的useEffect异步请求、用户交互事件等),要么包裹在act回调中,要么使用@testing-library封装的工具方法,否则会触发act警告
  • 补全被测组件缺失的isLoading状态定义:初始值设为true,接口返回后设为false,避免渲染result.name时出现result为undefined的报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 22:01:13