How to Mock Redux Toolkit in React

Testing React components that use Redux Toolkit (RTK) requires a strategy to isolate components from the actual global state. This article explains how to mock Redux Toolkit in React using Jest and React Testing Library, covering both the recommended approach of wrapping components in a test provider and the alternative method of mocking individual React-Redux hooks.

The most reliable way to test components using Redux Toolkit is to wrap them in a <Provider> with a real Redux store configured specifically for testing. This avoids fragile mocks and ensures your tests behave exactly like your application.

First, create a reusable render helper that configures a fresh store for each test:

import React from 'react';
import { render } from '@testing-library/react';
import { Provider } from 'react-redux';
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './userSlice'; // Import your actual reducers

export function renderWithProviders(
  ui,
  {
    preloadedState = {},
    store = configureStore({ reducer: { user: userReducer }, preloadedState }),
    ...renderOptions
  } = {}
) {
  function Wrapper({ children }) {
    return <Provider store={store}>{children}</Provider>;
  }
  return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) };
}

You can then use this helper in your test files to supply mock initial state:

import { screen } from '@testing-library/react';
import { renderWithProviders } from './test-utils';
import UserProfile from './UserProfile';

test('renders user profile with mock state', () => {
  const mockState = {
    user: { name: 'John Doe', loggedIn: true }
  };

  renderWithProviders(<UserProfile />, { preloadedState: mockState });

  expect(screen.getByText('John Doe')).toBeInTheDocument();
});

Method 2: Mocking React-Redux Hooks Directly

If you want to isolate a component completely without setting up a store, you can mock the useSelector and useDispatch hooks directly using Jest. This method is ideal for quick unit tests.

Mocking useSelector

To control the data your component reads from the Redux store, mock useSelector to return your desired mock state:

import { screen, render } from '@testing-library/react';
import * as reactRedux from 'react-redux';
import UserProfile from './UserProfile';

jest.mock('react-redux', () => ({
  ...jest.requireActual('react-redux'),
  useSelector: jest.fn(),
}));

test('displays mock user data', () => {
  // Setup the mock implementation for useSelector
  reactRedux.useSelector.mockImplementation((selectorFn) => 
    selectorFn({ user: { name: 'Jane Doe' } })
  );

  render(<UserProfile />);
  expect(screen.getByText('Jane Doe')).toBeInTheDocument();
});

Mocking useDispatch

To test if your component dispatches the correct actions, mock useDispatch to return a Jest spy function:

import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import * as reactRedux from 'react-redux';
import LogoutButton from './LogoutButton';

jest.mock('react-redux', () => ({
  ...jest.requireActual('react-redux'),
  useDispatch: jest.fn(),
}));

test('dispatches logout action on click', async () => {
  const mockDispatch = jest.fn();
  reactRedux.useDispatch.mockReturnValue(mockDispatch);

  render(<LogoutButton />);
  
  const button = screen.getByRole('button', { name: /logout/i });
  await userEvent.click(button);

  expect(mockDispatch).toHaveBeenCalledWith({ type: 'user/logout' });
});