如何为Router Guard Jasmine测试模拟RouterStateSnapshot

时间:2016-11-29 16:18:30

标签: angular jasmine angular2-routing

我有一个简单的路由器防护,我正在尝试测试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&lt; - test.bundle.ts:72431

3 个答案:

答案 0 :(得分:6)

我需要获取路由中的数据来测试我的后卫中的用户角色,所以我这样嘲笑它:

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);
  });
});

答案 1 :(得分:1)

基于我之前关于路由器的问题我试过这个......

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至少需要一个模拟方法。由于我没有测试RouterStateSnapshot的副作用,这似乎是额外的工作。

答案 2 :(得分:0)

如果仅是为了将模拟传递给守卫,则不必使用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);