1

So I'm attempting to unit test my interceptor with out using testbed. The interceptor merely appends the Auth headers with a bearer token. I can't seem to figure out how to actually check that those headers have been appended. When subscribe to the interceptor returning the observable next.handle() I get nothing as a response, further to that all code in the subscribe block doesn't execute. I'm using Angular version 15.2.2 and Jest 28.1.3 and RxJs 7.5.6.

Interceptor

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.authService.isLoggedIn()) {
  return this.authService.acquireToken().pipe(
    switchMap((data: any) => {
      if (data !== null) {
        let updatedRequest: HttpRequest<any>;
        const authToken = data.accessToken;
        updatedRequest = request.clone({
          setHeaders: {
            Authorization: `Bearer ${authToken}`,
          },
        });
        updatedRequest.headers.append('Authorization', `Bearer ${authToken}`);
        return next.handle(updatedRequest);
      }
    })
  );
} else {
  return EMPTY;
}

Unit test

it('[Intercept] Should intercept the API requests and append auth token if user logged in', (done: DoneCallback) => {
const next: any = {
  handle: () => {
    return Observable.create((subscriber) => {
      subscriber.complete();
    });
  },
};
const requestMock = new HttpRequest('GET', '/test');
const y = interceptor.intercept(requestMock, next).pipe(
  map((r) => r),
  catchError(() => throwError('err')),
  take(1),
  finalize(() => {
    done();
  })
);
y.subscribe((i) => {
  console.log('API call intercepted'), console.log(requestMock.headers);
});

});

Any help would be appreciated because I'm totally lost! Thanks all.

Lewis Morgans
  • 251
  • 1
  • 4
  • 14

1 Answers1

1
 updatedRequest.headers.append('Authorization', `Bearer ${authToken}`);

This line won't modify updatedRequest.headers, it will create new HttpHeaders instance instead.

The code inside subscribe is not executed because the Observable never emits any value, it just completes immediately.

This is how I test similar interceptor in my application:

it('should add authorization header', () => {

    // interceptor depends on AuthStateService
    authStateService.setState({
      token: 'fake-token'
    })

    const next: HttpHandler = {
      handle: () => {
        return new Observable((subscriber: Subscriber<any>) => {
          subscriber.complete();
        });
      }
    };
    const requestMock = new HttpRequest('GET', '/test');

    spyOn(next, 'handle').and.callThrough();

    tokenInterceptor.intercept(requestMock, next).subscribe();

    expect(next.handle).toHaveBeenCalledWith(requestMock.clone({
      headers: requestMock.headers.append('Authorization', `Bearer fake-token`)
    }))

  });
displayName
  • 986
  • 16
  • 40
  • Thanks for that @displayName. That's exactly the answer, working like a charm now. Not included in the question was: mockAuthenticationService = { isLoggedIn: () => true, acquireToken: () => of({ accessToken: 'lewis' }), }; So not really sure, attempting to log a response in your code also didn't work. And thank you for pointing out my mistake with the headers, it makes learning a lot more enjoyable! Will mark this as the resolution, cheers. – Lewis Morgans Mar 14 '23 at 10:37
  • @LewisMorgans I think code inside subscribe doesn't get executed because the Observable never emits any value. It just completes immediately. If you add `subscriber.next(someValue)` before `subscriber.complete()` it should get executed. However, it's not really important for the test if you write it this way. – displayName Mar 14 '23 at 10:44