【问题标题】:how do I test an interceptor which calls an observable with Angular 6+?如何测试使用 Angular 6+ 调用 observable 的拦截器?
【发布时间】: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 属性,名为apiUrlSessionService 有一个几乎同样简单的方法,名为 getToken(),它返回一个 Promise&lt;string&gt;

代码按预期工作:

但是,我很难测试这个...

我的实际测试很简单:

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


【解决方案1】:

因此,正如我的一个 cmets 所述,修复似乎是像这样使用 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 关键字 - 不是函数),但这不起作用。

【讨论】:

    猜你喜欢
    • 2018-07-08
    • 1970-01-01
    • 2019-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-28
    • 2018-12-24
    • 2020-11-08
    相关资源
    最近更新 更多