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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 16:20:15