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

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();
    })
    
  });
});

问题原因及修复方案

核心问题

  1. QueryKey匹配不命中:测试中硬编码了queryKey字符串,而组件使用的是QC.VENDOR_MEMBER_MANAGEMENT___GET_VENDOR_MEMBER_LIST常量,两者可能因拼写错误或常量值不一致导致Mock未触发,useQuery返回undefined。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 19:07:21