From 929abb9aa3c25535486534e4cf56bf6e4a46666c Mon Sep 17 00:00:00 2001 From: Jeremy Elbourn Date: Fri, 6 Nov 2015 10:01:03 -0800 Subject: [PATCH] chore(router): add tests for interaction between router-outer and @ViewChild. Closes #5164 --- .../integration/router_integration_spec.ts | 125 ++++++++++++------ 1 file changed, 88 insertions(+), 37 deletions(-) diff --git a/modules/angular2/test/router/integration/router_integration_spec.ts b/modules/angular2/test/router/integration/router_integration_spec.ts index a17bed2d60..a8fc17fc61 100644 --- a/modules/angular2/test/router/integration/router_integration_spec.ts +++ b/modules/angular2/test/router/integration/router_integration_spec.ts @@ -1,7 +1,7 @@ import { AsyncTestCompleter, beforeEach, - beforeEachBindings, + beforeEachProviders, ddescribe, describe, expect, @@ -17,9 +17,9 @@ import { import {bootstrap} from 'angular2/bootstrap'; import {Component, Directive, View} from 'angular2/src/core/metadata'; import {DOM} from 'angular2/src/core/dom/dom_adapter'; -import {provide} from 'angular2/core'; +import {provide, ViewChild, AfterViewInit} from 'angular2/core'; import {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens'; -import {RouteConfig, Route, Redirect} from 'angular2/src/router/route_config_decorator'; +import {RouteConfig, Route, Redirect, AuxRoute} from 'angular2/src/router/route_config_decorator'; import {PromiseWrapper} from 'angular2/src/facade/async'; import {BaseException, WrappedException} from 'angular2/src/facade/exceptions'; import { @@ -39,7 +39,7 @@ import {MockApplicationRef} from 'angular2/src/mock/mock_application_ref'; export function main() { describe('router injectables', () => { - beforeEachBindings(() => { + beforeEachProviders(() => { return [ ROUTER_PROVIDERS, provide(LocationStrategy, {useClass: MockLocationStrategy}), @@ -74,7 +74,7 @@ export function main() { }); describe('broken app', () => { - beforeEachBindings( + beforeEachProviders( () => { return [provide(ROUTER_PRIMARY_COMPONENT, {useValue: BrokenAppCmp})]; }); it('should rethrow exceptions from component constructors', @@ -91,7 +91,7 @@ export function main() { }); describe('back button app', () => { - beforeEachBindings( + beforeEachProviders( () => { return [provide(ROUTER_PRIMARY_COMPONENT, {useValue: HierarchyAppCmp})]; }); it('should change the url without pushing a new history state for back navigations', @@ -102,40 +102,39 @@ export function main() { var router = fixture.debugElement.componentInstance.router; var position = 0; var flipped = false; - var history = - [ - ['/parent/child', 'root { parent { hello } }', '/super-parent/child'], - ['/super-parent/child', 'root { super-parent { hello2 } }', '/parent/child'], - ['/parent/child', 'root { parent { hello } }', false] - ] + var history = [ + ['/parent/child', 'root { parent { hello } }', '/super-parent/child'], + ['/super-parent/child', 'root { super-parent { hello2 } }', '/parent/child'], + ['/parent/child', 'root { parent { hello } }', false] + ]; - router.subscribe((_) => { - var location = fixture.debugElement.componentInstance.location; - var element = fixture.debugElement.nativeElement; - var path = location.path(); + router.subscribe((_) => { + var location = fixture.debugElement.componentInstance.location; + var element = fixture.debugElement.nativeElement; + var path = location.path(); - var entry = history[position]; + var entry = history[position]; - expect(path).toEqual(entry[0]); - expect(element).toHaveText(entry[1]); + expect(path).toEqual(entry[0]); + expect(element).toHaveText(entry[1]); - var nextUrl = entry[2]; - if (nextUrl == false) { - flipped = true; - } + var nextUrl = entry[2]; + if (nextUrl == false) { + flipped = true; + } - if (flipped && position == 0) { - async.done(); - return; - } + if (flipped && position == 0) { + async.done(); + return; + } - position = position + (flipped ? -1 : 1); - if (flipped) { - location.back(); - } else { - router.navigateByUrl(nextUrl); - } - }); + position = position + (flipped ? -1 : 1); + if (flipped) { + location.back(); + } else { + router.navigateByUrl(nextUrl); + } + }); router.navigateByUrl(history[0][0]); }); @@ -143,7 +142,7 @@ export function main() { }); describe('hierarchical app', () => { - beforeEachBindings( + beforeEachProviders( () => { return [provide(ROUTER_PRIMARY_COMPONENT, {useValue: HierarchyAppCmp})]; }); it('should bootstrap an app with a hierarchy', @@ -165,7 +164,7 @@ export function main() { // TODO(btford): mock out level lower than LocationStrategy once that level exists xdescribe('custom app base ref', () => { - beforeEachBindings(() => { return [provide(APP_BASE_HREF, {useValue: '/my/app'})]; }); + beforeEachProviders(() => { return [provide(APP_BASE_HREF, {useValue: '/my/app'})]; }); it('should bootstrap', inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => { @@ -188,7 +187,7 @@ export function main() { // TODO: add a test in which the child component has bindings describe('querystring params app', () => { - beforeEachBindings( + beforeEachProviders( () => { return [provide(ROUTER_PRIMARY_COMPONENT, {useValue: QueryStringAppCmp})]; }); it('should recognize and return querystring params with the injected RouteParams', @@ -211,6 +210,35 @@ export function main() { }); })); }); + + describe('retrieving components loaded via outlet via @ViewChild', () => { + let tcb: TestComponentBuilder = null; + + beforeEachProviders(() => [provide(ROUTER_PRIMARY_COMPONENT, {useValue: AppCmp})]); + + beforeEach(inject([TestComponentBuilder], + (testComponentBuilder) => { tcb = testComponentBuilder; })); + + it('should get a reference and pass data to components loaded inside of outlets', + inject([AsyncTestCompleter], (async) => { + tcb.createAsync(AppWithViewChildren) + .then(fixture => { + let appInstance = fixture.debugElement.componentInstance; + let router = appInstance.router; + + router.subscribe((_) => { + fixture.detectChanges(); + + expect(appInstance.helloCmp).toBeAnInstanceOf(HelloCmp); + expect(appInstance.helloCmp.message).toBe('Ahoy'); + + async.done(); + }); + + router.navigateByUrl('/rainbow(pony)'); + }); + })); + }); }); } @@ -218,11 +246,13 @@ export function main() { @Component({selector: 'hello-cmp'}) @View({template: 'hello'}) class HelloCmp { + public message: string; } @Component({selector: 'hello2-cmp'}) @View({template: 'hello2'}) class Hello2Cmp { + public greeting: string; } @Component({selector: 'app-cmp'}) @@ -232,6 +262,27 @@ class AppCmp { constructor(public router: Router, public location: LocationStrategy) {} } +@Component({ + selector: 'app-cmp', + template: ` + Hello routing! + + `, + directives: ROUTER_DIRECTIVES +}) +@RouteConfig([ + new Route({path: '/rainbow', component: HelloCmp}), + new AuxRoute({name: 'pony', path: 'pony', component: Hello2Cmp}) +]) +class AppWithViewChildren implements AfterViewInit { + @ViewChild(HelloCmp) helloCmp: HelloCmp; + @ViewChild(Hello2Cmp) hello2Cmp: Hello2Cmp; + + constructor(public router: Router, public location: LocationStrategy) {} + + afterViewInit() { this.helloCmp.message = 'Ahoy'; } +} + @Component({selector: 'parent-cmp'}) @View({template: `parent { }`, directives: ROUTER_DIRECTIVES}) @RouteConfig([new Route({path: '/child', component: HelloCmp})])