| 
									
										
										
										
											2018-02-28 09:45:11 -08: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-06-18 10:29:29 +01:00
										 |  |  | import {Component, DoBootstrap, EventEmitter, Injector, Input, NgModule, Output, destroyPlatform} from '@angular/core'; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | import {BrowserModule} from '@angular/platform-browser'; | 
					
						
							|  |  |  | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; | 
					
						
							| 
									
										
										
										
											2018-02-27 17:06:06 -05:00
										 |  |  | import {Subject} from 'rxjs'; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 13:24:27 -07:00
										 |  |  | import {NgElementConstructor, createCustomElement} from '../src/create-custom-element'; | 
					
						
							| 
									
										
										
										
											2018-03-14 15:58:12 -07:00
										 |  |  | import {NgElementStrategy, NgElementStrategyEvent, NgElementStrategyFactory} from '../src/element-strategy'; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type WithFooBar = { | 
					
						
							|  |  |  |   fooFoo: string, | 
					
						
							|  |  |  |   barBar: string | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if (typeof customElements !== 'undefined') { | 
					
						
							| 
									
										
										
										
											2018-03-14 13:24:27 -07:00
										 |  |  |   describe('createCustomElement', () => { | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |     let NgElementCtor: NgElementConstructor<WithFooBar>; | 
					
						
							|  |  |  |     let strategy: TestStrategy; | 
					
						
							|  |  |  |     let strategyFactory: TestStrategyFactory; | 
					
						
							| 
									
										
										
										
											2018-03-01 22:34:21 -08:00
										 |  |  |     let injector: Injector; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     beforeAll(done => { | 
					
						
							|  |  |  |       destroyPlatform(); | 
					
						
							|  |  |  |       platformBrowserDynamic() | 
					
						
							|  |  |  |           .bootstrapModule(TestModule) | 
					
						
							|  |  |  |           .then(ref => { | 
					
						
							| 
									
										
										
										
											2018-03-01 22:34:21 -08:00
										 |  |  |             injector = ref.injector; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |             strategyFactory = new TestStrategyFactory(); | 
					
						
							|  |  |  |             strategy = strategyFactory.testStrategy; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-14 13:24:27 -07:00
										 |  |  |             NgElementCtor = createCustomElement(TestComponent, {injector, strategyFactory}); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // The `@webcomponents/custom-elements/src/native-shim.js` polyfill allows us to create
 | 
					
						
							|  |  |  |             // new instances of the NgElement which extends HTMLElement, as long as we define it.
 | 
					
						
							|  |  |  |             customElements.define('test-element', NgElementCtor); | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           .then(done, done.fail); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     afterAll(() => destroyPlatform()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should use a default strategy for converting component inputs', () => { | 
					
						
							|  |  |  |       expect(NgElementCtor.observedAttributes).toEqual(['foo-foo', 'barbar']); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should send input values from attributes when connected', () => { | 
					
						
							| 
									
										
										
										
											2018-03-06 14:02:25 -08:00
										 |  |  |       const element = new NgElementCtor(injector); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |       element.setAttribute('foo-foo', 'value-foo-foo'); | 
					
						
							|  |  |  |       element.setAttribute('barbar', 'value-barbar'); | 
					
						
							|  |  |  |       element.connectedCallback(); | 
					
						
							|  |  |  |       expect(strategy.connectedElement).toBe(element); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-02 10:08:16 -08:00
										 |  |  |       expect(strategy.getInputValue('fooFoo')).toBe('value-foo-foo'); | 
					
						
							|  |  |  |       expect(strategy.getInputValue('barBar')).toBe('value-barbar'); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should listen to output events after connected', () => { | 
					
						
							| 
									
										
										
										
											2018-03-06 14:02:25 -08:00
										 |  |  |       const element = new NgElementCtor(injector); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |       element.connectedCallback(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       let eventValue: any = null; | 
					
						
							|  |  |  |       element.addEventListener('some-event', (e: CustomEvent) => eventValue = e.detail); | 
					
						
							|  |  |  |       strategy.events.next({name: 'some-event', value: 'event-value'}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(eventValue).toEqual('event-value'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not listen to output events after disconnected', () => { | 
					
						
							| 
									
										
										
										
											2018-03-06 14:02:25 -08:00
										 |  |  |       const element = new NgElementCtor(injector); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |       element.connectedCallback(); | 
					
						
							|  |  |  |       element.disconnectedCallback(); | 
					
						
							|  |  |  |       expect(strategy.disconnectCalled).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       let eventValue: any = null; | 
					
						
							|  |  |  |       element.addEventListener('some-event', (e: CustomEvent) => eventValue = e.detail); | 
					
						
							|  |  |  |       strategy.events.next({name: 'some-event', value: 'event-value'}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(eventValue).toEqual(null); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should properly set getters/setters on the element', () => { | 
					
						
							| 
									
										
										
										
											2018-03-06 14:02:25 -08:00
										 |  |  |       const element = new NgElementCtor(injector); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |       element.fooFoo = 'foo-foo-value'; | 
					
						
							|  |  |  |       element.barBar = 'barBar-value'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(strategy.inputs.get('fooFoo')).toBe('foo-foo-value'); | 
					
						
							|  |  |  |       expect(strategy.inputs.get('barBar')).toBe('barBar-value'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Helpers
 | 
					
						
							|  |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'test-component', | 
					
						
							|  |  |  |   template: 'TestComponent|foo({{ fooFoo }})|bar({{ barBar }})', | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | class TestComponent { | 
					
						
							|  |  |  |   @Input() fooFoo: string = 'foo'; | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   @Input('barbar') barBar !: string; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @Output() bazBaz = new EventEmitter<boolean>(); | 
					
						
							|  |  |  |   @Output('quxqux') quxQux = new EventEmitter<Object>(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | @NgModule({ | 
					
						
							|  |  |  |   imports: [BrowserModule], | 
					
						
							|  |  |  |   declarations: [TestComponent], | 
					
						
							|  |  |  |   entryComponents: [TestComponent], | 
					
						
							|  |  |  | }) | 
					
						
							| 
									
										
										
										
											2018-06-18 10:29:29 +01:00
										 |  |  | class TestModule implements DoBootstrap { | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |   ngDoBootstrap() {} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class TestStrategy implements NgElementStrategy { | 
					
						
							|  |  |  |   connectedElement: HTMLElement|null = null; | 
					
						
							|  |  |  |   disconnectCalled = false; | 
					
						
							|  |  |  |   inputs = new Map<string, any>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   events = new Subject<NgElementStrategyEvent>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   connect(element: HTMLElement): void { this.connectedElement = element; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   disconnect(): void { this.disconnectCalled = true; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-02 10:08:16 -08:00
										 |  |  |   getInputValue(propName: string): any { return this.inputs.get(propName); } | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-02 10:08:16 -08:00
										 |  |  |   setInputValue(propName: string, value: string): void { this.inputs.set(propName, value); } | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class TestStrategyFactory implements NgElementStrategyFactory { | 
					
						
							|  |  |  |   testStrategy = new TestStrategy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   create(): NgElementStrategy { return this.testStrategy; } | 
					
						
							|  |  |  | } |