I want to test an http error interceptor case where next handle throws initially an error and the nested observable emits a value. The problem is that although 'switchMap's' code is executed as it is expected from the test, also the nested catchError's code is getting triggered.
The expected behavior is for the code to be terminated when return next.handle(cloneReq)
is executed.
I would like to get some insight on how to refactor the code of the test case to prevent the nested catchError's code to be triggered in this scenario.
error.interceptor.ts
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<any> {
return next.handle(request).pipe(
catchError((error: ErrorResponse) => {
if (error.status === 401) {
return this.authService
.refreshToken(localStorage.getItem('item')!)
.pipe(
switchMap((res: LoginResponse) => {
//some code here
return next.handle(cloneReq);
}),
catchError(x => {
this.authService.logOut();
return _throwError();
})
);
}
})
}
error.interceptor.spec.ts
it('should done some things', () => {
const error = {
status: 401,
ignore: false,
message: 'test-error',
};
const loginResponse: LoginResponse = {
accessToken: 'test-access-token123',
};
spyOnProperty(service, 'tokenRefreshed', 'get').and.returnValue(false);
spyHttpHandler.handle.and.returnValue(throwError(() => error));
spyRefreshToken.and.returnValue(of(loginResponse));
service.intercept(spyHttpRequest, spyHttpHandler).subscribe();
expect(spyLogout).not.toHaveBeenCalled();
});
Apparently after a lot of debugging the problem was that 'httphandler's' 'handle' function is spied only once but the actual calls to this function are two.
So, when the code reaches this point
return next.handle(cloneReq);
because the spy throws an error for all subsequent calls of the function, the nested catchError block is called.
The problem is fixed by changing the spy to the following:
spyHttpHandler.handle.and.returnValues(
throwError(() => error),
of(10)
);
With this change the second actual call of handle method returns a dummy observable with a value 10 and the test is terminated without calling the nested catchError block.