I have a simple HttpClient interceptor that just retries failed requests a set amount of times. Now, I'm trying to write unit tests for it but somehow I end up with an unfinished request. I've tried wrapping the test in fakeAsync
or using done
but it does not seem to help. Right now I am out of ideas.
The error I get is:
Error: Expected no open requests, found 1: GET mock/url
What am I missing?
server-error.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
import { retry } from 'rxjs/operators';
import { ConfigService } from '@app/shared/services/config.service';
/**
* Http error interceptor class
*/
@Injectable()
export class ServerErrorInterceptor implements HttpInterceptor {
constructor(private configService: ConfigService) {}
/**
* Intercepts failed requests and retries set amount of times before throwing an error
*
* @param request HTTP request
* @param next HTTP handler
*
* @returns Observable of Http event
*/
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(retry(this.configService.config.httpRetryCount));
}
}
server-error.interceptor.spec.ts
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController, TestRequest } from '@angular/common/http/testing';
import { HTTP_INTERCEPTORS, HttpClient, HttpErrorResponse } from '@angular/common/http';
import { ServerErrorInterceptor } from '@core/interceptors/server-error.interceptor';
import { ConfigService } from '@shared/services/config.service';
const mockUrl = 'mock/url';
const mockHttpRetryCount = 5;
const mockErrorText = 'Mock error!';
const mockConfigService: object = {
config: jest.fn().mockReturnValue({
httpRetryCount: mockHttpRetryCount
})
};
describe('ServerErrorInterceptor', () => {
let httpClient: HttpClient;
let httpTestingController: HttpTestingController;
let interceptor: ServerErrorInterceptor;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
ServerErrorInterceptor,
{ provide: ConfigService, useValue: mockConfigService },
{ provide: HTTP_INTERCEPTORS, useClass: ServerErrorInterceptor, multi: true }
]
});
httpClient = TestBed.get(HttpClient);
httpTestingController = TestBed.get(HttpTestingController);
interceptor = TestBed.get(ServerErrorInterceptor);
});
afterEach(() => {
httpTestingController.verify();
});
it('should be created', () => {
expect(interceptor).toBeTruthy();
});
it('should retry an errored request set amount of times', (): void => {
httpClient.get(mockUrl).subscribe(
null,
(response: HttpErrorResponse): void => {
expect(response.status).toEqual(500);
expect(response.message).toEqual(`Http failure response for ${mockUrl}: 500 Server Error`);
}
);
for (let i = 0; i < mockHttpRetryCount; i += 1) {
const request: TestRequest = httpTestingController.expectOne(mockUrl);
request.flush(mockErrorText, { status: 500, statusText: 'Server Error' });
}
});
});
I've actually found an answer myself. There were 3 separate bugs in my code:
ConfigService
was mocked the wrong way, and was returning undefined
for httpRetryCount
for
loop in the test should be fired mockHttpRetryCount + 1
to account for all the retries and then the final result (either positive or negative)