首页 > 解决方案 > How to test guards relying on http request?

问题描述

I have a problem with my test and I have no idea how to resolve that:

I have two methods in my service:

isAuthenticated () {
  const token = localStorage.getItem('token');
  if (token) {
    return this.verifyToken(token).pipe(
      map(data => true),
      catchError (error => of(false))
    );
  }
  return of(false);
}

verifyToken (token: string): Observable<any> {
  const data = {'token': token};
  return this.http.post(url/verify/, data);
}

And canActivate method in my guard:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
  return this.auth.isAuthenticated().pipe(
    map(data => {
      if (data) {
        this.router.navigate(['/url/']);
      }
      return !data;
    })
  );
}

So if user is authenticated he can't hit url (login page). And my test looks:

let guard: Guard;
let service: Service;

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [CommonModule],
    providers: [
      Service,
      Guard,
    ]
  }).compileComponents();
  guard = TestBed.get(Guard);
  service = TestBed.get(Service);
});

it('can't see login page when he is logged in', fakeAsync(() =>{
  spyOn(service, 'isAuthenticated').and.callFake(()=>{return true;});
  guard.canActivate(new ActivatedRouteSnapshot(), mockSnapshot).subscribe(
    x => expect(x).toBeFalsy()
  ); 
}));

I got

TypeError: this.auth.isAuthenticated(...).pipe is not a function

how should I test it correctly?

标签: angularjasmineangular6

解决方案


你的服务实现返回一个 Observable。你的间谍返回一个布尔值。

我会这样

it('can not see login page when he is logged in', () => {
  spyOn(service, 'isAuthenticated').and.callFake(() => { return of(true); });
  guard.canActivate(new ActivatedRouteSnapshot(), mockSnapshot).subscribe(
    x => expect(x).toBeFalsy()
  ); 
}));

如果将 Observable 转换为 Promise,则可以使用 Typescript 的 await / async 语法,而不是订阅 Observable。


推荐阅读