| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | import { | 
					
						
							|  |  |  |   AsyncTestCompleter, | 
					
						
							|  |  |  |   beforeEach, | 
					
						
							|  |  |  |   ddescribe, | 
					
						
							|  |  |  |   xdescribe, | 
					
						
							|  |  |  |   describe, | 
					
						
							|  |  |  |   dispatchEvent, | 
					
						
							|  |  |  |   expect, | 
					
						
							|  |  |  |   iit, | 
					
						
							|  |  |  |   inject, | 
					
						
							| 
									
										
											  
											
												refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
	{ path: '/foo', redirectTo: '/bar' },
	{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
	{ path: '/foo', redirectTo: ['Bar'] },
	{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
	{ path: '/tab', redirectTo: '/tab/users' }
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
	{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
	{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
											
										 
											2015-11-23 18:07:37 -08:00
										 |  |  |   beforeEachProviders, | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  |   it, | 
					
						
							|  |  |  |   xit, | 
					
						
							| 
									
										
										
										
											2015-09-03 22:01:36 -07:00
										 |  |  |   TestComponentBuilder | 
					
						
							| 
									
										
										
										
											2015-10-13 00:29:13 -07:00
										 |  |  | } from 'angular2/testing_internal'; | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-26 11:41:41 -07:00
										 |  |  | import {SpyRouter, SpyLocation} from './spies'; | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-10 22:11:13 -07:00
										 |  |  | import {provide, Component, View} from 'angular2/core'; | 
					
						
							| 
									
										
										
										
											2015-11-23 10:18:04 -08:00
										 |  |  | import {By} from 'angular2/platform/common_dom'; | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-24 11:24:53 -07:00
										 |  |  | import { | 
					
						
							|  |  |  |   Location, | 
					
						
							|  |  |  |   Router, | 
					
						
							|  |  |  |   RouteRegistry, | 
					
						
							|  |  |  |   RouterLink, | 
					
						
							|  |  |  |   RouterOutlet, | 
					
						
							|  |  |  |   Route, | 
					
						
							| 
									
										
										
										
											2015-09-21 19:58:45 -07:00
										 |  |  |   RouteParams, | 
					
						
							|  |  |  |   ComponentInstruction | 
					
						
							| 
									
										
										
										
											2015-08-24 11:24:53 -07:00
										 |  |  | } from 'angular2/router'; | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-19 15:09:34 -08:00
										 |  |  | import {DOM} from 'angular2/src/platform/dom/dom_adapter'; | 
					
						
							| 
									
										
											  
											
												refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
	{ path: '/foo', redirectTo: '/bar' },
	{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
	{ path: '/foo', redirectTo: ['Bar'] },
	{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
	{ path: '/tab', redirectTo: '/tab/users' }
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
	{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
	{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
											
										 
											2015-11-23 18:07:37 -08:00
										 |  |  | import {ResolvedInstruction} from 'angular2/src/router/instruction'; | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-18 10:05:55 -08:00
										 |  |  | let dummyInstruction = new ResolvedInstruction( | 
					
						
							|  |  |  |     new ComponentInstruction('detail', [], null, null, true, '0'), null, {}); | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-17 13:36:53 -07:00
										 |  |  | export function main() { | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |   describe('routerLink directive', function() { | 
					
						
							| 
									
										
										
										
											2015-08-24 11:24:53 -07:00
										 |  |  |     var tcb: TestComponentBuilder; | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
											  
											
												refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
	{ path: '/foo', redirectTo: '/bar' },
	{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
	{ path: '/foo', redirectTo: ['Bar'] },
	{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
	{ path: '/tab', redirectTo: '/tab/users' }
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
	{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
	{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
											
										 
											2015-11-23 18:07:37 -08:00
										 |  |  |     beforeEachProviders(() => [ | 
					
						
							| 
									
										
										
										
											2015-10-12 11:30:34 -07:00
										 |  |  |       provide(Location, {useValue: makeDummyLocation()}), | 
					
						
							|  |  |  |       provide(Router, {useValue: makeDummyRouter()}) | 
					
						
							| 
									
										
										
										
											2015-10-10 22:11:13 -07:00
										 |  |  |     ]); | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-24 11:24:53 -07:00
										 |  |  |     beforeEach(inject([TestComponentBuilder], (tcBuilder) => { tcb = tcBuilder; })); | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-24 11:24:53 -07:00
										 |  |  |     it('should update a[href] attribute', inject([AsyncTestCompleter], (async) => { | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |          tcb.createAsync(TestComponent) | 
					
						
							|  |  |  |              .then((testComponent) => { | 
					
						
							|  |  |  |                testComponent.detectChanges(); | 
					
						
							| 
									
										
										
										
											2015-11-02 15:11:57 -08:00
										 |  |  |                let anchorElement = | 
					
						
							|  |  |  |                    testComponent.debugElement.query(By.css('a.detail-view')).nativeElement; | 
					
						
							| 
									
										
										
										
											2015-10-26 13:57:41 +00:00
										 |  |  |                expect(DOM.getAttribute(anchorElement, 'href')).toEqual('detail'); | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  |                async.done(); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |        })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should call router.navigate when a link is clicked', | 
					
						
							| 
									
										
										
										
											2015-08-24 11:24:53 -07:00
										 |  |  |        inject([AsyncTestCompleter, Router], (async, router) => { | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |          tcb.createAsync(TestComponent) | 
					
						
							|  |  |  |              .then((testComponent) => { | 
					
						
							|  |  |  |                testComponent.detectChanges(); | 
					
						
							|  |  |  |                // TODO: shouldn't this be just 'click' rather than '^click'?
 | 
					
						
							| 
									
										
										
										
											2015-11-02 15:11:57 -08:00
										 |  |  |                testComponent.debugElement.query(By.css('a.detail-view')) | 
					
						
							|  |  |  |                    .triggerEventHandler('click', null); | 
					
						
							| 
									
										
										
										
											2015-09-08 21:41:56 -07:00
										 |  |  |                expect(router.spy('navigateByInstruction')).toHaveBeenCalledWith(dummyInstruction); | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  |                async.done(); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |        })); | 
					
						
							| 
									
										
										
										
											2015-11-02 15:11:57 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should call router.navigate when a link is clicked if target is _self', | 
					
						
							|  |  |  |        inject([AsyncTestCompleter, Router], (async, router) => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          tcb.createAsync(TestComponent) | 
					
						
							|  |  |  |              .then((testComponent) => { | 
					
						
							|  |  |  |                testComponent.detectChanges(); | 
					
						
							|  |  |  |                testComponent.debugElement.query(By.css('a.detail-view-self')) | 
					
						
							|  |  |  |                    .triggerEventHandler('click', null); | 
					
						
							|  |  |  |                expect(router.spy('navigateByInstruction')).toHaveBeenCalledWith(dummyInstruction); | 
					
						
							|  |  |  |                async.done(); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |        })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should NOT call router.navigate when a link is clicked if target is set to other than _self', | 
					
						
							|  |  |  |        inject([AsyncTestCompleter, Router], (async, router) => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          tcb.createAsync(TestComponent) | 
					
						
							|  |  |  |              .then((testComponent) => { | 
					
						
							|  |  |  |                testComponent.detectChanges(); | 
					
						
							|  |  |  |                testComponent.debugElement.query(By.css('a.detail-view-blank')) | 
					
						
							|  |  |  |                    .triggerEventHandler('click', null); | 
					
						
							|  |  |  |                expect(router.spy('navigateByInstruction')).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |                async.done(); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |        })); | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-24 11:24:53 -07:00
										 |  |  | @Component({selector: 'user-cmp'}) | 
					
						
							|  |  |  | @View({template: "hello {{user}}"}) | 
					
						
							|  |  |  | class UserCmp { | 
					
						
							|  |  |  |   user: string; | 
					
						
							|  |  |  |   constructor(params: RouteParams) { this.user = params.get('name'); } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | @Component({selector: 'test-component'}) | 
					
						
							|  |  |  | @View({ | 
					
						
							|  |  |  |   template: `
 | 
					
						
							|  |  |  |     <div> | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |       <a [routerLink]="['/Detail']" | 
					
						
							| 
									
										
										
										
											2015-11-02 15:11:57 -08:00
										 |  |  |          class="detail-view"> | 
					
						
							|  |  |  |            detail view | 
					
						
							|  |  |  |       </a> | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |       <a [routerLink]="['/Detail']" | 
					
						
							| 
									
										
										
										
											2015-11-02 15:11:57 -08:00
										 |  |  |          class="detail-view-self" | 
					
						
							|  |  |  |          target="_self"> | 
					
						
							|  |  |  |            detail view with _self target | 
					
						
							|  |  |  |       </a> | 
					
						
							| 
									
										
										
										
											2015-11-23 16:02:19 -08:00
										 |  |  |       <a [routerLink]="['/Detail']" | 
					
						
							| 
									
										
										
										
											2015-11-02 15:11:57 -08:00
										 |  |  |          class="detail-view-blank" | 
					
						
							|  |  |  |          target="_blank"> | 
					
						
							|  |  |  |            detail view with _blank target | 
					
						
							|  |  |  |       </a> | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  |     </div>`,
 | 
					
						
							|  |  |  |   directives: [RouterLink] | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class TestComponent { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function makeDummyLocation() { | 
					
						
							| 
									
										
										
										
											2015-08-26 11:41:41 -07:00
										 |  |  |   var dl = new SpyLocation(); | 
					
						
							| 
									
										
										
										
											2015-10-26 13:57:41 +00:00
										 |  |  |   dl.spy('prepareExternalUrl').andCallFake((url) => url); | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  |   return dl; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function makeDummyRouter() { | 
					
						
							| 
									
										
										
										
											2015-08-26 11:41:41 -07:00
										 |  |  |   var dr = new SpyRouter(); | 
					
						
							| 
									
										
										
										
											2015-07-17 13:36:53 -07:00
										 |  |  |   dr.spy('generate').andCallFake((routeParams) => dummyInstruction); | 
					
						
							| 
									
										
										
										
											2015-08-30 21:25:46 -07:00
										 |  |  |   dr.spy('isRouteActive').andCallFake((_) => false); | 
					
						
							| 
									
										
										
										
											2015-07-17 13:36:53 -07:00
										 |  |  |   dr.spy('navigateInstruction'); | 
					
						
							| 
									
										
										
										
											2015-07-02 17:38:19 -07:00
										 |  |  |   return dr; | 
					
						
							|  |  |  | } |