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...
});