How to Test a Functional Interceptor in Angular
seanbh
Posted on October 4, 2023
Photo by Ben Mullins on Unsplash
This post will build upon my previous one and show you how to test the functional interceptor that was implemented there:
import {
HttpRequest,
HttpInterceptorFn,
HttpHandlerFn,
HttpEvent,
} from '@angular/common/http';
import { Observable } from 'rxjs';
export const authInterceptor: HttpInterceptorFn = (
request: HttpRequest<unknown>,
next: HttpHandlerFn
): Observable<HttpEvent<unknown>> => {
const clonedRequest = request.clone({
setHeaders: {
Authorization: 'Bearer [the token]',
},
});
return next(clonedRequest);
};
I am going to compare and contrast testing class-based and functional interceptors in this post, but feel free to skip straight to the functional interceptor test if that is all you are interested in.
Class-Based Test
A simple class-based test might look like this:
import { TestBed } from '@angular/core/testing';
import {
HttpClientTestingModule,
HttpTestingController,
} from '@angular/common/http/testing';
import { AuthInterceptor } from './auth.interceptor';
import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
describe('AuthInterceptor', () => {
let httpTestingController: HttpTestingController;
let httpClient: HttpClient;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
AuthInterceptor,
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
],
});
httpTestingController = TestBed.inject(HttpTestingController);
httpClient = TestBed.inject(HttpClient);
});
afterEach(() => {
httpTestingController.verify();
});
it('should add auth headers ', () => {
//arrange
const url = '/mockendpoint';
//act
httpClient.get(url).subscribe();
// assert
const req = httpTestingController.expectOne(url);
expect(req.request.headers.get('Authorization')).toEqual(
'Bearer [the token]'
);
});
});
There is a fair bit of code here and I’ve gone over the details in a previous post and won’t repeat them here. The test itself is just making a (fake) HTTP request and then checking the header to verify that the token was added. It is the same regardless of whether the interceptor is class-based or functional. What does change is how we provide the interceptor.
Functional Test
Just like we did in the previous post, we need to switch to providing HttpClient using the standalone API, and then we can provide authInterceptor at the same time:
// removed the imports[]
providers: [
provideHttpClient(withInterceptors([authInterceptor])),
provideHttpClientTesting(),
],
Notice that we have also included the provideHttpClientTesting function call and removed the imports array that contained HttpClientTestingModule.
Remember, the shift to standalone includes replacing modules with function calls. Just like provideHttpClient replaced importing the HttpClientModule, provideHttpClientTesting replaces importing the HttpClientTestingModule.
Here’s the diff between the class-based and functional test:
The code difference between the class-based and functional tests
Here is the test in full:
import { TestBed } from '@angular/core/testing';
import {
HttpTestingController,
provideHttpClientTesting,
} from '@angular/common/http/testing';
import {
HttpClient,
provideHttpClient,
withInterceptors,
} from '@angular/common/http';
import { authInterceptor } from './auth.interceptor';
describe('AuthInterceptor', () => {
let httpTestingController: HttpTestingController;
let httpClient: HttpClient;
beforeEach(() => {
TestBed.configureTestingModule({
// here are the KEY changes
providers: [
provideHttpClient(withInterceptors([authInterceptor])),
provideHttpClientTesting(),
],
});
httpTestingController = TestBed.inject(HttpTestingController);
httpClient = TestBed.inject(HttpClient);
});
afterEach(() => {
httpTestingController.verify();
});
it('should add auth headers ', () => {
//arrange
const url = '/mockendpoint';
//act
httpClient.get(url).subscribe();
// assert
const req = httpTestingController.expectOne(url);
expect(req.request.headers.get('Authorization')).toEqual(
'Bearer [the token]'
);
});
});
That’s it! I hope you found this useful.
Bibliography
Posted on October 4, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.