Redux Logic Test Utilities
redux-logic-test provides testing utilities specifically designed to simplify the integration and unit testing of Redux Logic modules. It offers a `createMockStore` function that sets up a Redux store with a `redux-logic` middleware instance, allowing developers to easily inject logic, initial state, and mocked dependencies (like an API service) for isolated testing. The utility also includes built-in action tracking and a `whenComplete` helper to ensure all asynchronous logic operations have finished before assertions are made. The current stable version is 2.0.0, which primarily relaxed peer dependency constraints for Redux and Redux Logic without introducing API breaking changes. Release cadence is tied to updates in its core dependencies, `redux` and `redux-logic`, aiming for compatibility rather than frequent feature additions. Its key differentiator is its direct integration with `redux-logic`'s specific patterns, offering a more tailored testing experience than generic Redux testing utilities.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'createLogicMiddleware')
cause redux-logic is not installed or incorrectly resolved, which redux-logic-test depends on to create the middleware.fixEnsure 'redux-logic' is correctly installed in your project: `npm install redux-logic --save`. -
TypeError: Cannot read properties of undefined (reading 'Observable')
cause rxjs, a peer dependency of redux-logic, is missing or incorrectly resolved.fixInstall 'rxjs' in your project: `npm install rxjs --save`. -
Error: Peer dependency 'redux' is not installed.
cause The 'redux' package, a peer dependency of redux-logic-test, is missing.fixInstall 'redux' in your project: `npm install redux --save`. -
ReferenceError: require is not defined
cause Attempting to use CommonJS `require()` syntax in an ES Modules environment without proper configuration, or vice-versa with `import`.fixEnsure your project is configured for either ES Modules (using `import`) or CommonJS (using `require`). If using ES Modules, ensure your `package.json` has `"type": "module"` and use `import { createMockStore } from 'redux-logic-test';`. If using CommonJS, use `const { createMockStore } = require('redux-logic-test');`.
Warnings
- breaking Version 2.0.0 relaxed peer dependency constraints for 'redux' and 'redux-logic'. While not a direct API breaking change in 'redux-logic-test', ensure your project's `redux` and `redux-logic` versions are compatible with the newly allowed ranges, especially if upgrading from a version that had stricter requirements. This could lead to runtime errors if older versions of peer dependencies are used that are not compatible with the relaxed range.
- gotcha It is crucial to install `rxjs`, `redux`, and `redux-logic` as peer dependencies. `redux-logic-test` itself is a dev dependency, but its functionality relies heavily on these runtime dependencies being present in your project. Forgetting to install `rxjs` is a common oversight as it's an indirect dependency of `redux-logic`.
- gotcha Always call `store.whenComplete()` (or `store.logicMiddleware.whenComplete()`) and `await` it in async tests to ensure all asynchronous logic operations have finished before making assertions. Failing to do so can lead to flaky tests where assertions run before the logic has had a chance to dispatch final actions or update state.
Install
-
npm install redux-logic-test -
yarn add redux-logic-test -
pnpm add redux-logic-test
Imports
- createMockStore
import createMockStore from 'redux-logic-test';
import { createMockStore } from 'redux-logic-test'; - createMockStore (CommonJS)
const createMockStore = require('redux-logic-test').default.createMockStore;const { createMockStore } = require('redux-logic-test'); - Type (if using TypeScript)
import type { MockStore } from 'redux-logic-test';
Quickstart
import { createMockStore } from 'redux-logic-test';
import { createLogic } from 'redux-logic';
const API = {
get: (url) => Promise.resolve({ data: `Fetched data from ${url}` })
};
const fooLogic = createLogic({
type: 'FOO',
process({ API, getState, action }, dispatch, done) {
API.get(`/api/${action.payload}`)
.then(results => {
dispatch({ type: 'FOO_SUCCESS', payload: results.data });
})
.catch(error => {
dispatch({ type: 'FOO_FAILURE', payload: error.message });
})
.finally(() => done());
}
});
const logic = [fooLogic];
const injectedDeps = { API };
const initialState = { some: 'state' };
const reducer = (state = initialState, action) => {
switch(action.type) {
case 'FOO_SUCCESS': return { ...state, lastFetch: action.payload };
default: return state;
}
};
async function runTest() {
const store = createMockStore({
initialState,
reducer,
logic,
injectedDeps
});
store.dispatch({ type: 'FOO', payload: 'item123' });
store.dispatch({ type: 'BAR' }); // Will be tracked but not processed by logic
await store.whenComplete(); // Wait for fooLogic to finish
console.log('Final State:', store.getState());
console.log('Dispatched Actions:', store.actions);
// Example assertions (in a real test framework like Jest)
// expect(store.getState().lastFetch).toBe('Fetched data from /api/item123');
// expect(store.actions).toEqual([
// { type: 'FOO', payload: 'item123' },
// { type: 'BAR' },
// { type: 'FOO_SUCCESS', payload: 'Fetched data from /api/item123' }
// ]);
}
runTest();