I'm trying to unit test an angular guard which pipes an observable that belongs to an authentication service. The subscription happens in the guard canActivate() method.
I'm using a jasmine spy on the authentication service observable to return values, but the spy is never called in my unit test.
When testing a component, I use fixture.detectChanges(), but for this guard I can't find a way to test that it returns the right thing according to the observable value.
auth-guard.ts:
@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(
    private authService: AuthService,
    private router: Router
  ) {}
  canActivate(): Observable<boolean> {
    return this.authService.isAuthenticated$.pipe(
      map(e => {
        if (e) {
          return true;
        }
      }),
      catchError((err) => {
        this.router.navigate(['/login']);
        return of(false);
      })
    );
  }
}
auth.service.ts:
@Injectable()
export class AuthService {
  private isAuthenticated = new BehaviorSubject<boolean>(false);
  get isAuthenticated$(): Observable<boolean> { return this.isAuthenticated.asObservable(); }
  ...
}
auth-guard.spec.ts:
describe('Authuard', () => {
  let authGuard: AuthGuard;
  let authService: jasmine.SpyObj<AuthService>;
  beforeEach(() => {
    const authServiceSpy = jasmine.createSpyObj('AuthService', ['isAuthenticated$']);
    TestBed.configureTestingModule({
      providers: [
        AuthGuard,
        { provide: AuthService, useValue: authServiceSpy }
      ]
    });
    authGuard = TestBed.get(AuthGuard);
    authService = TestBed.get(AuthService);
  });
  it('should create', () => {
    expect(authGuard).toBeDefined();
  });
  /* This test fails */
  it('should return false when not authenticated', () => {
    authService.isAuthenticated$.and.returnValue(of(false));
    authGuard.canActivate().subscribe(canActivate => {
        expect(canActivate).toBe(false);
    });
  });
});
The second test fails with this.authService.isAuthenticated$.pipe is not a function. The value returned by the spy on isAuthenticated$ is not taken.
How can I test that the guard returns the right value when the observable value return by the authentication service changes? Is it possible to do it with jasmine spies?
Try throwError as below:
import { throwError } from 'rxjs';
it('should return false when not authenticated', () => {
    spyOn(authService,'isAuthenticated$').and.returnValue(throwError('error'));
    authGuard.canActivate().subscribe(canActivate => {
        expect(canActivate).toBeFalsy();
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With