How to Mock Custom Hooks in React
Testing React components often requires isolating them from external side effects, API calls, or complex state logic managed by custom hooks. This article provides a straightforward guide on how to mock custom hooks in React using Jest and React Testing Library, allowing you to control hook return values and write reliable, isolated unit tests.
Step 1: Identify the Custom Hook and Component
Consider a custom hook named useUser that fetches user
data, and a Profile component that consumes this hook.
// useUser.js
export const useUser = () => {
// Complex fetch logic here
return { user: null, loading: true };
};// Profile.js
import React from 'react';
import { useUser } from './useUser';
export const Profile = () => {
const { user, loading } = useUser();
if (loading) return <div>Loading...</div>;
return <div>Hello, {user.name}</div>;
};Step 2: Mock the
Hook Module Using jest.mock()
To mock the custom hook, use jest.mock() at the top of
your test file to intercept the module import. This prevents the actual
hook logic from executing during the test.
import { render, screen } from '@testing-library/react';
import { Profile } from './Profile';
import { useUser } from './useUser';
// 1. Mock the entire module path
jest.mock('./useUser');Step 3: Define Mock Return Values in Your Tests
Once the module is mocked, you can use Jest’s mock assertion methods,
such as mockReturnValue, to simulate different hook states
(like loading, success, or error) within individual test cases.
describe('Profile Component', () => {
beforeEach(() => {
// Clear mocks before each test to prevent state leakage
jest.clearAllMocks();
});
test('renders loading state', () => {
// 2. Define the mock return value for this test
useUser.mockReturnValue({
user: null,
loading: true,
});
render(<Profile />);
expect(screen.getByText('Loading...')).toBeInTheDocument();
});
test('renders user data when loaded', () => {
// 3. Define a different mock return value for this test
useUser.mockReturnValue({
user: { name: 'Jane Doe' },
loading: false,
});
render(<Profile />);
expect(screen.getByText('Hello, Jane Doe')).toBeInTheDocument();
});
});Alternative: Mocking Hooks with TS/TypeScript
If you are using TypeScript, type casting is required to let TypeScript know that the imported hook is a Jest mock function.
import { useUser } from './useUser';
jest.mock('./useUser');
const mockUseUser = useUser as jest.MockedFunction<typeof useUser>;
test('renders user data', () => {
mockUseUser.mockReturnValue({
user: { name: 'Jane Doe' },
loading: false,
});
// Render and assert...
});