I'm trying to unit test an http interceptor. The interceptor is used for authorization. I can test the basic success case, but I'm trying now to test the case where the API call fails because access token is out of date.
My question is, how do I spy on the AuthInterceptorService.getNewTokenAndRetryRequest() method? My interceptor & unit test code are below. When I run the unit tests, I get a "Error: Expected spy getNewTokenAndRetryRequest to have been called." error.
This is my unit test :
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
providers: [TokenStorageService,
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptorService,
multi: true
}
]
});
service = TestBed.inject(AuthInterceptorService);
});
it('should proceed to refresh token logic on 500 error', inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
let thownError: Error = null;
spyOn(service, "getNewTokenAndRetryRequest").and.stub();
Object.defineProperty(window.document, 'cookie', {
writable: true,
value: 'access_token=mycookie',
});
http.get('/data').subscribe(
response => {
expect(response).toBeTruthy();
}
);
const req = httpMock.expectOne(r =>
r.headers.has('Authorization') &&
r.headers.get('Authorization').startsWith('Bearer ewogIC') );
req.flush("failure",{ status: 500, statusText: "500 error" });
expect(service.getNewTokenAndRetryRequest).toHaveBeenCalled();
httpMock.verify();
}));
This is my code for the interceptor
export class AuthInterceptorService implements HttpInterceptor {
constructor(private tokenStorageService: TokenStorageService, private httpClient: HttpClient) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
const updatedHeaders:HttpHeaders = req.headers.set('Authorization', 'Bearer ' + this.tokenStorageService.getAccessToken());
const updatedRequest = req.clone({headers: updatedHeaders})
return next.handle(updatedRequest)
.pipe(
catchError((error: HttpErrorResponse) => {
if (error.status===500) {
console.log('500 error, try to use the refresh token');
try{
this.getNewTokenAndRetryRequest(req);
return of([]);
}catch (error) {
return throwError(error);
}
}else{
let errorMsg = `Error Code: ${error.status}, Message: ${error.message}`;
return throwError(error.error);
}
})
)
}
getNewTokenAndRetryRequest(req: HttpRequest<any>): void {
//do stuff
}
There could be a race condition where we are asserting too early. Try to assert in the subscribe callback.
Try making the following changes (follow !!):