| 
									
										
										
										
											2016-07-21 17:12:00 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							| 
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2016-07-21 17:12:00 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-06 16:19:52 -07:00
										 |  |  | import {Routes} from '../src/config'; | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  | import {createRouterState} from '../src/create_router_state'; | 
					
						
							|  |  |  | import {recognize} from '../src/recognize'; | 
					
						
							| 
									
										
										
										
											2017-05-03 11:17:27 +02:00
										 |  |  | import {DefaultRouteReuseStrategy} from '../src/route_reuse_strategy'; | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  | import {ActivatedRoute, advanceActivatedRoute, createEmptyState, RouterState, RouterStateSnapshot} from '../src/router_state'; | 
					
						
							| 
									
										
										
										
											2016-09-27 17:12:25 -07:00
										 |  |  | import {PRIMARY_OUTLET} from '../src/shared'; | 
					
						
							| 
									
										
										
										
											2016-07-25 12:15:07 -07:00
										 |  |  | import {DefaultUrlSerializer, UrlSegmentGroup, UrlTree} from '../src/url_tree'; | 
					
						
							| 
									
										
										
										
											2016-06-21 11:49:42 -07:00
										 |  |  | import {TreeNode} from '../src/utils/tree'; | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | describe('create router state', () => { | 
					
						
							| 
									
										
										
										
											2018-09-25 11:18:31 -04:00
										 |  |  |   let reuseStrategy: DefaultRouteReuseStrategy; | 
					
						
							|  |  |  |   beforeEach(() => { | 
					
						
							|  |  |  |     reuseStrategy = new DefaultRouteReuseStrategy(); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-11-29 23:21:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |   const emptyState = () => | 
					
						
							|  |  |  |       createEmptyState(new (UrlTree as any)(new UrlSegmentGroup([], {}), {}, null!), RootComponent); | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-03 12:30:19 +02:00
										 |  |  |   it('should create new state', () => { | 
					
						
							| 
									
										
										
										
											2016-06-21 11:49:42 -07:00
										 |  |  |     const state = createRouterState( | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |         reuseStrategy, | 
					
						
							|  |  |  |         createState( | 
					
						
							|  |  |  |             [ | 
					
						
							|  |  |  |               {path: 'a', component: ComponentA}, | 
					
						
							|  |  |  |               {path: 'b', component: ComponentB, outlet: 'left'}, | 
					
						
							|  |  |  |               {path: 'c', component: ComponentC, outlet: 'right'} | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |             'a(left:b//right:c)'), | 
					
						
							| 
									
										
										
										
											2016-06-21 11:49:42 -07:00
										 |  |  |         emptyState()); | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     checkActivatedRoute(state.root, RootComponent); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |     const c = (state as any).children(state.root); | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  |     checkActivatedRoute(c[0], ComponentA); | 
					
						
							|  |  |  |     checkActivatedRoute(c[1], ComponentB, 'left'); | 
					
						
							|  |  |  |     checkActivatedRoute(c[2], ComponentC, 'right'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should reuse existing nodes when it can', () => { | 
					
						
							|  |  |  |     const config = [ | 
					
						
							| 
									
										
										
										
											2016-06-21 11:49:42 -07:00
										 |  |  |       {path: 'a', component: ComponentA}, {path: 'b', component: ComponentB, outlet: 'left'}, | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  |       {path: 'c', component: ComponentC, outlet: 'left'} | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-29 23:21:41 -08:00
										 |  |  |     const prevState = | 
					
						
							|  |  |  |         createRouterState(reuseStrategy, createState(config, 'a(left:b)'), emptyState()); | 
					
						
							| 
									
										
										
										
											2016-06-02 14:44:57 -07:00
										 |  |  |     advanceState(prevState); | 
					
						
							| 
									
										
										
										
											2016-11-29 23:21:41 -08:00
										 |  |  |     const state = createRouterState(reuseStrategy, createState(config, 'a(left:c)'), prevState); | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(prevState.root).toBe(state.root); | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |     const prevC = (prevState as any).children(prevState.root); | 
					
						
							|  |  |  |     const currC = (state as any).children(state.root); | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(prevC[0]).toBe(currC[0]); | 
					
						
							|  |  |  |     expect(prevC[1]).not.toBe(currC[1]); | 
					
						
							|  |  |  |     checkActivatedRoute(currC[1], ComponentC, 'left'); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-06-19 14:44:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   it('should handle componentless routes', () => { | 
					
						
							| 
									
										
										
										
											2016-06-21 11:49:42 -07:00
										 |  |  |     const config = [{ | 
					
						
							|  |  |  |       path: 'a/:id', | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |       children: | 
					
						
							|  |  |  |           [{path: 'b', component: ComponentA}, {path: 'c', component: ComponentB, outlet: 'right'}] | 
					
						
							| 
									
										
										
										
											2016-06-21 11:49:42 -07:00
										 |  |  |     }]; | 
					
						
							| 
									
										
										
										
											2016-06-19 14:44:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-29 23:21:41 -08:00
										 |  |  |     const prevState = createRouterState( | 
					
						
							|  |  |  |         reuseStrategy, createState(config, 'a/1;p=11/(b//right:c)'), emptyState()); | 
					
						
							| 
									
										
										
										
											2016-06-19 14:44:20 -07:00
										 |  |  |     advanceState(prevState); | 
					
						
							| 
									
										
										
										
											2016-11-29 23:21:41 -08:00
										 |  |  |     const state = | 
					
						
							|  |  |  |         createRouterState(reuseStrategy, createState(config, 'a/2;p=22/(b//right:c)'), prevState); | 
					
						
							| 
									
										
										
										
											2016-06-19 14:44:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(prevState.root).toBe(state.root); | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |     const prevP = (prevState as any).firstChild(prevState.root)!; | 
					
						
							|  |  |  |     const currP = (state as any).firstChild(state.root)!; | 
					
						
							| 
									
										
										
										
											2016-06-19 14:44:20 -07:00
										 |  |  |     expect(prevP).toBe(currP); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |     const currC = (state as any).children(currP); | 
					
						
							| 
									
										
										
										
											2016-06-19 14:44:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(currP._futureSnapshot.params).toEqual({id: '2', p: '22'}); | 
					
						
							| 
									
										
										
										
											2017-03-17 10:09:42 -07:00
										 |  |  |     expect(currP._futureSnapshot.paramMap.get('id')).toEqual('2'); | 
					
						
							|  |  |  |     expect(currP._futureSnapshot.paramMap.get('p')).toEqual('22'); | 
					
						
							| 
									
										
										
										
											2016-06-19 14:44:20 -07:00
										 |  |  |     checkActivatedRoute(currC[0], ComponentA); | 
					
						
							|  |  |  |     checkActivatedRoute(currC[1], ComponentB, 'right'); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-02-27 15:04:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-04 21:18:14 +03:00
										 |  |  |   it('should not retrieve routes when `shouldAttach` is always false', () => { | 
					
						
							| 
									
										
										
										
											2018-02-27 15:04:36 +01:00
										 |  |  |     const config = [ | 
					
						
							|  |  |  |       {path: 'a', component: ComponentA}, {path: 'b', component: ComponentB, outlet: 'left'}, | 
					
						
							|  |  |  |       {path: 'c', component: ComponentC, outlet: 'left'} | 
					
						
							|  |  |  |     ]; | 
					
						
							| 
									
										
										
										
											2019-05-04 21:18:14 +03:00
										 |  |  |     spyOn(reuseStrategy, 'retrieve'); | 
					
						
							| 
									
										
										
										
											2018-02-27 15:04:36 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const prevState = | 
					
						
							|  |  |  |         createRouterState(reuseStrategy, createState(config, 'a(left:b)'), emptyState()); | 
					
						
							|  |  |  |     advanceState(prevState); | 
					
						
							| 
									
										
										
										
											2019-05-04 21:18:14 +03:00
										 |  |  |     createRouterState(reuseStrategy, createState(config, 'a(left:c)'), prevState); | 
					
						
							|  |  |  |     expect(reuseStrategy.retrieve).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2018-02-27 15:04:36 +01:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-09-25 11:18:31 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   it('should consistently represent future and current state', () => { | 
					
						
							|  |  |  |     const config = [ | 
					
						
							|  |  |  |       {path: '', pathMatch: 'full', component: ComponentA}, | 
					
						
							|  |  |  |       {path: 'product/:id', component: ComponentB} | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |     spyOn(reuseStrategy, 'shouldReuseRoute').and.callThrough(); | 
					
						
							|  |  |  |     const previousState = createRouterState(reuseStrategy, createState(config, ''), emptyState()); | 
					
						
							|  |  |  |     advanceState(previousState); | 
					
						
							|  |  |  |     (reuseStrategy.shouldReuseRoute as jasmine.Spy).calls.reset(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     createRouterState(reuseStrategy, createState(config, 'product/30'), previousState); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // One call for the root and one call for each of the children
 | 
					
						
							|  |  |  |     expect(reuseStrategy.shouldReuseRoute).toHaveBeenCalledTimes(2); | 
					
						
							|  |  |  |     const reuseCalls = (reuseStrategy.shouldReuseRoute as jasmine.Spy).calls; | 
					
						
							|  |  |  |     const future1 = reuseCalls.argsFor(0)[0]; | 
					
						
							|  |  |  |     const current1 = reuseCalls.argsFor(0)[1]; | 
					
						
							|  |  |  |     const future2 = reuseCalls.argsFor(1)[0]; | 
					
						
							|  |  |  |     const current2 = reuseCalls.argsFor(1)[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Routing from '' to 'product/30'
 | 
					
						
							|  |  |  |     expect(current1._routerState.url).toEqual(''); | 
					
						
							|  |  |  |     expect(future1._routerState.url).toEqual('product/30'); | 
					
						
							|  |  |  |     expect(current2._routerState.url).toEqual(''); | 
					
						
							|  |  |  |     expect(future2._routerState.url).toEqual('product/30'); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 14:44:57 -07:00
										 |  |  | function advanceState(state: RouterState): void { | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |   advanceNode((state as any)._root); | 
					
						
							| 
									
										
										
										
											2016-06-02 14:44:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function advanceNode(node: TreeNode<ActivatedRoute>): void { | 
					
						
							|  |  |  |   advanceActivatedRoute(node.value); | 
					
						
							|  |  |  |   node.children.forEach(advanceNode); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-06 16:19:52 -07:00
										 |  |  | function createState(config: Routes, url: string): RouterStateSnapshot { | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |   let res: RouterStateSnapshot = undefined!; | 
					
						
							| 
									
										
										
										
											2016-06-14 14:55:59 -07:00
										 |  |  |   recognize(RootComponent, config, tree(url), url).forEach(s => res = s); | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  |   return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-21 11:49:42 -07:00
										 |  |  | function checkActivatedRoute( | 
					
						
							|  |  |  |     actual: ActivatedRoute, cmp: Function, outlet: string = PRIMARY_OUTLET): void { | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  |   if (actual === null) { | 
					
						
							|  |  |  |     expect(actual).toBeDefined(); | 
					
						
							|  |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |     expect(actual.component as any).toBe(cmp); | 
					
						
							| 
									
										
										
										
											2016-06-01 13:29:28 -07:00
										 |  |  |     expect(actual.outlet).toEqual(outlet); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function tree(url: string): UrlTree { | 
					
						
							|  |  |  |   return new DefaultUrlSerializer().parse(url); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class RootComponent {} | 
					
						
							|  |  |  | class ComponentA {} | 
					
						
							|  |  |  | class ComponentB {} | 
					
						
							|  |  |  | class ComponentC {} |