I have created polling saga which calls backend API until the response from the API is marked as done or until saga encounters an error.
export function* pollingSaga() {
while (true) {
try {
yield call(/*call to BE API*/);
const response = yield select(getResponse)
if (response.result !== 'done') {
yield call(delay, POLLING_INTERVAL_MS)
} else {
yield put(actions.cancel())
return
}
} catch (error) {
yield put(actions.cancel())
return
}
}
}
I want to create test that checks if the delay is called properly and then if the response from API is done
to check if the saga dispatches proper cancel
action
it('should poll backend until maximum amount of rows is fetched', () => {
const gen = pollingQueryResultsSaga()
/*Here I would like to mock the call to the API so it returns response 'pending'*/
gen.next() // call
gen.next() // select 'pending' value
expect(gen.next().value).toEqual(call(delay, 1000);
/*Here I would like again mock API response but right now with 'done' value so my saga will return from `while` loop and dispatch cancel action */
gen.next() // new iteration, call
expect(gen.next().value).toEqual(put(actions.cancel());
gen.next()
expect(gen.next().done).toBe(true);
})
You can send a value to the generator by calling gen.next(value)
to change the response
value. See Generator.prototype.next().
The
value
will be assigned as a result of ayield
expression
E.g.
index.ts
:
import { call, put, select } from 'redux-saga/effects';
const api = () => '';
const getResponse = (state) => state.response;
const POLLING_INTERVAL_MS = 1000;
export const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export const actions = {
cancel: () => ({ type: 'CANCEL' }),
};
export function* pollingSaga() {
while (true) {
try {
yield call(api);
const response = yield select(getResponse);
console.log('response: ', response);
if (response.result !== 'done') {
yield call(delay, POLLING_INTERVAL_MS);
} else {
yield put(actions.cancel());
return;
}
} catch (error) {
yield put(actions.cancel());
return;
}
}
}
index.test.ts
:
import { call, put } from 'redux-saga/effects';
import { actions, delay, pollingSaga } from '.';
describe('72260266', () => {
it('should poll backend until maximum amount of rows is fetched', () => {
const gen = pollingSaga();
gen.next();
gen.next();
expect(gen.next({ result: 'pending' }).value).toEqual(call(delay, 1000));
gen.next();
gen.next();
expect(gen.next({ result: 'done' }).value).toEqual(put(actions.cancel()));
expect(gen.next().done).toBe(true);
});
});
Test result:
PASS redux-saga-examples packages/redux-saga-examples/src/stackoverflow/72260266/index.test.ts (5.039 s)
72260266
✓ should poll backend until maximum amount of rows is fetched (51 ms)
console.log
response: { result: 'pending' }
at packages/redux-saga-examples/src/stackoverflow/72260266/index.ts:16:15
console.log
response: { result: 'done' }
at packages/redux-saga-examples/src/stackoverflow/72260266/index.ts:16:15
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 72 | 80 | 33.33 | 88.89 |
index.ts | 72 | 80 | 33.33 | 88.89 | 24-25
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 7.19 s