I am testing this service:
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { HttpHeaders } from '@angular/common/http';
import { Observable, from, of } from 'rxjs';
import { catchError, tap, map } from 'rxjs/operators';
import { HttpErrorHandler, HandleError } from './http-error-handler.service';
import { ModelService } from './model.service';
import { Area } from '../models/area';
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'my-auth-token'
})
};
@Injectable({
providedIn: 'root',
})
export class AreaService {
apiUrl = 'api/areas'; // URL to web api
apiName = 'Areas';
private handleError: HandleError;
areasUnidad = new Map<string, Area[]>();
constructor(
private http: HttpClient,
private modelService: ModelService,
httpErrorHandler: HttpErrorHandler) {
this.handleError = httpErrorHandler.createHandleError(this.apiName + 'Service');
}
getAreas(): Observable<Area[]> {
return this.http.get<Area[]>(this.apiUrl)
.pipe(
catchError(this.handleError('get' + this.apiName, []))
);
}
getAreasUnidadLocal(unidad : string) : Observable<Area[]>{
const url = `${this.apiUrl}/${unidad}`;
if(this.areasUnidad.has(unidad)){
return of(this.areasUnidad.get(unidad));
}else{
return this.http.get<Area[]>(url)
.pipe(
map( respuestaAreas => {
this.areasUnidad.set(unidad, respuestaAreas);
return respuestaAreas;
}),
catchError(this.handleError('get' + this.apiName, []))
);
}
}
resetearCache() :void{
this.areasUnidad.clear();
}
}
And with examples I have done this:
import { HttpClientTestingModule, HttpTestingController } from "@angular/common/http/testing";
import { TestBed } from "@angular/core/testing";
import { AreaService } from "./area.service";
import { HttpErrorHandler } from './http-error-handler.service';
import { ModelService } from './model.service';
import { HttpClient } from '@angular/common/http';
import { MessageService } from "./message.service";
import { Area } from '../models/area';
import { UnidadLocal } from "../models/unidadLocal";
describe('AreaService', () => {
let httpTestingController: HttpTestingController;
let service: AreaService;
let http: HttpClient;
let mService: ModelService;
let hErrorHandler: HttpErrorHandler;
let apiUrl = 'api/areas'; // URL to web api
let apiName = 'Areas';
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
providers: [
AreaService,
HttpErrorHandler,
ModelService,
MessageService
]
});
});
beforeEach(() => {
httpTestingController = TestBed.get(HttpTestingController);
service = TestBed.get(AreaService);
http = TestBed.get(HttpClient);
mService = TestBed.get(ModelService);
hErrorHandler = TestBed.get(HttpErrorHandler);
});
afterEach(() => {
httpTestingController.verify();
});
it('Should created AreaService', () => {
expect(service).toBeTruthy();
});
it('Test to Constructor', () => {
let area = new AreaService(http, mService, hErrorHandler);
expect(area).toBeDefined();
});
it('getAreas should use GET to retrieve data', () => {
service.getAreas().subscribe();
const testRequest = httpTestingController.expectOne(apiUrl);
expect(testRequest.request.method).toEqual('GET');
});
it('getAreas should return expected data', (done) => {
const expectedData: Area[] = [
{
codArea: '001',
nombreArea: 'area1',
unidad: new UnidadLocal()
}
];
service.getAreas().subscribe(data => {
expect(data).toEqual(expectedData);
done();
});
const testRequest = httpTestingController.expectOne(apiUrl);
testRequest.flush(expectedData);
});
it('getAreas should return an empty object on error', (done) => {
const expectedData: Area[] = []
service.getAreas().subscribe(data => {
expect(data).toEqual(expectedData);
done();
});
const testRequest = httpTestingController.expectOne(apiUrl);
testRequest.flush('error', { status: 500, statusText: 'Broken Service' });
});
it('getAreasUnidadLocal should use GET to retrieve data', () => {
let unidad: string = "t";
service.getAreasUnidadLocal(unidad).subscribe();
const testRequest = httpTestingController.expectOne(apiUrl + "/" + unidad);
expect(testRequest.request.method).toEqual('GET');
});
it('getAreasUnidadLocal should return expected data', () => {
let unidad:string="t";
const expectedData: Area[] = [
{
codArea: '001',
nombreArea:'area1',
unidad:new UnidadLocal()
}
];
service.areasUnidad.set(unidad, expectedData);
service.getAreasUnidadLocal(unidad).subscribe(data => {
expect(data).toEqual(expectedData);
// done();
});
const testRequest = httpTestingController.expectOne(apiUrl+"/"+unidad);
testRequest.flush(expectedData);
});
it('getAreasUnidadLocal should return an empty object on error', (done) => {
let unidad: string = "t";
const expectedData: Area[] = []
service.getAreasUnidadLocal(unidad).subscribe(data => {
expect(data).toEqual(expectedData);
done();
});
const testRequest = httpTestingController.expectOne(apiUrl + "/" + unidad);
testRequest.flush('error', { status: 500, statusText: 'Broken Service' });
});
it('resetearCache 1', () => {
service.resetearCache();
expect(service.resetearCache).toBeTruthy();
expect(service.areasUnidad.size).toBe(0);
});
it('resetearCache 2', () => {
let spy = spyOn(service, "resetearCache");
service.resetearCache();
expect(spy).toHaveBeenCalled();
});
});
But I do not know how to test the error. I mean, the pipe
with the catchError
inside of those methods.
You can provide a spy of HttpClient
...
httpClientSpy = jasmine.createSpyObj('HttpClient', {
get: of({})
});
TestBed.configureTestingModule({
providers: [
...
{ provide: HttpClient, useValue: httpClientSpy },
],
});
and simply do
httpClientSpy.get.and.returnValue(throwError({ error: 'some error' }));