| 
									
										
										
										
											2017-03-14 00:34:53 +00:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @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
 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-04-23 10:47:27 -07:00
										 |  |  | import {Compiler, Component, ComponentFactory, ComponentRef, Injector, NgModule, Testability, TestabilityRegistry} from '@angular/core'; | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  | import {TestBed, getTestBed, inject} from '@angular/core/testing'; | 
					
						
							| 
									
										
										
										
											2017-03-14 00:34:53 +00:00
										 |  |  | import * as angular from '@angular/upgrade/src/common/angular1'; | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  | import {DowngradeComponentAdapter, groupNodesBySelector} from '@angular/upgrade/src/common/downgrade_component_adapter'; | 
					
						
							| 
									
										
										
										
											2017-03-14 00:34:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 19:21:18 +02:00
										 |  |  | import {nodes, withEachNg1Version} from './test_helpers'; | 
					
						
							| 
									
										
										
										
											2017-03-14 00:34:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 19:21:18 +02:00
										 |  |  | withEachNg1Version(() => { | 
					
						
							| 
									
										
										
										
											2017-03-14 00:34:53 +00:00
										 |  |  |   describe('DowngradeComponentAdapter', () => { | 
					
						
							|  |  |  |     describe('groupNodesBySelector', () => { | 
					
						
							|  |  |  |       it('should return an array of node collections for each selector', () => { | 
					
						
							|  |  |  |         const contentNodes = nodes( | 
					
						
							|  |  |  |             '<div class="x"><span>div-1 content</span></div>' + | 
					
						
							|  |  |  |             '<input type="number" name="myNum">' + | 
					
						
							|  |  |  |             '<input type="date" name="myDate">' + | 
					
						
							|  |  |  |             '<span>span content</span>' + | 
					
						
							|  |  |  |             '<div class="x"><span>div-2 content</span></div>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const selectors = ['input[type=date]', 'span', '.x']; | 
					
						
							| 
									
										
										
										
											2017-03-14 14:55:37 -07:00
										 |  |  |         const projectableNodes = groupNodesBySelector(selectors, contentNodes); | 
					
						
							| 
									
										
										
										
											2017-03-14 00:34:53 +00:00
										 |  |  |         expect(projectableNodes[0]).toEqual(nodes('<input type="date" name="myDate">')); | 
					
						
							|  |  |  |         expect(projectableNodes[1]).toEqual(nodes('<span>span content</span>')); | 
					
						
							|  |  |  |         expect(projectableNodes[2]) | 
					
						
							|  |  |  |             .toEqual(nodes( | 
					
						
							|  |  |  |                 '<div class="x"><span>div-1 content</span></div>' + | 
					
						
							|  |  |  |                 '<div class="x"><span>div-2 content</span></div>')); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should collect up unmatched nodes for the wildcard selector', () => { | 
					
						
							|  |  |  |         const contentNodes = nodes( | 
					
						
							|  |  |  |             '<div class="x"><span>div-1 content</span></div>' + | 
					
						
							|  |  |  |             '<input type="number" name="myNum">' + | 
					
						
							|  |  |  |             '<input type="date" name="myDate">' + | 
					
						
							|  |  |  |             '<span>span content</span>' + | 
					
						
							|  |  |  |             '<div class="x"><span>div-2 content</span></div>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const selectors = ['.x', '*', 'input[type=date]']; | 
					
						
							| 
									
										
										
										
											2017-03-14 14:55:37 -07:00
										 |  |  |         const projectableNodes = groupNodesBySelector(selectors, contentNodes); | 
					
						
							| 
									
										
										
										
											2017-03-14 00:34:53 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         expect(projectableNodes[0]) | 
					
						
							|  |  |  |             .toEqual(nodes( | 
					
						
							|  |  |  |                 '<div class="x"><span>div-1 content</span></div>' + | 
					
						
							|  |  |  |                 '<div class="x"><span>div-2 content</span></div>')); | 
					
						
							|  |  |  |         expect(projectableNodes[1]) | 
					
						
							|  |  |  |             .toEqual(nodes( | 
					
						
							|  |  |  |                 '<input type="number" name="myNum">' + | 
					
						
							|  |  |  |                 '<span>span content</span>')); | 
					
						
							|  |  |  |         expect(projectableNodes[2]).toEqual(nodes('<input type="date" name="myDate">')); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should return an array of empty arrays if there are no nodes passed in', () => { | 
					
						
							|  |  |  |         const selectors = ['.x', '*', 'input[type=date]']; | 
					
						
							| 
									
										
										
										
											2017-03-14 14:55:37 -07:00
										 |  |  |         const projectableNodes = groupNodesBySelector(selectors, []); | 
					
						
							| 
									
										
										
										
											2017-03-14 00:34:53 +00:00
										 |  |  |         expect(projectableNodes).toEqual([[], [], []]); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should return an empty array for each selector that does not match', () => { | 
					
						
							|  |  |  |         const contentNodes = nodes( | 
					
						
							|  |  |  |             '<div class="x"><span>div-1 content</span></div>' + | 
					
						
							|  |  |  |             '<input type="number" name="myNum">' + | 
					
						
							|  |  |  |             '<input type="date" name="myDate">' + | 
					
						
							|  |  |  |             '<span>span content</span>' + | 
					
						
							|  |  |  |             '<div class="x"><span>div-2 content</span></div>'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-14 14:55:37 -07:00
										 |  |  |         const projectableNodes = groupNodesBySelector([], contentNodes); | 
					
						
							| 
									
										
										
										
											2017-03-14 00:34:53 +00:00
										 |  |  |         expect(projectableNodes).toEqual([]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-14 14:55:37 -07:00
										 |  |  |         const noMatchSelectorNodes = groupNodesBySelector(['.not-there'], contentNodes); | 
					
						
							| 
									
										
										
										
											2017-03-14 00:34:53 +00:00
										 |  |  |         expect(noMatchSelectorNodes).toEqual([[]]); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     describe('testability', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       let adapter: DowngradeComponentAdapter; | 
					
						
							|  |  |  |       let content: string; | 
					
						
							|  |  |  |       let compiler: Compiler; | 
					
						
							|  |  |  |       let element: angular.IAugmentedJQuery; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       class mockScope implements angular.IScope { | 
					
						
							| 
									
										
										
										
											2018-02-23 15:18:21 +02:00
										 |  |  |         private destroyListeners: (() => void)[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-22 19:51:03 +02:00
										 |  |  |         $new() { return this; } | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  |         $watch(exp: angular.Ng1Expression, fn?: (a1?: any, a2?: any) => void) { | 
					
						
							|  |  |  |           return () => {}; | 
					
						
							| 
									
										
										
										
											2017-09-22 19:51:03 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  |         $on(event: string, fn?: (event?: any, ...args: any[]) => void) { | 
					
						
							| 
									
										
										
										
											2018-02-23 15:18:21 +02:00
										 |  |  |           if (event === '$destroy' && fn) { | 
					
						
							|  |  |  |             this.destroyListeners.push(fn); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  |           return () => {}; | 
					
						
							| 
									
										
										
										
											2017-09-22 19:51:03 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  |         $destroy() { | 
					
						
							| 
									
										
										
										
											2018-02-23 15:18:21 +02:00
										 |  |  |           let listener: (() => void)|undefined; | 
					
						
							|  |  |  |           while ((listener = this.destroyListeners.shift())) listener(); | 
					
						
							| 
									
										
										
										
											2017-09-22 19:51:03 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  |         $apply(exp?: angular.Ng1Expression) { | 
					
						
							|  |  |  |           return () => {}; | 
					
						
							| 
									
										
										
										
											2017-09-22 19:51:03 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  |         $digest() { | 
					
						
							|  |  |  |           return () => {}; | 
					
						
							| 
									
										
										
										
											2017-09-22 19:51:03 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  |         $evalAsync(exp: angular.Ng1Expression, locals?: any) { | 
					
						
							|  |  |  |           return () => {}; | 
					
						
							| 
									
										
										
										
											2017-09-22 19:51:03 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  |         $$childTail: angular.IScope; | 
					
						
							|  |  |  |         $$childHead: angular.IScope; | 
					
						
							|  |  |  |         $$nextSibling: angular.IScope; | 
					
						
							|  |  |  |         [key: string]: any; | 
					
						
							|  |  |  |         $id = 'mockScope'; | 
					
						
							|  |  |  |         $parent: angular.IScope; | 
					
						
							|  |  |  |         $root: angular.IScope; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       function getAdaptor(): DowngradeComponentAdapter { | 
					
						
							|  |  |  |         let attrs = undefined as any; | 
					
						
							|  |  |  |         let scope: angular.IScope;  // mock
 | 
					
						
							|  |  |  |         let ngModel = undefined as any; | 
					
						
							|  |  |  |         let parentInjector: Injector;  // testbed
 | 
					
						
							|  |  |  |         let $injector = undefined as any; | 
					
						
							|  |  |  |         let $compile = undefined as any; | 
					
						
							|  |  |  |         let $parse = undefined as any; | 
					
						
							|  |  |  |         let componentFactory: ComponentFactory<any>;  // testbed
 | 
					
						
							| 
									
										
										
										
											2017-09-25 12:39:51 +03:00
										 |  |  |         let wrapCallback = (cb: any) => cb; | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         content = `
 | 
					
						
							|  |  |  |           <h1> new component </h1> | 
					
						
							|  |  |  |           <div> a great component </div> | 
					
						
							|  |  |  |           <comp></comp> | 
					
						
							|  |  |  |         `;
 | 
					
						
							|  |  |  |         element = angular.element(content); | 
					
						
							|  |  |  |         scope = new mockScope(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @Component({ | 
					
						
							|  |  |  |           selector: 'comp', | 
					
						
							|  |  |  |           template: '', | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         class NewComponent { | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @NgModule({ | 
					
						
							|  |  |  |           providers: [{provide: 'hello', useValue: 'component'}], | 
					
						
							|  |  |  |           declarations: [NewComponent], | 
					
						
							|  |  |  |           entryComponents: [NewComponent], | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         class NewModule { | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const modFactory = compiler.compileModuleSync(NewModule); | 
					
						
							|  |  |  |         const module = modFactory.create(TestBed); | 
					
						
							|  |  |  |         componentFactory = module.componentFactoryResolver.resolveComponentFactory(NewComponent) !; | 
					
						
							|  |  |  |         parentInjector = TestBed; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return new DowngradeComponentAdapter( | 
					
						
							|  |  |  |             element, attrs, scope, ngModel, parentInjector, $injector, $compile, $parse, | 
					
						
							|  |  |  |             componentFactory, wrapCallback); | 
					
						
							| 
									
										
										
										
											2017-09-22 19:51:03 +02:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       beforeEach((inject([Compiler], (inject_compiler: Compiler) => { | 
					
						
							|  |  |  |         compiler = inject_compiler; | 
					
						
							|  |  |  |         adapter = getAdaptor(); | 
					
						
							|  |  |  |       }))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       afterEach(() => { | 
					
						
							|  |  |  |         let registry = TestBed.get(TestabilityRegistry); | 
					
						
							|  |  |  |         registry.unregisterAllApplications(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should add testabilities hook when creating components', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let registry = TestBed.get(TestabilityRegistry); | 
					
						
							|  |  |  |         adapter.createComponent([]); | 
					
						
							|  |  |  |         expect(registry.getAllTestabilities().length).toEqual(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         adapter = getAdaptor();  // get a new adaptor to creat a new component
 | 
					
						
							|  |  |  |         adapter.createComponent([]); | 
					
						
							|  |  |  |         expect(registry.getAllTestabilities().length).toEqual(2); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should remove the testability hook when destroy a component', () => { | 
					
						
							|  |  |  |         const registry = TestBed.get(TestabilityRegistry); | 
					
						
							|  |  |  |         expect(registry.getAllTestabilities().length).toEqual(0); | 
					
						
							|  |  |  |         adapter.createComponent([]); | 
					
						
							|  |  |  |         expect(registry.getAllTestabilities().length).toEqual(1); | 
					
						
							| 
									
										
										
										
											2017-09-25 12:39:51 +03:00
										 |  |  |         adapter.registerCleanup(); | 
					
						
							| 
									
										
										
										
											2017-09-08 11:50:13 -07:00
										 |  |  |         element.remove !(); | 
					
						
							|  |  |  |         expect(registry.getAllTestabilities().length).toEqual(0); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-14 00:34:53 +00:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-02-15 19:21:18 +02:00
										 |  |  | }); |