シンプルなルーターガードを使用しており、canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot )
をテストしようとしています。このnew ActivatedRouteSnapshot()
のようなActivatedRouteSnapshotを作成できますが、モックされたRouterStateSnapshot
の作成方法がわかりません。
私が試したコードごとに...
let createEmptyStateSnapshot = function(
urlTree: UrlTree, rootComponent: Type<any>){
const emptyParams = {};
const emptyData = {};
const emptyQueryParams = {};
const fragment = '';
const activated = new ActivatedRouteSnapshot();
const state = new RouterStateSnapshot(new TreeNode<ActivatedRouteSnapshot>(activated, []));
return {
state: state,
activated: activated
}
}
だが import {TreeNode} from "@angular/router/src/utils/tree";
私は次のようになっているので、翻訳する必要があります...
Uncaught SyntaxError:webpack:///~/@angular/router/src/utils/tree.js:8:0 <-test.bundle.ts:72431での予期しないトークンのエクスポート
私はそれをわずかに異なってやることができましたが、あなたのために働くはずです:
...
let mockSnapshot:any = jasmine.createSpyObj<RouterStateSnapshot>("RouterStateSnapshot", ['toString']);
@Component({
template: '<router-outlet></router-outlet>'
})
class RoutingComponent { }
@Component({
template: ''
})
class DummyComponent { }
describe('Testing guard', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([
{path: 'route1', component: DummyComponent},
{path: 'route2', component: DummyComponent},
...
])
],
declarations: [DummyComponent, RoutingComponent],
providers: [
GuardClass,
{provide: RouterStateSnapshot, useValue: mockSnapshot}
]
}).compileComponents());
it('should not allow user to overcome the guard for whatever reasons',
inject([GuardClass], (guard:GuardClass) => {
let fixture = TestBed.createComponent(RoutingComponent);
expect(guard.canActivate(new ActivatedRouteSnapshot(), mockSnapshot)).toBe(false);
})
...
私は警備員のユーザーの役割をテストするためにルートでデータを取得する必要があったので、次のようにock笑しました。
class MockActivatedRouteSnapshot {
private _data: any;
get data(){
return this._data;
}
}
describe('Auth Guard', () => {
let guard: AuthGuard;
let route: ActivatedRouteSnapshot;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [AuthGuard, {
provide: ActivatedRouteSnapshot,
useClass: MockActivatedRouteSnapshot
}]
});
guard = TestBed.get(AuthGuard);
});
it('should return false if the user is not admin', () => {
const expected = cold('(a|)', {a: false});
route = TestBed.get(ActivatedRouteSnapshot);
spyOnProperty(route, 'data', 'get').and.returnValue({roles: ['admin']});
expect(guard.canActivate(route)).toBeObservable(expected);
});
});
私がこれを試したルーターに関する以前の質問に基づいて...
_let mockSnapshot: any;
...
mockSnapshot = jasmine.createSpyObj("RouterStateSnapshot", ['toString']);
...
TestBed.configureTestingModule({
imports: [RouterTestingModule],
providers:[
{provide: RouterStateSnapshot, useValue: mockSnapshot}
]
}).compileComponents();
...
let test = guard.canActivate(
new ActivatedRouteSnapshot(),
TestBed.get(RouterStateSnapshot)
);
_
私が今抱えている問題は、ここでtoStringが必要なことですmockSnapshot = jasmine.createSpyObj("RouterStateSnapshot", ['toString']);
。これは、jasmine createSpyObjが少なくとも1つのモックメソッドを必要とするためです。私はRouterStateSnapshotの副作用をテストしていないので、これは何の役にも立たないように思えます。
モックをガードに渡すだけの場合は、他の回答で提案されているように、createSpyObj
を使用する必要はありません。最も簡単な解決策は、ガードのcanActivate
メソッドで使用される必須フィールドのみをモックすることです。また、ソリューションに型安全性を追加することをお勧めします。
const mock = <T, P extends keyof T>(obj: Pick<T, P>): T => obj as T;
it('should call foo', () => {
const route = mock<ActivatedRouteSnapshot, 'params'>({
params: {
val: '1234'
}
});
const state = mock<RouterStateSnapshot, "url" | "root">({
url: "my/super/url",
root: route // or another mock, if required
});
const guard = createTheGuard();
const result = guard.canActivate(route, state);
...
});
状態スナップショットを使用しない場合は、代わりにnull
を渡すだけです
const result = guard.canActivate(route, null as any);