Skip to content


Folders and files

Last commit message
Last commit date

Latest commit



77 Commits

Repository files navigation


Full redux environment testing helper for redux-saga.

redux-saga is a great library that provides an easy way to test your sagas step-by-step, but it's tightly coupled to the saga implementation. Try a non-breaking reorder of the internal yields, and the tests will fail.

This tester library provides a full redux environment to run your sagas in, taking a black-box approach to testing. You can dispatch actions, observe the state of the store at any time, retrieve a history of actions and listen for specific actions to occur.

Getting Started


$ npm install --save-dev redux-saga-tester

Basic Example

Suppose we have a saga that waits for a START action, performs some async (or sync) actions (eg. fetching data from an API), and dispatches a SUCCESS action upon completion. Here's how we would test it:

import ourSaga from './saga';

describe('ourSaga test', () => {
    let sagaTester = null;

    beforeEach(() => {
        // Init code
        sagaTester = new SagaTester({ initialState });

    it('should retrieve data from the server and send a SUCCESS action', async () => {
        // Our test (Actions is our standard redux action component). Start the saga with the START action

        // Wait for the saga to finish (it emits the SUCCESS action when its done)
        const successAction = await sagaTester.waitFor(Actions.types.SUCCESS);

        // Check that the success action is what we expect it to be
            Actions.actions.success({ data: expectedData })

This is of course an example of testing a saga that contains async actions. Generally when testing it is perferred to use sync mocks. In that case, there's no need to async/await.

Full example

Can be found under the examples directory.

import chaiAsPromised from 'chai-as-promised';
import { call, take, put } from 'redux-saga/effects';
import SagaTester from 'redux-saga-tester';


const someValue = 'SOME_VALUE';
const someResult = 'SOME_RESULT';
const someOtherValue = 'SOME_OTHER_VALUE';
const middlewareMeta = 'MIDDLEWARE_TEST';
const fetchRequestActionType = 'FETCH_REQUEST'
const fetchSuccessActionType = 'FETCH_SUCCESS'

const initialState = { someKey : someValue };
const reducer = (state = someValue, action) =>
    action.type === fetchSuccessActionType ? someOtherValue : state;
const middleware = store => next => action => next({
    meta : middlewareMeta
// options are passed to createSagaMiddleware
const options = { onError => console.error.bind(console) }
const fetchApi = () => someResult;

const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms))

function* listenAndFetch() {
    yield take(fetchRequestActionType);
    const result = yield call(fetchApi);
    yield call(delay, 500); // For async example.
    yield put({ type : fetchSuccessActionType, payload : result });

it('Showcases the tester API', async () => {
    // Start up the saga tester
    const sagaTester = new SagaTester({
        reducers : { someKey : reducer },
        middlewares : [middleware],

    // Check that state was populated with initialState

    // Dispatch the event to start the saga
    sagaTester.dispatch({type : fetchRequestActionType});

    // Hook into the success action
    await sagaTester.waitFor(fetchSuccessActionType);

    // Check that all actions have the meta property from the middleware
    sagaTester.getCalledActions().forEach(action => {

    // Check that the new state was affected by the reducer
        someKey : someOtherValue

    // Check that the saga listens only once
    sagaTester.dispatch({ type : fetchRequestActionType });

    // Reset the state and action list, dispatch again
    // and check that it was called
    sagaTester.dispatch({ type : fetchRequestActionType });


new SagaTester(options) => sagaTester

Create a new SagaTester instance.

  1. options: Object
    • initialState : Object
    • reducers : Object | Function
    • middlewares : Array[Function]
    • combineReducers : Function
    • ignoreReduxActions : Boolean
    • options : Object
      • Options for createSagaMiddleware (see docs).

sagaTester.start(saga, [...args])

Starts execution of the provided saga.

  1. saga : Function
    • The saga generator function to start
  2. [...args] : Any
    • Optional Arguments to pass to the generator on start


Dispatches an action to the redux store.


Assigns the newState into the current state. (Only works with the default reducer.)

sagaTester.getState() => Object

Returns the state of the redux store.

sagaTester.waitFor(actionType, futureOnly) => Promise<action>

Returns a promise that will resolve if the specified action is dispatched to the store.

  1. actionType : String
  2. futureOnly : Boolean
    • Causes waitFor to only resolve if the action is called in the future.

The promise resolves with the matching action object.

sagaTester.wasCalled(actionType) => Boolean

Returns whether the specified was dispatched in the past.

sagaTester.numCalled(actionType) => Number

Returns the number of times an action with the given type was dispatched.

sagaTester.getLatestCalledAction() => Action

Returns the last action dispatched to the store.

sagaTester.getCalledActions() => Array[Actions]

Returns an array of all actions dispatched.


Reset the store state back to initialState.

  1. clearActionList : Boolean
    • Clears the history of past actions (defaults to false).