如何测试使用Angular 6+调用可观察对象的拦截器?

时间:2019-02-15 16:02:07

标签: angular unit-testing angular-http-interceptors angular-unit-test

我建立了一个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属性,名为apiUrlSessionService具有几乎同样简单的名为getToken()的方法,该方法返回Promise<string>

代码按预期工作: response with authorization header

但是,我很难对此进行测试...

我的实际测试非常简单:

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'));
});

1 个答案:

答案 0 :(得分:0)

因此,正如我的评论之一所述,解决方法似乎是像这样使用fakeAsync()tick()

beforeEach(()=>{
    spyOn(sessionService, 'getToken').and.returnValue(Promise.resolve('foobar'));
});
it('should add authorization header for API call', fakeAsync(() => {
    http.get('bar').subscribe();
    tick();
    httpMock.expectOne(req => req.headers.has('Authorization'));
}));

尽管有道理,但如果有人可以澄清为什么我需要tick() ...我认为解决的承诺就足够了。我确实尝试过使用await http.get().toPromise();(并使用async关键字-而不是函数),但这没用。