angular - Angular 单元测试 HTTP 错误拦截器 catchError/ErrorEvent/Error
问题描述
我的 HTTP 拦截器有非常奇怪的问题,我真的无法管理。更准确地说,当更改ErrorEvent
为Error
或反之时,它涵盖了 if/else 条件之一,但使另一个条件不在代码覆盖范围内。我正在使用 Angular 9、Jest 24 和 RxJS 6。
http-error.interceptor.ts
import {
HttpErrorResponse,
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest
} from '@angular/common/http';
import { catchError } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs';
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
let errorMessage: string;
return next.handle(request).pipe(
catchError((err: HttpErrorResponse) => {
if (err.error instanceof ErrorEvent) {
// Client-side error.
errorMessage = `An error occurred: ${err.error.message}`;
alert('Network error.');
} else {
// Server-side error.
alert('Server unavailable.');
errorMessage = `Backend returned code ${err.status}, body was: ${err.error}`;
}
return throwError(errorMessage);
})
);
}
}
使用此设置,下面的测试在没有覆盖else
部件的情况下通过。
http-error.interceptor.spec.ts
import { TestBed } from '@angular/core/testing';
import { HttpErrorInterceptor } from './http-error.interceptor';
import {
HttpClientTestingModule,
HttpTestingController
} from '@angular/common/http/testing';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { RegisterService } from './register.service';
describe('HttpErrorInterceptor', () => {
let httpErrorInterceptor: HttpErrorInterceptor;
let httpTestingController: HttpTestingController;
let registerService: RegisterService;
beforeEach(async () =>
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
RegisterService,
{
provide: HTTP_INTERCEPTORS,
useClass: HttpErrorInterceptor,
multi: true
}
]
})
);
beforeEach(() => {
httpErrorInterceptor = new HttpErrorInterceptor();
httpTestingController = TestBed.inject(HttpTestingController);
registerService = TestBed.inject(RegisterService);
});
it('should catch errors when calling fake URL', async () => {
const fakeURL = 'https://fakeapi.com';
const fakeDataToBeSend = {
firstName: 'Daniel',
lastName: 'Danielecki',
email: 'daniel.danielecki@foo.com'
};
jest.spyOn(window, 'alert').mockImplementation(() => {}); // Note: window.alert = jest.fn() works too, but it contaminates other tests, therefore try to avoid it.
// Make an HTTP POST request
await registerService.registerUser(fakeDataToBeSend, fakeURL).subscribe(); // https://github.com/angular/angular/issues/18345 ????
httpTestingController
.expectOne(fakeURL)
.error(new ErrorEvent('Network error.')); //Error type instance can't be passed.
expect(window.alert).toHaveBeenCalledWith('Network error.');
// httpTestingController
// .expectOne(fakeURL)
// .error(new ErrorEvent('Server unavailable.')); //Error type instance can't be passed.
// expect(window.alert).toHaveBeenCalledWith('Server unavailable.');
});
现在,在我要更改的http-error.interceptor.tsErrorEvent
中Error
,测试将失败。但是,如果在http-error.interceptor.spec.ts中,我将进行如下更改,测试通过。但是,if
没有涵盖,但是else
。
// httpTestingController
// .expectOne(fakeURL)
// .error(new ErrorEvent('Network error.')); //Error type instance can't be passed.
// expect(window.alert).toHaveBeenCalledWith('Network error.');
httpTestingController
.expectOne(fakeURL)
.error(new ErrorEvent('Server unavailable.')); //Error type instance can't be passed.
expect(window.alert).toHaveBeenCalledWith('Server unavailable.')
解决方案
推荐阅读
- gnupg - 如何使用 *.pub/*.sec 文件加密/解密另一个文件?
- mysql - nodejs用'SET @'XXX''表达mysql查询
- javascript - 如何让用户能够添加另一个选择数据?
- amazon-dynamodb - 如何在 GraphQL 中添加业务键/唯一约束 - AppSync AWS
- sql-server - F# - 如何在数据库中高效地存储和加载 DU/记录树
- pass-by-reference - 如何在 Visual Basic 中将变量分配给控件元素参数的指针?
- c# - 当我有 .AspNetCore.Session cookie 时,如何在 asp .net core 2.1 中获取会话?
- r - 如何将 RGB 值的向量转换为十六进制
- java - 在 Microsoft Word 中查找文本并替换为 Java 字符串数组
- go - Golang - Visual Studio Code 中的本地导入警告