In redux-saga
, I am using yield delay(1000);
.
During my unit test, I do expect(generator.next().value).toEqual(delay(1000));
.
I expect the test to pass.
This is my sagas.js
:
import { delay } from 'redux-saga';
export function* incrementAsync() {
yield delay(1000);
}
This is my sagas.test.js
import { delay } from 'redux-saga';
import { incrementAsync } from '../sagas';
describe('incrementAsync Saga test', () => {
it('should incrementAsync', () => {
const generator = incrementAsync();
expect(generator.next().value).toEqual(delay(1000));
});
});
● incrementAsync Saga test › should incrementAsync
expect(received).toEqual(expected)
Expected value to equal:
{"@@redux-saga/CANCEL_PROMISE": [Function anonymous]}
Received:
{"@@redux-saga/CANCEL_PROMISE": [Function anonymous]}
Difference:
Compared values have no visual difference.
How can I test redux-saga delay ?
There are two main ways to test Sagas: testing the saga generator function step-by-step or running the full saga and asserting the side effects.
By Mahesh Jawadi, October 1, 2021. Redux Saga is a middleware library that lets the Redux store interact with resources outside of itself asynchronously. It also handles asynchronous logic in applications. For example, Ajax calls, logging, accessing browsers local storage.
Such a powerful & elegant tool as Redux-Saga, a Redux side effect manager, is said to be deprecated, and no longer being maintained, starting from Jan 27, 2021.
You need to do something - as written this will call sleep (returning a promise) and then immediately throw it away! If you yield a call() then redux-saga will wait for the promise to resolve, e.g.: yield call(sleep, 2) . The best solution is in the answer above - using the delay utility function.
A good way to test Redux Saga calls is by using the call
effect. In this case, you can slightly refactor your saga as follows:
import { delay } from 'redux-saga';
import { call } from 'redux-saga/effects';
export function* incrementAsync() {
yield call(delay, 1000);
}
You would then test this like so:
import { delay } from 'redux-saga';
import { call } from 'redux-saga/effects';
describe('incrementAsync', () => {
it('should incrementAsync()', () => {
const generator = incrementAsync();
expect(generator.next().value).toEqual(call(delay, 1000));
});
});
This works because the result of the yield to call
is a simple object, describing a call to the delay
function. No need for any mocks :)
There is also of course the great redux-saga-test-plan
helper library. Using that, your test would become the following:
import { testSaga } from 'redux-saga-test-plan';
import { delay } from 'redux-saga';
import { call } from 'redux-saga/effects';
describe('incrementAsync', () => {
it('should incrementAsync()', () => {
testSaga(incrementAsync)
.next()
.call(delay, 1000)
.next()
.isDone();
});
});
If you check delay
saga effect code you can see that it is a bound function:
export const delay = call.bind(null, delayUtil)
so if you import delay
in two different modules it will be two different functions that have no visual difference.
You can check this in the codesandbox example (see test tab):
const testFunction = () => {};
describe("example bound functions equality test", () => {
it("Two bound functions are not equal", () => {
expect(testFunction.bind(this))
.not.toEqual(testFunction.bind(this));
});
});
Result is:
To test your saga you should mock your delay
effect (if you are using Jest);
import { delay } from "redux-saga";
import { incrementAsync } from "../sagas";
jest.mock("redux-saga");
describe("incrementAsync Saga test", () => {
it("should incrementAsync", () => {
const generator = incrementAsync();
expect(generator.next().value).toEqual(delay(1000));
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With