| 
									
										
										
										
											2017-12-01 14:23:03 -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-08-06 16:40:16 +02:00
										 |  |  | import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core'; | 
					
						
							| 
									
										
										
										
											2018-09-06 18:50:57 -07:00
										 |  |  | import {RendererStyleFlags2, RendererType2} from '../../src/render/api'; | 
					
						
							| 
									
										
										
										
											2018-10-11 13:13:57 -07:00
										 |  |  | import {AttributeMarker, defineComponent, defineDirective, templateRefExtractor} from '../../src/render3/index'; | 
					
						
							| 
									
										
										
										
											2018-09-06 18:50:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementAttribute, elementClassProp, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, elementStyleProp, elementStyling, elementStylingApply, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, load, projection, projectionDef, reference, text, textBinding, template, elementStylingMap, directiveInject} from '../../src/render3/instructions'; | 
					
						
							| 
									
										
										
										
											2018-09-26 16:02:40 -07:00
										 |  |  | import {InitialStylingFlags, RenderFlags} from '../../src/render3/interfaces/definition'; | 
					
						
							| 
									
										
										
										
											2018-09-06 18:50:57 -07:00
										 |  |  | import {RElement, Renderer3, RendererFactory3, domRendererFactory3, RText, RComment, RNode, RendererStyleFlags3, ProceduralRenderer3} from '../../src/render3/interfaces/renderer'; | 
					
						
							| 
									
										
										
										
											2018-10-18 14:47:53 -07:00
										 |  |  | import {NO_CHANGE} from '../../src/render3/tokens'; | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  | import {HEADER_OFFSET, CONTEXT} from '../../src/render3/interfaces/view'; | 
					
						
							| 
									
										
										
										
											2018-10-18 09:23:18 +02:00
										 |  |  | import {enableBindings, disableBindings} from '../../src/render3/state'; | 
					
						
							| 
									
										
										
										
											2018-05-09 15:30:16 -07:00
										 |  |  | import {sanitizeUrl} from '../../src/sanitization/sanitization'; | 
					
						
							|  |  |  | import {Sanitizer, SecurityContext} from '../../src/sanitization/security'; | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-01 15:19:27 +02:00
										 |  |  | import {NgIf} from './common_with_def'; | 
					
						
							| 
									
										
										
										
											2018-09-21 18:38:13 -07:00
										 |  |  | import {ComponentFixture, TemplateFixture, createComponent, renderToHtml} from './render_util'; | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  | import {getContext} from '../../src/render3/context_discovery'; | 
					
						
							| 
									
										
										
										
											2018-09-28 12:38:16 -07:00
										 |  |  | import {StylingIndex} from '../../src/render3/interfaces/styling'; | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  | import {MONKEY_PATCH_KEY_NAME} from '../../src/render3/interfaces/context'; | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-03 11:42:48 +01:00
										 |  |  | describe('render3 integration test', () => { | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   describe('render', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should render basic template', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       expect(renderToHtml(Template, {}, 2)).toEqual('<span title="Hello">Greetings</span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |       function Template(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           elementStart(0, 'span', ['title', 'Hello']); | 
					
						
							|  |  |  |           { text(1, 'Greetings'); } | 
					
						
							|  |  |  |           elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-04-14 11:52:53 -07:00
										 |  |  |       expect(ngDevMode).toHaveProperties({ | 
					
						
							|  |  |  |         firstTemplatePass: 1, | 
					
						
							| 
									
										
										
										
											2018-05-16 05:56:01 -07:00
										 |  |  |         tNode: 3,  // 1 for div, 1 for text, 1 for host element
 | 
					
						
							| 
									
										
										
										
											2018-09-13 16:07:23 -07:00
										 |  |  |         tView: 2,  // 1 for root view, 1 for template
 | 
					
						
							| 
									
										
										
										
											2018-04-14 11:52:53 -07:00
										 |  |  |         rendererCreateElement: 1, | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should render and update basic "Hello, World" template', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           elementStart(0, 'h1'); | 
					
						
							|  |  |  |           { text(1); } | 
					
						
							|  |  |  |           elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |           textBinding(1, interpolation1('Hello, ', ctx.name, '!')); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 2, 1); | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       fixture.component.name = 'World'; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<h1>Hello, World!</h1>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.component.name = 'New World'; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<h1>Hello, New World!</h1>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('text bindings', () => { | 
					
						
							|  |  |  |     it('should render "undefined" as "" when used with `bind()`', () => { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |       function Template(rf: RenderFlags, name: string) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           text(0); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |           textBinding(0, bind(name)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       expect(renderToHtml(Template, 'benoit', 1, 1)).toEqual('benoit'); | 
					
						
							|  |  |  |       expect(renderToHtml(Template, undefined, 1, 1)).toEqual(''); | 
					
						
							| 
									
										
										
										
											2018-05-15 22:07:20 +02:00
										 |  |  |       expect(ngDevMode).toHaveProperties({ | 
					
						
							|  |  |  |         firstTemplatePass: 0, | 
					
						
							| 
									
										
										
										
											2018-05-30 13:53:48 -07:00
										 |  |  |         tNode: 2, | 
					
						
							| 
									
										
										
										
											2018-09-13 16:07:23 -07:00
										 |  |  |         tView: 2,  // 1 for root view, 1 for template
 | 
					
						
							| 
									
										
										
										
											2018-05-15 22:07:20 +02:00
										 |  |  |         rendererSetText: 2, | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should render "null" as "" when used with `bind()`', () => { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |       function Template(rf: RenderFlags, name: string) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           text(0); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |           textBinding(0, bind(name)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       expect(renderToHtml(Template, 'benoit', 1, 1)).toEqual('benoit'); | 
					
						
							|  |  |  |       expect(renderToHtml(Template, null, 1, 1)).toEqual(''); | 
					
						
							| 
									
										
										
										
											2018-05-15 22:07:20 +02:00
										 |  |  |       expect(ngDevMode).toHaveProperties({ | 
					
						
							|  |  |  |         firstTemplatePass: 0, | 
					
						
							| 
									
										
										
										
											2018-05-30 13:53:48 -07:00
										 |  |  |         tNode: 2, | 
					
						
							| 
									
										
										
										
											2018-09-13 16:07:23 -07:00
										 |  |  |         tView: 2,  // 1 for root view, 1 for template
 | 
					
						
							| 
									
										
										
										
											2018-05-15 22:07:20 +02:00
										 |  |  |         rendererSetText: 2, | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support creation-time values in text nodes', () => { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |       function Template(rf: RenderFlags, value: string) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           text(0); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |           textBinding(0, rf & RenderFlags.Create ? value : NO_CHANGE); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       expect(renderToHtml(Template, 'once', 1, 1)).toEqual('once'); | 
					
						
							|  |  |  |       expect(renderToHtml(Template, 'twice', 1, 1)).toEqual('once'); | 
					
						
							| 
									
										
										
										
											2018-05-15 22:07:20 +02:00
										 |  |  |       expect(ngDevMode).toHaveProperties({ | 
					
						
							|  |  |  |         firstTemplatePass: 0, | 
					
						
							| 
									
										
										
										
											2018-05-30 13:53:48 -07:00
										 |  |  |         tNode: 2, | 
					
						
							| 
									
										
										
										
											2018-09-13 16:07:23 -07:00
										 |  |  |         tView: 2,  // 1 for root view, 1 for template
 | 
					
						
							| 
									
										
										
										
											2018-05-15 22:07:20 +02:00
										 |  |  |         rendererSetText: 1, | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   describe('ngNonBindable handling', () => { | 
					
						
							|  |  |  |     it('should keep local ref for host element', () => { | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * <b ngNonBindable #myRef id="my-id"> | 
					
						
							|  |  |  |        *   <i>Hello {{ name }}!</i> | 
					
						
							|  |  |  |        * </b> | 
					
						
							|  |  |  |        * {{ myRef.id }} | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |           elementStart(0, 'b', ['id', 'my-id'], ['myRef', '']); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |           disableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 14:33:48 -07:00
										 |  |  |           elementStart(2, 'i'); | 
					
						
							|  |  |  |           text(3, 'Hello {{ name }}!'); | 
					
						
							|  |  |  |           elementEnd(); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |           enableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |           elementEnd(); | 
					
						
							|  |  |  |           text(4); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |           const ref = reference(1) as any; | 
					
						
							| 
									
										
										
										
											2018-09-26 14:33:48 -07:00
										 |  |  |           textBinding(4, interpolation1(' ', ref.id, ' ')); | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       }, 5, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<b id="my-id"><i>Hello {{ name }}!</i></b> my-id '); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should invoke directives for host element', () => { | 
					
						
							|  |  |  |       let directiveInvoked: boolean = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       class TestDirective { | 
					
						
							| 
									
										
										
										
											2018-09-26 14:33:48 -07:00
										 |  |  |         ngOnInit() { directiveInvoked = true; } | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |           type: TestDirective, | 
					
						
							|  |  |  |           selectors: [['', 'directive', '']], | 
					
						
							|  |  |  |           factory: () => new TestDirective() | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * <b ngNonBindable directive> | 
					
						
							|  |  |  |        *   <i>Hello {{ name }}!</i> | 
					
						
							|  |  |  |        * </b> | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |           elementStart(0, 'b', ['directive', '']); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |           disableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 14:33:48 -07:00
										 |  |  |           elementStart(1, 'i'); | 
					
						
							|  |  |  |           text(2, 'Hello {{ name }}!'); | 
					
						
							|  |  |  |           elementEnd(); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |           enableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |           elementEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, 3, 0, [TestDirective]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<b directive=""><i>Hello {{ name }}!</i></b>'); | 
					
						
							|  |  |  |       expect(directiveInvoked).toEqual(true); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not invoke directives for nested elements', () => { | 
					
						
							|  |  |  |       let directiveInvoked: boolean = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       class TestDirective { | 
					
						
							| 
									
										
										
										
											2018-09-26 14:33:48 -07:00
										 |  |  |         ngOnInit() { directiveInvoked = true; } | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |           type: TestDirective, | 
					
						
							|  |  |  |           selectors: [['', 'directive', '']], | 
					
						
							|  |  |  |           factory: () => new TestDirective() | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * <b ngNonBindable> | 
					
						
							|  |  |  |        *   <i directive>Hello {{ name }}!</i> | 
					
						
							|  |  |  |        * </b> | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |           elementStart(0, 'b'); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |           disableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 14:33:48 -07:00
										 |  |  |           elementStart(1, 'i', ['directive', '']); | 
					
						
							|  |  |  |           text(2, 'Hello {{ name }}!'); | 
					
						
							|  |  |  |           elementEnd(); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |           enableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |           elementEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, 3, 0, [TestDirective]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<b><i directive="">Hello {{ name }}!</i></b>'); | 
					
						
							|  |  |  |       expect(directiveInvoked).toEqual(false); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |   describe('Siblings update', () => { | 
					
						
							|  |  |  |     it('should handle a flat list of static/bound text nodes', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           text(0, 'Hello '); | 
					
						
							|  |  |  |           text(1); | 
					
						
							|  |  |  |           text(2, '!'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |           textBinding(1, bind(ctx.name)); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 3, 1); | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       fixture.component.name = 'world'; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('Hello world!'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.component.name = 'monde'; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('Hello monde!'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should handle a list of static/bound text nodes as element children', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           elementStart(0, 'b'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             text(1, 'Hello '); | 
					
						
							|  |  |  |             text(2); | 
					
						
							|  |  |  |             text(3, '!'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |           textBinding(2, bind(ctx.name)); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 4, 1); | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       fixture.component.name = 'world'; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<b>Hello world!</b>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.component.name = 'mundo'; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<b>Hello mundo!</b>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should render/update text node as a child of a deep list of elements', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           elementStart(0, 'b'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementStart(1, 'b'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |               elementStart(2, 'b'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |               { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |                 elementStart(3, 'b'); | 
					
						
							|  |  |  |                 { text(4); } | 
					
						
							|  |  |  |                 elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |               } | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |               elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |           textBinding(4, interpolation1('Hello ', ctx.name, '!')); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 5, 1); | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       fixture.component.name = 'world'; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<b><b><b><b>Hello world!</b></b></b></b>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.component.name = 'mundo'; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<b><b><b><b>Hello mundo!</b></b></b></b>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should update 2 sibling elements', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           elementStart(0, 'b'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |             element(1, 'span'); | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementStart(2, 'span', ['class', 'foo']); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             {} | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |           elementAttribute(2, 'id', bind(ctx.id)); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 3, 1); | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       fixture.component.id = 'foo'; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<b><span></span><span class="foo" id="foo"></span></b>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.component.id = 'bar'; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<b><span></span><span class="foo" id="bar"></span></b>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should handle sibling text node after element with child text node', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           elementStart(0, 'p'); | 
					
						
							|  |  |  |           { text(1, 'hello'); } | 
					
						
							|  |  |  |           elementEnd(); | 
					
						
							|  |  |  |           text(2, 'world'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       }, 3); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<p>hello</p>world'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('basic components', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class TodoComponent { | 
					
						
							|  |  |  |       value = ' one'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       static ngComponentDef = defineComponent({ | 
					
						
							| 
									
										
										
										
											2018-01-22 15:27:21 -08:00
										 |  |  |         type: TodoComponent, | 
					
						
							| 
									
										
										
										
											2018-03-29 16:41:45 -07:00
										 |  |  |         selectors: [['todo']], | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         consts: 3, | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |         vars: 1, | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         template: function TodoTemplate(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementStart(0, 'p'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |               text(1, 'Todo'); | 
					
						
							|  |  |  |               text(2); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |             textBinding(2, bind(ctx.value)); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         }, | 
					
						
							|  |  |  |         factory: () => new TodoComponent | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-29 12:58:41 -07:00
										 |  |  |     const defs = [TodoComponent]; | 
					
						
							| 
									
										
										
										
											2018-03-25 21:32:39 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     it('should support a basic component template', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |           element(0, 'todo'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 1, 0, defs); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<todo><p>Todo one</p></todo>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support a component template with sibling', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |           element(0, 'todo'); | 
					
						
							| 
									
										
										
										
											2018-03-21 15:10:34 -07:00
										 |  |  |           text(1, 'two'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 2, 0, defs); | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<todo><p>Todo one</p></todo>two'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support a component template with component sibling', () => { | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * <todo></todo> | 
					
						
							|  |  |  |        * <todo></todo> | 
					
						
							|  |  |  |        */ | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |           element(0, 'todo'); | 
					
						
							|  |  |  |           element(1, 'todo'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 2, 0, defs); | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<todo><p>Todo one</p></todo><todo><p>Todo one</p></todo>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support a component with binding on host element', () => { | 
					
						
							|  |  |  |       let cmptInstance: TodoComponentHostBinding|null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       class TodoComponentHostBinding { | 
					
						
							|  |  |  |         title = 'one'; | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							| 
									
										
										
										
											2018-01-22 15:27:21 -08:00
										 |  |  |           type: TodoComponentHostBinding, | 
					
						
							| 
									
										
										
										
											2018-03-29 16:41:45 -07:00
										 |  |  |           selectors: [['todo']], | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |           consts: 1, | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |           vars: 1, | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           template: function TodoComponentHostBindingTemplate( | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |               rf: RenderFlags, ctx: TodoComponentHostBinding) { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |               text(0); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |             if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |               textBinding(0, bind(ctx.title)); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           }, | 
					
						
							|  |  |  |           factory: () => cmptInstance = new TodoComponentHostBinding, | 
					
						
							| 
									
										
										
										
											2018-08-21 00:03:21 -07:00
										 |  |  |           hostVars: 1, | 
					
						
							| 
									
										
										
										
											2017-12-20 16:26:07 -08:00
										 |  |  |           hostBindings: function(directiveIndex: number, elementIndex: number): void { | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             // host bindings
 | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementProperty( | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |                 elementIndex, 'title', bind(load<TodoComponentHostBinding>(directiveIndex).title)); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |           element(0, 'todo'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 1, 0, [TodoComponentHostBinding]); | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<todo title="one">one</todo>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       cmptInstance !.title = 'two'; | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<todo title="two">two</todo>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 20:31:24 -07:00
										 |  |  |     it('should support root component with host attribute', () => { | 
					
						
							|  |  |  |       class HostAttributeComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: HostAttributeComp, | 
					
						
							| 
									
										
										
										
											2018-03-29 16:41:45 -07:00
										 |  |  |           selectors: [['host-attr-comp']], | 
					
						
							| 
									
										
										
										
											2018-03-16 20:31:24 -07:00
										 |  |  |           factory: () => new HostAttributeComp(), | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |           consts: 0, | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |           vars: 0, | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           template: (rf: RenderFlags, ctx: HostAttributeComp) => {}, | 
					
						
							| 
									
										
										
										
											2018-03-16 20:31:24 -07:00
										 |  |  |           attributes: ['role', 'button'] | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(HostAttributeComp); | 
					
						
							|  |  |  |       expect(fixture.hostElement.getAttribute('role')).toEqual('button'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     it('should support component with bindings in template', () => { | 
					
						
							|  |  |  |       /** <p> {{ name }} </p>*/ | 
					
						
							|  |  |  |       class MyComp { | 
					
						
							|  |  |  |         name = 'Bess'; | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							| 
									
										
										
										
											2018-01-22 15:27:21 -08:00
										 |  |  |           type: MyComp, | 
					
						
							| 
									
										
										
										
											2018-03-29 16:41:45 -07:00
										 |  |  |           selectors: [['comp']], | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |           consts: 2, | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |           vars: 1, | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           template: function MyCompTemplate(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |               elementStart(0, 'p'); | 
					
						
							|  |  |  |               { text(1); } | 
					
						
							|  |  |  |               elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |             if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |               textBinding(1, bind(ctx.name)); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           }, | 
					
						
							|  |  |  |           factory: () => new MyComp | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |           element(0, 'comp'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 1, 0, [MyComp]); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<comp><p>Bess</p></comp>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support a component with sub-views', () => { | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * % if (condition) { | 
					
						
							|  |  |  |        *   <div>text</div> | 
					
						
							|  |  |  |        * % } | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       class MyComp { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |         // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |         condition !: boolean; | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							| 
									
										
										
										
											2018-01-22 15:27:21 -08:00
										 |  |  |           type: MyComp, | 
					
						
							| 
									
										
										
										
											2018-03-29 16:41:45 -07:00
										 |  |  |           selectors: [['comp']], | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |           consts: 1, | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |           vars: 0, | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           template: function MyCompTemplate(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |               container(0); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |             if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |               containerRefreshStart(0); | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 if (ctx.condition) { | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |                   let rf1 = embeddedViewStart(0, 2, 0); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |                   if (rf1 & RenderFlags.Create) { | 
					
						
							|  |  |  |                     elementStart(0, 'div'); | 
					
						
							|  |  |  |                     { text(1, 'text'); } | 
					
						
							|  |  |  |                     elementEnd(); | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |                   embeddedViewEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |                 } | 
					
						
							|  |  |  |               } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |               containerRefreshEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             } | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           factory: () => new MyComp, | 
					
						
							|  |  |  |           inputs: {condition: 'condition'} | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /** <comp [condition]="condition"></comp> */ | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |           element(0, 'comp'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |           elementProperty(0, 'condition', bind(ctx.condition)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 1, 1, [MyComp]); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       fixture.component.condition = true; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<comp><div>text</div></comp>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       fixture.component.condition = false; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<comp></comp>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 17:22:41 +02:00
										 |  |  |   describe('ng-container', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should insert as a child of a regular element', () => { | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * <div>before|<ng-container>Greetings<span></span></ng-container>|after</div> | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       function Template() { | 
					
						
							|  |  |  |         elementStart(0, 'div'); | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           text(1, 'before|'); | 
					
						
							|  |  |  |           elementContainerStart(2); | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             text(3, 'Greetings'); | 
					
						
							|  |  |  |             element(4, 'span'); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           elementContainerEnd(); | 
					
						
							|  |  |  |           text(5, '|after'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         elementEnd(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const fixture = new TemplateFixture(Template, () => {}, 6); | 
					
						
							| 
									
										
										
										
											2018-07-26 17:22:41 +02:00
										 |  |  |       expect(fixture.html).toEqual('<div>before|Greetings<span></span>|after</div>'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-01 15:19:27 +02:00
										 |  |  |     it('should add and remove DOM nodes when ng-container is a child of a regular element', () => { | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * {% if (value) { %} | 
					
						
							|  |  |  |        * <div> | 
					
						
							|  |  |  |        *  <ng-container>content</ng-container> | 
					
						
							|  |  |  |        * </div> | 
					
						
							|  |  |  |        * {% } %} | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       const TestCmpt = createComponent('test-cmpt', function(rf: RenderFlags, ctx: {value: any}) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |           container(0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |           containerRefreshStart(0); | 
					
						
							|  |  |  |           if (ctx.value) { | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |             let rf1 = embeddedViewStart(0, 3, 0); | 
					
						
							| 
									
										
										
										
											2018-08-01 15:19:27 +02:00
										 |  |  |             { | 
					
						
							|  |  |  |               if (rf1 & RenderFlags.Create) { | 
					
						
							|  |  |  |                 elementStart(0, 'div'); | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                   elementContainerStart(1); | 
					
						
							|  |  |  |                   { text(2, 'content'); } | 
					
						
							|  |  |  |                   elementContainerEnd(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 elementEnd(); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             embeddedViewEnd(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           containerRefreshEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       }, 1); | 
					
						
							| 
									
										
										
										
											2018-08-01 15:19:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(TestCmpt); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.component.value = true; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('<div>content</div>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fixture.component.value = false; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should add and remove DOM nodes when ng-container is a child of an embedded view (JS block)', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          /** | 
					
						
							|  |  |  |           * {% if (value) { %} | 
					
						
							|  |  |  |           *  <ng-container>content</ng-container> | 
					
						
							|  |  |  |           * {% } %} | 
					
						
							|  |  |  |           */ | 
					
						
							|  |  |  |          const TestCmpt = | 
					
						
							|  |  |  |              createComponent('test-cmpt', function(rf: RenderFlags, ctx: {value: any}) { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  container(0); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |                if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |                  containerRefreshStart(0); | 
					
						
							|  |  |  |                  if (ctx.value) { | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |                    let rf1 = embeddedViewStart(0, 2, 0); | 
					
						
							| 
									
										
										
										
											2018-08-01 15:19:27 +02:00
										 |  |  |                    { | 
					
						
							|  |  |  |                      if (rf1 & RenderFlags.Create) { | 
					
						
							|  |  |  |                        elementContainerStart(0); | 
					
						
							|  |  |  |                        { text(1, 'content'); } | 
					
						
							|  |  |  |                        elementContainerEnd(); | 
					
						
							|  |  |  |                      } | 
					
						
							|  |  |  |                    } | 
					
						
							|  |  |  |                    embeddedViewEnd(); | 
					
						
							|  |  |  |                  } | 
					
						
							|  |  |  |                  containerRefreshEnd(); | 
					
						
							|  |  |  |                } | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |              }, 1); | 
					
						
							| 
									
										
										
										
											2018-08-01 15:19:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |          const fixture = new ComponentFixture(TestCmpt); | 
					
						
							|  |  |  |          expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          fixture.component.value = true; | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  |          expect(fixture.html).toEqual('content'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          fixture.component.value = false; | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  |          expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should add and remove DOM nodes when ng-container is a child of an embedded view (ViewContainerRef)', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          function ngIfTemplate(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |            if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |              elementContainerStart(0); | 
					
						
							|  |  |  |              { text(1, 'content'); } | 
					
						
							|  |  |  |              elementContainerEnd(); | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          /** | 
					
						
							|  |  |  |           * <ng-container *ngIf="value">content</ng-container> | 
					
						
							|  |  |  |           */ | 
					
						
							|  |  |  |          // equivalent to:
 | 
					
						
							|  |  |  |          /** | 
					
						
							|  |  |  |           * <ng-template [ngIf]="value"> | 
					
						
							|  |  |  |           *  <ng-container> | 
					
						
							|  |  |  |           *    content | 
					
						
							|  |  |  |           *  </ng-container> | 
					
						
							|  |  |  |           * </ng-template> | 
					
						
							|  |  |  |           */ | 
					
						
							|  |  |  |          const TestCmpt = | 
					
						
							|  |  |  |              createComponent('test-cmpt', function(rf: RenderFlags, ctx: {value: any}) { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |                  template(0, ngIfTemplate, 2, 0, null, [AttributeMarker.SelectOnly, 'ngIf']); | 
					
						
							| 
									
										
										
										
											2018-08-01 15:19:27 +02:00
										 |  |  |                } | 
					
						
							|  |  |  |                if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |                  elementProperty(0, 'ngIf', bind(ctx.value)); | 
					
						
							|  |  |  |                } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |              }, 1, 1, [NgIf]); | 
					
						
							| 
									
										
										
										
											2018-08-01 15:19:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |          const fixture = new ComponentFixture(TestCmpt); | 
					
						
							|  |  |  |          expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          fixture.component.value = true; | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  |          expect(fixture.html).toEqual('content'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          fixture.component.value = false; | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  |          expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-06 16:40:16 +02:00
										 |  |  |     // https://stackblitz.com/edit/angular-tfhcz1?file=src%2Fapp%2Fapp.component.ts
 | 
					
						
							|  |  |  |     it('should add and remove DOM nodes when ng-container is a child of a delayed embedded view', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          class TestDirective { | 
					
						
							|  |  |  |            constructor(private _tplRef: TemplateRef<any>, private _vcRef: ViewContainerRef) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            createAndInsert() { this._vcRef.insert(this._tplRef.createEmbeddedView({})); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            clear() { this._vcRef.clear(); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |              type: TestDirective, | 
					
						
							|  |  |  |              selectors: [['', 'testDirective', '']], | 
					
						
							| 
									
										
										
										
											2018-09-21 18:38:13 -07:00
										 |  |  |              factory: | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |                  () => testDirective = new TestDirective( | 
					
						
							| 
									
										
										
										
											2018-09-21 18:38:13 -07:00
										 |  |  |                      directiveInject(TemplateRef as any), directiveInject(ViewContainerRef as any)), | 
					
						
							| 
									
										
										
										
											2018-08-06 16:40:16 +02:00
										 |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          function embeddedTemplate(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |            if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |              elementContainerStart(0); | 
					
						
							|  |  |  |              { text(1, 'content'); } | 
					
						
							|  |  |  |              elementContainerEnd(); | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          let testDirective: TestDirective; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          `<ng-template testDirective>
 | 
					
						
							|  |  |  |             <ng-container> | 
					
						
							|  |  |  |               content | 
					
						
							|  |  |  |             </ng-container> | 
					
						
							|  |  |  |           </ng-template>`; | 
					
						
							|  |  |  |          const TestCmpt = createComponent('test-cmpt', function(rf: RenderFlags) { | 
					
						
							|  |  |  |            if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |              template( | 
					
						
							|  |  |  |                  0, embeddedTemplate, 2, 0, null, [AttributeMarker.SelectOnly, 'testDirective']); | 
					
						
							| 
									
										
										
										
											2018-08-06 16:40:16 +02:00
										 |  |  |            } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |          }, 1, 0, [TestDirective]); | 
					
						
							| 
									
										
										
										
											2018-08-06 16:40:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |          const fixture = new ComponentFixture(TestCmpt); | 
					
						
							|  |  |  |          expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          testDirective !.createAndInsert(); | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  |          expect(fixture.html).toEqual('content'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          testDirective !.clear(); | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  |          expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-01 15:19:27 +02:00
										 |  |  |     it('should render at the component view root', () => { | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * <ng-container>component template</ng-container> | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       const TestCmpt = createComponent('test-cmpt', function(rf: RenderFlags) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |           elementContainerStart(0); | 
					
						
							|  |  |  |           { text(1, 'component template'); } | 
					
						
							|  |  |  |           elementContainerEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       }, 2); | 
					
						
							| 
									
										
										
										
											2018-08-01 15:19:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       function App() { element(0, 'test-cmpt'); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       const fixture = new TemplateFixture(App, () => {}, 1, 0, [TestCmpt]); | 
					
						
							| 
									
										
										
										
											2018-08-01 15:19:27 +02:00
										 |  |  |       expect(fixture.html).toEqual('<test-cmpt>component template</test-cmpt>'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-06 17:46:49 +02:00
										 |  |  |     it('should render inside another ng-container', () => { | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * <ng-container> | 
					
						
							|  |  |  |        *   <ng-container> | 
					
						
							|  |  |  |        *     <ng-container> | 
					
						
							|  |  |  |        *       content | 
					
						
							|  |  |  |        *     </ng-container> | 
					
						
							|  |  |  |        *   </ng-container> | 
					
						
							|  |  |  |        * </ng-container> | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       const TestCmpt = createComponent('test-cmpt', function(rf: RenderFlags) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |           elementContainerStart(0); | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             elementContainerStart(1); | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               elementContainerStart(2); | 
					
						
							|  |  |  |               { text(3, 'content'); } | 
					
						
							|  |  |  |               elementContainerEnd(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             elementContainerEnd(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           elementContainerEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       }, 4); | 
					
						
							| 
									
										
										
										
											2018-08-06 17:46:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       function App() { element(0, 'test-cmpt'); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       const fixture = new TemplateFixture(App, () => {}, 1, 0, [TestCmpt]); | 
					
						
							| 
									
										
										
										
											2018-08-06 17:46:49 +02:00
										 |  |  |       expect(fixture.html).toEqual('<test-cmpt>content</test-cmpt>'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should render inside another ng-container at the root of a delayed view', () => { | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |       let testDirective: TestDirective; | 
					
						
							| 
									
										
										
										
											2018-08-06 17:46:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       class TestDirective { | 
					
						
							|  |  |  |         constructor(private _tplRef: TemplateRef<any>, private _vcRef: ViewContainerRef) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         createAndInsert() { this._vcRef.insert(this._tplRef.createEmbeddedView({})); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         clear() { this._vcRef.clear(); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |           type: TestDirective, | 
					
						
							|  |  |  |           selectors: [['', 'testDirective', '']], | 
					
						
							| 
									
										
										
										
											2018-09-21 18:38:13 -07:00
										 |  |  |           factory: | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |               () => testDirective = new TestDirective( | 
					
						
							| 
									
										
										
										
											2018-09-21 18:38:13 -07:00
										 |  |  |                   directiveInject(TemplateRef as any), directiveInject(ViewContainerRef as any)), | 
					
						
							| 
									
										
										
										
											2018-08-06 17:46:49 +02:00
										 |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       function embeddedTemplate(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |           elementContainerStart(0); | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             elementContainerStart(1); | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               elementContainerStart(2); | 
					
						
							|  |  |  |               { text(3, 'content'); } | 
					
						
							|  |  |  |               elementContainerEnd(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             elementContainerEnd(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           elementContainerEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       /** | 
					
						
							|  |  |  |        * <ng-template testDirective> | 
					
						
							|  |  |  |        *   <ng-container> | 
					
						
							|  |  |  |        *     <ng-container> | 
					
						
							|  |  |  |        *       <ng-container> | 
					
						
							|  |  |  |        *         content | 
					
						
							|  |  |  |        *       </ng-container> | 
					
						
							|  |  |  |        *     </ng-container> | 
					
						
							|  |  |  |        *   </ng-container> | 
					
						
							|  |  |  |        * </ng-template> | 
					
						
							|  |  |  |        */ | 
					
						
							| 
									
										
										
										
											2018-08-06 17:46:49 +02:00
										 |  |  |       const TestCmpt = createComponent('test-cmpt', function(rf: RenderFlags) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |           template(0, embeddedTemplate, 4, 0, null, [AttributeMarker.SelectOnly, 'testDirective']); | 
					
						
							| 
									
										
										
										
											2018-08-06 17:46:49 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       }, 1, 0, [TestDirective]); | 
					
						
							| 
									
										
										
										
											2018-08-06 17:46:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       function App() { element(0, 'test-cmpt'); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(TestCmpt); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       testDirective !.createAndInsert(); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('content'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       testDirective !.createAndInsert(); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('contentcontent'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       testDirective !.clear(); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 17:22:41 +02:00
										 |  |  |     it('should support directives and inject ElementRef', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       class Directive { | 
					
						
							|  |  |  |         constructor(public elRef: ElementRef) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |           type: Directive, | 
					
						
							|  |  |  |           selectors: [['', 'dir', '']], | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |           factory: () => directive = new Directive(directiveInject(ElementRef)), | 
					
						
							| 
									
										
										
										
											2018-07-26 17:22:41 +02:00
										 |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       let directive: Directive; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * <div><ng-container dir></ng-container></div> | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       function Template() { | 
					
						
							|  |  |  |         elementStart(0, 'div'); | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           elementContainerStart(1, [AttributeMarker.SelectOnly, 'dir']); | 
					
						
							|  |  |  |           elementContainerEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         elementEnd(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       const fixture = new TemplateFixture(Template, () => {}, 2, 0, [Directive]); | 
					
						
							| 
									
										
										
										
											2018-07-26 17:22:41 +02:00
										 |  |  |       expect(fixture.html).toEqual('<div></div>'); | 
					
						
							|  |  |  |       expect(directive !.elRef.nativeElement.nodeType).toBe(Node.COMMENT_NODE); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 14:10:42 +02:00
										 |  |  |     it('should support ViewContainerRef when ng-container is at the root of a view', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       function ContentTemplate(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |           text(0, 'Content'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       class Directive { | 
					
						
							|  |  |  |         contentTpl: TemplateRef<{}>|null = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         constructor(private _vcRef: ViewContainerRef) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         insertView() { this._vcRef.createEmbeddedView(this.contentTpl as TemplateRef<{}>); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         clear() { this._vcRef.clear(); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |           type: Directive, | 
					
						
							|  |  |  |           selectors: [['', 'dir', '']], | 
					
						
							|  |  |  |           factory: () => directive = new Directive(directiveInject(ViewContainerRef as any)), | 
					
						
							|  |  |  |           inputs: {contentTpl: 'contentTpl'}, | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       let directive: Directive; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * <ng-container dir [contentTpl]="content"> | 
					
						
							|  |  |  |        *    <ng-template #content>Content</ng-template> | 
					
						
							|  |  |  |        * </ng-container> | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       const App = createComponent('app', function(rf: RenderFlags) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |           elementContainerStart(0, [AttributeMarker.SelectOnly, 'dir']); | 
					
						
							|  |  |  |           template(1, ContentTemplate, 1, 0, '', null, ['content', ''], templateRefExtractor); | 
					
						
							|  |  |  |           elementContainerEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |           const content = reference(2) as any; | 
					
						
							|  |  |  |           elementProperty(0, 'contentTpl', bind(content)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, 3, 1, [Directive]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       directive !.insertView(); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('Content'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       directive !.clear(); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support ViewContainerRef on <ng-template> inside <ng-container>', () => { | 
					
						
							|  |  |  |       function ContentTemplate(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |           text(0, 'Content'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       class Directive { | 
					
						
							|  |  |  |         constructor(private _tplRef: TemplateRef<{}>, private _vcRef: ViewContainerRef) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         insertView() { this._vcRef.createEmbeddedView(this._tplRef); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         clear() { this._vcRef.clear(); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |           type: Directive, | 
					
						
							|  |  |  |           selectors: [['', 'dir', '']], | 
					
						
							|  |  |  |           factory: | 
					
						
							|  |  |  |               () => directive = new Directive( | 
					
						
							|  |  |  |                   directiveInject(TemplateRef as any), directiveInject(ViewContainerRef as any)), | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       let directive: Directive; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * <ng-container> | 
					
						
							|  |  |  |        *    <ng-template dir>Content</ng-template> | 
					
						
							|  |  |  |        * </ng-container> | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       const App = createComponent('app', function(rf: RenderFlags) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |           elementContainerStart(0); | 
					
						
							|  |  |  |           template( | 
					
						
							|  |  |  |               1, ContentTemplate, 1, 0, '', [AttributeMarker.SelectOnly, 'dir'], [], | 
					
						
							|  |  |  |               templateRefExtractor); | 
					
						
							|  |  |  |           elementContainerEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, 2, 0, [Directive]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       directive !.insertView(); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual('Content'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       directive !.clear(); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  |       expect(fixture.html).toEqual(''); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 17:22:41 +02:00
										 |  |  |     it('should not set any attributes', () => { | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        * <div><ng-container id="foo"></ng-container></div> | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       function Template() { | 
					
						
							|  |  |  |         elementStart(0, 'div'); | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           elementContainerStart(1, ['id', 'foo']); | 
					
						
							|  |  |  |           elementContainerEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         elementEnd(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       const fixture = new TemplateFixture(Template, () => {}, 2); | 
					
						
							| 
									
										
										
										
											2018-07-26 17:22:41 +02:00
										 |  |  |       expect(fixture.html).toEqual('<div></div>'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |   describe('tree', () => { | 
					
						
							|  |  |  |     interface Tree { | 
					
						
							|  |  |  |       beforeLabel?: string; | 
					
						
							|  |  |  |       subTrees?: Tree[]; | 
					
						
							|  |  |  |       afterLabel?: string; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     interface ParentCtx { | 
					
						
							|  |  |  |       beforeTree: Tree; | 
					
						
							|  |  |  |       projectedTree: Tree; | 
					
						
							|  |  |  |       afterTree: Tree; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |     function showLabel(rf: RenderFlags, ctx: {label: string | undefined}) { | 
					
						
							|  |  |  |       if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |         container(0); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |       if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |         containerRefreshStart(0); | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           if (ctx.label != null) { | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |             let rf1 = embeddedViewStart(0, 1, 1); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |             if (rf1 & RenderFlags.Create) { | 
					
						
							|  |  |  |               text(0); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (rf1 & RenderFlags.Update) { | 
					
						
							|  |  |  |               textBinding(0, bind(ctx.label)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             embeddedViewEnd(); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         containerRefreshEnd(); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |     function showTree(rf: RenderFlags, ctx: {tree: Tree}) { | 
					
						
							|  |  |  |       if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |         container(0); | 
					
						
							|  |  |  |         container(1); | 
					
						
							|  |  |  |         container(2); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |         containerRefreshStart(0); | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           const rf0 = embeddedViewStart(0, 1, 0); | 
					
						
							|  |  |  |           { showLabel(rf0, {label: ctx.tree.beforeLabel}); } | 
					
						
							| 
									
										
										
										
											2018-02-06 17:27:16 -08:00
										 |  |  |           embeddedViewEnd(); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |         containerRefreshEnd(); | 
					
						
							|  |  |  |         containerRefreshStart(1); | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           for (let subTree of ctx.tree.subTrees || []) { | 
					
						
							| 
									
										
										
										
											2018-08-21 00:03:21 -07:00
										 |  |  |             const rf0 = embeddedViewStart(0, 3, 0); | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |             { showTree(rf0, {tree: subTree}); } | 
					
						
							|  |  |  |             embeddedViewEnd(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         containerRefreshEnd(); | 
					
						
							|  |  |  |         containerRefreshStart(2); | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           const rf0 = embeddedViewStart(0, 1, 0); | 
					
						
							|  |  |  |           { showLabel(rf0, {label: ctx.tree.afterLabel}); } | 
					
						
							|  |  |  |           embeddedViewEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         containerRefreshEnd(); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class ChildComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |       // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |       beforeTree !: Tree; | 
					
						
							|  |  |  |       // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |       afterTree !: Tree; | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |       static ngComponentDef = defineComponent({ | 
					
						
							| 
									
										
										
										
											2018-03-29 16:41:45 -07:00
										 |  |  |         selectors: [['child']], | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |         type: ChildComponent, | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         consts: 3, | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |         vars: 0, | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |         template: function ChildComponentTemplate( | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |             rf: RenderFlags, ctx: {beforeTree: Tree, afterTree: Tree}) { | 
					
						
							|  |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-03 20:04:36 -07:00
										 |  |  |             projectionDef(); | 
					
						
							|  |  |  |             container(0); | 
					
						
							|  |  |  |             projection(1); | 
					
						
							|  |  |  |             container(2); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |             containerRefreshStart(0); | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2018-08-21 00:03:21 -07:00
										 |  |  |               const rf0 = embeddedViewStart(0, 3, 0); | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |               { showTree(rf0, {tree: ctx.beforeTree}); } | 
					
						
							|  |  |  |               embeddedViewEnd(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             containerRefreshEnd(); | 
					
						
							|  |  |  |             containerRefreshStart(2); | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2018-08-21 00:03:21 -07:00
										 |  |  |               const rf0 = embeddedViewStart(0, 3, 0); | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |               { showTree(rf0, {tree: ctx.afterTree}); } | 
					
						
							|  |  |  |               embeddedViewEnd(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             containerRefreshEnd(); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |           } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         factory: () => new ChildComponent, | 
					
						
							|  |  |  |         inputs: {beforeTree: 'beforeTree', afterTree: 'afterTree'} | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |     function parentTemplate(rf: RenderFlags, ctx: ParentCtx) { | 
					
						
							|  |  |  |       if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-03-25 21:32:39 -07:00
										 |  |  |         elementStart(0, 'child'); | 
					
						
							| 
									
										
										
										
											2018-03-21 15:10:34 -07:00
										 |  |  |         { container(1); } | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |         elementEnd(); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |       if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |         elementProperty(0, 'beforeTree', bind(ctx.beforeTree)); | 
					
						
							|  |  |  |         elementProperty(0, 'afterTree', bind(ctx.afterTree)); | 
					
						
							|  |  |  |         containerRefreshStart(1); | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-08-21 00:03:21 -07:00
										 |  |  |           const rf0 = embeddedViewStart(0, 3, 0); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           { showTree(rf0, {tree: ctx.projectedTree}); } | 
					
						
							|  |  |  |           embeddedViewEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         containerRefreshEnd(); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should work with a tree', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const ctx: ParentCtx = { | 
					
						
							|  |  |  |         beforeTree: {subTrees: [{beforeLabel: 'a'}]}, | 
					
						
							|  |  |  |         projectedTree: {beforeLabel: 'p'}, | 
					
						
							|  |  |  |         afterTree: {afterLabel: 'z'} | 
					
						
							|  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2018-03-29 12:58:41 -07:00
										 |  |  |       const defs = [ChildComponent]; | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       expect(renderToHtml(parentTemplate, ctx, 2, 2, defs)).toEqual('<child>apz</child>'); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |       ctx.projectedTree = {subTrees: [{}, {}, {subTrees: [{}, {}]}, {}]}; | 
					
						
							|  |  |  |       ctx.beforeTree.subTrees !.push({afterLabel: 'b'}); | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       expect(renderToHtml(parentTemplate, ctx, 2, 2, defs)).toEqual('<child>abz</child>'); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |       ctx.projectedTree.subTrees ![1].afterLabel = 'h'; | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       expect(renderToHtml(parentTemplate, ctx, 2, 2, defs)).toEqual('<child>abhz</child>'); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  |       ctx.beforeTree.subTrees !.push({beforeLabel: 'c'}); | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |       expect(renderToHtml(parentTemplate, ctx, 2, 2, defs)).toEqual('<child>abchz</child>'); | 
					
						
							| 
									
										
										
										
											2018-01-25 15:32:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // To check the context easily:
 | 
					
						
							|  |  |  |       // console.log(JSON.stringify(ctx));
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |   describe('element bindings', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('elementAttribute', () => { | 
					
						
							|  |  |  |       it('should support attribute bindings', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |             element(0, 'span'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |             elementAttribute(0, 'title', bind(ctx.title)); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |         }, 1, 1); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |         fixture.component.title = 'Hello'; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         // initial binding
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         expect(fixture.html).toEqual('<span title="Hello"></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // update binding
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.component.title = 'Hi!'; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span title="Hi!"></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // remove attribute
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.component.title = null; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should stringify values used attribute bindings', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |             element(0, 'span'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |             elementAttribute(0, 'title', bind(ctx.title)); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |         }, 1, 1); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |         fixture.component.title = NaN; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span title="NaN"></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.component.title = {toString: () => 'Custom toString'}; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span title="Custom toString"></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should update bindings', () => { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         function Template(rf: RenderFlags, c: any) { | 
					
						
							|  |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |             element(0, 'b'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |             elementAttribute(0, 'a', interpolationV(c)); | 
					
						
							|  |  |  |             elementAttribute(0, 'a0', bind(c[1])); | 
					
						
							|  |  |  |             elementAttribute(0, 'a1', interpolation1(c[0], c[1], c[16])); | 
					
						
							|  |  |  |             elementAttribute(0, 'a2', interpolation2(c[0], c[1], c[2], c[3], c[16])); | 
					
						
							|  |  |  |             elementAttribute(0, 'a3', interpolation3(c[0], c[1], c[2], c[3], c[4], c[5], c[16])); | 
					
						
							|  |  |  |             elementAttribute( | 
					
						
							|  |  |  |                 0, 'a4', interpolation4(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[16])); | 
					
						
							|  |  |  |             elementAttribute( | 
					
						
							|  |  |  |                 0, 'a5', | 
					
						
							|  |  |  |                 interpolation5(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[16])); | 
					
						
							|  |  |  |             elementAttribute( | 
					
						
							|  |  |  |                 0, 'a6', interpolation6( | 
					
						
							|  |  |  |                              c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], | 
					
						
							|  |  |  |                              c[11], c[16])); | 
					
						
							|  |  |  |             elementAttribute( | 
					
						
							|  |  |  |                 0, 'a7', interpolation7( | 
					
						
							|  |  |  |                              c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], | 
					
						
							|  |  |  |                              c[11], c[12], c[13], c[16])); | 
					
						
							|  |  |  |             elementAttribute( | 
					
						
							|  |  |  |                 0, 'a8', interpolation8( | 
					
						
							|  |  |  |                              c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], | 
					
						
							|  |  |  |                              c[11], c[12], c[13], c[14], c[15], c[16])); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         } | 
					
						
							|  |  |  |         let args = ['(', 0, 'a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 6, 'g', 7, ')']; | 
					
						
							| 
									
										
										
										
											2018-08-21 00:03:21 -07:00
										 |  |  |         expect(renderToHtml(Template, args, 1, 54)) | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             .toEqual( | 
					
						
							|  |  |  |                 '<b a="(0a1b2c3d4e5f6g7)" a0="0" a1="(0)" a2="(0a1)" a3="(0a1b2)" a4="(0a1b2c3)" a5="(0a1b2c3d4)" a6="(0a1b2c3d4e5)" a7="(0a1b2c3d4e5f6)" a8="(0a1b2c3d4e5f6g7)"></b>'); | 
					
						
							|  |  |  |         args = args.reverse(); | 
					
						
							| 
									
										
										
										
											2018-08-21 00:03:21 -07:00
										 |  |  |         expect(renderToHtml(Template, args, 1, 54)) | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             .toEqual( | 
					
						
							|  |  |  |                 '<b a=")7g6f5e4d3c2b1a0(" a0="7" a1=")7(" a2=")7g6(" a3=")7g6f5(" a4=")7g6f5e4(" a5=")7g6f5e4d3(" a6=")7g6f5e4d3c2(" a7=")7g6f5e4d3c2b1(" a8=")7g6f5e4d3c2b1a0("></b>'); | 
					
						
							|  |  |  |         args = args.reverse(); | 
					
						
							| 
									
										
										
										
											2018-08-21 00:03:21 -07:00
										 |  |  |         expect(renderToHtml(Template, args, 1, 54)) | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |             .toEqual( | 
					
						
							|  |  |  |                 '<b a="(0a1b2c3d4e5f6g7)" a0="0" a1="(0)" a2="(0a1)" a3="(0a1b2)" a4="(0a1b2c3)" a5="(0a1b2c3d4)" a6="(0a1b2c3d4e5)" a7="(0a1b2c3d4e5f6)" a8="(0a1b2c3d4e5f6g7)"></b>'); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should not update DOM if context has not changed', () => { | 
					
						
							|  |  |  |         const ctx: {title: string | null} = {title: 'Hello'}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementStart(0, 'span'); | 
					
						
							|  |  |  |             container(1); | 
					
						
							|  |  |  |             elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |             elementAttribute(0, 'title', bind(ctx.title)); | 
					
						
							|  |  |  |             containerRefreshStart(1); | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               if (true) { | 
					
						
							| 
									
										
										
										
											2018-08-21 00:03:21 -07:00
										 |  |  |                 let rf1 = embeddedViewStart(1, 1, 1); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |                 { | 
					
						
							|  |  |  |                   if (rf1 & RenderFlags.Create) { | 
					
						
							|  |  |  |                     elementStart(0, 'b'); | 
					
						
							|  |  |  |                     {} | 
					
						
							|  |  |  |                     elementEnd(); | 
					
						
							|  |  |  |                   } | 
					
						
							| 
									
										
										
										
											2018-08-21 00:03:21 -07:00
										 |  |  |                   if (rf1 & RenderFlags.Update) { | 
					
						
							|  |  |  |                     elementAttribute(0, 'title', bind(ctx.title)); | 
					
						
							|  |  |  |                   } | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |                 embeddedViewEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |             containerRefreshEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |         }, 2, 1); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |         fixture.component.title = 'Hello'; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         // initial binding
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         expect(fixture.html).toEqual('<span title="Hello"><b title="Hello"></b></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         // update DOM manually
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.hostElement.querySelector('b') !.setAttribute('title', 'Goodbye'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         // refresh with same binding
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span title="Hello"><b title="Goodbye"></b></span>'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |         // refresh again with same binding
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span title="Hello"><b title="Goodbye"></b></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-02-16 11:36:50 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it('should support host attribute bindings', () => { | 
					
						
							|  |  |  |         let hostBindingDir: HostBindingDir; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class HostBindingDir { | 
					
						
							|  |  |  |           /* @HostBinding('attr.aria-label') */ | 
					
						
							|  |  |  |           label = 'some label'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |             type: HostBindingDir, | 
					
						
							| 
									
										
										
										
											2018-03-29 16:41:45 -07:00
										 |  |  |             selectors: [['', 'hostBindingDir', '']], | 
					
						
							| 
									
										
										
										
											2018-02-16 11:36:50 -08:00
										 |  |  |             factory: function HostBindingDir_Factory() { | 
					
						
							|  |  |  |               return hostBindingDir = new HostBindingDir(); | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2018-08-21 00:03:21 -07:00
										 |  |  |             hostVars: 1, | 
					
						
							| 
									
										
										
										
											2018-02-16 11:36:50 -08:00
										 |  |  |             hostBindings: function HostBindingDir_HostBindings(dirIndex: number, elIndex: number) { | 
					
						
							| 
									
										
										
										
											2018-10-08 16:04:46 -07:00
										 |  |  |               elementAttribute(elIndex, 'aria-label', bind(load<HostBindingDir>(dirIndex).label)); | 
					
						
							| 
									
										
										
										
											2018-02-16 11:36:50 -08:00
										 |  |  |             } | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |             element(0, 'div', ['hostBindingDir', '']); | 
					
						
							| 
									
										
										
										
											2018-02-16 11:36:50 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |         }, 1, 0, [HostBindingDir]); | 
					
						
							| 
									
										
										
										
											2018-02-16 11:36:50 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual(`<div aria-label="some label" hostbindingdir=""></div>`); | 
					
						
							| 
									
										
										
										
											2018-02-16 11:36:50 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         hostBindingDir !.label = 'other label'; | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual(`<div aria-label="other label" hostbindingdir=""></div>`); | 
					
						
							| 
									
										
										
										
											2018-02-16 11:36:50 -08:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('elementStyle', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support binding to styles', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementStart(0, 'span'); | 
					
						
							| 
									
										
										
										
											2018-07-11 10:58:18 -07:00
										 |  |  |             elementStyling(null, ['border-color']); | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |             elementStyleProp(0, 0, ctx.color); | 
					
						
							| 
									
										
										
										
											2018-07-11 09:56:47 -07:00
										 |  |  |             elementStylingApply(0); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         }, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |         fixture.component.color = 'red'; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span style="border-color: red;"></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.component.color = 'green'; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span style="border-color: green;"></span>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fixture.component.color = null; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support binding to styles with suffix', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementStart(0, 'span'); | 
					
						
							| 
									
										
										
										
											2018-07-11 10:58:18 -07:00
										 |  |  |             elementStyling(null, ['font-size']); | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |             elementStyleProp(0, 0, ctx.time, 'px'); | 
					
						
							| 
									
										
										
										
											2018-07-11 09:56:47 -07:00
										 |  |  |             elementStylingApply(0); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         }, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |         fixture.component.time = '100'; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span style="font-size: 100px;"></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.component.time = 200; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span style="font-size: 200px;"></span>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fixture.component.time = null; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('elementClass', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support CSS class toggle', () => { | 
					
						
							| 
									
										
										
										
											2018-10-11 13:13:57 -07:00
										 |  |  |         /** <span [class.active]="class"></span> */ | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementStart(0, 'span'); | 
					
						
							| 
									
										
										
										
											2018-07-11 10:58:18 -07:00
										 |  |  |             elementStyling(['active']); | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |             elementClassProp(0, 0, ctx.class); | 
					
						
							| 
									
										
										
										
											2018-07-11 09:56:47 -07:00
										 |  |  |             elementStylingApply(0); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         }, 1); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |         fixture.component.class = true; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span class="active"></span>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fixture.component.class = false; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span class=""></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // truthy values
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.component.class = 'a_string'; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span class="active"></span>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fixture.component.class = 10; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span class="active"></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // falsy values
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.component.class = ''; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span class=""></span>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fixture.component.class = 0; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span class=""></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should work correctly with existing static classes', () => { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-11 09:56:47 -07:00
										 |  |  |             elementStart(0, 'span'); | 
					
						
							|  |  |  |             elementStyling( | 
					
						
							| 
									
										
										
										
											2018-07-11 10:58:18 -07:00
										 |  |  |                 ['existing', 'active', InitialStylingFlags.VALUES_MODE, 'existing', true]); | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |             elementEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |             elementClassProp(0, 1, ctx.class); | 
					
						
							| 
									
										
										
										
											2018-07-11 09:56:47 -07:00
										 |  |  |             elementStylingApply(0); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         }, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |         fixture.component.class = true; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span class="existing active"></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |         fixture.component.class = false; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<span class="existing"></span>'); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-10-11 13:13:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |       it('should apply classes properly when nodes are components', () => { | 
					
						
							|  |  |  |         const MyComp = createComponent('my-comp', (rf: RenderFlags, ctx: any) => { | 
					
						
							|  |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |             text(0, 'Comp Content'); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }, 1, 0, []); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** | 
					
						
							|  |  |  |          * <my-comp [class.active]="class"></my-comp> | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |             elementStart(0, 'my-comp'); | 
					
						
							|  |  |  |             { elementStyling(['active']); } | 
					
						
							|  |  |  |             elementEnd(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |             elementClassProp(0, 0, ctx.class); | 
					
						
							|  |  |  |             elementStylingApply(0); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }, 1, 0, [MyComp]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |         fixture.component.class = true; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<my-comp class="active">Comp Content</my-comp>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fixture.component.class = false; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html).toEqual('<my-comp class="">Comp Content</my-comp>'); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 13:13:57 -07:00
										 |  |  |       it('should apply classes properly when nodes have LContainers', () => { | 
					
						
							|  |  |  |         let structuralComp !: StructuralComp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class StructuralComp { | 
					
						
							|  |  |  |           tmp !: TemplateRef<any>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           constructor(public vcr: ViewContainerRef) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           create() { this.vcr.createEmbeddedView(this.tmp); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |             type: StructuralComp, | 
					
						
							|  |  |  |             selectors: [['structural-comp']], | 
					
						
							|  |  |  |             factory: () => structuralComp = | 
					
						
							|  |  |  |                          new StructuralComp(directiveInject(ViewContainerRef as any)), | 
					
						
							|  |  |  |             inputs: {tmp: 'tmp'}, | 
					
						
							|  |  |  |             consts: 1, | 
					
						
							|  |  |  |             vars: 0, | 
					
						
							|  |  |  |             template: (rf: RenderFlags, ctx: StructuralComp) => { | 
					
						
							|  |  |  |               if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                 text(0, 'Comp Content'); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         function FooTemplate(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |             text(0, 'Temp Content'); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** | 
					
						
							|  |  |  |          * <ng-template #foo> | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |          *     Temp Content | 
					
						
							| 
									
										
										
										
											2018-10-11 13:13:57 -07:00
										 |  |  |          * </ng-template> | 
					
						
							|  |  |  |          * <structural-comp [class.active]="class" [tmp]="foo"></structural-comp> | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |           if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |             template(0, FooTemplate, 1, 0, '', null, ['foo', ''], templateRefExtractor); | 
					
						
							|  |  |  |             elementStart(2, 'structural-comp'); | 
					
						
							|  |  |  |             elementStyling(['active']); | 
					
						
							|  |  |  |             elementEnd(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |             const foo = reference(1) as any; | 
					
						
							|  |  |  |             elementClassProp(2, 0, ctx.class); | 
					
						
							|  |  |  |             elementStylingApply(2); | 
					
						
							|  |  |  |             elementProperty(2, 'tmp', bind(foo)); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }, 3, 1, [StructuralComp]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |         fixture.component.class = true; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html) | 
					
						
							|  |  |  |             .toEqual('<structural-comp class="active">Comp Content</structural-comp>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         structuralComp.create(); | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html) | 
					
						
							|  |  |  |             .toEqual('<structural-comp class="active">Comp Content</structural-comp>Temp Content'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |         fixture.component.class = false; | 
					
						
							|  |  |  |         fixture.update(); | 
					
						
							|  |  |  |         expect(fixture.html) | 
					
						
							|  |  |  |             .toEqual('<structural-comp class="">Comp Content</structural-comp>Temp Content'); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-10-18 14:47:53 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       let mockClassDirective: DirWithClassDirective; | 
					
						
							|  |  |  |       class DirWithClassDirective { | 
					
						
							|  |  |  |         static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |           type: DirWithClassDirective, | 
					
						
							|  |  |  |           selectors: [['', 'DirWithClass', '']], | 
					
						
							|  |  |  |           factory: () => mockClassDirective = new DirWithClassDirective(), | 
					
						
							|  |  |  |           inputs: {'klass': 'class'} | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public classesVal: string = ''; | 
					
						
							|  |  |  |         set klass(value: string) { this.classesVal = value; } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should delegate all initial classes to a [class] input binding if present on a directive on the same element', | 
					
						
							|  |  |  |          () => { | 
					
						
							|  |  |  |            /** | 
					
						
							|  |  |  |             * <my-comp class="apple orange banana" DirWithClass></my-comp> | 
					
						
							|  |  |  |             */ | 
					
						
							|  |  |  |            const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |              if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                elementStart(0, 'div', ['DirWithClass']); | 
					
						
							|  |  |  |                elementStyling([ | 
					
						
							|  |  |  |                  InitialStylingFlags.VALUES_MODE, 'apple', true, 'orange', true, 'banana', true | 
					
						
							|  |  |  |                ]); | 
					
						
							|  |  |  |                elementEnd(); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |              if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |                elementStylingApply(0); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }, 1, 0, [DirWithClassDirective]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |            expect(mockClassDirective !.classesVal).toEqual('apple orange banana'); | 
					
						
							|  |  |  |          }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should update `[class]` and bindings in the provided directive if the input is matched', | 
					
						
							|  |  |  |          () => { | 
					
						
							|  |  |  |            /** | 
					
						
							|  |  |  |             * <my-comp DirWithClass></my-comp> | 
					
						
							|  |  |  |            */ | 
					
						
							|  |  |  |            const App = createComponent('app', function(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |              if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                elementStart(0, 'div', ['DirWithClass']); | 
					
						
							|  |  |  |                elementStyling(); | 
					
						
							|  |  |  |                elementEnd(); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |              if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |                elementStylingMap(0, 'cucumber grape'); | 
					
						
							|  |  |  |                elementStylingApply(0); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }, 1, 0, [DirWithClassDirective]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const fixture = new ComponentFixture(App); | 
					
						
							|  |  |  |            expect(mockClassDirective !.classesVal).toEqual('cucumber grape'); | 
					
						
							|  |  |  |          }); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-08 11:48:54 -08:00
										 |  |  |   describe('template data', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should re-use template data and node data', () => { | 
					
						
							|  |  |  |       /** | 
					
						
							|  |  |  |        *  % if (condition) { | 
					
						
							|  |  |  |        *    <div></div> | 
					
						
							|  |  |  |        *  % } | 
					
						
							|  |  |  |        */ | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |       function Template(rf: RenderFlags, ctx: any) { | 
					
						
							|  |  |  |         if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-02-06 16:11:20 -08:00
										 |  |  |           container(0); | 
					
						
							| 
									
										
										
										
											2017-12-08 11:48:54 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |         if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |           containerRefreshStart(0); | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             if (ctx.condition) { | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |               let rf1 = embeddedViewStart(0, 1, 0); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |               if (rf1 & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |                 element(0, 'div'); | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |               } | 
					
						
							|  |  |  |               embeddedViewEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-08 11:48:54 -08:00
										 |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:57:09 -07:00
										 |  |  |           containerRefreshEnd(); | 
					
						
							| 
									
										
										
										
											2017-12-08 11:48:54 -08:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-10 18:19:16 -08:00
										 |  |  |       expect((Template as any).ngPrivateData).toBeUndefined(); | 
					
						
							| 
									
										
										
										
											2017-12-08 11:48:54 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       renderToHtml(Template, {condition: true}, 1); | 
					
						
							| 
									
										
										
										
											2017-12-08 11:48:54 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-10 18:19:16 -08:00
										 |  |  |       const oldTemplateData = (Template as any).ngPrivateData; | 
					
						
							| 
									
										
										
										
											2018-06-07 22:42:32 -07:00
										 |  |  |       const oldContainerData = (oldTemplateData as any).data[HEADER_OFFSET]; | 
					
						
							|  |  |  |       const oldElementData = oldContainerData.tViews[0][HEADER_OFFSET]; | 
					
						
							| 
									
										
										
										
											2017-12-08 11:48:54 -08:00
										 |  |  |       expect(oldContainerData).not.toBeNull(); | 
					
						
							|  |  |  |       expect(oldElementData).not.toBeNull(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |       renderToHtml(Template, {condition: false}, 1); | 
					
						
							|  |  |  |       renderToHtml(Template, {condition: true}, 1); | 
					
						
							| 
									
										
										
										
											2017-12-08 11:48:54 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-10 18:19:16 -08:00
										 |  |  |       const newTemplateData = (Template as any).ngPrivateData; | 
					
						
							| 
									
										
										
										
											2018-06-07 22:42:32 -07:00
										 |  |  |       const newContainerData = (oldTemplateData as any).data[HEADER_OFFSET]; | 
					
						
							|  |  |  |       const newElementData = oldContainerData.tViews[0][HEADER_OFFSET]; | 
					
						
							| 
									
										
										
										
											2017-12-08 11:48:54 -08:00
										 |  |  |       expect(newTemplateData === oldTemplateData).toBe(true); | 
					
						
							|  |  |  |       expect(newContainerData === oldContainerData).toBe(true); | 
					
						
							|  |  |  |       expect(newElementData === oldElementData).toBe(true); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-31 11:14:06 -07:00
										 |  |  |   describe('component styles', () => { | 
					
						
							|  |  |  |     it('should pass in the component styles directly into the underlying renderer', () => { | 
					
						
							|  |  |  |       class StyledComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: StyledComp, | 
					
						
							|  |  |  |           styles: ['div { color: red; }'], | 
					
						
							|  |  |  |           consts: 1, | 
					
						
							|  |  |  |           vars: 0, | 
					
						
							|  |  |  |           encapsulation: 100, | 
					
						
							|  |  |  |           selectors: [['foo']], | 
					
						
							|  |  |  |           factory: () => new StyledComp(), | 
					
						
							|  |  |  |           template: (rf: RenderFlags, ctx: StyledComp) => { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |               element(0, 'div'); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-09-06 18:50:57 -07:00
										 |  |  |       const rendererFactory = new ProxyRenderer3Factory(); | 
					
						
							| 
									
										
										
										
											2018-07-31 11:14:06 -07:00
										 |  |  |       new ComponentFixture(StyledComp, {rendererFactory}); | 
					
						
							|  |  |  |       expect(rendererFactory.lastCapturedType !.styles).toEqual(['div { color: red; }']); | 
					
						
							|  |  |  |       expect(rendererFactory.lastCapturedType !.encapsulation).toEqual(100); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-05 15:23:59 -07:00
										 |  |  |   describe('component animations', () => { | 
					
						
							|  |  |  |     it('should pass in the component styles directly into the underlying renderer', () => { | 
					
						
							|  |  |  |       const animA = {name: 'a'}; | 
					
						
							|  |  |  |       const animB = {name: 'b'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       class AnimComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: AnimComp, | 
					
						
							|  |  |  |           consts: 0, | 
					
						
							|  |  |  |           vars: 0, | 
					
						
							| 
									
										
										
										
											2018-10-16 11:09:04 -07:00
										 |  |  |           data: { | 
					
						
							|  |  |  |             animations: [ | 
					
						
							|  |  |  |               animA, | 
					
						
							|  |  |  |               animB, | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |           }, | 
					
						
							| 
									
										
										
										
											2018-09-05 15:23:59 -07:00
										 |  |  |           selectors: [['foo']], | 
					
						
							|  |  |  |           factory: () => new AnimComp(), | 
					
						
							|  |  |  |           template: (rf: RenderFlags, ctx: AnimComp) => {} | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-09-06 18:50:57 -07:00
										 |  |  |       const rendererFactory = new ProxyRenderer3Factory(); | 
					
						
							| 
									
										
										
										
											2018-09-05 15:23:59 -07:00
										 |  |  |       new ComponentFixture(AnimComp, {rendererFactory}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const capturedAnimations = rendererFactory.lastCapturedType !.data !['animations']; | 
					
						
							|  |  |  |       expect(Array.isArray(capturedAnimations)).toBeTruthy(); | 
					
						
							|  |  |  |       expect(capturedAnimations.length).toEqual(2); | 
					
						
							|  |  |  |       expect(capturedAnimations).toContain(animA); | 
					
						
							|  |  |  |       expect(capturedAnimations).toContain(animB); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should include animations in the renderType data array even if the array is empty', () => { | 
					
						
							|  |  |  |       class AnimComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: AnimComp, | 
					
						
							|  |  |  |           consts: 0, | 
					
						
							|  |  |  |           vars: 0, | 
					
						
							| 
									
										
										
										
											2018-10-16 11:09:04 -07:00
										 |  |  |           data: { | 
					
						
							|  |  |  |             animations: [], | 
					
						
							|  |  |  |           }, | 
					
						
							| 
									
										
										
										
											2018-09-05 15:23:59 -07:00
										 |  |  |           selectors: [['foo']], | 
					
						
							|  |  |  |           factory: () => new AnimComp(), | 
					
						
							|  |  |  |           template: (rf: RenderFlags, ctx: AnimComp) => {} | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-09-06 18:50:57 -07:00
										 |  |  |       const rendererFactory = new ProxyRenderer3Factory(); | 
					
						
							| 
									
										
										
										
											2018-09-05 15:23:59 -07:00
										 |  |  |       new ComponentFixture(AnimComp, {rendererFactory}); | 
					
						
							|  |  |  |       const data = rendererFactory.lastCapturedType !.data; | 
					
						
							|  |  |  |       expect(data.animations).toEqual([]); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-09-06 18:50:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should allow [@trigger] bindings to be picked up by the underlying renderer', () => { | 
					
						
							|  |  |  |       class AnimComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: AnimComp, | 
					
						
							|  |  |  |           consts: 1, | 
					
						
							|  |  |  |           vars: 1, | 
					
						
							|  |  |  |           selectors: [['foo']], | 
					
						
							|  |  |  |           factory: () => new AnimComp(), | 
					
						
							|  |  |  |           template: (rf: RenderFlags, ctx: AnimComp) => { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |               element(0, 'div', [AttributeMarker.SelectOnly, '@fooAnimation']); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |               elementAttribute(0, '@fooAnimation', bind(ctx.animationValue)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         animationValue = '123'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const rendererFactory = new MockRendererFactory(['setAttribute']); | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(AnimComp, {rendererFactory}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const renderer = rendererFactory.lastRenderer !; | 
					
						
							|  |  |  |       fixture.component.animationValue = '456'; | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const spy = renderer.spies['setAttribute']; | 
					
						
							|  |  |  |       const [elm, attr, value] = spy.calls.mostRecent().args; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(attr).toEqual('@fooAnimation'); | 
					
						
							|  |  |  |       expect(value).toEqual('456'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should allow creation-level [@trigger] properties to be picked up by the underlying renderer', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          class AnimComp { | 
					
						
							|  |  |  |            static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |              type: AnimComp, | 
					
						
							|  |  |  |              consts: 1, | 
					
						
							|  |  |  |              vars: 1, | 
					
						
							|  |  |  |              selectors: [['foo']], | 
					
						
							|  |  |  |              factory: () => new AnimComp(), | 
					
						
							|  |  |  |              template: (rf: RenderFlags, ctx: AnimComp) => { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  element(0, 'div', ['@fooAnimation', '']); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const rendererFactory = new MockRendererFactory(['setAttribute']); | 
					
						
							|  |  |  |          const fixture = new ComponentFixture(AnimComp, {rendererFactory}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const renderer = rendererFactory.lastRenderer !; | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const spy = renderer.spies['setAttribute']; | 
					
						
							|  |  |  |          const [elm, attr, value] = spy.calls.mostRecent().args; | 
					
						
							|  |  |  |          expect(attr).toEqual('@fooAnimation'); | 
					
						
							|  |  |  |        }); | 
					
						
							| 
									
										
										
										
											2018-09-05 15:23:59 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  |   describe('element discovery', () => { | 
					
						
							|  |  |  |     it('should only monkey-patch immediate child nodes in a component', () => { | 
					
						
							|  |  |  |       class StructuredComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: StructuredComp, | 
					
						
							|  |  |  |           selectors: [['structured-comp']], | 
					
						
							|  |  |  |           factory: () => new StructuredComp(), | 
					
						
							|  |  |  |           consts: 2, | 
					
						
							|  |  |  |           vars: 0, | 
					
						
							|  |  |  |           template: (rf: RenderFlags, ctx: StructuredComp) => { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |               elementStart(0, 'div'); | 
					
						
							|  |  |  |               elementStart(1, 'p'); | 
					
						
							|  |  |  |               elementEnd(); | 
					
						
							|  |  |  |               elementEnd(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(StructuredComp); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const host = fixture.hostElement; | 
					
						
							|  |  |  |       const parent = host.querySelector('div') as any; | 
					
						
							|  |  |  |       const child = host.querySelector('p') as any; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(parent[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  |       expect(child[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should only monkey-patch immediate child nodes in a sub component', () => { | 
					
						
							|  |  |  |       class ChildComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: ChildComp, | 
					
						
							|  |  |  |           selectors: [['child-comp']], | 
					
						
							|  |  |  |           factory: () => new ChildComp(), | 
					
						
							|  |  |  |           consts: 3, | 
					
						
							|  |  |  |           vars: 0, | 
					
						
							|  |  |  |           template: (rf: RenderFlags, ctx: ChildComp) => { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |               element(0, 'div'); | 
					
						
							|  |  |  |               element(1, 'div'); | 
					
						
							|  |  |  |               element(2, 'div'); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       class ParentComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: ParentComp, | 
					
						
							|  |  |  |           selectors: [['parent-comp']], | 
					
						
							|  |  |  |           directives: [ChildComp], | 
					
						
							|  |  |  |           factory: () => new ParentComp(), | 
					
						
							|  |  |  |           consts: 2, | 
					
						
							|  |  |  |           vars: 0, | 
					
						
							|  |  |  |           template: (rf: RenderFlags, ctx: ParentComp) => { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |               elementStart(0, 'section'); | 
					
						
							|  |  |  |               elementStart(1, 'child-comp'); | 
					
						
							|  |  |  |               elementEnd(); | 
					
						
							|  |  |  |               elementEnd(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(ParentComp); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const host = fixture.hostElement; | 
					
						
							|  |  |  |       const child = host.querySelector('child-comp') as any; | 
					
						
							| 
									
										
										
										
											2018-09-10 11:22:35 -07:00
										 |  |  |       expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const [kid1, kid2, kid3] = Array.from(host.querySelectorAll('child-comp > *')); | 
					
						
							|  |  |  |       expect(kid1[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  |       expect(kid2[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  |       expect(kid3[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should only monkey-patch immediate child nodes in an embedded template container', () => { | 
					
						
							|  |  |  |       class StructuredComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: StructuredComp, | 
					
						
							|  |  |  |           selectors: [['structured-comp']], | 
					
						
							|  |  |  |           directives: [NgIf], | 
					
						
							|  |  |  |           factory: () => new StructuredComp(), | 
					
						
							|  |  |  |           consts: 2, | 
					
						
							|  |  |  |           vars: 1, | 
					
						
							|  |  |  |           template: (rf: RenderFlags, ctx: StructuredComp) => { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |               elementStart(0, 'section'); | 
					
						
							|  |  |  |               template(1, (rf, ctx) => { | 
					
						
							|  |  |  |                 if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                   elementStart(0, 'div'); | 
					
						
							|  |  |  |                   element(1, 'p'); | 
					
						
							|  |  |  |                   elementEnd(); | 
					
						
							|  |  |  |                   element(2, 'div'); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |               }, 3, 0, null, ['ngIf', '']); | 
					
						
							|  |  |  |               elementEnd(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |               elementProperty(1, 'ngIf', true); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(StructuredComp); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const host = fixture.hostElement; | 
					
						
							|  |  |  |       const [section, div1, p, div2] = Array.from(host.querySelectorAll('section, div, p')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(section.nodeName.toLowerCase()).toBe('section'); | 
					
						
							|  |  |  |       expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(div1.nodeName.toLowerCase()).toBe('div'); | 
					
						
							|  |  |  |       expect(div1[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(p.nodeName.toLowerCase()).toBe('p'); | 
					
						
							|  |  |  |       expect(p[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(div2.nodeName.toLowerCase()).toBe('div'); | 
					
						
							|  |  |  |       expect(div2[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should return a context object from a given dom node', () => { | 
					
						
							|  |  |  |       class StructuredComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: StructuredComp, | 
					
						
							|  |  |  |           selectors: [['structured-comp']], | 
					
						
							|  |  |  |           directives: [NgIf], | 
					
						
							|  |  |  |           factory: () => new StructuredComp(), | 
					
						
							|  |  |  |           consts: 2, | 
					
						
							|  |  |  |           vars: 0, | 
					
						
							|  |  |  |           template: (rf: RenderFlags, ctx: StructuredComp) => { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |               element(0, 'section'); | 
					
						
							|  |  |  |               element(1, 'div'); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(StructuredComp); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const section = fixture.hostElement.querySelector('section') !; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |       const sectionContext = getContext(section) !; | 
					
						
							|  |  |  |       const sectionLView = sectionContext.lViewData !; | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |       expect(sectionContext.nodeIndex).toEqual(HEADER_OFFSET); | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  |       expect(sectionLView.length).toBeGreaterThan(HEADER_OFFSET); | 
					
						
							|  |  |  |       expect(sectionContext.native).toBe(section); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const div = fixture.hostElement.querySelector('div') !; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |       const divContext = getContext(div) !; | 
					
						
							|  |  |  |       const divLView = divContext.lViewData !; | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |       expect(divContext.nodeIndex).toEqual(HEADER_OFFSET + 1); | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  |       expect(divLView.length).toBeGreaterThan(HEADER_OFFSET); | 
					
						
							|  |  |  |       expect(divContext.native).toBe(div); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(divLView).toBe(sectionLView); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should cache the element context on a element was pre-emptively monkey-patched', () => { | 
					
						
							|  |  |  |       class StructuredComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: StructuredComp, | 
					
						
							|  |  |  |           selectors: [['structured-comp']], | 
					
						
							|  |  |  |           factory: () => new StructuredComp(), | 
					
						
							|  |  |  |           consts: 1, | 
					
						
							|  |  |  |           vars: 0, | 
					
						
							|  |  |  |           template: (rf: RenderFlags, ctx: StructuredComp) => { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |               element(0, 'section'); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(StructuredComp); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const section = fixture.hostElement.querySelector('section') !as any; | 
					
						
							|  |  |  |       const result1 = section[MONKEY_PATCH_KEY_NAME]; | 
					
						
							|  |  |  |       expect(Array.isArray(result1)).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |       const context = getContext(section) !; | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  |       const result2 = section[MONKEY_PATCH_KEY_NAME]; | 
					
						
							|  |  |  |       expect(Array.isArray(result2)).toBeFalsy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(result2).toBe(context); | 
					
						
							|  |  |  |       expect(result2.lViewData).toBe(result1); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should cache the element context on an intermediate element that isn\'t pre-emptively monkey-patched', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          class StructuredComp { | 
					
						
							|  |  |  |            static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |              type: StructuredComp, | 
					
						
							|  |  |  |              selectors: [['structured-comp']], | 
					
						
							|  |  |  |              factory: () => new StructuredComp(), | 
					
						
							|  |  |  |              consts: 2, | 
					
						
							|  |  |  |              vars: 0, | 
					
						
							|  |  |  |              template: (rf: RenderFlags, ctx: StructuredComp) => { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  elementStart(0, 'section'); | 
					
						
							|  |  |  |                  element(1, 'p'); | 
					
						
							|  |  |  |                  elementEnd(); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const fixture = new ComponentFixture(StructuredComp); | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const section = fixture.hostElement.querySelector('section') !as any; | 
					
						
							|  |  |  |          expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const p = fixture.hostElement.querySelector('p') !as any; | 
					
						
							|  |  |  |          expect(p[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |          const pContext = getContext(p) !; | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  |          expect(pContext.native).toBe(p); | 
					
						
							|  |  |  |          expect(p[MONKEY_PATCH_KEY_NAME]).toBe(pContext); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should be able to pull in element context data even if the element is decorated using styling', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          class StructuredComp { | 
					
						
							|  |  |  |            static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |              type: StructuredComp, | 
					
						
							|  |  |  |              selectors: [['structured-comp']], | 
					
						
							|  |  |  |              factory: () => new StructuredComp(), | 
					
						
							|  |  |  |              consts: 1, | 
					
						
							|  |  |  |              vars: 0, | 
					
						
							|  |  |  |              template: (rf: RenderFlags, ctx: StructuredComp) => { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  elementStart(0, 'section'); | 
					
						
							|  |  |  |                  elementStyling(['class-foo']); | 
					
						
							|  |  |  |                  elementEnd(); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |                if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |                  elementStylingApply(0); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const fixture = new ComponentFixture(StructuredComp); | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const section = fixture.hostElement.querySelector('section') !as any; | 
					
						
							|  |  |  |          const result1 = section[MONKEY_PATCH_KEY_NAME]; | 
					
						
							|  |  |  |          expect(Array.isArray(result1)).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const elementResult = result1[HEADER_OFFSET];  // first element
 | 
					
						
							|  |  |  |          expect(Array.isArray(elementResult)).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2018-10-12 18:49:00 -07:00
										 |  |  |          expect(elementResult[StylingIndex.ElementPosition]).toBe(section); | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |          const context = getContext(section) !; | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  |          const result2 = section[MONKEY_PATCH_KEY_NAME]; | 
					
						
							|  |  |  |          expect(Array.isArray(result2)).toBeFalsy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          expect(context.native).toBe(section); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should monkey-patch immediate child nodes in a content-projected region with a reference to the parent component', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          /* | 
					
						
							|  |  |  |            <!-- DOM view --> | 
					
						
							|  |  |  |            <section> | 
					
						
							|  |  |  |              <projection-comp> | 
					
						
							|  |  |  |                welcome | 
					
						
							|  |  |  |                <header> | 
					
						
							|  |  |  |                  <h1> | 
					
						
							|  |  |  |                    <p>this content is projected</p> | 
					
						
							|  |  |  |                    this content is projected also | 
					
						
							|  |  |  |                  </h1> | 
					
						
							|  |  |  |                </header> | 
					
						
							|  |  |  |              </projection-comp> | 
					
						
							|  |  |  |            </section> | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |          class ProjectorComp { | 
					
						
							|  |  |  |            static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |              type: ProjectorComp, | 
					
						
							|  |  |  |              selectors: [['projector-comp']], | 
					
						
							|  |  |  |              factory: () => new ProjectorComp(), | 
					
						
							|  |  |  |              consts: 4, | 
					
						
							|  |  |  |              vars: 0, | 
					
						
							|  |  |  |              template: (rf: RenderFlags, ctx: ProjectorComp) => { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  projectionDef(); | 
					
						
							|  |  |  |                  text(0, 'welcome'); | 
					
						
							|  |  |  |                  elementStart(1, 'header'); | 
					
						
							|  |  |  |                  elementStart(2, 'h1'); | 
					
						
							|  |  |  |                  projection(3); | 
					
						
							|  |  |  |                  elementEnd(); | 
					
						
							|  |  |  |                  elementEnd(); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |                if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          class ParentComp { | 
					
						
							|  |  |  |            static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |              type: ParentComp, | 
					
						
							|  |  |  |              selectors: [['parent-comp']], | 
					
						
							|  |  |  |              directives: [ProjectorComp], | 
					
						
							|  |  |  |              factory: () => new ParentComp(), | 
					
						
							|  |  |  |              consts: 5, | 
					
						
							|  |  |  |              vars: 0, | 
					
						
							|  |  |  |              template: (rf: RenderFlags, ctx: ParentComp) => { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  elementStart(0, 'section'); | 
					
						
							|  |  |  |                  elementStart(1, 'projector-comp'); | 
					
						
							|  |  |  |                  elementStart(2, 'p'); | 
					
						
							|  |  |  |                  text(3, 'this content is projected'); | 
					
						
							|  |  |  |                  elementEnd(); | 
					
						
							|  |  |  |                  text(4, 'this content is projected also'); | 
					
						
							|  |  |  |                  elementEnd(); | 
					
						
							|  |  |  |                  elementEnd(); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const fixture = new ComponentFixture(ParentComp); | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const host = fixture.hostElement; | 
					
						
							|  |  |  |          const textNode = host.firstChild as any; | 
					
						
							|  |  |  |          const section = host.querySelector('section') !as any; | 
					
						
							|  |  |  |          const projectorComp = host.querySelector('projector-comp') !as any; | 
					
						
							|  |  |  |          const header = host.querySelector('header') !as any; | 
					
						
							|  |  |  |          const h1 = host.querySelector('h1') !as any; | 
					
						
							|  |  |  |          const p = host.querySelector('p') !as any; | 
					
						
							|  |  |  |          const pText = p.firstChild as any; | 
					
						
							|  |  |  |          const projectedTextNode = p.nextSibling; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          expect(projectorComp.children).toContain(header); | 
					
						
							|  |  |  |          expect(h1.children).toContain(p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          expect(textNode[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  |          expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2018-09-10 11:22:35 -07:00
										 |  |  |          expect(projectorComp[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  |          expect(header[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  |          expect(h1[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); | 
					
						
							|  |  |  |          expect(p[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  |          expect(pText[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); | 
					
						
							|  |  |  |          expect(projectedTextNode[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |          const parentContext = getContext(section) !; | 
					
						
							|  |  |  |          const shadowContext = getContext(header) !; | 
					
						
							|  |  |  |          const projectedContext = getContext(p) !; | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |          const parentComponentData = parentContext.lViewData; | 
					
						
							|  |  |  |          const shadowComponentData = shadowContext.lViewData; | 
					
						
							|  |  |  |          const projectedComponentData = projectedContext.lViewData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          expect(projectedComponentData).toBe(parentComponentData); | 
					
						
							|  |  |  |          expect(shadowComponentData).not.toBe(parentComponentData); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should return `null` when an element context is retrieved that isn\'t situated in Angular', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          const elm1 = document.createElement('div'); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |          const context1 = getContext(elm1); | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  |          expect(context1).toBeFalsy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const elm2 = document.createElement('div'); | 
					
						
							|  |  |  |          document.body.appendChild(elm2); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |          const context2 = getContext(elm2); | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  |          expect(context2).toBeFalsy(); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should return `null` when an element context is retrieved that is a DOM node that was not created by Angular', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          class StructuredComp { | 
					
						
							|  |  |  |            static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |              type: StructuredComp, | 
					
						
							|  |  |  |              selectors: [['structured-comp']], | 
					
						
							|  |  |  |              factory: () => new StructuredComp(), | 
					
						
							|  |  |  |              consts: 1, | 
					
						
							|  |  |  |              vars: 0, | 
					
						
							|  |  |  |              template: (rf: RenderFlags, ctx: StructuredComp) => { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  element(0, 'section'); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const fixture = new ComponentFixture(StructuredComp); | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const section = fixture.hostElement.querySelector('section') !as any; | 
					
						
							|  |  |  |          const manuallyCreatedElement = document.createElement('div'); | 
					
						
							|  |  |  |          section.appendChild(manuallyCreatedElement); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |          const context = getContext(manuallyCreatedElement); | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  |          expect(context).toBeFalsy(); | 
					
						
							|  |  |  |        }); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should by default monkey-patch the bootstrap component with context details', () => { | 
					
						
							|  |  |  |       class StructuredComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: StructuredComp, | 
					
						
							|  |  |  |           selectors: [['structured-comp']], | 
					
						
							|  |  |  |           factory: () => new StructuredComp(), | 
					
						
							|  |  |  |           consts: 0, | 
					
						
							|  |  |  |           vars: 0, | 
					
						
							|  |  |  |           template: (rf: RenderFlags, ctx: StructuredComp) => {} | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(StructuredComp); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const hostElm = fixture.hostElement; | 
					
						
							|  |  |  |       const component = fixture.component; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-10 11:22:35 -07:00
										 |  |  |       const componentLViewData = (component as any)[MONKEY_PATCH_KEY_NAME]; | 
					
						
							|  |  |  |       expect(Array.isArray(componentLViewData)).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-10 11:22:35 -07:00
										 |  |  |       const hostLViewData = (hostElm as any)[MONKEY_PATCH_KEY_NAME]; | 
					
						
							|  |  |  |       expect(hostLViewData).toBe(componentLViewData); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const context1 = getContext(hostElm) !; | 
					
						
							| 
									
										
										
										
											2018-09-10 11:22:35 -07:00
										 |  |  |       expect(context1.lViewData).toBe(hostLViewData); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |       expect(context1.native).toEqual(hostElm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const context2 = getContext(component) !; | 
					
						
							|  |  |  |       expect(context2).toBe(context1); | 
					
						
							| 
									
										
										
										
											2018-09-10 11:22:35 -07:00
										 |  |  |       expect(context2.lViewData).toBe(hostLViewData); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |       expect(context2.native).toEqual(hostElm); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should by default monkey-patch the directives with LViewData so that they can be examined', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          let myDir1Instance: MyDir1|null = null; | 
					
						
							|  |  |  |          let myDir2Instance: MyDir2|null = null; | 
					
						
							|  |  |  |          let myDir3Instance: MyDir2|null = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          class MyDir1 { | 
					
						
							|  |  |  |            static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |              type: MyDir1, | 
					
						
							|  |  |  |              selectors: [['', 'my-dir-1', '']], | 
					
						
							|  |  |  |              factory: () => myDir1Instance = new MyDir1() | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          class MyDir2 { | 
					
						
							|  |  |  |            static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |              type: MyDir2, | 
					
						
							|  |  |  |              selectors: [['', 'my-dir-2', '']], | 
					
						
							|  |  |  |              factory: () => myDir2Instance = new MyDir2() | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          class MyDir3 { | 
					
						
							|  |  |  |            static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |              type: MyDir3, | 
					
						
							|  |  |  |              selectors: [['', 'my-dir-3', '']], | 
					
						
							|  |  |  |              factory: () => myDir3Instance = new MyDir2() | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          class StructuredComp { | 
					
						
							|  |  |  |            static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |              type: StructuredComp, | 
					
						
							|  |  |  |              selectors: [['structured-comp']], | 
					
						
							|  |  |  |              directives: [MyDir1, MyDir2, MyDir3], | 
					
						
							|  |  |  |              factory: () => new StructuredComp(), | 
					
						
							|  |  |  |              consts: 2, | 
					
						
							|  |  |  |              vars: 0, | 
					
						
							|  |  |  |              template: (rf: RenderFlags, ctx: StructuredComp) => { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  element(0, 'div', ['my-dir-1', '', 'my-dir-2', '']); | 
					
						
							|  |  |  |                  element(1, 'div', ['my-dir-3']); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const fixture = new ComponentFixture(StructuredComp); | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const hostElm = fixture.hostElement; | 
					
						
							|  |  |  |          const div1 = hostElm.querySelector('div:first-child') !as any; | 
					
						
							|  |  |  |          const div2 = hostElm.querySelector('div:last-child') !as any; | 
					
						
							|  |  |  |          const context = getContext(hostElm) !; | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |          const componentView = context.lViewData[context.nodeIndex]; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |          expect(componentView).toContain(myDir1Instance); | 
					
						
							|  |  |  |          expect(componentView).toContain(myDir2Instance); | 
					
						
							|  |  |  |          expect(componentView).toContain(myDir3Instance); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |          expect(Array.isArray((myDir1Instance as any)[MONKEY_PATCH_KEY_NAME])).toBeTruthy(); | 
					
						
							|  |  |  |          expect(Array.isArray((myDir2Instance as any)[MONKEY_PATCH_KEY_NAME])).toBeTruthy(); | 
					
						
							|  |  |  |          expect(Array.isArray((myDir3Instance as any)[MONKEY_PATCH_KEY_NAME])).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const d1Context = getContext(myDir1Instance) !; | 
					
						
							|  |  |  |          const d2Context = getContext(myDir2Instance) !; | 
					
						
							|  |  |  |          const d3Context = getContext(myDir3Instance) !; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |          expect(d1Context.lViewData).toEqual(componentView); | 
					
						
							|  |  |  |          expect(d2Context.lViewData).toEqual(componentView); | 
					
						
							|  |  |  |          expect(d3Context.lViewData).toEqual(componentView); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |          expect((myDir1Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(d1Context); | 
					
						
							|  |  |  |          expect((myDir2Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(d2Context); | 
					
						
							|  |  |  |          expect((myDir3Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(d3Context); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |          expect(d1Context.nodeIndex).toEqual(HEADER_OFFSET); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |          expect(d1Context.native).toBe(div1); | 
					
						
							|  |  |  |          expect(d1Context.directives as any[]).toEqual([myDir1Instance, myDir2Instance]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |          expect(d2Context.nodeIndex).toEqual(HEADER_OFFSET); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |          expect(d2Context.native).toBe(div1); | 
					
						
							|  |  |  |          expect(d2Context.directives as any[]).toEqual([myDir1Instance, myDir2Instance]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |          expect(d3Context.nodeIndex).toEqual(HEADER_OFFSET + 1); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |          expect(d3Context.native).toBe(div2); | 
					
						
							|  |  |  |          expect(d3Context.directives as any[]).toEqual([myDir3Instance]); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should monkey-patch the exact same context instance of the DOM node, component and any directives on the same element', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          let myDir1Instance: MyDir1|null = null; | 
					
						
							|  |  |  |          let myDir2Instance: MyDir2|null = null; | 
					
						
							|  |  |  |          let childComponentInstance: ChildComp|null = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          class MyDir1 { | 
					
						
							|  |  |  |            static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |              type: MyDir1, | 
					
						
							|  |  |  |              selectors: [['', 'my-dir-1', '']], | 
					
						
							|  |  |  |              factory: () => myDir1Instance = new MyDir1() | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          class MyDir2 { | 
					
						
							|  |  |  |            static ngDirectiveDef = defineDirective({ | 
					
						
							|  |  |  |              type: MyDir2, | 
					
						
							|  |  |  |              selectors: [['', 'my-dir-2', '']], | 
					
						
							|  |  |  |              factory: () => myDir2Instance = new MyDir2() | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          class ChildComp { | 
					
						
							|  |  |  |            static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |              type: ChildComp, | 
					
						
							|  |  |  |              selectors: [['child-comp']], | 
					
						
							|  |  |  |              factory: () => childComponentInstance = new ChildComp(), | 
					
						
							|  |  |  |              consts: 1, | 
					
						
							|  |  |  |              vars: 0, | 
					
						
							|  |  |  |              template: (rf: RenderFlags, ctx: ChildComp) => { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  element(0, 'div'); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          class ParentComp { | 
					
						
							|  |  |  |            static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |              type: ParentComp, | 
					
						
							|  |  |  |              selectors: [['parent-comp']], | 
					
						
							|  |  |  |              directives: [ChildComp, MyDir1, MyDir2], | 
					
						
							|  |  |  |              factory: () => new ParentComp(), | 
					
						
							|  |  |  |              consts: 1, | 
					
						
							|  |  |  |              vars: 0, | 
					
						
							|  |  |  |              template: (rf: RenderFlags, ctx: ParentComp) => { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  element(0, 'child-comp', ['my-dir-1', '', 'my-dir-2', '']); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const fixture = new ComponentFixture(ParentComp); | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const childCompHostElm = fixture.hostElement.querySelector('child-comp') !as any; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const lViewData = childCompHostElm[MONKEY_PATCH_KEY_NAME]; | 
					
						
							|  |  |  |          expect(Array.isArray(lViewData)).toBeTruthy(); | 
					
						
							|  |  |  |          expect((myDir1Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(lViewData); | 
					
						
							|  |  |  |          expect((myDir2Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(lViewData); | 
					
						
							|  |  |  |          expect((childComponentInstance as any)[MONKEY_PATCH_KEY_NAME]).toBe(lViewData); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const childNodeContext = getContext(childCompHostElm) !; | 
					
						
							|  |  |  |          expect(childNodeContext.component).toBeFalsy(); | 
					
						
							|  |  |  |          expect(childNodeContext.directives).toBeFalsy(); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(myDir1Instance); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(myDir2Instance); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(childComponentInstance); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          expect(getContext(myDir1Instance)).toBe(childNodeContext); | 
					
						
							|  |  |  |          expect(childNodeContext.component).toBeFalsy(); | 
					
						
							|  |  |  |          expect(childNodeContext.directives !.length).toEqual(2); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(myDir1Instance, false); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(myDir2Instance, false); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(childComponentInstance); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          expect(getContext(myDir2Instance)).toBe(childNodeContext); | 
					
						
							|  |  |  |          expect(childNodeContext.component).toBeFalsy(); | 
					
						
							|  |  |  |          expect(childNodeContext.directives !.length).toEqual(2); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(myDir1Instance, false); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(myDir2Instance, false); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(childComponentInstance); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          expect(getContext(childComponentInstance)).toBe(childNodeContext); | 
					
						
							|  |  |  |          expect(childNodeContext.component).toBeTruthy(); | 
					
						
							|  |  |  |          expect(childNodeContext.directives !.length).toEqual(2); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(myDir1Instance, false); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(myDir2Instance, false); | 
					
						
							|  |  |  |          assertMonkeyPatchValueIsLViewData(childComponentInstance, false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          function assertMonkeyPatchValueIsLViewData(value: any, yesOrNo = true) { | 
					
						
							|  |  |  |            expect(Array.isArray((value as any)[MONKEY_PATCH_KEY_NAME])).toBe(yesOrNo); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should monkey-patch sub components with the view data and then replace them with the context result once a lookup occurs', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          class ChildComp { | 
					
						
							|  |  |  |            static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |              type: ChildComp, | 
					
						
							|  |  |  |              selectors: [['child-comp']], | 
					
						
							|  |  |  |              factory: () => new ChildComp(), | 
					
						
							|  |  |  |              consts: 3, | 
					
						
							|  |  |  |              vars: 0, | 
					
						
							|  |  |  |              template: (rf: RenderFlags, ctx: ChildComp) => { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  element(0, 'div'); | 
					
						
							|  |  |  |                  element(1, 'div'); | 
					
						
							|  |  |  |                  element(2, 'div'); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          class ParentComp { | 
					
						
							|  |  |  |            static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |              type: ParentComp, | 
					
						
							|  |  |  |              selectors: [['parent-comp']], | 
					
						
							|  |  |  |              directives: [ChildComp], | 
					
						
							|  |  |  |              factory: () => new ParentComp(), | 
					
						
							|  |  |  |              consts: 2, | 
					
						
							|  |  |  |              vars: 0, | 
					
						
							|  |  |  |              template: (rf: RenderFlags, ctx: ParentComp) => { | 
					
						
							|  |  |  |                if (rf & RenderFlags.Create) { | 
					
						
							|  |  |  |                  elementStart(0, 'section'); | 
					
						
							|  |  |  |                  elementStart(1, 'child-comp'); | 
					
						
							|  |  |  |                  elementEnd(); | 
					
						
							|  |  |  |                  elementEnd(); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const fixture = new ComponentFixture(ParentComp); | 
					
						
							|  |  |  |          fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const host = fixture.hostElement; | 
					
						
							|  |  |  |          const child = host.querySelector('child-comp') as any; | 
					
						
							| 
									
										
										
										
											2018-09-10 11:22:35 -07:00
										 |  |  |          expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |          const context = getContext(child) !; | 
					
						
							|  |  |  |          expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 15:02:54 -07:00
										 |  |  |          const componentData = context.lViewData[context.nodeIndex]; | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |          const component = componentData[CONTEXT]; | 
					
						
							|  |  |  |          expect(component instanceof ChildComp).toBeTruthy(); | 
					
						
							|  |  |  |          expect(component[MONKEY_PATCH_KEY_NAME]).toBe(context.lViewData); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const componentContext = getContext(component) !; | 
					
						
							|  |  |  |          expect(component[MONKEY_PATCH_KEY_NAME]).toBe(componentContext); | 
					
						
							| 
									
										
										
										
											2018-10-04 20:40:39 -07:00
										 |  |  |          expect(componentContext.nodeIndex).toEqual(context.nodeIndex); | 
					
						
							| 
									
										
										
										
											2018-08-29 13:52:03 -07:00
										 |  |  |          expect(componentContext.native).toEqual(context.native); | 
					
						
							|  |  |  |          expect(componentContext.lViewData).toEqual(context.lViewData); | 
					
						
							|  |  |  |        }); | 
					
						
							| 
									
										
										
										
											2018-08-22 16:57:40 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 15:30:16 -07:00
										 |  |  |   describe('sanitization', () => { | 
					
						
							|  |  |  |     it('should sanitize data using the provided sanitization interface', () => { | 
					
						
							|  |  |  |       class SanitizationComp { | 
					
						
							|  |  |  |         static ngComponentDef = defineComponent({ | 
					
						
							|  |  |  |           type: SanitizationComp, | 
					
						
							|  |  |  |           selectors: [['sanitize-this']], | 
					
						
							|  |  |  |           factory: () => new SanitizationComp(), | 
					
						
							| 
									
										
										
										
											2018-08-16 18:53:21 -07:00
										 |  |  |           consts: 1, | 
					
						
							| 
									
										
										
										
											2018-08-18 11:14:50 -07:00
										 |  |  |           vars: 1, | 
					
						
							| 
									
										
										
										
											2018-05-09 15:30:16 -07:00
										 |  |  |           template: (rf: RenderFlags, ctx: SanitizationComp) => { | 
					
						
							|  |  |  |             if (rf & RenderFlags.Create) { | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |               element(0, 'a'); | 
					
						
							| 
									
										
										
										
											2018-05-09 15:30:16 -07:00
										 |  |  |             } | 
					
						
							|  |  |  |             if (rf & RenderFlags.Update) { | 
					
						
							|  |  |  |               elementProperty(0, 'href', bind(ctx.href), sanitizeUrl); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         private href = ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         updateLink(href: any) { this.href = href; } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const sanitizer = new LocalSanitizer((value) => { return 'http://bar'; }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const fixture = new ComponentFixture(SanitizationComp, {sanitizer}); | 
					
						
							|  |  |  |       fixture.component.updateLink('http://foo'); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |       const anchor = fixture.hostElement.querySelector('a') !; | 
					
						
							|  |  |  |       expect(anchor.getAttribute('href')).toEqual('http://bar'); | 
					
						
							| 
									
										
										
										
											2018-05-09 15:30:16 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       fixture.component.updateLink(sanitizer.bypassSecurityTrustUrl('http://foo')); | 
					
						
							|  |  |  |       fixture.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-27 14:28:22 -07:00
										 |  |  |       expect(anchor.getAttribute('href')).toEqual('http://foo'); | 
					
						
							| 
									
										
										
										
											2018-05-09 15:30:16 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-12-01 14:23:03 -08:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2018-05-09 15:30:16 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class LocalSanitizedValue { | 
					
						
							|  |  |  |   constructor(public value: any) {} | 
					
						
							|  |  |  |   toString() { return this.value; } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class LocalSanitizer implements Sanitizer { | 
					
						
							|  |  |  |   constructor(private _interceptor: (value: string|null|any) => string) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   sanitize(context: SecurityContext, value: LocalSanitizedValue|string|null): string|null { | 
					
						
							|  |  |  |     if (value instanceof LocalSanitizedValue) { | 
					
						
							|  |  |  |       return value.toString(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return this._interceptor(value); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bypassSecurityTrustHtml(value: string) {} | 
					
						
							|  |  |  |   bypassSecurityTrustStyle(value: string) {} | 
					
						
							|  |  |  |   bypassSecurityTrustScript(value: string) {} | 
					
						
							|  |  |  |   bypassSecurityTrustResourceUrl(value: string) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bypassSecurityTrustUrl(value: string) { return new LocalSanitizedValue(value); } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-07-31 11:14:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 18:50:57 -07:00
										 |  |  | class ProxyRenderer3Factory implements RendererFactory3 { | 
					
						
							| 
									
										
										
										
											2018-07-31 11:14:06 -07:00
										 |  |  |   lastCapturedType: RendererType2|null = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   createRenderer(hostElement: RElement|null, rendererType: RendererType2|null): Renderer3 { | 
					
						
							|  |  |  |     this.lastCapturedType = rendererType; | 
					
						
							|  |  |  |     return domRendererFactory3.createRenderer(hostElement, rendererType); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-09-06 18:50:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class MockRendererFactory implements RendererFactory3 { | 
					
						
							|  |  |  |   lastRenderer: any; | 
					
						
							|  |  |  |   private _spyOnMethods: string[]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   constructor(spyOnMethods?: string[]) { this._spyOnMethods = spyOnMethods || []; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   createRenderer(hostElement: RElement|null, rendererType: RendererType2|null): Renderer3 { | 
					
						
							|  |  |  |     const renderer = this.lastRenderer = new MockRenderer(this._spyOnMethods); | 
					
						
							|  |  |  |     return renderer; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MockRenderer implements ProceduralRenderer3 { | 
					
						
							|  |  |  |   public spies: {[methodName: string]: any} = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   constructor(spyOnMethods: string[]) { | 
					
						
							|  |  |  |     spyOnMethods.forEach(methodName => { | 
					
						
							|  |  |  |       this.spies[methodName] = spyOn(this as any, methodName).and.callThrough(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   destroy(): void {} | 
					
						
							|  |  |  |   createComment(value: string): RComment { return document.createComment(value); } | 
					
						
							|  |  |  |   createElement(name: string, namespace?: string|null): RElement { | 
					
						
							|  |  |  |     return document.createElement(name); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   createText(value: string): RText { return document.createTextNode(value); } | 
					
						
							|  |  |  |   appendChild(parent: RElement, newChild: RNode): void { parent.appendChild(newChild); } | 
					
						
							|  |  |  |   insertBefore(parent: RNode, newChild: RNode, refChild: RNode|null): void { | 
					
						
							|  |  |  |     parent.insertBefore(newChild, refChild, false); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   removeChild(parent: RElement, oldChild: RNode): void { parent.removeChild(oldChild); } | 
					
						
							|  |  |  |   selectRootElement(selectorOrNode: string|any): RElement { | 
					
						
							|  |  |  |     return ({} as any); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   setAttribute(el: RElement, name: string, value: string, namespace?: string|null): void {} | 
					
						
							|  |  |  |   removeAttribute(el: RElement, name: string, namespace?: string|null): void {} | 
					
						
							|  |  |  |   addClass(el: RElement, name: string): void {} | 
					
						
							|  |  |  |   removeClass(el: RElement, name: string): void {} | 
					
						
							|  |  |  |   setStyle( | 
					
						
							|  |  |  |       el: RElement, style: string, value: any, | 
					
						
							|  |  |  |       flags?: RendererStyleFlags2|RendererStyleFlags3): void {} | 
					
						
							|  |  |  |   removeStyle(el: RElement, style: string, flags?: RendererStyleFlags2|RendererStyleFlags3): void {} | 
					
						
							|  |  |  |   setProperty(el: RElement, name: string, value: any): void {} | 
					
						
							|  |  |  |   setValue(node: RText, value: string): void {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // TODO(misko): Deprecate in favor of addEventListener/removeEventListener
 | 
					
						
							|  |  |  |   listen(target: RNode, eventName: string, callback: (event: any) => boolean | void): () => void { | 
					
						
							|  |  |  |     return () => {}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |