How to Mock React State in Unit Tests

This article explains how to mock React state when writing unit tests for your components. We will cover the industry-standard approaches using Jest and React Testing Library, including mocking the useState hook directly, mocking custom hooks, and the recommended practice of triggering state changes through simulated user interactions.

The most resilient way to test React state is by not mocking the state itself, but rather testing the behavior that triggers the state change. Testing implementation details like useState makes your tests fragile when refactoring.

Using React Testing Library, you can simulate user interactions to assert that the UI updates correctly when state changes:

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Counter from './Counter';

test('increments the counter state on click', async () => {
  render(<Counter />);
  
  const button = screen.getByRole('button', { name: /increment/i });
  const countDisplay = screen.getByTestId('count-value');

  expect(countDisplay).toHaveTextContent('0');

  await userEvent.click(button);

  expect(countDisplay).toHaveTextContent('1');
});

Method 2: Mocking useState Directly with Jest

If you must mock the state value directly to test how a component renders under specific state conditions, you can spy on React.useState. This is useful for isolating complex state logic.

Here is how to mock the return value of useState:

import React from 'react';
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';

test('mocks the initial state value', () => {
  const mockState = 'Mocked Value';
  const setMockState = jest.fn();

  // Spy on React.useState and override its return value
  jest.spyOn(React, 'useState').mockImplementation(() => [mockState, setMockState]);

  render(<MyComponent />);

  expect(screen.getByText('Mocked Value')).toBeInTheDocument();
});

Note: Always call jest.restoreAllMocks() in your afterEach block to prevent the mocked state from leaking into other tests.

Method 3: Mocking Custom Hooks

If your state is managed inside a custom hook, mocking the hook is much cleaner and less intrusive than mocking React’s built-in useState.

For example, if you have a custom hook called useUserStatus:

import { render, screen } from '@testing-library/react';
import Profile from './Profile';
import { useUserStatus } from './useUserStatus';

// Mock the entire module containing the custom hook
jest.mock('./useUserStatus');

test('displays online status when user is online', () => {
  // Define the mocked return value for this specific test
  useUserStatus.mockReturnValue({ isOnline: true, status: 'Active' });

  render(<Profile />);

  expect(screen.getByText('Online')).toBeInTheDocument();
});