简体   繁体   English

Mocking Observable 在 Jest 中抛出错误

[英]Mocking Observable to throw error in Jest

I am trying to mock the PUT call of HttpClient of Angular to throw error.我试图模拟 Angular 的HttpClientPUT调用以引发错误。 I am using throwError for it.我正在使用throwError It isn't working.它不工作。 What should I change to make it throw the error and call the handleError method?我应该改变什么让它抛出错误并调用handleError方法? I am using Jest .我正在使用 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.您必须订阅httpService.requestCall('some-url', ApiMethod.PUT, {}) function 返回的 observable。 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.正如在另一个答案中已经指出的那样,您必须订阅返回的 observable。

I just wanted to add another approach which uses marble-testing , so you don't have to manually subscribe to that observable:我只是想添加另一种使用marble-testing 的方法,因此您不必手动订阅该 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 . TestSchedulerrxjs/testing中可用,并且run的回调提供了几个帮助器,例如: coldhotflushexpectObservableexpectSubscriptionstime

What I personally like about this is that everything is synchronous, so you might not have to call done() when following such approach.我个人喜欢的是一切都是同步的,所以在遵循这种方法时你可能不必调用done()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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