I'm trying to write tests for the following function that uses retryWhen
operator:
// some API I'm using and mocking out in test
import { geoApi } from "api/observable";
export default function retryEpic(actions$) {
return actions$.pipe(
filter(action => action === 'A'),
switchMap(action => {
return of(action).pipe(
mergeMap(() => geoApi.ipLocation$()),
map(data => ({ data })),
retryWhen(errors => {
return errors.pipe(take(2));
}),
);
}),
);
}
The code is supposed to perform a request to some remote API geoApi.ipLocation$()
. If it gets an error, it retries 2 times before giving up.
I have written the following test code that uses Jest and RxJS TestScheduler:
function basicTestScheduler() {
return new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
}
const mockApi = jest.fn();
jest.mock('api/observable', () => {
return {
geoApi: {
ipLocation$: (...args) => mockApi(...args),
},
};
});
describe('retryEpic()', () => {
it('retries fetching 2 times before succeeding', () => {
basicTestScheduler().run(({ hot, cold, expectObservable, expectSubscriptions }) => {
const actions$ = hot('-A');
// The first two requests fail, third one succeeds
const stream1 = cold('-#', {}, new Error('Network fail'));
const stream2 = cold('-#', {}, new Error('Network fail'));
const stream3 = cold('-r', { r: 123 });
mockApi.mockImplementationOnce(() => stream1);
mockApi.mockImplementationOnce(() => stream2);
mockApi.mockImplementationOnce(() => stream3);
expectObservable(retryEpic(actions$)).toBe('----S', {
S: { data: 123 },
});
expectSubscriptions(stream1.subscriptions).toBe('-^!');
expectSubscriptions(stream2.subscriptions).toBe('--^!');
expectSubscriptions(stream3.subscriptions).toBe('---^');
});
});
});
This test fails.
However, when I replace retryWhen(...)
with simply retry(2)
, then the test succeeds.
Looks like I don't quite understand how to implement retry
with retryWhen
. I suspect this take(2)
is closing the stream and kind of preventing everything from continuing. But I don't quite understand it.
I actually want to write some additional logic inside retryWhen()
, but first I need to understand how to properly implement retry()
with retryWhen()
. Or perhaps that's actually not possible?
Additional resources
My implementation of retryWhen
+ take
was based on this SO answer:
Official docs: