如何使用Vitest模拟RTK Query Hook?
解决Vitest模拟RTK Query Hook时返回undefined的问题
问题分析
你遇到的TypeError: Cannot destructure property 'data' of 'useGetFieldValueQuery(...)' as it is undefined错误,说明useGetFieldValueQuery被调用后返回了undefined。虽然你已经确认mock路径正确且能看到Mock called日志,但大概率是mock的导出结构与实际模块的导出方式不匹配,或者mock函数的返回值未被正确绑定。
解决方案
方案1:显式在测试用例中设置mock返回值
避免模块加载顺序导致的mock初始化问题,先在vi.mock中仅定义空的mock函数,再在测试用例里显式设置返回值:
import { vi } from "vitest" import { ReactElement } from "react" import { render, screen } from "@testing-library/react" import { FormProvider, useForm } from "react-hook-form" import SelectField from "./SelectField" import { useGetFieldValueQuery } from "path/to/rtkQueryCreateApi" // 仅初始化mock函数,不设置返回值 vi.mock("path/to/rtkQueryCreateApi", () => ({ useGetFieldValueQuery: vi.fn(), })) const mockElement = { label: "Test Select Label", fieldName: "testField", componentType: "select", // 注意:原componentType为checkbox,与SelectField组件不匹配,改为select id: "test-select", width: 3, } type WrapperProps = { children: ReactElement } describe("SelectField Component", () => { it("renders options correctly from string filter", () => { // 在测试用例中显式设置mock的返回值 useGetFieldValueQuery.mockReturnValue({ data: { d: { results: [ { id: "1", text: "Option 1" }, { id: "2", text: "Option 2" }, ], }, }, isLoading: false, isError: false, isSuccess: true, error: null, refetch: vi.fn(), }) const Wrapper = ({ children }: WrapperProps) => { const methods = useForm() return <FormProvider {...methods}>{children}</FormProvider> } render( <Wrapper> <SelectField element={mockElement} errors={undefined} /> </Wrapper>, ) expect(screen.getByText("Option 1")).toBeInTheDocument() expect(screen.getByText("Option 2")).toBeInTheDocument() }) })
方案2:匹配实际模块的导出结构
如果你的RTK Query API是默认导出API对象(而非直接命名导出hook),比如实际模块代码如下:
// path/to/rtkQueryCreateApi.ts const api = createApi({ /* 配置 */ }) export default api export const { useGetFieldValueQuery } = api
那么需要调整mock的结构,确保默认导出的对象包含目标hook:
vi.mock("path/to/rtkQueryCreateApi", () => ({ default: { useGetFieldValueQuery: vi.fn(() => ({ data: { d: { results: [ { id: "1", text: "Option 1" }, { id: "2", text: "Option 2" }, ], }, }, isLoading: false, isError: false, isSuccess: true, error: null, refetch: vi.fn(), })), }, // 同时保留命名导出(如果组件是直接导入hook的话) useGetFieldValueQuery: vi.fn(() => ({ /* 同上返回值 */ })), }))
额外注意点
你的mockElement中componentType设置为"checkbox",但组件是SelectField,这可能导致组件渲染复选框而非下拉选项,即使mock数据正确也无法找到预期文本,建议改为组件预期的类型(比如"select")。
内容的提问来源于stack exchange,提问作者user8467470
相关产品推荐
相关产品推荐

