React Testing Library渲染VendorTable报错:元素类型无效(undefined)
问题排查:VendorTable单元测试useQuery Mock导致组件渲染错误
我为VendorTable组件编写了单元测试,但持续出现错误,怀疑是useQuery的Mock设置存在问题。
报错信息
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
组件代码(vendorTable.tsx)
import React, { useState } from "react"; import { Table } from "antd"; import * as QC from "api/Cache/VendorMemberManagement"; import * as Request from "api/Resources/VendorMemberManagement"; import { useQuery } from "react-query"; const cols = [ { key: "colA", title: "COL A", dataIndex: "colA", width: 180, }, { key: "colB", title: "COL B", dataIndex: "colB", width: 180, }, { key: "colC", title: "COL C", dataIndex: "colC", width: 180, }, ] const VendorTable = () => { const [dataList, setDataList] = useState([]); const vendorMemberList = useQuery( [QC.VENDOR_MEMBER_MANAGEMENT___GET_VENDOR_MEMBER_LIST], async () => { return await Request.getVendorMemberList(); }, { onSuccess: async (data) => { setDataList(data); }, } ); return ( <Table columns={cols} dataSource={dataList} pagination={false} scroll={{ y: "calc(100vh - 228px)" }} /> ) }; export default VendorTable;
测试代码(vendorTable.spec.tsx)
import React from "react"; import { render, waitFor, screen } from "@testing-library/react"; import { QueryClient, QueryClientProvider, } from "react-query"; import VendorTable from "../VendorTable"; import { RecoilRoot } from "recoil"; jest.mock("react-query", () => { return { ...jest.requireActual("react-query"), useQuery: jest .fn() .mockImplementation((queryKey) => { if (queryKey[0] === "VENDOR_MEMBER_MANAGEMENT___GET_VENDOR_MEMBER_LIST") { return { data: [ { colA: "Test_A", colB: "Test_B", colC: "Test_C", }, ], isFetching: false, isSuccess: true, }; } }), }; }); describe("VendorTable", () => { test("VendorTable component renders correctly", async () => { const queryClient = new QueryClient(); const { getByText } = render( <RecoilRoot> <QueryClientProvider client={queryClient}> <VendorTable /> </QueryClientProvider> </RecoilRoot> ); await waitFor(() => { expect(getByText("COL A")).toBeInTheDocument(); }) }); });
问题原因及修复方案
核心问题
- QueryKey匹配不命中:测试中硬编码了queryKey字符串,而组件使用的是
QC.VENDOR_MEMBER_MANAGEMENT___GET_VENDOR_MEMBER_LIST常量,两者可能因拼写错误或常量值不一致导致Mock未触发,useQuery返回undefined。 - Mock无默认返回值:当useQuery的Mock未匹配到目标queryKey时,会返回undefined,react-query内部依赖useQuery返回的对象结构,进而引发组件渲染错误。
修复方案
方案一:修正useQuery Mock(快速解决)
- 导入
QC常量,用它来匹配queryKey,避免硬编码错误。 - 给Mock添加默认返回值,确保始终返回符合react-query规范的对象。
修改后的Mock部分:
import * as QC from "api/Cache/VendorMemberManagement"; jest.mock("react-query", () => { return { ...jest.requireActual("react-query"), useQuery: jest.fn().mockImplementation((queryKey) => { if (queryKey[0] === QC.VENDOR_MEMBER_MANAGEMENT___GET_VENDOR_MEMBER_LIST) { return { data: [ { colA: "Test_A", colB: "Test_B", colC: "Test_C" }, ], isFetching: false, isSuccess: true, }; } // 默认返回有效结构 return { data: [], isFetching: false, isSuccess: false }; }), }; });
方案二:Mock请求函数(推荐)
直接MockRequest.getVendorMemberList请求函数,而非useQuery,这样测试更贴近组件实际逻辑,避免Mock框架内部API的风险。
修改后的测试代码:
import React from "react"; import { render, waitFor, screen } from "@testing-library/react"; import { QueryClient, QueryClientProvider } from "react-query"; import VendorTable from "../VendorTable"; import { RecoilRoot } from "recoil"; import * as Request from "api/Resources/VendorMemberManagement"; // Mock请求函数 jest.mock("api/Resources/VendorMemberManagement", () => ({ getVendorMemberList: jest.fn().mockResolvedValue([ { colA: "Test_A", colB: "Test_B", colC: "Test_C" }, ]), })); describe("VendorTable", () => { test("VendorTable component renders correctly", async () => { const queryClient = new QueryClient(); render( <RecoilRoot> <QueryClientProvider client={queryClient}> <VendorTable /> </QueryClientProvider> </RecoilRoot> ); await waitFor(() => { expect(screen.getByText("COL A")).toBeInTheDocument(); expect(screen.getByText("Test_A")).toBeInTheDocument(); }); }); });
内容的提问来源于stack exchange,提问作者Lin FangTzu
相关产品推荐
相关产品推荐

