如何在Jest中断言Apollo useQuery查询已被调用指定次数?
解决useQuery调用次数断言失败的问题
错误原因
你当前的useQuery mock方式有误:你把useQuery设成了一个普通函数,它的返回值是jest.fn,但useQuery本身并不是Jest的mock/spy函数。而toHaveBeenCalledTimes这类匹配器只能作用于mock/spy函数,所以会抛出类型错误。
修复方案
方案1:修改jest.mock的定义,让useQuery本身成为mock函数
直接将useQuery赋值为jest.fn(),并返回组件渲染所需的hook返回值(比如loading、data等):
jest.mock('@apollo/client', () => { const actual = jest.requireActual('@apollo/client'); return { ...actual, // 让useQuery本身是mock函数,同时返回组件需要的状态 useQuery: jest.fn(() => ({ loading: false, data: {}, // 根据你的业务场景替换为真实测试数据 error: null })), }; }); const mountComponent = () => { return render( <MockedProvider mocks={mocks} addTypename={false}> <MyComponent /> </MockedProvider> ); }; describe('MyComponent', () => { it('should only call the query 1 time', async () => { mountComponent(); // 如果组件是同步渲染时调用useQuery,直接断言即可 expect(useQuery).toHaveBeenCalledTimes(1); // 若useQuery是异步触发(比如依赖状态变化),再用waitFor包裹 // await waitFor(() => { // expect(useQuery).toHaveBeenCalledTimes(1); // }); }); });
方案2:使用jest.spyOn来监听useQuery
如果你更倾向于保留原模块的其他实现,仅监听useQuery,可以用spyOn替代jest.mock:
import { useQuery } from '@apollo/client'; const mountComponent = () => { return render( <MockedProvider mocks={mocks} addTypename={false}> <MyComponent /> </MockedProvider> ); }; describe('MyComponent', () => { let useQuerySpy; beforeEach(() => { // 创建spy并mock返回值 useQuerySpy = jest.spyOn(require('@apollo/client'), 'useQuery') .mockReturnValue({ loading: false, data: {}, error: null }); }); afterEach(() => { // 测试后恢复原函数,避免影响其他测试 useQuerySpy.mockRestore(); }); it('should only call the query 1 time', async () => { mountComponent(); expect(useQuerySpy).toHaveBeenCalledTimes(1); }); });
关键注意点
- 确保
useQuery本身是Jest的mock/spy函数,而非返回mock函数的普通函数 - 根据组件的渲染逻辑(同步/异步)决定是否需要
waitFor - mock的返回值要匹配组件的依赖(比如组件依赖
loading状态显示内容,就需要正确设置该字段)
内容的提问来源于stack exchange,提问作者que1326
相关产品推荐
相关产品推荐

