在Jasmine测试中模拟RouterStateSnapshot

时间:2016-12-08 18:59:18

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

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

我的方法如下:

false

我的测试摘录如下:

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() ); } ); 的第二个参数,而不是简单地传入null?

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

这是我用于自定义路由器状态序列化程序

的单元测试的解决方案

定制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 };
  }
}

定制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创建具有适当类型的对象和代理以传递所需的属性