I'm writing an Angular 10 app. I need to create an Interceptor that will retry all failed idempotent HTTP requests. After reading some online tutorials, I wrote an Interceptor that I thought would do the trick. Then I wrote a test to verify that it was working. Unforunately, my test will not fail; even when I modify the Interceptor to make the test fail, it doesn't fail.
Here's the Interceptor:
export class RetryInterceptor implements HttpInterceptor {
// private IDEMPOTENT_METHODS = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'PUT', 'TRACE']; // this is the real prod code.
private IDEMPOTENT_METHODS = ['POST']; // this should cause my test to fail, but it doesn't.
constructor(private router: Router, private logger: NGXLogger) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('here'); // I've confirmed that this is being printed to the console.
if (this.IDEMPOTENT_METHODS.includes(request.method)){
console.log('there'); // I've confirmed that this is being printed to the console.
return next.handle(request)
.pipe(
retry(1));
}
else{
return next.handle(request);
}
}
}
Here's the test:
describe('RetryInterceptor', () => {
let httpTestingController: HttpTestingController;
let http: HttpClient;
let router: Router;
let location: Location;
let fixture;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
LoggerTestingModule,
RouterTestingModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: httpTranslateLoader,
deps: [HttpClient]
}
})
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: RetryInterceptor,
multi: true,
},
],
});
httpTestingController = TestBed.inject(HttpTestingController);
http = TestBed.inject(HttpClient);
router = TestBed.inject(Router);
location = TestBed.inject(Location);
fixture = TestBed.createComponent(AppRootComponent);
router.initialNavigation();
});
it('should not retry POSTs', fakeAsync( // I am expecting this to fail.
() => {
http.post('/api/resource', {}).subscribe(response => expect(response).toBeTruthy());
httpTestingController.expectOne({method: 'POST', url: '/api/resource'}).error(
new ErrorEvent('network error', { message: 'bad request' }), { status: 400 });
tick(); // the first tick is intended to make a call to the httpTestingController, which will return an error, which will be caught by my Interceptor.
tick(); // on the second tick, my Interceptor should retry the failed call. this should, in turn, fail the test, because I have not set up a second expectation.
})
);
});
Can anyone spot what I'm doing wrong? Is my Interceptor broke? or is my test broke?
interceptor is fine. you need to verify your http testing controller at the end of your test to catch unexpected requests:
// insert this at end of test or in an afterEach() block
httpTestingController.verify()
generally, any unit test relating to http requests should end with a verify.
docs:
https://angular.io/guide/http#testing-http-requests https://angular.io/api/common/http/testing/HttpTestingController#verify