How to Mock Redux Store in React

Testing React components that rely on a Redux store requires a way to simulate state and actions. This article provides a straightforward guide on how to mock a Redux store in React applications using popular testing libraries like Jest, React Testing Library, and redux-mock-store. You will learn the best practices for setting up mock providers, simulating state changes, and testing dispatched actions.

The most reliable way to test components using Redux is to wrap them in a real Redux store preloaded with test data. This approach, recommended by the Redux team, ensures your tests behave exactly like your production application.

First, create a helper function in your test setup file to wrap your components with a <Provider>:

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

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 inside your test suites to pass a specific initial state:

test('renders user name from Redux store', () => {
  const { getByText } = renderWithProviders(<UserProfile />, {
    preloadedState: {
      user: { name: 'John Doe' }
    }
  });

  expect(getByText(/John Doe/i)).toBeInTheDocument();
});

Method 2: Using the redux-mock-store Library

If you need to inspect which actions were dispatched to the store rather than testing state changes, the redux-mock-store library is the ideal choice.

First, install the library:

npm install redux-mock-store --save-dev

Next, configure the mock store in your test file:

import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import MyComponent from './MyComponent';

const mockStore = configureStore([]);

test('dispatches login action on button click', () => {
  const initialState = { user: { loggedIn: false } };
  const store = mockStore(initialState);

  render(
    <Provider store={store}>
      <MyComponent />
    </Provider>
  );

  fireEvent.click(screen.getByRole('button', { name: /log in/i }));

  const actions = store.getActions();
  expect(actions[0]).toEqual({ type: 'user/login' });
});

Method 3: Mocking Redux Hooks with Jest

If you want to avoid wrapping your components with providers entirely, you can mock the React Redux hooks (useSelector and useDispatch) directly using Jest. This method is lightweight and suitable for simple unit tests.

Here is how you can spy on and mock these hooks:

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

describe('MyComponent with Mocked Hooks', () => {
  const useSelectorMock = jest.spyOn(reactRedux, 'useSelector');
  const useDispatchMock = jest.spyOn(reactRedux, 'useDispatch');

  beforeEach(() => {
    useSelectorMock.mockClear();
    useDispatchMock.mockClear();
  });

  test('displays correct user status', () => {
    // Mock selector return value
    useSelectorMock.mockReturnValue({ name: 'Jane Doe', role: 'Admin' });
    
    // Mock dispatch function
    const dummyDispatch = jest.fn();
    useDispatchMock.mockReturnValue(dummyDispatch);

    render(<MyComponent />);

    expect(screen.getByText('Jane Doe')).toBeInTheDocument();
    expect(screen.getByText('Admin')).toBeInTheDocument();
  });
});