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

React Testing Library中Mock自定义Hook渲染组件失败求助

问题排查:React组件测试Mock自定义Hook后无法找到预期文本

问题描述

我在测试一个使用自定义Hook(useCollection)的React组件时遇到问题。该Hook从Firestore数据库获取数据并返回对象数组,组件通过array.map将数据渲染为列表。我编写测试用例Mock了该Hook,使其返回包含{id:"Belfast"}的对象数组,但测试报错TestingLibraryElementError: Unable to find an element with the text: Belfast.,无法找到预期文本。

组件代码

import React from "react";
import useCollection from "../CustomHooks/UseCollection";

export default function MyComponent() {
  const { collectionData } = useCollection('Location', null);

  return (
    <div>
      <ul>{collectionData.map((item) => (<li key={item.id}>{item.id}</li>))}</ul>
    </div>
  );
}

原测试代码

import { render, screen, waitFor } from '@testing-library/react';
import MyComponent from './MyComponent';
import useCollection from '../CustomHooks/UseCollection';

it('render my component', () => {
    screen.debug()
    const mockUseCollection = jest.fn(() => ({
        collectionData: [{id:"Belfast"},{id:"Derry"}],
    }));

    jest.mock('../CustomHooks/UseCollection', () => ({
        useCollection: mockUseCollection,
    }));

    const { getByText } = render(<MyComponent />);
    expect(getByText("Belfast")).toBeInTheDocument();
})

问题原因

  1. jest.mock执行时机错误:jest.mock会被自动提升到模块代码最顶部执行,在测试函数内部调用时,组件已经导入了原始的useCollection Hook,导致Mock未生效。
  2. Mock导出方式不匹配:组件中useCollection是默认导入,但原测试代码按命名导出的方式Mock,导致组件实际使用的还是原始Hook,而非自定义的mock函数。

解决方案

方案1:将jest.mock移到模块顶部,匹配默认导出

调整测试代码结构,确保Mock在组件导入前执行,同时正确模拟默认导出:

import { render, screen } from '@testing-library/react';

// 先执行Mock,再导入组件
jest.mock('../CustomHooks/UseCollection', () => ({
  __esModule: true, // 标记为ES模块,处理默认导出逻辑
  default: jest.fn(() => ({
    collectionData: [{id:"Belfast"},{id:"Derry"}],
  })),
}));
import MyComponent from './MyComponent';

it('renders the component with mocked data', () => {
    render(<MyComponent />);
    expect(screen.getByText("Belfast")).toBeInTheDocument();
    expect(screen.getByText("Derry")).toBeInTheDocument();
})

方案2:动态Mock(适用于多测试用例需不同返回值的场景)

如果需要在不同测试用例中返回不同的Mock数据,可使用jest.doMock并重新导入组件:

import { render, screen } from '@testing-library/react';

it('renders the component with mocked data', () => {
    const mockUseCollection = jest.fn(() => ({
        collectionData: [{id:"Belfast"},{id:"Derry"}],
    }));

    jest.doMock('../CustomHooks/UseCollection', () => ({
        __esModule: true,
        default: mockUseCollection,
    }));

    // 重新导入组件,确保使用Mock后的Hook
    const MyComponent = require('./MyComponent').default;

    render(<MyComponent />);
    expect(screen.getByText("Belfast")).toBeInTheDocument();
})

注意事项

  • 确保collectionData初始值不为空:若真实Hook在加载阶段返回空数组,Mock需保证返回有数据的数组,避免map调用报错。
  • 优先使用screen.getByText:这是Testing Library推荐的写法,无需解构,更直观。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 12:53:12