I am currently in the process of testing an Http Interception service that utilizes routing to redirect to another URL upon encountering an error response. All of my tests are passing smoothly since I am not specifically testing the routing functionality itself, however, an exception keeps popping up on my console.
Unhandled Promise rejection: Cannot match any routes. URL Segment: 'login' ; Zone: ProxyZone ; Task: Promise.then ; Value: Error: Cannot match any routes. URL Segment: 'login'
Despite attempting to put a spy on my router service for the navigateByUrl function, it seems like the spy is not being invoked as expected, resulting in the persistent occurrence of the same error. I have experimented with RouterTestingModule and Router Stubbing, but it appears that my service is utilizing a different Router Service rather than the one provided in my .spec file.
Below is a snippet of my .spec code (I have withheld the URL for confidentiality reasons):
import { TestBed } from '@angular/core/testing';
import { AuthInterceptorService } from './auth-interceptor.service';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpService } from '../http/http.service';
import { InternalDataService } from '../internal-data/internal-data.service';
import { Router } from '@angular/router';
describe('Service: AuthInterceptor', () => {
let service: HttpService;
let httpMock: HttpTestingController;
let data: InternalDataService;
let router = {
navigate: jasmine.createSpy('navigateByUrl')
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
],
providers: [
HttpService,
InternalDataService,
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptorService,
multi: true
},
{
provide: Router,
useValue: router,
}
],
});
service = TestBed.get(HttpService);
httpMock = TestBed.get(HttpTestingController);
router.navigate.and.callFake(() => {});
});
it('should add authentication header', () => {
data = TestBed.get(InternalDataService);
data.setAuthToken('Test');
service.getProducts().subscribe(res => {
expect(res).toBeTruthy();
})
const httpRequest = httpMock.expectOne('<doesnt matter>');
expect(httpRequest.request.headers.has('Authorization')).toEqual(true);
expect(httpRequest.request.headers.get('Authorization')).toEqual('Token Test');
});
Below is the code snippet for my Service:
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpResponse, HttpErrorResponse } from '@angular/common/http';
import { InternalDataService } from '../internal-data/internal-data.service';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthInterceptorService implements HttpInterceptor {
private token: string;
constructor(private internal: InternalDataService, private router: Router) {
this.internal.getAuthToken.subscribe( msg => this.token = msg );
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if(request.url.match('.*\/auth$') == null) { // ignore if it's an authentication url
request = request.clone({
setHeaders: {
Authorization: `Token ${this.token}`
}
});
}
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
if(error.status == 401 || error.status == 403){
this.internal.setIsAuth(false);
this.router.navigateByUrl('/login');
}
return throwError(error);
})
);
}
}
If anyone can pinpoint what might be going wrong here, your insight would be greatly appreciated.