feat(router): add RouterTestModule

This commit is contained in:
vsavkin 2016-07-07 14:13:32 -07:00
parent c43dd5a655
commit 72544ba551
5 changed files with 128 additions and 78 deletions

View File

@ -25,6 +25,21 @@ import {DefaultUrlSerializer, UrlSerializer} from './url_tree';
*/ */
export const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkWithHref, RouterLinkActive]; export const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkWithHref, RouterLinkActive];
export const ROUTER_PROVIDERS: any[] = [
Location, {provide: LocationStrategy, useClass: PathLocationStrategy},
{provide: UrlSerializer, useClass: DefaultUrlSerializer}, {
provide: Router,
useFactory: setupRouter,
deps: [
ApplicationRef, ComponentResolver, UrlSerializer, RouterOutletMap, Location, Injector,
AppModuleFactoryLoader, ROUTES, ROUTER_CONFIGURATION
]
},
RouterOutletMap,
{provide: ActivatedRoute, useFactory: (r: Router) => r.routerState.root, deps: [Router]},
{provide: AppModuleFactoryLoader, useClass: SystemJsAppModuleLoader},
{provide: ROUTER_CONFIGURATION, useValue: {enableTracing: false}}
];
/** /**
* Router module. * Router module.
@ -37,24 +52,7 @@ export const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkWithHref,
* *
* @experimental * @experimental
*/ */
@AppModule({ @AppModule({directives: ROUTER_DIRECTIVES, providers: ROUTER_PROVIDERS})
directives: ROUTER_DIRECTIVES,
providers: [
Location, {provide: LocationStrategy, useClass: PathLocationStrategy},
{provide: UrlSerializer, useClass: DefaultUrlSerializer}, {
provide: Router,
useFactory: setupRouter,
deps: [
ApplicationRef, ComponentResolver, UrlSerializer, RouterOutletMap, Location, Injector,
AppModuleFactoryLoader, ROUTES, ROUTER_CONFIGURATION
]
},
RouterOutletMap,
{provide: ActivatedRoute, useFactory: (r: Router) => r.routerState.root, deps: [Router]},
{provide: AppModuleFactoryLoader, useClass: SystemJsAppModuleLoader},
{provide: ROUTER_CONFIGURATION, useValue: {enableTracing: false}}
]
})
export class RouterModule { export class RouterModule {
constructor(private injector: Injector) { constructor(private injector: Injector) {
setTimeout(() => { setTimeout(() => {

View File

@ -1,44 +1,21 @@
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
import {Location} from '@angular/common';
import {Location, LocationStrategy} from '@angular/common';
import {SpyLocation} from '@angular/common/testing';
import {MockLocationStrategy} from '@angular/common/testing/mock_location_strategy';
import {ComponentFixture, TestComponentBuilder} from '@angular/compiler/testing'; import {ComponentFixture, TestComponentBuilder} from '@angular/compiler/testing';
import {AppModule, AppModuleFactory, AppModuleFactoryLoader, Compiler, Component, Injectable, Injector, Type} from '@angular/core'; import {AppModule, AppModuleFactory, AppModuleFactoryLoader, Compiler, Component, Injectable} from '@angular/core';
import {ComponentResolver} from '@angular/core'; import {beforeEach, beforeEachProviders, configureModule, describe, fakeAsync, inject, it, tick} from '@angular/core/testing';
import {beforeEach, beforeEachProviders, ddescribe, describe, fakeAsync, iit, inject, it, tick, xdescribe, xit} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/matchers'; import {expect} from '@angular/platform-browser/testing/matchers';
import {Observable} from 'rxjs/Observable'; import {Observable} from 'rxjs/Observable';
import {of } from 'rxjs/observable/of'; import {of } from 'rxjs/observable/of';
import {ActivatedRoute, ActivatedRouteSnapshot, CanActivate, CanDeactivate, Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Params, ROUTER_DIRECTIVES, Resolve, Router, RouterStateSnapshot, RoutesRecognized, provideRoutes} from '../index';
import {ActivatedRoute, ActivatedRouteSnapshot, CanActivate, CanDeactivate, DefaultUrlSerializer, Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Params, ROUTER_DIRECTIVES, Resolve, Router, RouterOutletMap, RouterStateSnapshot, Routes, RoutesRecognized, UrlSerializer, provideRoutes} from '../index'; import {RouterTestModule, SpyAppModuleFactoryLoader} from '../testing';
describe('Integration', () => { describe('Integration', () => {
beforeEach(() => {
beforeEachProviders(() => { configureModule({
let config: Routes = [{path: '', component: BlankCmp}, {path: 'simple', component: SimpleCmp}]; modules: [RouterTestModule],
providers: [provideRoutes(
return [ [{path: '', component: BlankCmp}, {path: 'simple', component: SimpleCmp}])]
RouterOutletMap, });
{provide: UrlSerializer, useClass: DefaultUrlSerializer},
{provide: Location, useClass: SpyLocation},
{provide: LocationStrategy, useClass: MockLocationStrategy},
{
provide: Router,
useFactory:
(resolver: ComponentResolver, urlSerializer: UrlSerializer, outletMap: RouterOutletMap,
location: Location, loader: AppModuleFactoryLoader, injector: Injector) => {
return new Router(
RootCmp, resolver, urlSerializer, outletMap, location, injector, loader, config);
},
deps: [
ComponentResolver, UrlSerializer, RouterOutletMap, Location, AppModuleFactoryLoader,
Injector
]
},
{provide: AppModuleFactoryLoader, useClass: SpyAppModuleFactoryLoader},
{provide: ActivatedRoute, useFactory: (r: Router) => r.routerState.root, deps: [Router]},
];
}); });
it('should navigate with a provided config', it('should navigate with a provided config',
@ -1095,7 +1072,7 @@ describe('Integration', () => {
it('works', fakeAsync(inject( it('works', fakeAsync(inject(
[Router, TestComponentBuilder, Location, AppModuleFactoryLoader], [Router, TestComponentBuilder, Location, AppModuleFactoryLoader],
(router: Router, tcb: TestComponentBuilder, location: Location, (router: Router, tcb: TestComponentBuilder, location: Location,
loader: AppModuleFactoryLoader) => { loader: SpyAppModuleFactoryLoader) => {
@Component({ @Component({
selector: 'lazy', selector: 'lazy',
template: 'lazy-loaded-parent {<router-outlet></router-outlet>}', template: 'lazy-loaded-parent {<router-outlet></router-outlet>}',
@ -1118,8 +1095,9 @@ describe('Integration', () => {
}) })
class LoadedModule { class LoadedModule {
} }
(<any>loader).expectedPath = 'expected';
(<any>loader).expected = LoadedModule;
loader.stubbedModules = {expected: LoadedModule};
const fixture = createRoot(tcb, router, RootCmp); const fixture = createRoot(tcb, router, RootCmp);
@ -1137,8 +1115,8 @@ describe('Integration', () => {
fakeAsync(inject( fakeAsync(inject(
[Router, TestComponentBuilder, Location, AppModuleFactoryLoader], [Router, TestComponentBuilder, Location, AppModuleFactoryLoader],
(router: Router, tcb: TestComponentBuilder, location: Location, (router: Router, tcb: TestComponentBuilder, location: Location,
loader: AppModuleFactoryLoader) => { loader: SpyAppModuleFactoryLoader) => {
(<any>loader).expectedPath = 'expected'; loader.stubbedModules = {};
const fixture = createRoot(tcb, router, RootCmp); const fixture = createRoot(tcb, router, RootCmp);
router.resetConfig([{path: 'lazy', loadChildren: 'invalid'}]); router.resetConfig([{path: 'lazy', loadChildren: 'invalid'}]);
@ -1158,22 +1136,6 @@ describe('Integration', () => {
}); });
}); });
@Injectable()
class SpyAppModuleFactoryLoader implements AppModuleFactoryLoader {
public expected: any;
public expectedPath: string;
constructor(private compiler: Compiler) {}
load(path: string): Promise<AppModuleFactory<any>> {
if (path === this.expectedPath) {
return this.compiler.compileAppModuleAsync(this.expected);
} else {
return <any>Promise.reject(new Error('boom'));
}
}
}
function expectEvents(events: Event[], pairs: any[]) { function expectEvents(events: Event[], pairs: any[]) {
for (let i = 0; i < events.length; ++i) { for (let i = 0; i < events.length; ++i) {
expect((<any>events[i].constructor).name).toBe(pairs[i][0].name); expect((<any>events[i].constructor).name).toBe(pairs[i][0].name);

View File

@ -0,0 +1,9 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export * from './testing/router_test_module';

View File

@ -0,0 +1,81 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Location, LocationStrategy} from '@angular/common';
import {SpyLocation} from '@angular/common/testing';
import {MockLocationStrategy} from '@angular/common/testing/mock_location_strategy';
import {AppModule, AppModuleFactory, AppModuleFactoryLoader, Compiler, ComponentResolver, Injectable, Injector} from '@angular/core';
import {Router, RouterOutletMap, Routes, UrlSerializer} from '../index';
import {ROUTES} from '../src/router_config_loader';
import {ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from '../src/router_module';
/**
* A spy for {@link AppModuleFactoryLoader} that allows tests to simulate the loading of app module
* factories.
*
* @experimental
*/
@Injectable()
export class SpyAppModuleFactoryLoader implements AppModuleFactoryLoader {
public stubbedModules: {[path: string]: any} = {};
constructor(private compiler: Compiler) {}
load(path: string): Promise<AppModuleFactory<any>> {
if (this.stubbedModules[path]) {
return this.compiler.compileAppModuleAsync(this.stubbedModules[path]);
} else {
return <any>Promise.reject(new Error(`Cannot find module ${path}`));
}
}
}
/**
* A module setting up the router that should be used for testing.
* It provides spy implementations of Location, LocationStrategy, and AppModuleFactoryLoader.
*
* # Example:
*
* ```
* beforeEach(() => {
* configureModule({
* modules: [RouterTestModule],
* providers: [provideRoutes(
* [{path: '', component: BlankCmp}, {path: 'simple', component: SimpleCmp}])]
* });
* });
* ```
*
* @experimental
*/
@AppModule({
directives: ROUTER_DIRECTIVES,
providers: [
ROUTER_PROVIDERS,
{provide: Location, useClass: SpyLocation},
{provide: LocationStrategy, useClass: MockLocationStrategy},
{provide: AppModuleFactoryLoader, useClass: SpyAppModuleFactoryLoader},
{
provide: Router,
useFactory: (resolver: ComponentResolver, urlSerializer: UrlSerializer,
outletMap: RouterOutletMap, location: Location, loader: AppModuleFactoryLoader,
injector: Injector, routes: Routes) => {
return new Router(
null, resolver, urlSerializer, outletMap, location, injector, loader, routes);
},
deps: [
ComponentResolver, UrlSerializer, RouterOutletMap, Location, AppModuleFactoryLoader,
Injector, ROUTES
]
},
]
})
export class RouterTestModule {
}

View File

@ -132,11 +132,6 @@ export declare class Router {
/** @stable */ /** @stable */
export declare const ROUTER_DIRECTIVES: (typeof RouterOutlet | typeof RouterLink | typeof RouterLinkWithHref | typeof RouterLinkActive)[]; export declare const ROUTER_DIRECTIVES: (typeof RouterOutlet | typeof RouterLink | typeof RouterLinkWithHref | typeof RouterLinkActive)[];
/** @experimental */
export declare class RouterAppModule {
constructor(injector: Injector);
}
/** @deprecated */ /** @deprecated */
export declare type RouterConfig = Route[]; export declare type RouterConfig = Route[];
@ -178,6 +173,11 @@ export declare class RouterLinkWithHref implements OnChanges, OnDestroy {
onClick(button: number, ctrlKey: boolean, metaKey: boolean): boolean; onClick(button: number, ctrlKey: boolean, metaKey: boolean): boolean;
} }
/** @experimental */
export declare class RouterModule {
constructor(injector: Injector);
}
/** @stable */ /** @stable */
export declare class RouterOutlet { export declare class RouterOutlet {
activatedRoute: ActivatedRoute; activatedRoute: ActivatedRoute;