diff --git a/modules/@angular/router/src/router_module.ts b/modules/@angular/router/src/router_module.ts index fb44124c23..b03edc34fc 100644 --- a/modules/@angular/router/src/router_module.ts +++ b/modules/@angular/router/src/router_module.ts @@ -25,6 +25,21 @@ import {DefaultUrlSerializer, UrlSerializer} from './url_tree'; */ 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. @@ -37,24 +52,7 @@ export const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkWithHref, * * @experimental */ -@AppModule({ - 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}} - ] -}) +@AppModule({directives: ROUTER_DIRECTIVES, providers: ROUTER_PROVIDERS}) export class RouterModule { constructor(private injector: Injector) { setTimeout(() => { diff --git a/modules/@angular/router/test/router.spec.ts b/modules/@angular/router/test/router.spec.ts index d5608764b4..089f46e15e 100644 --- a/modules/@angular/router/test/router.spec.ts +++ b/modules/@angular/router/test/router.spec.ts @@ -1,44 +1,21 @@ import 'rxjs/add/operator/map'; - -import {Location, LocationStrategy} from '@angular/common'; -import {SpyLocation} from '@angular/common/testing'; -import {MockLocationStrategy} from '@angular/common/testing/mock_location_strategy'; +import {Location} from '@angular/common'; import {ComponentFixture, TestComponentBuilder} from '@angular/compiler/testing'; -import {AppModule, AppModuleFactory, AppModuleFactoryLoader, Compiler, Component, Injectable, Injector, Type} from '@angular/core'; -import {ComponentResolver} from '@angular/core'; -import {beforeEach, beforeEachProviders, ddescribe, describe, fakeAsync, iit, inject, it, tick, xdescribe, xit} from '@angular/core/testing'; +import {AppModule, AppModuleFactory, AppModuleFactoryLoader, Compiler, Component, Injectable} from '@angular/core'; +import {beforeEach, beforeEachProviders, configureModule, describe, fakeAsync, inject, it, tick} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/matchers'; import {Observable} from 'rxjs/Observable'; import {of } from 'rxjs/observable/of'; - -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 {ActivatedRoute, ActivatedRouteSnapshot, CanActivate, CanDeactivate, Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Params, ROUTER_DIRECTIVES, Resolve, Router, RouterStateSnapshot, RoutesRecognized, provideRoutes} from '../index'; +import {RouterTestModule, SpyAppModuleFactoryLoader} from '../testing'; describe('Integration', () => { - - beforeEachProviders(() => { - let config: Routes = [{path: '', component: BlankCmp}, {path: 'simple', component: SimpleCmp}]; - - return [ - 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]}, - ]; + beforeEach(() => { + configureModule({ + modules: [RouterTestModule], + providers: [provideRoutes( + [{path: '', component: BlankCmp}, {path: 'simple', component: SimpleCmp}])] + }); }); it('should navigate with a provided config', @@ -1095,7 +1072,7 @@ describe('Integration', () => { it('works', fakeAsync(inject( [Router, TestComponentBuilder, Location, AppModuleFactoryLoader], (router: Router, tcb: TestComponentBuilder, location: Location, - loader: AppModuleFactoryLoader) => { + loader: SpyAppModuleFactoryLoader) => { @Component({ selector: 'lazy', template: 'lazy-loaded-parent {}', @@ -1118,8 +1095,9 @@ describe('Integration', () => { }) class LoadedModule { } - (loader).expectedPath = 'expected'; - (loader).expected = LoadedModule; + + + loader.stubbedModules = {expected: LoadedModule}; const fixture = createRoot(tcb, router, RootCmp); @@ -1137,8 +1115,8 @@ describe('Integration', () => { fakeAsync(inject( [Router, TestComponentBuilder, Location, AppModuleFactoryLoader], (router: Router, tcb: TestComponentBuilder, location: Location, - loader: AppModuleFactoryLoader) => { - (loader).expectedPath = 'expected'; + loader: SpyAppModuleFactoryLoader) => { + loader.stubbedModules = {}; const fixture = createRoot(tcb, router, RootCmp); 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> { - if (path === this.expectedPath) { - return this.compiler.compileAppModuleAsync(this.expected); - } else { - return Promise.reject(new Error('boom')); - } - } -} - function expectEvents(events: Event[], pairs: any[]) { for (let i = 0; i < events.length; ++i) { expect((events[i].constructor).name).toBe(pairs[i][0].name); diff --git a/modules/@angular/router/testing.ts b/modules/@angular/router/testing.ts new file mode 100644 index 0000000000..d8667e21e9 --- /dev/null +++ b/modules/@angular/router/testing.ts @@ -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'; \ No newline at end of file diff --git a/modules/@angular/router/testing/router_test_module.ts b/modules/@angular/router/testing/router_test_module.ts new file mode 100644 index 0000000000..a812178375 --- /dev/null +++ b/modules/@angular/router/testing/router_test_module.ts @@ -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> { + if (this.stubbedModules[path]) { + return this.compiler.compileAppModuleAsync(this.stubbedModules[path]); + } else { + return 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 { +} diff --git a/tools/public_api_guard/router/index.d.ts b/tools/public_api_guard/router/index.d.ts index aa7f15c3d0..349ddde55e 100644 --- a/tools/public_api_guard/router/index.d.ts +++ b/tools/public_api_guard/router/index.d.ts @@ -132,11 +132,6 @@ export declare class Router { /** @stable */ export declare const ROUTER_DIRECTIVES: (typeof RouterOutlet | typeof RouterLink | typeof RouterLinkWithHref | typeof RouterLinkActive)[]; -/** @experimental */ -export declare class RouterAppModule { - constructor(injector: Injector); -} - /** @deprecated */ export declare type RouterConfig = Route[]; @@ -178,6 +173,11 @@ export declare class RouterLinkWithHref implements OnChanges, OnDestroy { onClick(button: number, ctrlKey: boolean, metaKey: boolean): boolean; } +/** @experimental */ +export declare class RouterModule { + constructor(injector: Injector); +} + /** @stable */ export declare class RouterOutlet { activatedRoute: ActivatedRoute;