如何使我的Jasmine测试到达mergeMap中的此回调?

时间:2018-12-12 18:49:59

标签: angular unit-testing jasmine jwt karma-jasmine

我正在使用Angular6,并且试图使我的Jasmine测试到达mergeMap波纹管内部的回调,但是经过几天的工作,我却无能为力。

callback inside mergeMap highlighted

我的测试正确返回了刷新方法,但似乎并没有通过管道。

这是我要测试的完整方法:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
    if (
      this.jwtInterceptor.isWhitelistedDomain(req) &&
      !this.jwtInterceptor.isBlacklistedRoute(req)
    ) {
      const newRequest = req.clone();
      return next.handle(newRequest).pipe(
        tap(() => {
          const token = this.jwtHelper.tokenGetter();
          if (token) {
            const expirationTime = this.jwtHelper
              .getTokenExpirationDate()
              .getTime();
            const expirationLeft = expirationTime - Date.now();
            const expired =
              expirationLeft > 0 && expirationLeft < 5 * 60 * 1000;
            if (expired && !this.isUpdating) {
              this.isUpdating = true;
              return this.refresh().pipe(
                mergeMap(() => { // this is the unreachable part
                  return this.jwtInterceptor.intercept(req, next);
                })
              );
            }
          }
        }),
        catchError(err => {
          if (err instanceof HttpErrorResponse && err.status === 401) {
            this.router.navigate([this.config.routeToGoIfNotLoggedIn]);
          }
          return throwError(err);
        })
      );
    } else {
      return next.handle(req);
    }
  }

这里返回了我的this.refresh()方法:

refresh(): Observable<any> {
    const refreshObservable = this.authAPI.refreshToken();
    const refreshSubject = new ReplaySubject<any>(1);
    refreshSubject.subscribe(
      data => {
        localStorage.setItem('token', data.jwt);
        this.isUpdating = false;
      },
      err => {
        this.isUpdating = false;
        this.userLoggedService.removeUserLoggedAndToken();
      }
    );

    refreshObservable.subscribe(refreshSubject);
    return refreshSubject;
  }
}

这是我在refresh()内部触发的this.authAPI.refreshToken():

  refreshToken() {
    return this.http.get(`${this.config.baseAPIUrl}refreshToken`);
  }

在我的httpTestingController中正确捕获了http调用,最终的期望是触发了this.jwtInterceptor.intercept(req,next)。

这是我失败的那部分的规格:

it('should call Refresh method if token is expiring in 5 minutes', () => {
    const nowInMillisec = Number(new Date());
    const FourMinutesFromNow = nowInMillisec + 4 * 60000;
    spyOn(
      jwtService,
      'getTokenExpirationDate'
    ).and.returnValue(new Date(FourMinutesFromNow));

    const jwtInterceptor = TestBed.get(JwtInterceptor);
    const spyOnJwtInterceptor = spyOn(jwtInterceptor, 'intercept');

    dummyService.fakeHttpCall().subscribe();
    httpTestingController.expectOne(
      `${MockAuthConfig.baseAPIUrl}user/fake-call`
    );

    const callbackHttpFired = httpTestingController.expectOne(
      `${MockAuthConfig.baseAPIUrl}refreshToken`
    );
    expect(callbackHttpFired.request.url).toEqual(
      `${MockAuthConfig.baseAPIUrl}refreshToken`
    );
    expect(spyOnJwtInterceptor).toHaveBeenCalled(); // this spy is never fired... :(
  });

有什么想法吗? 非常感谢你!

1 个答案:

答案 0 :(得分:1)

这里done()的使用至关重要,因为subscribe的调用是异步的,其余测试在subscribe退出之前运行。另外,您应该分别测试refresh方法。首次测试refresh

中是否调用了intercept

然后应使用

更改签名。
it('should call Refresh method if token is expiring in 5 minutes', (done) => {    
  ...
  jwtInterceptor.intecept.subscribe(() => { 
    expect(spyOnJwtInterceptor).toHaveBeenCalled();
    done();
  });
}

因此,测试方法将等待,直到调用done()。期望会按计划进行。