【问题标题】:Mocking RouterStateSnapshot in Jasmine testing在 Jasmine 测试中模拟 RouterStateSnapshot
【发布时间】:2016-12-08 18:59:17
【问题描述】:

虽然我已经编写 Angular 2 有一段时间了,但我只是在编写我的第一个 Jasmine 测试并且遇到了一些困难。我正在尝试测试实现CanActivateCanActivate 服务方法是否正常运行,并按预期返回truefalse

我的方法是这样的:

canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> {
    return this.store$
        .map( ( store: StoreState ) => store.currentUser )
        .first()
        .map( ( user ) => {
            if ( user.isAuthenticated ) {
                return true;
            }

            // TODO: This needs refactoring. Need to provide RouterStateSnapshot in test,
            // rather than ignoring it!
            this.redirectUrl = state ? state.url : '';
            this.injector.get( Router ).navigate( ['/login'] );
            return false;
        } );
}

我的测试摘录如下所示:

service = TestBed.get( AuthGuardService );

it( 'should prevent navigation', () => {
    service.canActivate(null, null).subscribe((res) => expect( res ).toBeTruthy() );
} );

我如何模拟/存根/无论我调用service.canActivate 的第二个参数,而不是简单地传入null?

【问题讨论】:

    标签: unit-testing angular jasmine karma-jasmine angular2-routing


    【解决方案1】:
    describe('AuthGuard', () => {
      let mockSnapshot: RouterStateSnapshot;
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          imports: [
            // so we can get the Router injected
            RouterTestingModule,
            // other imports as needed
          ],
          // usual config here
        });
    
        // create a jasmine spy object, of the required type
        // toString is because we have to mock at least one method
        mockSnapshot = createSpyObj<RouterStateSnapshot>('RouterStateSnapshot', ['toString']);
      });
    
      it('should prevent non-authenticated access',
        async(inject([AuthGuard, AuthService, Router], (guard: AuthGuard, auth: AuthService, router: Router) => {
          // ensure we're logged out
          auth.logout();
    
          // set the url on our mock snapshot
          mockSnapshot.url = '/protected';
    
          // so we can spy on what's been called on the router object navigate method
          spyOn(router, 'navigate');
    
          expect(guard.canActivate(null, mockSnapshot)).toBeFalsy();
    
          // check that our guard re-directed the user to another url
          expect(router.navigate).toHaveBeenCalled();
        })));
      });
    })
    

    【讨论】:

      【解决方案2】:

      这是我用于自定义路由器状态序列化器单元测试的解决方案

      custom-serializer.ts

      import { RouterStateSerializer } from '@ngrx/router-store';
      import { RouterStateSnapshot, Params } from '@angular/router';
      
      /**
       * The RouterStateSerializer takes the current RouterStateSnapshot
       * and returns any pertinent information needed. The snapshot contains
       * all information about the state of the router at the given point in time.
       * The entire snapshot is complex and not always needed. In this case, you only
       * need the URL and query parameters from the snapshot in the store. Other items could be
       * returned such as route parameters and static route data.
       */
      
      export interface RouterStateUrl {
        url: string;
        params: Params;
        queryParams: Params;
      }
      
      export class CustomRouterStateSerializer
        implements RouterStateSerializer<RouterStateUrl> {
        serialize(routerState: RouterStateSnapshot): RouterStateUrl {
          let route = routerState.root;
      
          while (route.firstChild) {
            route = route.firstChild;
          }
      
          const { url, root: { queryParams } } = routerState;
          const { params } = route;
      
          // Only return an object including the URL, params and query params
          // instead of the entire snapshot
          return { url, params, queryParams };
        }
      }
      

      custom-serializer.spec.ts

      import { CustomRouterStateSerializer } from './utils';
      import { RouterStateSnapshot } from '@angular/router';
      
      
      describe('Utils CustomRouterStateSerializer', () => {
          let mockSnapshot: RouterStateSnapshot;
          let serializer: CustomRouterStateSerializer;
          let mockSnapshotProxy;
          beforeEach(() => {
              mockSnapshot = jasmine.createSpyObj<RouterStateSnapshot>('RouterStateSnapshot', ['toString']);
              serializer = new CustomRouterStateSerializer();
          });
      
          it('should serialize RouterStateSnapshot to subset of params', () => {
              mockSnapshotProxy = new Proxy(mockSnapshot, {
                  get(target, prop) {
                      if (prop === 'root') {
                          return {
                              params: {
                                  id: 100
                              },
                              queryParams: {
                                  name: 'John'
                              }
                          };
                      } else if (prop === 'url') {
                          return '/orders';
                      }
                  },
              });
              const result = serializer.serialize(mockSnapshotProxy);
              expect(result.url).toBe('/orders');
              expect(result.params.id).toBe(100);
              expect(result.queryParams.name).toBe('John');
          });
      
      });
      

      我使用 jasmine.createSpyObj 创建具有正确类型和代理的对象以传入所需的属性

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-13
        • 2013-06-09
        • 1970-01-01
        相关资源
        最近更新 更多