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

组件用具名导入时,如何用Jest spyOn监听useCurrentUser Hook?

解决方案

问题根源在于全局mock的写法导致具名导入的函数引用无法被jest.spyOn正确追踪,调整mock实现即可解决:

方法一:将全局mock改为可追踪的jest.fn

修改setupTests.ts里的mock,用jest.fn()包裹目标函数,让它成为Jest可追踪的mock函数:

// setupTests.ts
jest.mock('hooks', () => ({
  useCurrentUser: jest.fn(() => mockOwner), // 用jest.fn包裹原函数
}));

之后在测试用例中,直接修改这个mock函数的返回值即可,无需spyOn:

// component.test.ts
import { useCurrentUser } from 'hooks'; // 和组件保持一致的具名导入

test('delete organization', async () => {
  // 直接修改mock函数的返回值
  (useCurrentUser as jest.Mock).mockReturnValueOnce({
    ...mockOwner,
    tenantId: 2,
  });

  render(
    <MockedProvider>
      <GeneralSettings organization={{ ...mockOrganization }} />
    </MockedProvider>
  );

  expect(useCurrentUser).toHaveBeenCalledTimes(1);
  expect(await screen.findByTestId('delete-org')).toBeInTheDocument();
});

方法二:保留spyOn用法,调整全局mock结构

如果坚持使用spyOn,需要让mock模块导出可扩展的对象,结合原模块的导出结构:

// setupTests.ts
jest.mock('hooks', () => {
  // 保留原模块的其他导出
  const originalModule = jest.requireActual('hooks');
  return {
    ...originalModule,
    useCurrentUser: jest.fn(() => mockOwner),
  };
});

测试用例中正常使用spyOn即可,不管组件是具名还是整体导入都能生效:

// component.test.ts
import * as hooks from 'hooks';

test('delete organization', async () => {
  const spy = jest.spyOn(hooks, 'useCurrentUser').mockReturnValueOnce({
    ...mockOwner,
    tenantId: 2,
  });

  render(
    <MockedProvider>
      <GeneralSettings organization={{ ...mockOrganization }} />
    </MockedProvider>
  );

  expect(spy).toHaveBeenCalledTimes(1);
  expect(await screen.findByTestId('delete-org')).toBeInTheDocument();
});

核心逻辑

当组件使用具名导入时,会直接绑定模块导出的useCurrentUser属性。如果全局mock返回的是普通函数,这个引用是固定不可修改的;换成jest.fn()后,函数本身是Jest可追踪的对象,不管是直接修改返回值还是用spyOn替换实现,都能同步到组件的引用上。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 21:47:21