Redux Waitfor Middleware
raw JSON →Redux Waitfor Middleware (current stable version 1.0.1) is a lightweight utility designed to facilitate testing of Redux applications, particularly for asynchronous flows. It operates as a standard Redux middleware, recording dispatched actions and providing a `waitFor` method that allows tests to pause execution until a specific set of actions has been dispatched within a given timeout. The library is primarily used in testing environments to assert on the sequence and payload of actions after asynchronous operations complete, such as API calls. Its release cadence appears to be stable, with the current version being quite mature. A key differentiator is its simplicity and direct focus on action-based waiting, making it less verbose than complex mocking or promise-chaining in some test scenarios. It also handles the case where actions are already dispatched, immediately resolving the wait.
Common errors
error Error: Timeout of XXXXms reached waiting for actions: ACTION_TYPE_A, ACTION_TYPE_B ↓
clean() isn't prematurely clearing an action you're waiting for from a prior test. error TypeError: Cannot read properties of undefined (reading 'waitFor') ↓
const waitForMiddleware = createWaitForMiddleware(); is called and waitForMiddleware is accessible where you are attempting to use its methods. It's often passed around or made available via a setup function in testing frameworks. Warnings
gotcha Actions dispatched before the `waitFor` call but after the last `clean()` call will immediately resolve the `waitFor` promise. This can lead to flaky tests if `clean()` is not called consistently between test cases. ↓
breaking The `waitFor` method throws an `Error` if the specified actions are not dispatched within the provided timeout. This will fail the test by default and needs to be handled if non-receipt of an action is an expected test outcome. ↓
Install
npm install redux-waitfor-middleware yarn add redux-waitfor-middleware pnpm add redux-waitfor-middleware Imports
- createWaitForMiddleware wrong
const createWaitForMiddleware = require('redux-waitfor-middleware');correctimport createWaitForMiddleware from 'redux-waitfor-middleware'; - waitFor
const waitForMiddleware = createWaitForMiddleware(); await waitForMiddleware.waitFor(['ACTION_TYPE']); - clean
waitForMiddleware.clean();
Quickstart
import createWaitForMiddleware from 'redux-waitfor-middleware';
import { createStore, applyMiddleware } from 'redux';
// A dummy reducer for demonstration
const exampleReducer = (state = { data: [] }, action) => {
switch (action.type) {
case 'FETCH_DATA_REQUEST':
return { ...state, loading: true };
case 'FETCH_DATA_SUCCESS':
return { ...state, loading: false, data: action.payload };
case 'FETCH_DATA_FAILURE':
return { ...state, loading: false, error: action.error };
default:
return state;
}
};
const waitForMiddleware = createWaitForMiddleware();
const store = createStore(exampleReducer, applyMiddleware(waitForMiddleware));
async function simulateFetch() {
store.dispatch({ type: 'FETCH_DATA_REQUEST' });
console.log('Dispatched FETCH_DATA_REQUEST');
// Simulate an async operation
setTimeout(() => {
store.dispatch({ type: 'FETCH_DATA_SUCCESS', payload: ['item1', 'item2'] });
console.log('Dispatched FETCH_DATA_SUCCESS');
}, 100);
}
async function runTest() {
console.log('Running test...');
simulateFetch();
try {
const successActions = await waitForMiddleware.waitFor(['FETCH_DATA_SUCCESS'], 500);
console.log('Test passed! Received actions:', successActions);
console.assert(successActions.length === 1, 'Expected one success action');
console.assert(successActions[0].payload.includes('item1'), 'Payload check');
} catch (error) {
console.error('Test failed:', error.message);
} finally {
// Always clean up after a test
waitForMiddleware.clean();
console.log('Cleaned recorded actions.');
}
}
runTest();