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

如何在Vitest中Mock React Query的useFetchQueries Hook并测试组件

在Vitest中Mock自定义Hook测试Product组件

问题背景

我写了下面这些React组件和自定义Hook代码,想在Vitest里Mock useFetchQueries返回的数据来测试Product组件,已经写了部分Mock代码,但不知道怎么正确用到测试里。

Product组件代码

export const Product = () => {
  const navigate = useNavigate()
  const { id } = useParams()
  const { data } = useFetchQueries()
  return (
    <Modal>
      <Box>
        {data.data
          .filter((elem: TableElemType) => elem.id.toString() === id)
          .map((elem: TableElemType) => {
            return <ProductData data={elem} key={elem.id} />
          })}
      </Box>
    </Modal>
  )
}

useFetchQueries Hook代码

export const useFetchQueries = () => {
  const fetcher = async () => {
    const res = await fetch(`https://reqres.in/api/products`)
      .then((res) => res.json())
      .then((data) => {
        return data
      })
      .catch((err) => {
        return err.message
      })
    console.log(res)
    return res
  }
  return useQuery(['products'], async () => fetcher())
}

我写的Mock代码

vi.mock('./useFetchQueries', () => ({
    useFetchQueries: vi.fn().mockReturnValue({ data: { data: ['string'] } }),
}))

describe('ProducData', () => {
    it('if renders proper data', async () => {
        render(renderWithRouter(<Product />, '/5'))
        expect(useFetchQueries).toHaveBeenCalled()
    })
})

解决方案

1. 修正Mock数据结构

你的useFetchQueries返回的是react-query的useQuery结果,而真实接口返回的data.data是产品对象数组,所以Mock的数据要和真实结构匹配,不能用['string'],得换成符合TableElemType的对象数组:

vi.mock('./useFetchQueries', () => ({
  useFetchQueries: vi.fn().mockReturnValue({
    data: {
      data: [
        { id: 5, name: '测试产品5', /* 其他符合TableElemType的字段 */ },
        { id: 6, name: '测试产品6', /* 其他字段 */ }
      ]
    }
  })
}))

2. 完善测试逻辑

要确保路由参数正确传递,等待组件渲染完成,还要断言内容是否正确渲染:

import { render, screen, waitFor } from '@testing-library/react'
import { Product } from './Product'
import { useFetchQueries } from './useFetchQueries'
import renderWithRouter from './path-to-your-renderWithRouter'

vi.mock('./useFetchQueries')

describe('Product组件', () => {
  it('渲染匹配ID的产品数据', async () => {
    // TypeScript类型断言,避免类型报错
    const mockUseFetchQueries = useFetchQueries as jest.Mock
    mockUseFetchQueries.mockReturnValue({
      data: {
        data: [
          { id: 5, name: '测试产品5', description: '这是测试产品' },
          { id: 6, name: '测试产品6', description: '另一个测试产品' }
        ]
      }
    })

    // 用你封装的renderWithRouter渲染组件,传递路径/5(对应id=5)
    render(renderWithRouter(<Product />, '/5'))

    // 等待异步数据渲染完成,查询匹配的产品名称
    const targetProduct = await screen.findByText('测试产品5')
    expect(targetProduct).toBeInTheDocument()

    // 断言不渲染ID不匹配的产品
    expect(screen.queryByText('测试产品6')).not.toBeInTheDocument()

    // 验证Hook确实被调用了
    expect(mockUseFetchQueries).toHaveBeenCalled()
  })
})

3. 注意点

  • 如果你的组件会处理useQuery的加载状态(比如显示loading),可以在Mock里加上isLoading: false,避免组件一直处于加载状态
  • 确保renderWithRouter正确配置了React Router环境,比如用<MemoryRouter>包裹组件,并且能正确解析路径参数
  • TypeScript项目里,需要对Mock的Hook做类型断言,避免类型不兼容的报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:15:38