【发布时间】:2019-02-19 04:57:14
【问题描述】:
我已经建立了一个 HttpInterceptor,它紧跟 Angular 文档中的那个。
但是,我需要将异步调用作为拦截器的一部分。我创建了一个带有简化版本代码的StackBlitz(但语义相同)。
拦截器长这样:
export class AuthInterceptor implements HttpInterceptor {
constructor(private session: SessionService, private config: ConfigurationService) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
const apiRoot = this.config.apiUrl;
if (apiRoot && req.url.startsWith(apiRoot)) {
return this.addAuth(req).pipe(switchMap(x => next.handle(x)));
} else {
return next.handle(req);
}
}
private addAuth(original: HttpRequest<any>): Observable<HttpRequest<any>> {
return from(this.session.getToken()).pipe(
map(token => {
const req = original.clone({
setHeaders: { Authorization: `Bearer ${token}` }
});
return req;
})
);
}
}
这很简单:
- 检查我们调用的 URL 是否需要我们的令牌 (
req.url.startsWith()) - 如果是,则获取我们的令牌并将其添加为 header
- 如果没有,只需继续管道
ConfigurationService 有一个简单的string 属性,名为apiUrl。
SessionService 有一个几乎同样简单的方法,名为 getToken(),它返回一个 Promise<string>。
但是,我很难测试这个...
我的实际测试很简单:
it('should add authorization header for API call', () => {
http.get('bar').subscribe();
httpMock.expectOne(req => req.headers.has('Authorization'));
});
我已经正确地模拟了getToken() 和apiUrl,以便apiUrl='bar' 和getToken() 返回Promise.resolve('foobar')。
当通过addAuth() 路径时,问题似乎只是。如果我测试反例,它会起作用:
it('should NOT add authorization header for non-API call', () => {
http.get('baz').subscribe();
httpMock.expectOne(req => !req.headers.has('Authorization'));
});
【问题讨论】:
-
我从未使用过 Observable 但
subscribe方法是异步的,不是吗?它将解释为什么标头不可用。 -
@SamuelVaillant 这是一个很好的观点。但我只是关注documentation。我认为这与一些未解决的承诺有关......
-
因此,通过包装
fakeAsync()并在.subscribe()之后调用tick(),它似乎可以工作。我会做更多的挖掘,看看是否有更直观的方法...... -
感谢您的提醒!
标签: angular unit-testing angular-http-interceptors angular-unit-test