Jest mock React类组件方法报type is invalid错误如何解决
问题根源
你当前的mock写法存在两个核心问题,直接触发了报错:
jest.mock工厂函数返回的普通对象丢失了原模块的default导出:原组件通过export default导出类,你直接展开jest.requireActual返回的模块对象后,导入的MyDataTable实际上是包含default属性的普通模块对象,不是组件类本身。React渲染时接收到object类型的组件,就会抛出「type is invalid」的类型错误。- 你尝试在模块层面添加的
loadIframe属性不会生效:loadIframe是类的实例原型方法,不是模块导出的静态方法,就算修正了导出问题,组件实例调用的还是原型链上的原有方法,无法达到拦截效果。
正确实现方案
不要用jest.mock整体mock组件模块,直接在类原型上监听、mock实例方法即可,既不会破坏组件正常导出,也能精准拦截方法调用,阻止真实iframe加载。
修改后的测试代码:
import "@testing-library/jest-dom"; import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import axios from "axios"; import MyDataTable from "../../components/DataTable/MyDataTable"; jest.mock("axios"); beforeEach(() => { // 监听类原型上的loadIframe方法,替换为mock实现 jest.spyOn(MyDataTable.prototype, "loadIframe").mockImplementation((id) => { // 此处可自定义mock逻辑,留空即可完全阻止原有setState执行,避免iframe加载 // 若需要验证iframe渲染逻辑,可手动设置符合预期的state }); }); afterEach(() => { // 恢复原有方法,避免mock污染其他测试用例 jest.restoreAllMocks(); }); describe("My tests", () => { it("should load iframe on row click", async () => { const data = [ ["row 1, col 1", "row 1, col 2"], ["row 2, col 1", "row 2, col 2"] ]; axios.post.mockResolvedValue({ data }); render(<MyDataTable id="test_id"/>); await waitFor(() => expect(axios.post).toHaveBeenCalled()); userEvent.click(screen.getAllByRole("gridcell")[0]); // 可直接断言mock方法被调用 expect(MyDataTable.prototype.loadIframe).toHaveBeenCalled(); // 若mock中保留了iframe渲染逻辑,再添加DOM存在性断言即可 }); });
可选的整模块mock写法(不推荐)
如果必须使用jest.mock整体mock模块,需要手动继承原类重写实例方法,同时保留default导出,维护成本更高:
jest.mock("../../components/DataTable/MyDataTable", () => { const actualModule = jest.requireActual("../../components/DataTable/MyDataTable"); const OriginalComponent = actualModule.default; return { ...actualModule, default: class MockedDataTable extends OriginalComponent { loadIframe = jest.fn((id) => { // 自定义mock逻辑 }) } } });
内容的提问来源于stack exchange,提问作者Clunis
相关产品推荐
相关产品推荐

