我想测试一个 http 错误拦截器情况,其中下一个句柄最初抛出一个错误,并且嵌套的可观察对象发出一个值。问题是,虽然“switchMap”的代码按照测试的预期执行,但嵌套的 catchError 的代码也被触发。
预期的行为是在执行
return next.handle(cloneReq)
时终止代码。
我想了解如何重构测试用例的代码以防止在这种情况下触发嵌套的 catchError 代码。
错误拦截器.ts
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<any> {
return next.handle(request).pipe(
catchError((error: ErrorResponse) => {
if (error.status === 401) {
return this.authService
.refreshToken(localStorage.getItem('item')!)
.pipe(
switchMap((res: LoginResponse) => {
//some code here
return next.handle(cloneReq);
}),
catchError(x => {
this.authService.logOut();
return _throwError();
})
);
}
})
}
error.interceptor.spec.ts
it('should done some things', () => {
const error = {
status: 401,
ignore: false,
message: 'test-error',
};
const loginResponse: LoginResponse = {
accessToken: 'test-access-token123',
};
spyOnProperty(service, 'tokenRefreshed', 'get').and.returnValue(false);
spyHttpHandler.handle.and.returnValue(throwError(() => error));
spyRefreshToken.and.returnValue(of(loginResponse));
service.intercept(spyHttpRequest, spyHttpHandler).subscribe();
expect(spyLogout).not.toHaveBeenCalled();
});
显然经过大量调试后,问题是“httphandler”的“handle”函数仅被监视一次,但对该函数的实际调用是两次。
所以,当代码到达这里时
返回 next.handle(cloneReq);
因为间谍会为函数的所有后续调用抛出错误,所以调用嵌套的 catchError 块。
通过将间谍更改为以下内容可以解决问题:
spyHttpHandler.handle.and.returnValues(
throwError(() => error),
of(10)
);
通过此更改,handle 方法的第二次实际调用将返回一个值为 10 的虚拟可观察量,并且测试将在不调用嵌套的 catchError 块的情况下终止。