Search code examples
angularrxjsjestjsobservableangular-jest

Mocking Observable to throw error in Jest


I am trying to mock the PUT call of HttpClient of Angular to throw error. I am using throwError for it. It isn't working. What should I change to make it throw the error and call the handleError method? I am using Jest.

it(`should call the 'handleError' method when a request to store data was not successful`, () => {
    const error: HttpErrorResponse = {
      status: 401,
      message: 'You are not logged in',
    } as HttpErrorResponse;

    jest.spyOn(httpClientServiceMock, 'put').mockReturnValue(throwError(error));
    const spy = jest.spyOn(httpService, 'handleError');

    httpService.requestCall('some-url', ApiMethod.PUT, {});
    expect(spy).toBeCalled();
  });

service file

  requestCall(url: string, method: ApiMethod, data?: any): Observable<any> {
    const headers = {
      'X-XSRF-TOKEN': this.xsrfToken,
      'Content-Type': 'application/json; charset=UTF-8',
    };

    const requestConfig = {
      withCredentials: true,
      headers,
    };

    switch (method) {
      case ApiMethod.GET:
        return this._http.get(url, { withCredentials: true });
      case ApiMethod.PUT:
        return this._http
          .put(url, data, requestConfig)
          .pipe(catchError((error) => this.handleError(error)));
    }
  }

  handleError(error: HttpErrorResponse): any {
    if (error.error instanceof ErrorEvent) {
      console.error(`An error occurred: ${error.error.message}`);
    }

    return throwError({ error: error.message, status: error.status });
  }

Solution

  • You were pretty close!

    You have to subscribe to observable returned from httpService.requestCall('some-url', ApiMethod.PUT, {}) function. There are additional changes required as this is asynchronous

    const { of , throwError, operators: {
        catchError
      }
    } = rxjs;
    
    const httpClientServiceMock = {
      put: () => of ({
        value: 'test'
      })
    };
    
    const httpService = {
      requestCall(url, data, requestConfig) {
    
        return httpClientServiceMock
          .put(url, data, requestConfig)
          .pipe(catchError((error) => this.handleError(error)));
      },
      handleError(error) {
        return throwError({});
      }
    };
    const ApiMethod = {
      PUT: ''
    }
    
    
    
    const {
      expect,
      test,
      run,
      it,
      describe,
      jest
    } = jestLite.core;
    
    describe('httpService', () => {
    
      it(`should call the 'handleError' method when a request to store data was not successful`, done => {
        const error = {
          status: 401,
          message: 'You are not logged in',
        }
    
        jest.spyOn(httpClientServiceMock, 'put').mockReturnValue(throwError(error));
        const spy = jest.spyOn(httpService, 'handleError');
    
        httpService
          .requestCall('some-url', ApiMethod.PUT, {})
          .subscribe(pr => {
            done.fail(new Error(`It shouldn't go this path!`))
          }, error => {
            expect(spy).toBeCalled();
            done();
          });
    
      });
    
    });
    
    run().then(result => {
      console.log(result[0]);
    })
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/core.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>