如何在执行matchSnapshot测试前等待API返回结果
React异步请求组件快照测试失败解决方案
问题根源
你当前的测试存在3个核心错误:
- 无效等待:
await mockGetMovies等待的是mock函数对象本身,不是函数执行后返回的Promise实例,完全没有等接口返回、状态更新的逻辑执行完成 - 不必要的手动act包裹:你使用的@testing-library/react内部已经自动对所有更新逻辑做了act封装,手动包裹反而容易导致状态更新没有被正确捕获
- 未等待异步重渲染完成就执行快照:组件拿到接口返回后需要执行setMovies触发重渲染,你在重渲染执行前就对container做了快照,自然只能拿到加载中状态
修正后的测试代码
import React from 'react'; import { render, screen } from '@testing-library/react'; import { getMovies } from '../app/requests/getMovies'; import Home from '.'; jest.mock('../app/requests/getMovies'); const mockGetMovies = getMovies as jest.Mock; describe('/', () => { beforeEach(() => { mockGetMovies.mockResolvedValue([ { Title: 'Titanic', }, ]); }); it('should render the homepage', async () => { const { container } = render(<Home />); // 异步等待目标元素渲染完成,内部自动处理act逻辑 await screen.findByText('Movies (1)'); // 此时生成的快照就是加载完成后的预期状态 expect(container).toMatchInlineSnapshot(` <div> <main> <h1> Movies (1) </h1> </main> </div> `); }); });
方案说明
findBy*是React Testing Library提供的异步查询API,内部自动结合了等待逻辑和act封装,会持续查询直到匹配到对应元素或者超时,刚好适配组件异步请求后重渲染的场景- 如果你不想依赖文本查询,也可以用
waitFor包裹断言逻辑,效果完全一致:await waitFor(() => { expect(screen.getByRole('heading', { name: /Movies \(1\)/ })).toBeInTheDocument(); })
内容的提问来源于stack exchange,提问作者coding1223322
相关产品推荐
相关产品推荐

