I'm trying to test my redux-saga functions by using Redux Saga Test Plan library and I'm stuck due to delay functions in my saga.
If I remove the line, yield delay(1000)
all tests pass without any error.
saga.js
export function* addWorkoutSaga({ payload }) {
try {
yield put(beginAjaxCall());
yield delay(1000);
yield call(WorkoutService.add, payload);
yield call(toast.success, "Item added successfully.");
yield put(closeModal(Modal.AddWorkout));
yield put(addWorkout.success());
yield call(fetchWorkoutsSaga);
}
catch (error) {
console.log(error)
yield put(addWorkout.failure({ errorMessage: error.statusText }));
yield call(toast.error, "Error occured. Please try again.");
}
}
saga.test.js
import {
call,
put,
//takeLatest,
delay
} from 'redux-saga/effects';
import * as matchers from 'redux-saga-test-plan/matchers';
import { expectSaga } from 'redux-saga-test-plan';
import { throwError } from 'redux-saga-test-plan/providers';
import {
fetchWorkouts,
addWorkout,
//editWorkout,
deleteWorkout
} from '../../actions/workoutApiActionsForSaga';
import { WorkoutService } from "../../services";
import {
fetchWorkoutsSaga,
deleteWorkoutSaga,
addWorkoutSaga
} from '../workouts.saga'
describe('testing Workouts Sagas with redux-saga-test-plan', () => {
const fakeAddPayload = {
payload: {
id: '6e8dbbc8-233f-41b1-ade3-ca568b35918c',
date: '2019-05-27T18:10:35.282Z',
workoutType: 'Running',
calories: 100
}
};
const errorToThrow = {
statusText: 'custom Error Message'
};
it('should call addWorkoutSaga function', () => {
return expectSaga(addWorkoutSaga, fakeAddPayload)
.provide([
[matchers.call.fn(delay), null],
[matchers.call.fn(WorkoutService.add), null],
[matchers.call.fn(fetchWorkoutsSaga), null]
])
.call(WorkoutService.add, fakeAddPayload.payload)
.put(addWorkout.success())
.call(fetchWorkoutsSaga)
.run();
});
});
When I ran the test, I got the following error because expected value is not equal to the actual value.
Expected
--------
{ '@@redux-saga/IO': true,
combinator: false,
type: 'CALL',
payload:
{ context: null,
fn: [Function: add],
args:
[ { id: '6e8dbbc8-233f-41b1-ade3-ca568b35918c',
date: '2019-05-27T18:10:35.282Z',
workoutType: 'Running',
calories: 100 } ] } }
Actual:
------
1. { '@@redux-saga/IO': true,
combinator: false,
type: 'CALL',
payload: { context: null, fn: [Function: delayP], args: [ 1000 ] } }
at new SagaTestError (node_modules/redux-saga-test-plan/lib/shared/SagaTestError.js:17:57)
at node_modules/redux-saga-test-plan/lib/expectSaga/expectations.js:67:13
at node_modules/redux-saga-test-plan/lib/expectSaga/index.js:563:7
at Array.forEach (<anonymous>)
at checkExpectations (node_modules/redux-saga-test-plan/lib/expectSaga/index.js:562:18)
It seems to me that, the error is related to delay
function. When I tried to change the delay function to yield call(delay, 1000)
, it throws this error
Error: instead of writing `yield call(delay, 1000)` where delay is an effect from `redux-saga/effects` you should write `yield delay(1000)`
If I changed the line to yield call(delay(1000));
, it showed the following different error
Error: call: argument of type {context, fn} has undefined or null `fn`
Could you please help me how I could test my saga with delays? I don't want to remove the delay statements in the code to make the tests pass.
You can simply mock call
which delay
uses under the hood.
As described in further detail here: https://github.com/jfairbank/redux-saga-test-plan/issues/257