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

使用MockProvider模拟useMutation时触发InvariantError求助

Apollo Client MockProvider模拟useMutation触发InvariantError排查

问题背景

已成功使用Apollo Client的MockProvider模拟普通GQL查询,但模拟useMutation时触发InvariantError,无法正常执行测试。

组件代码(AddTaskForm.jsx)

import React, { useState } from 'react';
import { useMutation, gql } from '@apollo/client';

// Define the GraphQL mutation
const ADD_TASK = gql`
  mutation AddTask($title: String!) {
    addTask(title: $title) {
      id
      title
    }
  }
`;

export const AddTaskForm = () => {
  const [title, setTitle] = useState('');

  const [addTask, { data, loading, error }] = useMutation(ADD_TASK);

  const handleSubmit = async (e) => {
    e.preventDefault();

    try {
      await addTask({ variables: { title } });
      setTitle(''); 
    } catch (err) {
      console.error('Error adding task', err);
    }
  };

  return (
    <div>
      <h2>Add New Task</h2>
      <form onSubmit={handleSubmit}>
        <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Enter task title" />
        <button type="submit" disabled={loading}>
          {loading ? 'Adding...' : 'Add Task'}
        </button>
      </form>
      {error && <p>Error occurred: {error.message}</p>}
      {data && <p>Task {data.addTask} added successfully!</p>}
    </div>
  );
};

export default AddTaskForm;

测试代码(AddTaskForm.test.js)

// AddTaskForm.test.js
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { MockedProvider } from '@apollo/client/testing';
import userEvent from '@testing-library/user-event';
import AddTaskForm, { ADD_TASK } from './AddTaskForm';

// Mock GraphQL mutation response
const mocks = [
  {
    request: {
      query: ADD_TASK,
      variables: { title: 'Test Task' },
    },
    result: {
      data: {
        addTask: {
          id: '1',
          title: 'Test Task',
        },
      },
    },
  },
];

test('should add a task successfully', async () => {
  render(
    <MockedProvider mocks={mocks} addTypename={false}>
      <AddTaskForm />
    </MockedProvider>
  );

  const input = screen.getByPlaceholderText(/enter task title/i);
  const submitButton = screen.getByText(/add task/i);

  userEvent.type(input, 'Test Task');
  fireEvent.click(submitButton);

  expect(submitButton).toBeDisabled();
  expect(submitButton).toHaveTextContent('Adding...');

  await waitFor(() => {
    expect(screen.getByText('Task "Test Task" added successfully!')).toBeInTheDocument();
  });

  expect(input.value).toBe('');
});

错误信息

An error occurred! For more details, see the full error text at [链接已移除]
Invariant Violation: An error occurred! For more details, see the full error text at [链接已移除]
at new InvariantError (C:\dev\AKOM\frontend\node_modules\ts-invariant\lib\invariant.js:11:28)
at Object.originalInvariant [as invariant] (C:\dev\AKOM\frontend\node_modules\ts-invariant\lib\invariant.js:24:15)

排查关键点及解决方案

1. 组件渲染数据的错误

组件中成功提示直接渲染data.addTask(对象),会输出[object Object]而非期望的任务标题,导致测试无法匹配目标文本,进而触发内部错误。

修复组件:
将成功提示行修改为:

{data && <p>Task "{data.addTask.title}" added successfully!</p>}

2. 事件触发方式不规范

测试中用fireEvent.click(submitButton)触发提交,不如直接模拟表单提交更贴合真实用户行为,可能导致状态更新异常。

修改测试:
替换按钮点击为表单提交:

// 移除fireEvent.click(submitButton)
const form = screen.getByRole('form');
userEvent.submit(form);

3. Mock匹配严格性验证

Apollo MockedProvider对mutation请求的匹配是严格的,需确保请求变量与mock变量完全一致(包括大小写、空格)。若测试输入与mock变量存在差异,会导致找不到匹配的mock触发错误。当前测试中变量一致,若后续有动态输入场景,可使用matchVariables选项实现灵活匹配。

4. Apollo版本对应错误排查

错误码76在Apollo Client 3.x中通常对应找不到匹配的mutation mock,需检查mock的result.data结构是否与mutation定义完全一致,确保字段无遗漏或错误。

验证修改

修复组件渲染和测试事件触发方式后,重新运行测试即可正常通过,不再触发InvariantError。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 22:47:06