typescriptjasminekarma-jasminejasmine-node

How to make a jasmine test of .pipe(catchError(this.handleError('get' + this.apiName, [])));


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.


Solution

  • 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' }));