I have been using MockProvider from Apollo Client successfully in mocking normal GQL queries, but when I try to mock mutations it does not seem to work.
If I try to mock a useMutation using the MockProvider I get an InvariantError.
The component I am trying to test is :
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;
My test file looks like this :
// 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'; // Mock provider from Apollo
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 component with MockedProvider to mock Apollo's useMutation
render(
<MockedProvider mocks={mocks} addTypename={false}>
<AddTaskForm />
</MockedProvider>
);
// Ensure the form and button are present
const input = screen.getByPlaceholderText(/enter task title/i);
const submitButton = screen.getByText(/add task/i);
// Simulate typing into the input field
userEvent.type(input, 'Test Task');
// Simulate clicking the submit button
fireEvent.click(submitButton);
// Ensure the loading state is displayed
expect(submitButton).toBeDisabled();
expect(submitButton).toHaveTextContent('Adding...');
// Wait for mutation to complete
await waitFor(() => {
expect(screen.getByText('Task "Test Task" added successfully!')).toBeInTheDocument();
});
// Check that input is cleared after task is added
expect(input.value).toBe('');
});
However when I run the test I get an "Invariant" error that looks like this :
An error occurred! For more details, see the full error text at https://go.apollo.dev/c/err#%7B%22version%22%3A%223.11.1%22%2C%22message%22%3A76%2C%22args%22%3A%5B%5D%7D Invariant Violation: An error occurred! For more details, see the full error text at https://go.apollo.dev/c/err#%7B%22version%22%3A%223.11.1%22%2C%22message%22%3A76%2C%22args%22%3A%5B%5D%7D 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)
Navigating to this URL gives me nothing useful.
I have carefully analyzed my component and test and I can't see anything wrong with the code that I have.
You are not exporting ADD_TASK
from your component file, so you pass a nonexistent variable (=undefined
) into the mock.