How to Mock React Hooks
This article explains how to mock React hooks when writing unit tests
for your React applications. You will learn how to mock custom hooks
using Jest’s mocking utilities, spy on built-in React hooks like
useState and useEffect, and use React Testing
Library to test hooks in isolation.
Mocking Custom React Hooks
The most common scenario is mocking a custom hook that fetches data
or manages complex state. To mock a custom hook, you can use
jest.mock() to mock the module containing the hook, and
then define its return value in your test suite.
Suppose you have a custom hook called useUser:
// useUser.js
export const useUser = () => {
return { user: { name: 'John Doe' }, loading: false };
};To mock this hook in your test file:
import { render, screen } from '@testing-library/react';
import { MyComponent } from './MyComponent';
import { useUser } from './useUser';
// 1. Mock the entire module path
jest.mock('./useUser');
test('renders mocked user data', () => {
// 2. Define the mocked return value for this specific test
useUser.mockReturnValue({
user: { name: 'Jane Smith' },
loading: false,
});
render(<MyComponent />);
expect(screen.getByText('Jane Smith')).toBeInTheDocument();
});Mocking Built-In React Hooks
Sometimes you need to mock built-in hooks from the core
'react' library, such as useContext or
useMemo. You can achieve this by using
jest.spyOn().
Here is how to mock the useContext hook:
import React from 'react';
import { render, screen } from '@testing-library/react';
import { MyComponent } from './MyComponent';
test('mocks useContext', () => {
// Spy on the useContext hook of the React object
const useContextSpy = jest.spyOn(React, 'useContext');
// Provide the mock return value
useContextSpy.mockReturnValue({ theme: 'dark' });
render(<MyComponent />);
expect(screen.getByRole('button')).toHaveClass('dark-theme');
// Clear mock after the test
useContextSpy.mockRestore();
});Mocking State Hooks
(useState)
While it is generally recommended to test state transitions through
user interactions rather than mocking useState directly,
you can mock useState using jest.spyOn if your
test architecture requires it.
import React from 'react';
import { render } from '@testing-library/react';
import { MyComponent } from './MyComponent';
test('mocks useState setter function', () => {
const setMock = jest.fn();
// Mock useState to return a specific state and our mock setter
jest.spyOn(React, 'useState').mockImplementation((initialState) => [initialState, setMock]);
render(<MyComponent />);
// Trigger action in component and assert setMock was called
});Testing Hooks without
Mocking: renderHook
If you want to test the behavior of a custom hook itself rather than
mocking its output in a component, use the renderHook
utility provided by @testing-library/react. This avoids
mocking altogether and executes the hook in a virtual component.
import { renderHook, act } from '@testing-library/react';
import { useCounter } from './useCounter';
test('should increment counter', () => {
const { result } = renderHook(() => useCounter());
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});