How to Mock Redux Actions in React

Testing React components that rely on Redux often requires isolating the component’s behavior from the actual Redux store and side effects. This article provides a straightforward guide on how to mock Redux actions using popular testing tools like Jest and redux-mock-store. You will learn how to mock action creators, mock the React-Redux dispatch hook, and verify that the correct actions are triggered during user interactions.

Why Mock Redux Actions?

When writing unit tests for React components, you want to test the component in isolation. If your component dispatches Redux actions (especially asynchronous ones like Thunks that fetch data from an API), running the real actions can make your tests slow, flaky, and dependent on external services. Mocking these actions allows you to:


Method 1: Mocking the useDispatch Hook with Jest

The most direct way to test if a component dispatches the correct Redux action is to mock the useDispatch hook from the react-redux library.

Step-by-Step Implementation

  1. Mock the react-redux module at the top of your test file.
  2. Create a mock dispatch function using jest.fn().
  3. Assert that the mock dispatch function was called with the correct action object.
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { useDispatch } from 'react-redux';
import MyComponent from './MyComponent';
import { updateUser } from './actions';

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

// Mock the specific action creator
jest.mock('./actions', () => ({
  updateUser: jest.fn(() => ({ type: 'UPDATE_USER', payload: 'John Doe' })),
}));

describe('MyComponent', () => {
  let mockDispatch;

  beforeEach(() => {
    mockDispatch = jest.fn();
    useDispatch.mockReturnValue(mockDispatch);
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  it('should dispatch the updateUser action when the button is clicked', () => {
    render(<MyComponent />);
    
    const button = screen.getByRole('button', { name: /update profile/i });
    fireEvent.click(button);

    // Verify that dispatch was called
    expect(mockDispatch).toHaveBeenCalledTimes(1);
    
    // Verify it was called with the correct action
    expect(mockDispatch).toHaveBeenCalledWith(updateUser());
  });
});

Method 2: Using redux-mock-store

If your component is wrapped in a <Provider> and you want to test the flow of actions through a simulated Redux store, redux-mock-store is the industry standard. This package records the history of dispatched actions so you can inspect them later.

Install the Dependency

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

Step-by-Step Implementation

  1. Configure the mock store with any required middleware (like redux-thunk).
  2. Provide the mock store to your rendered component using the <Provider> wrapper.
  3. Inspect the dispatched actions list using store.getActions().
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import MyComponent from './MyComponent';

const middlewares = [thunk];
const mockStore = configureStore(middlewares);

describe('MyComponent with Redux Mock Store', () => {
  let store;

  beforeEach(() => {
    // Define the initial state of your mock store
    const initialState = { user: { name: 'Guest' } };
    store = mockStore(initialState);
  });

  it('should record the dispatched action in the store history', () => {
    render(
      <Provider store={store}>
        <MyComponent />
      </Provider>
    );

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

    // Get the list of actions dispatched to the mock store
    const actions = store.getActions();

    // Verify the structure of the dispatched action
    expect(actions[0]).toEqual({
      type: 'LOGIN_SUCCESS',
      payload: { username: 'Guest' },
    });
  });
});

Method 3: Mocking Action Creators Directly

If you prefer not to mock the useDispatch hook itself, you can mock the specific action creator functions imported into your component file.

import { fetchUserData } from './actions';

// Mock the module containing the action creators
jest.mock('./actions', () => ({
  fetchUserData: jest.fn(() => ({ type: 'FETCH_USER_MOCK' })),
}));

describe('Action Creator Mocking', () => {
  it('should call the mocked action creator function', () => {
    // Your component rendering logic here
    
    // Assert that the action creator itself was invoked
    expect(fetchUserData).toHaveBeenCalled();
  });
});

Using these three approaches, you can easily verify that your React components trigger the correct business logic in response to user events without needing to spin up a fully-functional Redux environment during testing.