Unit test for api polling done on Redux-saga side
soumyaa1804 opened this issue · comments
Description
I am polling an API and using similar code as given in this code pen
I am trying to test the saga part of it using Jest but I am confused how to test a generator function with a delay and while loop.
In the codepen the delay is a function:
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
Can someone please help here?
Greetings!
In the codepen the actual code where delay
is being used looks like:
yield call(delay, 400);
When you run a generator for testing, you can step through that yield by calling generator.next()
.
It's hard to explain without seeing the test you've written so far, could you share that here?
Sure. The following is the saga that I have. Here getData
is the data service we have created which is simple api fetching function
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
const url = 'https://08ad1pao69.execute-api.us-east-1.amazonaws.com/dev/random_joke';
function* pollSaga(action) {
while (true) {
try {
const { data } = yield call(getData, url);
yield put(getDataSuccessAction(data));
yield call(delay, 4000);
} catch (err) {
yield put(getDataFailureAction(err));
}
}
}
And this is the test I have written so far:
describe('API polling', () => {
jest.useFakeTimers();
const url = 'https://08ad1pao69.execute-api.us-east-1.amazonaws.com/dev/random_joke';
it('should call success action', () => {
const gen = pollSaga(action);
fetch.resetMocks();
fetch.mockResponseOnce(JSON.stringify(pollingSuccessResponse));
expect(gen.next(mockSuccessPolling).value).toEqual(
call(getData, url)
);
expect(gen.next(mockSuccessPolling).value).toEqual(
put(getDataSuccessAction(pollingSuccessResponse))
);
expect(gen.next().done).toBeTruthy();
});
it('should be failure', () => {
const gen = pollSaga(action);
fetch.resetMocks();
fetch.mockResponseOnce(JSON.stringify(failureResponse));
expect(gen.next(mockSuccessPolling).value).toEqual(
call(getData, url)
);
expect(gen.throw(failureResponse.statusCode).value).toEqual(
put(getDataFailureAction(505))
);
expect(gen.next().done).toBeTruthy();
});
});
These tests are failing. I suppose as I have not considered the while
loop and also the delay
that is why it is failing. Please let me know what I am doing wrong?! Thanks
Anything that is wrapped in yield call
doesn't actually run any side-effects, it merely describes the side-effect that ought to be called. In this way, there is no need to mock your fetch. The code I wrote below confirms that you are dispatching the getDataSuccessAction
For the success:
const gen = pollSaga();
console.log(gen.next().value); // call(getData)
const dataSuccess = gen.next({ data: '123' }).value;
assert.deepEqual(dataSuccess, put(getDataSuccessAction('123')));
console.log(gen.next({ data: '123' }).value); // put(getDataSuccessAction)
console.log(gen.next().value); // call(delay)
For the failure test, you just need to throw the generator at the right place to have to properly go into the catch statement:
const gen = pollSaga();
gen.next(); // call(getData)
const dataError = gen.throw(new Error("something"));
assert.deepEqual(dataError.value.payload.action.payload.message, "something");
I'm going to close this issue for now. If you -- or anyone else -- still has issues with testing api polling please let me know here!