I am running an experiment where I am learning angular and typescript via testing someone else code (e.g. automated unit and end to end tests). After I get it under test, I plan to repurposes it for a pet project I am working on for a university classroom.
I am at least half way through unit testing the code from here: http://jasonwatmore.com/post/2018/05/16/angular-6-user-registration-and-login-example-tutorial
I have been trying for some time to get the following code under unit test but everything I have tried from my own ideas or ideas from the internet have been unsuccessful thus far:
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from "@angular/common/http";
import { AuthenticationService } from "src/app/authenticationService/AuthenticationService";
import { Observable, throwError } from "rxjs";
import { catchError } from "rxjs/operators";
import { Injectable } from "@angular/core";
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthenticationService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('before error handle')
return next.handle(request).pipe(catchError(err => {
console.log('in error handle')
if (err.status === 401) {
// auto logout if 401 response returned from api
this.authenticationService.logout();
location.reload(true);
}
const error = err.error.message || err.statusText;
return throwError(error);
}))
}
}
The following test code and several variations have been unsuccessful to get the 'in error handle' message to show up in the console log:
import { ErrorInterceptor } from "./ErrorInterceptor";
import { of, throwError, defer } from "rxjs";
describe('ErrorInterceptor', () => {
let errorInterceptor;
let authenticationServiceSpy;
beforeEach(() => {
authenticationServiceSpy = jasmine.createSpyObj('AuthenticationService', ['logout']);
errorInterceptor = new ErrorInterceptor(authenticationServiceSpy);
})
it('should create', () => {
expect(errorInterceptor).toBeTruthy();
})
describe('intercept', () => {
let httpRequestSpy;
let httpHandlerSpy;
const error = {status: 401, statusText: 'error'};
it('should auto logout if 401 response returned from api', () => {
//arrange
httpRequestSpy = jasmine.createSpyObj('HttpRequest', ['doesNotMatter']);
httpHandlerSpy = jasmine.createSpyObj('HttpHandler', ['handle']);
httpHandlerSpy.handle.and.returnValue({
pipe: () => {
return fakeAsyncResponseWithError({});
}
});
//act
errorInterceptor.intercept(httpRequestSpy, httpHandlerSpy);
//assert
//TBD
function fakeAsyncResponseWithError<T>(data: T) {
return defer(() => throwError(error));
}
})
})
})
The basic way to handle errors in Angular is to use Angular's HttpClient service along with RxJS operators throwError and catchError. The HTTP request is made, and it returns the data with a response if anything wrong happens then it returns an error object with an error status code.
First, ng test uses Webpack to compile your code into a JavaScript bundle. The entry point for the bundle is src/test. ts . This file initializes the Angular testing environment – the TestBed – and then imports all files in the directory tree that match the pattern . spec.
Fixtures have access to a debugElement , which will give you access to the internals of the component fixture. Change detection isn't done automatically, so you'll call detectChanges on a fixture to tell Angular to run change detection.
A couple of issues here.
httpHandlerSpy.handle()
needs to be an Observable, since that will already have the pipe operator on it and then the HttpInterceptor code can pipe it to catchError as required.I put together a Stackblitz to demonstrate how I'd approach this.
From the Stackblitz, here is the spec (it
function):
it('should auto logout if 401 response returned from api', () => {
//arrange
httpRequestSpy = jasmine.createSpyObj('HttpRequest', ['doesNotMatter']);
httpHandlerSpy = jasmine.createSpyObj('HttpHandler', ['handle']);
httpHandlerSpy.handle.and.returnValue(throwError(
{error:
{message: 'test-error'}
}
));
//act
errorInterceptor.intercept(httpRequestSpy, httpHandlerSpy)
.subscribe(
result => console.log('good', result),
err => {
console.log('error', err);
expect(err).toEqual('test-error');
}
);
//assert
})
I hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With