I've been writing some tests against an Angular Interceptor and had issues getting an instance of the interceptor.

Tests worked, roighly, like this. First create the test bed:

view plain print about
1beforeEach(() => {
2 TestBed.configureTestingModule({
3 imports: [HttpClientTestingModule, HttpClientModule],
4 providers: [
5 {
6 provide: HTTP_INTERCEPTORS,
7 useClass: MyCustomInterceptor,
8 multi: true
9 }
10 ]
11 });
12 });

Then some code to get the Interceptor:

view plain print about
1beforeEach(() => {
2 myCustomInterceptor= TestBed.inject(MyCustomInterceptor);
3 });

Then a test like this:

view plain print about
1it('should be created', () => {
2 expect(myCustomInterceptor).toBeTruthy();
3 });

That worked great. But, it was flawed. The interceptor I'm checking as an instance for is not the one actually used to intercept HTTP calls.

Here is a sample test of the interceptor:

view plain print about
1it('should run interceptor', () => {
2 httpClient.get('someUrl').subscribe(response => {
3 // expect something to happen
4 });
5 const req = httpMock.expectOne('someUrl');
6 req.flush({});
7});

That was all working fine and dandy. But, once I had to validate an instance value inside the interceptor, things went bad. This kept failing:

view plain print about
1it('should run interceptor', () => {
2 httpClient.get('someUrl').subscribe(response => {
3 expect(myCustomInterceptor.property)toBe('someValue');
4 });
5 const req = httpMock.expectOne('someUrl');
6 req.flush({});
7});

I could step through the test code with breakpoints and see that the value inside the interceptor was being set properly, but when reviewing the value in the test it was always undefined or some default value.

I batted my head around quite a bit trying to solve this. It seemed as if the interceptor instance in the test was different than the interceptor instance being used to intercept HTTP calls. Why is this?

Go back and look at the providers array:

view plain print about
1providers: [
2 {
3 provide: HTTP_INTERCEPTORS,
4 useClass: MyCustomInterceptor,
5 multi: true
6 }
7]

The providers array is looking at HTTP_INTERCEPTORS and replacing it with my custom interceptor. But, when I save the value in the beforeEach():

view plain print about
1myCustomInterceptor= TestBed.inject(MyCustomInterceptor);

I'm not getting the HTTP_INTERCEPTORS, I'm getting a brand new instance of MyCustomInterceptor.

The solution was to change how we pull the injector out of the test bed:

view plain print about
1myCustomInterceptor= TestBed.inject(HTTP_INTERCEPTORS)[1];

The TestBed.inject(HTTP_INTERCEPTORS) returns an array of the interceptors. The one I wanted was in the second position.

Once I did that, all my subsequent tests started succeeding because my tests and real code were now using the same instance.