How to test Redux Toolkit Query with Jest and React Testing Library
This article goes over how to test RTK Query API with Jest and React Testing Library.
Prerequisites
Install and set up:
Enable jest-fetch-mock
in setupTests
:
// src/setupTests.ts
import fetchMock from 'jest-fetch-mock';
fetchMock.enableMocks();
We’ll be testing RTK Query’s createApi example. This means the auto-generated React hook is exported from api.ts
:
// src/api.ts
export const { useGetPokemonByNameQuery } = pokemonApi;
Test
Create api.test.tsx
:
touch api.test.tsx
Create an empty test:
it('renders hook', () => {
// ...
});
Use renderHook to render the hook:
import { useGetPokemonByNameQuery } from './api';
it('renders hook', () => {
renderHook(() => useGetPokemonByNameQuery('pikachu'));
});
The test should fail with the error:
Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
Create a wrapper
component using the Redux store:
// ...
import { store } from './store';
import { Provider } from 'react-redux';
import type { ReactNode } from 'react';
function Wrapper(props: { children: ReactNode }) {
return <Provider store={store}>{props.children}</Provider>;
}
it('renders hook', () => {
renderHook(() => useGetPokemonByNameQuery('pikachu'), { wrapper: Wrapper });
});
The test should now pass.
Mock the fetch call in beforeAll
:
const data = {};
beforeAll(() => {
fetchMock.mockOnceIf('https://pokeapi.co/api/v2/pokemon/pikachu', () =>
Promise.resolve({
status: 200,
body: JSON.stringify({ data }),
})
);
});
Assert that the hook result
is correct:
it('renders hook', () => {
const { result } = renderHook(() => useGetPokemonByNameQuery('pikachu'), {
wrapper: Wrapper,
});
expect(result.current).toMatchObject({
status: 'pending',
endpointName: 'getPokemonByName',
isLoading: true,
isSuccess: false,
isError: false,
isFetching: true,
});
});
Assert that fetchMock
is called:
it('renders hook', () => {
// ...
expect(fetchMock).toBeCalled();
});
But the test should fail. This is because we need to use waitFor
to wait for the request to finish:
it('renders hook', async () => {
// ...
await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(fetchMock).toBeCalledTimes(1);
});
The test should pass again.
Finally, assert that the updated hook result
is correct:
it('renders hook', async () => {
// ...
expect(result.current).toMatchObject({
status: 'fulfilled',
endpointName: 'getPokemonByName',
data: {},
isLoading: false,
isSuccess: true,
isError: false,
currentData: {},
isFetching: false,
});
});
Demo
See CodeSandbox: