Jest spyOn useMutation遇类型错误,求助模拟数据使用方案
问题
我是Jest测试新手,尝试在测试中使用jest.spyOn监听ReactQuery的useMutation,测试代码如下:
it('should execute custom onSuccess callback', async () => { const onSuccess = jest.fn(); const spyQuery = jest.spyOn(ReactQuery, 'useMutation').mockReturnValue({mutate: onSuccess}); const user = userEvent.setup(); const contextValue = { user: mockedUser, folders: mockedFolders }; render(<main role="main"></main>); renderWithAllProviders( <AddressBookProvider {...contextValue}> <AddToAddressBook /> </AddressBookProvider> ); //data to submit// const submitButton = screen.getByRole('button', { name: /MOBILE_WEB_GENERAL_DONE/i, }); await user.click(submitButton); expect(spyQuery).toHaveBeenCalledTimes(1);
运行时出现类型不匹配错误:
Argument of type '{ mutate: jest.Mock<any, any>; }' is not assignable to parameter of type 'UseMutationResult<unknown, unknown, unknown, unknown>'.
测试中需要使用mockedUser和mockedFolders模拟数据,求解决帮助。
解决方法
1. 补全UseMutationResult必填字段
ReactQuery的useMutation返回的UseMutationResult是包含多个属性的强类型,仅返回mutate会触发TypeScript类型校验错误。需要补全核心必填字段,示例如下:
import { UseMutationResult } from '@tanstack/react-query'; // 模拟完整的UseMutationResult结构 const spyQuery = jest.spyOn(ReactQuery, 'useMutation').mockReturnValue({ mutate: onSuccess, mutateAsync: jest.fn(), isLoading: false, isError: false, isSuccess: false, error: null, data: null } as UseMutationResult);
也可以用类型断言快速跳过校验,但补全字段更贴近真实运行场景,避免后续测试出现隐性问题。
2. 优化测试逻辑
- 移除重复的
render调用:你先渲染了空<main>,后续又用renderWithAllProviders渲染目标组件,这会导致DOM混乱,保留后者即可。 - 强化断言逻辑:除了验证
useMutation的调用次数,直接断言onSuccess的执行情况,更贴合测试目标。
调整后的完整测试代码:
import { UseMutationResult } from '@tanstack/react-query'; it('should execute custom onSuccess callback', async () => { const onSuccess = jest.fn(); const mockUseMutation = jest.spyOn(ReactQuery, 'useMutation') .mockReturnValue({ mutate: jest.fn().mockImplementation(() => { // 手动触发onSuccess,模拟mutation成功后的流程 onSuccess(); }), mutateAsync: jest.fn(), isLoading: false, isError: false, isSuccess: false, error: null, data: null } as UseMutationResult); const user = userEvent.setup(); const contextValue = { user: mockedUser, folders: mockedFolders }; // 仅保留一次渲染 renderWithAllProviders( <AddressBookProvider {...contextValue}> <AddToAddressBook /> </AddressBookProvider> ); // 补充表单填写逻辑(替换你的//data to submit//注释) const submitButton = screen.getByRole('button', { name: /MOBILE_WEB_GENERAL_DONE/i, }); await user.click(submitButton); // 双重验证:useMutation被调用,且onSuccess执行 expect(mockUseMutation).toHaveBeenCalledTimes(1); expect(onSuccess).toHaveBeenCalledTimes(1); });
3. 确保模拟数据类型匹配
mockedUser和mockedFolders需要与AddressBookProvider上下文要求的类型完全匹配,比如上下文要求user包含id、username等字段,模拟数据必须对应这些字段,避免上下文传递时出现类型错误。
内容的提问来源于stack exchange,提问作者shivetay
相关产品推荐
相关产品推荐

