Error when testing HttpInterceptor Angular 10

474 views Asked by At

I'm working on an Angular 10 application that uses an HttpInterceptor for adding a specific header to all responses. Unfortunately, when trying to test this interceptor, I keep getting the following error:

Error: Expected one matching request for criteria "Match by function: ", found none.

Or a similar variant:

Error: Expected one matching request for criteria "Match URL: /endpoint", found none.

My expectation is that this test would pass but I'm, now, at a loss as to figuring out why it's not working.

Here is my interceptor:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    constructor(private kc: KeycloakService) { }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return Observable.fromPromise(this.kc.getToken()).mergeMap(auth => {
            if (auth) {
                req = req.clone({
                    setHeaders: {
                        Token: auth
                    }
                });
            }

            return next.handle(req);
        })
    }
}

Here is my test:

// imports removed for clarity

describe('Interceptor', () => {
    let http: HttpClient;
    let httpController: HttpTestingController;
    let mockKeycloakService: KeycloakService;
    let interceptor: AuthInterceptor;

    const TEST_TOKEN = 'test-token';

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [HttpClientTestingModule],
            providers: [
                KeycloakService,
                {
                    provide: HTTP_INTERCEPTORS,
                    useClass: AuthInterceptor,
                    multi: true
                }
            ],
        });

        http = TestBed.inject(HttpClient);
        httpController = TestBed.inject(HttpTestingController);
        mockKeycloakService = TestBed.inject(KeycloakService);

        spyOn(mockKeycloakService, 'getToken').and.returnValue(new Promise<string>(() => TEST_TOKEN));

        interceptor = new AuthInterceptor(mockService);
    });

    // removed for clarity

    it('adds token to all responses', done => {
        let endpoint = '/endpoint';
        http.get<HttpResponse<any>>(endpoint).subscribe(res => {
            expect(res).toBeTruthy();
            expect(res.headers).toBeTruthy();
            expect(res.headers.get('Token')).toBe(TEST_TOKEN);
        });
        let req = httpController.expectOne(endpoint);

        // The first error occurred when I tried this:
        // let req = httpController.expectOne(res => res.headers.has('Token') && res.headers.get('Token') === TEST_TOKEN);

        let body = { test: 'test-value' };
        console.log(`The URL is: ${req.request.url}`);
        expect(req.request.body).toEqual(body);

        req.flush(body);
        httpController.verify();
    });

    // removed for clarity
});

That said, it's probably worth pointing out that I've tried applying solutions from the following resources to no avail (most seem to be similar to what I already have anyways and many seem to be for older versions of Angular):

  • Unit testing HttpInterceptor from Angular 4: Here, I found a useful article that does almost exactly what I need but it doesn't actually work for my case (I'm getting the above errors). I say almost exactly because the Service I'm using to get the token doesn't actually use HttpClient from what I can tell.
  • This isn't exactly like my issue but it was similar enough to try it out. I tried using the workaround described by textbook but apparently that wasn't close enough to the issue I was having.
  • I also tried to spyOn the http.get(...) function in my test which caused the above error to be eliminated but it didn't call my intercept function when I did that.

Any help is much appreciated - thank you!

0

There are 0 answers