How to Mock Redux Reducers in React
Testing React applications that use Redux often requires isolating components from the actual global state. This guide demonstrates how to mock Redux reducers and store states in your Jest and React Testing Library setups. You will learn the best practices for mocking reducer behaviors, creating mock stores, and overriding initial states to ensure clean, reliable tests.
Why Mock Redux Reducers?
Reducers are pure functions that take the current state and an action, then return a new state. Because they are pure, unit testing a reducer directly does not require mocking; you simply pass inputs and assert the outputs.
However, when integration testing React components wrapped in a Redux
<Provider>, you must control the state the components
read. Mocking the reducers or the store allows you to: * Set up specific
state scenarios (e.g., logged-in vs. logged-out states). * Avoid
executing complex reducer logic during component tests. * Verify how
components react to state changes.
Method 1: Mocking Store State with Preloaded State (Recommended)
The official Redux recommendation is to avoid mocking the reducer
functions directly. Instead, create a real Redux store in your test
environment but pass a mocked preloadedState. This ensures
your components interact with a real Redux flow while using your test
data.
1. Create a Custom Render Function
Set up a helper function in your testing utility file to wrap components with a Redux Provider containing a custom-configured store.
// test-utils.jsx
import React from 'react';
import { render } from '@testing-library/react';
import { configureStore } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';
import userReducer from './userSlice';
export function renderWithRedux(
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 }) };
}2. Use the Custom Render in Tests
Now, you can mock the reducer’s state by passing your desired state
object as preloadedState.
// UserProfile.test.jsx
import React from 'react';
import { screen } from '@testing-library/react';
import { renderWithRedux } from './test-utils';
import UserProfile from './UserProfile';
test('renders user profile with mocked Redux state', () => {
const mockState = {
user: {
name: 'John Doe',
isLoggedIn: true,
},
};
renderWithRedux(<UserProfile />, { preloadedState: mockState });
expect(screen.getByText('Welcome, John Doe')).toBeInTheDocument();
});Method 2: Mocking Reducer Functions with Jest
If you must mock the actual reducer function itself—for instance, to prevent it from running during a test or to spy on its calls—you can use Jest’s module mocking capabilities.
// userSlice.js
const initialState = { name: 'Guest' };
export default function userReducer(state = initialState, action) {
switch (action.type) {
case 'SET_USER':
return { ...state, name: action.payload };
default:
return state;
}
}In your test file, intercept the reducer file import and replace the default export with a mock function:
// UserComponent.test.jsx
import userReducer from './userSlice';
// Mock the entire slice module
jest.mock('./userSlice', () => {
return {
__esModule: true,
default: jest.fn(() => ({ name: 'Mocked Jest User' })),
};
});
test('uses the mocked reducer output', () => {
// The mocked reducer will now return 'Mocked Jest User'
// regardless of the action dispatched.
expect(userReducer()).toEqual({ name: 'Mocked Jest User' });
});Method 3: Mocking with redux-mock-store
For scenarios where you only want to test if correct actions are
dispatched without mutating the state, you can use the
redux-mock-store library.
1. Install the library
npm install redux-mock-store --save-dev2. Configure and use the mock store
import configureStore from 'redux-mock-store';
import { Provider } from 'react-redux';
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
const mockStore = configureStore([]);
test('should dispatch action on button click', () => {
const store = mockStore({
myReducer: { data: 'initial' },
});
render(
<Provider store={store}>
<MyComponent />
</Provider>
);
// Assert actions dispatched to the mock store
const actions = store.getActions();
expect(actions).toEqual([]);
});