如何使用React Testing Library模拟基于Hook实现的服务返回数据
问题修复方案
你目前的mock失败主要是核心实现不匹配导致的,按如下步骤修改即可:
1. 修正jest.mock的调用规则与返回结构
jest.mock不能放在beforeEach内部,必须放在测试文件顶级作用域,jest的模块mock提升机制不支持块级调用- 你的
usePanelClient调用后会返回一个函数,二次调用才会拿到接口方法集合,mock的结构要和原实现完全对齐 - 原axios请求返回的是包含
data字段的响应对象,mock的getPendingAwards返回值要符合该结构
2. 补充缺失的依赖mock
组件引入了useUtils自定义Hook,未mock会导致解构formatCurrency时报错,需要同步mock该依赖。
3. 异步逻辑需要等待完成
组件内的接口调用是异步操作,断言数据渲染前需要等待异步任务执行完毕,使用React Testing Library的waitFor工具即可。
修正后的完整测试代码
import React from 'react' import { render, waitFor } from '@testing-library/react' import { Router } from 'react-router-dom' import { createMemoryHistory } from 'history' import PendingAwards from './PendingAwards' // 模块mock必须放在顶级作用域 jest.mock('../../../clients/PanelClient/usePanelClient', () => { return jest.fn(() => { // 对齐原Hook返回结构:usePanelClient()返回一个函数 const mockData = { quantity: 820, amount: 26681086.12, commission: 5528957.841628, } return () => ({ // 对齐axios返回结构:{data: 实际数据} getPendingAwards: jest.fn(() => Promise.resolve({ data: mockData })), }) }) }) // 补充mock useUtils依赖 jest.mock('../../../hooks/useUtils', () => ({ __esModule: true, default: () => ({ formatCurrency: (val) => `R$ ${val.toFixed(2).replace('.', ',')}` }) })) // 静态资源mock(如果你的测试环境已默认配置svg mock可以省略) jest.mock('../../../assets/img/panel/ico-file.svg', () => 'mock-file-icon') jest.mock('../../../assets/img/panel/ico-exclamation.svg', () => 'mock-exclamation-icon') jest.mock('../../../assets/img/panel/awesome-pause-circle.svg', () => 'mock-pause-icon') describe('PendingAwards Component', () => { it('组件正常挂载且正确渲染待奖励数据', async () => { const history = createMemoryHistory() const { getByText } = render( <Router history={history}> <PendingAwards /> </Router>, ) // 等待异步接口返回、数据渲染完成 await waitFor(() => { expect(getByText('820')).toBeInTheDocument() expect(getByText('R$ 26681086,12')).toBeInTheDocument() }) }) it('地址栏包含scrollTo参数时触发滚动到顶部', () => { const history = createMemoryHistory() history.push({ search: '?scrollTo=pendingAwards', }) window.scrollTo = jest.fn() render( <Router history={history}> <PendingAwards /> </Router>, ) expect(window.scrollTo).toHaveBeenCalledWith({ behavior: 'smooth', top: 0 }) }) })
额外注意点
如果仍有路由相关报错可以检查你的React Router版本,v6的Router组件用法和v5不同,替换为MemoryRouter组件即可直接使用。
内容的提问来源于stack exchange,提问作者Matheus Ribeiro
相关产品推荐
相关产品推荐

