Как юнит-тест можно активировать методом защиты angular2 с помощью жасмина?
Извините за вопрос такого типа. Но я не могу найти ни одного блога или учебных пособий для YouTube по написанию тестирования файла защиты canActivate. Ни в официальной документации нет ничего упомянутого.
Любая помощь будет высоко ценится.
3 ответа
Так как никто не ответил на мой вопрос, поэтому я вставляю свой фрагмент кода для справки, чтобы помочь людям, которые могут получить эту ситуацию.
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);
});
});
Этот вопрос довольно старый - но так как я сам пытался найти подробную документацию для модульного тестирования, я просто хотел изложить здесь свой подход. В общем, если есть зависимости в моей охране / сервисе / компоненте / что бы я ни думал, все они должны быть высмеяны, а не настоящие сервисы. Поскольку эти услуги не то, что мы хотим проверить в нашем модульном тесте для охранника - мы просто хотим проверить охранника. Итак, вот общий пример того, как я сделал бы это для охранника, возвращающего наблюдаемое:
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());
});
});
и это то, что я бы сделал в вашем конкретном случае (должен работать с angular 6, canActivate также должен принимать 2 параметра):
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();
});
});
Если ваш Guard асинхронный, его можно протестировать с помощью асинхронного тестирования:
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);
},
});
});
});