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

如何使用Jest模拟React组件内部的函数?

解决React函数组件内部私有函数无法被Jest spyOn模拟的问题

问题根源

你遇到的错误本质是:getServiceHistory是函数组件内部的私有闭包函数,既不是组件的实例方法,也没有对外导出。你尝试通过<RolloutPage/>(React元素对象)去spy这个函数,而这个元素对象里根本不存在getServiceHistory属性,自然会返回undefined导致报错。

可行解决方案

方案1:将函数提取为独立导出的工具函数

把getServiceHistory从组件内部抽离出来,单独导出,这样测试时可以直接mock这个函数:

组件代码修改:

// rolloutPage.js
export const getServiceHistory = async (serviceName, account) => {
  return await fetch(/* 原有请求逻辑 */);
};

const RolloutPage = () => {
  // 直接使用导出的函数
  return <Page>{/* 组件原有内容 */}</Page>;
};
export default withRouter(RolloutPage);

测试代码修改:

import { getServiceHistory } from './rolloutPage';
import RolloutPage from './rolloutPage';

test('测试组件业务逻辑', () => {
  jest.spyOn(getServiceHistory).mockImplementation(() => 
    Promise.resolve({ json: () => Promise.resolve({ serviceTimelineDataMock }) })
  );

  render(
    <MemoryRouter>
      <RolloutPage />
    </MemoryRouter>
  );

  // 后续添加断言逻辑,比如验证数据渲染、函数调用情况等
});

方案2:直接Mock全局fetch(更推荐)

既然getServiceHistory的核心是调用fetch发起请求,直接mock全局的fetch API是更简洁的方式,无需修改组件代码:

测试代码:

import RolloutPage from './rolloutPage';

beforeEach(() => {
  // 全局mock fetch,模拟返回预期数据
  global.fetch = jest.fn(() => 
    Promise.resolve({ json: () => Promise.resolve({ serviceTimelineDataMock }) })
  );
});

afterEach(() => {
  // 测试后恢复mock,避免影响其他测试用例
  jest.restoreAllMocks();
});

test('测试组件业务逻辑', () => {
  render(
    <MemoryRouter>
      <RolloutPage />
    </MemoryRouter>
  );

  // 可额外断言fetch是否按预期调用
  expect(fetch).toHaveBeenCalled();
});

方案3:通过ref暴露内部函数(不推荐)

如果必须要直接mock组件内部的getServiceHistory(不建议,会增加组件与测试的耦合度),可以用forwardRef和useImperativeHandle将函数暴露给外部:

组件代码修改:

import { forwardRef, useImperativeHandle } from 'react';

const RolloutPage = forwardRef((props, ref) => {
  const getServiceHistory = async (serviceName, account) => {
    return await fetch(/* 原有请求逻辑 */);
  };

  // 仅暴露指定函数给外部ref
  useImperativeHandle(ref, () => ({
    getServiceHistory
  }));

  return <Page>{/* 组件原有内容 */}</Page>;
});
export default withRouter(RolloutPage);

测试代码修改:

import { render } from '@testing-library/react';
import { useRef } from 'react';
import RolloutPage from './rolloutPage';

test('测试组件业务逻辑', () => {
  const componentRef = useRef(null);

  render(
    <MemoryRouter>
      <RolloutPage ref={componentRef} />
    </MemoryRouter>
  );

  // 现在可以spy暴露出来的函数
  jest.spyOn(componentRef.current, 'getServiceHistory').mockImplementation(() => 
    Promise.resolve({ json: () => Promise.resolve({ serviceTimelineDataMock }) })
  );

  // 后续添加断言逻辑
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 03:52:42