How to Mock Redux Middleware in React
Mocking Redux middleware in React is a crucial technique for
isolating your components and action creators during unit testing. By
replacing real middleware—such as Redux Thunk, Redux Saga, or custom
logging middleware—with mocks, you can assert that specific actions are
dispatched and side effects are triggered without executing actual API
calls or complex asynchronous workflows. This article demonstrates how
to mock Redux middleware using the popular redux-mock-store
library and Jest spy functions.
Why Mock Redux Middleware?
In a production React application, Redux middleware handles side effects like asynchronous data fetching, logging, and routing. When writing unit tests for your components or action creators, running actual middleware can make tests slow, unpredictable, and dependent on external services. Mocking middleware allows you to:
- Prevent real API calls from being initiated during tests.
- Verify that the correct actions are dispatched in response to user events.
- Test how components behave when middleware succeeds or fails.
Method 1: Using redux-mock-store
The most common way to mock Redux middleware is by using the
redux-mock-store library. This library allows you to create
a mock Redux store configured with your actual middleware (like
redux-thunk) while intercepting dispatched actions for
assertion.
First, install the library:
npm install redux-mock-store --save-devNext, configure the mock store with your middleware in your test file:
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { fetchUserData } from './actions';
const middleware = [thunk];
const mockStore = configureMockStore(middleware);
describe('Mocking Redux Thunk Middleware', () => {
it('should dispatch the correct actions on API success', async () => {
// Arrange: Create a mock store with initial state
const store = mockStore({ user: {} });
// Act: Dispatch an asynchronous action creator (thunk)
await store.dispatch(fetchUserData());
// Assert: Check the exact actions dispatched to the store
const actions = store.getActions();
expect(actions[0].type).toEqual('FETCH_USER_REQUEST');
expect(actions[1].type).toEqual('FETCH_USER_SUCCESS');
});
});Method 2: Mocking Custom Middleware with Jest
If you have written a custom Redux middleware and want to test that it behaves correctly under certain conditions, you can mock the middleware’s curried function signature using Jest.
Redux middleware follows a specific triple-curried function pattern:
store => next => action. Here is how you can mock and
spy on this structure using Jest:
const createMockMiddleware = () => {
const next = jest.fn();
const store = {
getState: jest.fn(() => ({})),
dispatch: jest.fn(),
};
return { store, next };
};
describe('Custom Middleware Testing', () => {
it('should pass the action to the next middleware', () => {
const { store, next } = createMockMiddleware();
// Your custom middleware
const myCustomMiddleware = store => next => action => {
return next(action);
};
const action = { type: 'TEST_ACTION' };
// Execute the middleware chain
myCustomMiddleware(store)(next)(action);
// Verify that "next" was called with the correct action
expect(next).toHaveBeenCalledWith(action);
});
});Using these two approaches, you can easily control the behavior of both third-party and custom Redux middleware, ensuring your React components and Redux logic are thoroughly tested in isolation.