Я пытаюсь написать тесты для следующей функции, которая использует оператор retryWhen
:
// 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));
}),
);
}),
);
}
Код должен выполнить запрос к некоторому удаленному API geoApi.ipLocation$()
. Если он получает ошибку, он повторяет 2 раза, прежде чем сдаться.
Я написал следующий тестовый код, который использует Jest и Rx JS 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('---^');
});
});
});
Этот тест не пройден.
Однако, когда я заменяю retryWhen(...)
просто retry(2)
, тогда тест завершается успешно.
Похоже, я не совсем понимаю, как реализовать retry
с retryWhen
. Я подозреваю, что take(2)
закрывает поток и препятствует тому, чтобы все продолжалось. Но я не совсем понимаю.
Я на самом деле хочу написать некоторые дополнительные логики c внутри retryWhen()
, но сначала мне нужно понять, как правильно реализовать retry()
с retryWhen()
. Или, возможно, это на самом деле невозможно?
Дополнительные ресурсы
Моя реализация retryWhen
+ take
была основана на этом ответе SO:
Официальные документы: