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.
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
import {Injectable} from '@angular/core';
import {Router, CanActivate} from '@angular/router';
import {StorageService} from '../storage.service';
@Injectable()
export class LoggedInGuard implements CanActivate {
constructor(private router: Router, private storageService: StorageService) {
}
/**Overriding canActivate to guard routes
*
* This method returns true if the user is not logged in
* @returns {boolean}
*/
canActivate() {
if (this.storageService.isLoggedIn) {
return true;
} else {
this.router.navigate(['home']);
return false;
}
}
}
sampleLoggedIn.guard.spec.ts
import {TestBed, async} from '@angular/core/testing';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';
import {CommonModule} from '@angular/common';
import 'rxjs/Rx';
import 'rxjs/add/observable/throw';
import {Router} from '@angular/router';
import 'rxjs/add/operator/map';
import {LoggedInGuard} from './loggedin.guard';
import {StorageService} from '../storage.service';
import {CookieService} from 'angular2-cookie/core';
describe('Logged in guard should', () => {
let loggedInGuard: LoggedInGuard;
let storageService: StorageService;
let router = {
navigate: jasmine.createSpy('navigate')
};
// async beforeEach
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [FormsModule, CommonModule, HttpModule],
providers: [LoggedInGuard, StorageService, CookieService,
{provide: Router, useValue: router}
]
})
.compileComponents(); // compile template and css
}));
// synchronous beforeEach
beforeEach(() => {
loggedInGuard = TestBed.get(LoggedInGuard);
storageService = TestBed.get(StorageService);
});
it('be able to hit route when user is logged in', () => {
storageService.isLoggedIn = true;
expect(loggedInGuard.canActivate()).toBe(true);
});
it('not be able to hit route when user is not logged in', () => {
storageService.isLoggedIn = false;
expect(loggedInGuard.canActivate()).toBe(false);
});
});
canActivate()
. –
Grosso 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();
});
});
{ provide: Router, useClass: { navigate: () => null } }
could cause TypeError: ctor is not a constructor
error. Use useValue
instead of useClass
. –
Pilot 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);
},
});
});
});
© 2022 - 2024 — McMap. All rights reserved.
canActivate()
method in your guard is indeed called or the code that's inside thecanActivate()
method? – Soble