简体   繁体   中英

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

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/jest-lite@1.0.0-alpha.4/dist/core.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>

As already pointed out in the other answer, you have to subscribe to the returned observable.

I just wanted to add another approach which uses marble-testing , so you don't have to manually subscribe to that observable:

let testScheduler;

beforeEach(() => testScheduler = new TestScheduler(assertionFn))

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

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

  testScheduler.run(({ cold, expectObservable }) => {
    const src$ = httpService.requestCall('some-url', ApiMethod.PUT, {});
    
    expectObservable(src$).toBe('#', null, { error: error.message, status: error.status });
    expect(spy).toBeCalled();
  });
});

TestScheduler is available in rxjs/testing and the run 's callback provides several helpers, such as: cold , hot , flush , expectObservable , expectSubscriptions and time .

What I personally like about this is that everything is synchronous, so you might not have to call done() when following such approach.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM