U gebruikt een verouderde browser. Upgrade uw browser om deze site correct weer te geven.

Testing Angular Request Interceptors


Need to test a response interceptor? We've got you covered.

If you want to read more about interceptors, and how they can be used to keep your domain models clean, look no further.


In a previous post we examined how to test an Angular response interceptor. We registered the response interceptor with the testing module and triggered a HTTP request using the HttpClientTestingModule. This allowed us to rely on Angular to call the interceptor, rather than having to mock inputs for the intercept method ourselves.

While the technique for testing request interceptors is largely the same, the differences are enough to warrant walking through a separate example.

Let's take a look at an interceptor that modifies the body of an outgoing request.

snakify.interceptor.ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ... omitted other imports
import { mapKeys, snakeCase } from 'lodash/fp'

@Injectable()
export class SnakifyInterceptor implements HttpInterceptor {

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {

    if (request.method === 'PUT' || request.method === 'POST') {
      const modifiedRequest = this.modifyRequest(request)
      return next.handle(modifiedRequest)
    }

    return next.handle(request)
  }

  private modifyRequest(request: HttpRequest<unknown>) {
    if (!request.body) { return request }

    const body = mapKeys(snakeCase, request.body as object)
    return request.clone({ body })
  }
}

This interceptor takes any request with a PUT or POST method and modifies the request body. As the name suggests, we're doing the inverse of the 'CamelifyInterceptor' of the previous post, that is converting every key on the request body from camelCase to snake_case.

Though it looks like a clean and straightforward approach, this interceptor is not suitable for real-world applications.

It fails to account for nested objects, so
{ toughShell: { withInner: 'soft' } } ends up as
{ tough_shell: { withInner: 'soft' } }.

The interceptor doesn't deal with numbers very well either. { l33t: 42 } returns { l_33_t: 42 }, which - unless you're familiar with lodash's words parser - probably isn't what you expected.

The focus of this article is on unit testing, not the functionality of the interceptor :)

The easiest way to test this interceptor is to register the interceptor in the testing module. We use the HttpClientTestingModule to create a PUT or POST request and get the resulting request body from the HttpTestingController.

snakify.interceptor.spec.ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
describe('SnakifyInterceptor', () => {
  let client: HttpClient
  let controller: HttpTestingController

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule
      ],
      providers: [
        // register the interceptor
        {
          provide: HTTP_INTERCEPTORS,
          useClass: SnakifyInterceptor,
          multi: true
        }
      ]
    })

    client = TestBed.inject(HttpClient)
    controller = TestBed.inject(HttpTestingController)
  })

  it('should convert a request body to snake case', () => {
    const body = { snakifyThis: true, aNDThIs: 'test' }
    const expected = { snakify_this: true, a_nd_th_is: 'test' }

    client.put('/test', body).subscribe()

    const put = controller.expectOne('/test')
    expect(put.request.body).toEqual(expected)
  })
})

The main difference between the response interceptor test and its request sibling is the location of the expect statement. In the case of a response interceptor we need to access the result of the HTTP call, so we nest the test assertion inside the subscribe method. But in this case we're not interested in the response at all, and we can access the request body from the controller.

Though we still need to subscribe to the put request so it actually fires, there's no need to fake any asynchronous code in this test.

We can use the same setup to test other changes to the request as well. To test whether an interceptor added request headers, for example. It's a complete and versatile interceptor test setup, in just a few lines of code.

Happy testing!


We gebruiken cookies en vergelijkbare technologieën om de gebruikerservaring te verbeteren en om content te leveren die relevant is voor onze doelgroepen. Afhankelijk van hun doel, kunnen analyse- en marketingcookies worden gebruikt naast technisch noodzakelijke cookies. Door op "Akkoord" te klikken, verklaart u akkoord te gaan met het gebruik van bovengenoemde cookies.