组件用具名导入时,如何用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
相关产品推荐
相关产品推荐

