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
相关产品推荐
相关产品推荐

