It looks like you inverted the logic of the mergeMap()
operator used in retryWhen()
. You should return timer(100)
if there are less than 3 attempts, like this:
describe('marble', () => {
let service: SocketService;
beforeEach(() => service = new SocketService());
it('should make 3 attempts and reconnect on 3rd', () => {
const values = {
a: {
status: 200
}
};
const expected = '203ms a';
(service as any).socket = {};
spyOn(localStorage, 'getItem').and.returnValue('hello');
testScheduler.run(({ cold, expectObservable }) => {
const source$ = createRetryableStream(
cold('-#'),
cold('-#'),
cold('-a', values)
).pipe(
retryWhen(errors => errors.pipe(
mergeMap((err, i) => {
return 3 > i
? timer(100, testScheduler)
: throwError(err);
})
))
);
// trigger close socket event to make listener work
service.onClose.next();
expectObservable(source$).toBe(expected, values);
});
});
});
Other than that, expecting more than one terminal event was not correct. You can only have one terminal event (either error or completion) at most (which means that you don't have to have any).
If an error happens in some inner observable and gets handled by an inner operator, it won't be visible from the outside. So, expected values can not be like -# 5s # 5s (a|)
. Based on marbles '-#'
, '-#'
and '-a'
provided to the cold
observables, the expected output will be '203ms a'
(waiting 3 times 1 ms for 3 -
signs + two timer
s waiting 100 ms for two errors, then emitting a
).
Since source observable doesn't have terminal event (the last one, which you were targeting to re-subscribe with retryWhen
), you can't have terminal event in expected marbles at all. If you need terminal event, use this -a|
in third cold
observable and '203ms a|'
as expected
.