Sorry for asking this type of question. But I'm not able to find any blog or youtube tutorials on writing the canActivate guard file testing. Nor in the official documentation there is anything mentioned.
any help will be much appreciated.
Sorry for asking this type of question. But I'm not able to find any blog or youtube tutorials on writing the canActivate guard file testing. Nor in the official documentation there is anything mentioned.
any help will be much appreciated.
This question is pretty old - but as I was trying to find some detailed unit testing documentation myself right now, I just wanted to put my approach here. In general, if there are dependencies in my guard / service / component / whatever I think these should all be mocked and not the real services should be used. As theses services are not what we want to test in our unit test for the guard - we just want to test the guard. So here is a generic example how I would do it for a guard returning an observable:
import { MyGuard } from './path/to/your/guard';
import { TestBed } from '@angular/core/testing';
import { finalize } from 'rxjs/operators';
describe('MyGuard Test', () => {
const createMockRoute = (id: string) => {
return {
params: { id: id }
} as any;
};
const createMockRouteState = () => null;
let guard: MyGuard;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
MyGuard,
]
});
guard = TestBed.get(MyGuard);
});
it('should not be able to activate invalid route', done => {
const route = createMockRoute(null);
const state = createMockRouteState();
const res$ = guard.canActivate(route, state);
res$.pipe(finalize(done)).subscribe(res => expect(res).toBeFalsy());
});
});
and this is what I would do in your specific case (should work with angular 6, canActivate should also take 2 params):
import { LoggedInGuard } from './loggedin.guard';
import { TestBed } from '@angular/core/testing';
import { Router } from '@angular/router';
import { StorageService } from '../storage.service';
describe('LoggedInGuard', () => {
let guard: LoggedInGuard;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
LoggedInGuard,
{ provide: Router, useClass: { navigate: () => null } },
{ provide: StorageService, useClass: { } }
]
});
guard = TestBed.get(LoggedInGuard);
});
it('should not be able to activate when logged out', () => {
const storageService = TestBed.get(StorageService);
storageService.isLoggedIn = false;
const res = guard.canActivate(null, null);
expect(res).toBeFalsy();
});
it('should be able to activate when logged in', () => {
const storageService = TestBed.get(StorageService);
storageService.isLoggedIn = true;
const res = guard.canActivate(null, null);
expect(res).toBeTruthy();
});
});
If your Guard is asynchronous, it can be tested with asynchronous testing:
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed, waitForAsync } from '@angular/core/testing';
import { Observable, of } from 'rxjs';
describe('MyGuard', () => {
let guard: MyGuard;
let service: MyAsyncService;
// async beforeEach
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
],
providers: [
MyGuard,
MyAsyncService,
],
});
}));
// synchronous beforeEach
beforeEach(() => {
guard = TestBed.inject(MyGuard);
service = TestBed.inject(MyAsyncService);
});
it('should allow if service reports as allowed', (done) => {
service.canFoo = (): Observable<boolean> => of(true);
guard.canActivate(null, null).subscribe({
next: (allowed: boolean) => {
expect(allowed).toBeTrue();
done();
},
error: err => {
fail(err);
},
});
});
it('should reject if service reports as not allowed', () => {
service.canFoo = (): Observable<boolean> => of(false);
guard.canActivate(null, null).subscribe({
next: (allowed: boolean) => {
expect(allowed).toBeFalse();
done();
},
error: err => {
fail(err);
},
});
});
});
since no one answered my question, so I'm pasting my code snippet for the reference to help people who might get this situation.
sampleLoggedIn.guard.ts
sampleLoggedIn.guard.spec.ts