Angular 13 如何对拦截器的catchError方法进行单元测试

Angular 13 How to Unit Test Interceptor catchError method

我正在处理一个现有的 Angular 项目,我有以下带有错误处理的拦截器。 这是代码:

public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
   
    const sendAccessToken = this.moduleConfig.resourceServer.sendAccessToken;
    
    if (sendAccessToken) {
      const token = this.authStorage.getItem('access_token');
      const header = 'Bearer ' + token;

      const headers = req.headers.set('Authorization', header);

      req = req.clone({ headers });
    }
    
    return next.handle(req).pipe(
      catchError(err => {
        let errorMessage: string;
        if (err instanceof HttpErrorResponse) {

          switch (err.status) {
            
            case 401: {
              errorMessage = 'Autorisation required.';
              break;
            }

            default: {
              const erreurText = err.error.messages[0].message
              break;
            }
          }
        }

        this.toastr.error(errorMessage);
        const error = err.error;

        return error;

      }),
    ) as any;
  }

这是我的测试,我想在其中触发捕手错误,但我不知道该怎么做:

  it('#should handle incorrect url', () => {
    const requestMock = new HttpRequest('GET', '/wrongtest');
    interceptor.intercept(requestMock, next).subscribe(() => {
      expect(requestMock.headers.has('Authorization')).toEqual(false);
    });
  });

任何人都可以指导我如何触发我的 HttpRequest 中的错误。

提前致谢。

假设您使用 jasmine 进行测试:

  1. 注入所有测试依赖项:
// Necessary to inject the right HTTP interceptor
const interceptorOf = <T>(type: Type<T>) =>
  TestBed
    .inject(HTTP_INTERCEPTORS)
    .find(interceptor => interceptor instanceof type) as unknown as T

describe('...', () => {
  let httpClient: HttpClient
  let httpMock: HttpTestingController
  let interceptor: ErrorInterceptor

  beforeEach(async () =>
    await TestBed.configureTestingModule({
      imports: [
        // Load all your interceptor's dependencies
        HttpClientTestingModule,
      ],
      providers: [
        {
          provide: HTTP_INTERCEPTORS,
          deps: [], // Fill with your interceptor's dependencies 
          useClass: ErrorInterceptor,
          multi: true
        },
      ],
    }).compileComponents()
    httpMock = TestBed.inject(HttpTestingController)
    httpClient = TestBed.inject(HttpClient)
    interceptor = interceptorOf(ErrorInterceptor)
  })
})
  1. 调用普通端点并模拟响应:
it('should do something', async () =>{
    const observable$ = httpClient.get(testUrl)
    const serviceUnavailable = new HttpErrorResponse({
      status: 503,
      statusText: 'Service Unavailable',
      url: testUrl
    })

    const httpReqPromise = firstValueFrom(observable$)
    httpMock.expectOne(testUrl).flush('error', serviceUnavailable)
    
    try {
      await httpReqPromise
      fail('It should have not succeeded')
    } catch(error) {
       expect(error instanceof HttpErrorResponse).toBeTrue()
       expect(error.status).toBe(503)
    }
})

注1:您的catchError管道用法无效;你不应该 return 一个错误,而是一个将被用来代替崩溃的可观察对象。

catchError(err => {
  ...
  const error = err.error;
  return of(error);
})

注意 2:如果您像我在上面的代码片段中所做的那样,您的错误将传播到“下一个”回调中,该回调应该将以下承诺解析为成功

it('should do something', async () =>{
    const observable$ = httpClient.get(testUrl)
    const serviceUnavailable = new HttpErrorResponse({
      status: 503,
      statusText: 'Service Unavailable',
      url: testUrl
    })

    const httpReqPromise = firstValueFrom(observable$)
    httpMock.expectOne(testUrl).flush('error', serviceUnavailable)
    
    try {
      const error = await httpReqPromise
      expect(error instanceof HttpErrorResponse).toBeTrue()
      expect(error.status).toBe(503)
    } catch(__) {
      fail('It should have not thrown')
    }
})