Apollo 14: Testing Apollo
easy⏱ 5 mincourseapollo
MockedProvider and mock structure
Apollo provides MockedProvider as a test wrapper. It replaces ApolloProvider and accepts a mocks array. Each mock is an object with request (containing query and variables) and result (containing data). When a component inside MockedProvider executes a matching query, the mock result is returned instead of hitting the network. Mocks are consumed in order — if you render the same query twice, you need two mock entries.
import { MockedProvider } from '@apollo/client/testing';
const mocks = [
{
request: {
query: GET_USERS,
variables: {},
},
result: {
data: {
users: [
{ id: '1', name: 'Alice', email: 'alice@test.com' },
{ id: '2', name: 'Bob', email: 'bob@test.com' },
],
},
},
},
];
render(
<MockedProvider mocks={mocks} addTypename={false}>
<UserList />
</MockedProvider>
);
Write a test with mocked query
Create a test that wraps UserList in MockedProvider with a mock for GET_USERS. Use addTypename={false} to simplify mocks. After rendering, wait for the loading state to resolve (use waitFor or findByText). Assert that user names appear in the document. Then add a second test with result: { errors: [new GraphQLError('Not found')] } to test the error state.
Testing error states
Test both GraphQL errors and network errors. For GraphQL errors: { request: {...}, result: { errors: [new GraphQLError('Oops')] } }. For network errors: { request: {...}, error: new Error('Network error') }. Always test the error UI path — it's easy to miss broken error states in development but critical in production.
const errorMock = {
request: { query: GET_USERS },
error: new Error('Network error'),
};
render(
<MockedProvider mocks={[errorMock]} addTypename={false}>
<UserList />
</MockedProvider>
);
await screen.findByText(/error/i);
Testing reactive variables
Reactive variables can be tested by setting them before rendering, then asserting the result. Since reactive variables are global singletons, reset them in beforeEach to avoid test pollution: beforeEach(() => { favoritesVar([]); }). You can also test that UI updates when the variable changes: set the var, wait for re-render, assert new UI state.
beforeEach(() => {
favoritesVar([]); // Reset before each test
});
test('shows favorite count', () => {
favoritesVar(['1', '2']); // Set initial state
render(<FavoriteCount />);
expect(screen.getByText('2 favorites')).toBeInTheDocument();
});