web-dev-qa-db-ja.com

ルーターガードジャスミンテストのRouterStateSnapshotをモックする方法

シンプルなルーターガードを使用しており、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での予期しないトークンのエクスポート

15
Jackie

私はそれをわずかに異なってやることができましたが、あなたのために働くはずです:

...

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);
  })
 ...
10
nastyklad

私は警備員のユーザーの役割をテストするためにルートでデータを取得する必要があったので、次のように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);
  });
});
6
ramon22

私がこれを試したルーターに関する以前の質問に基づいて...

_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の副作用をテストしていないので、これは何の役にも立たないように思えます。

1
Jackie

モックをガードに渡すだけの場合は、他の回答で提案されているように、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);
0
Valeriy Katkov