| 
									
										
										
										
											2018-05-15 21:07:59 +02: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-20 15:20:12 +02:00
										 |  |  | import {AttributeMarker} from '@angular/compiler/src/core'; | 
					
						
							| 
									
										
										
										
											2018-07-12 15:10:55 -07:00
										 |  |  | import {MockDirectory, setup} from '@angular/compiler/test/aot/test_util'; | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  | import {compile, expectEmit} from './mock_compile'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | describe('compiler compliance: bindings', () => { | 
					
						
							|  |  |  |   const angularFiles = setup({ | 
					
						
							| 
									
										
										
										
											2018-08-01 09:52:34 +02:00
										 |  |  |     compileAngular: false, | 
					
						
							|  |  |  |     compileFakeCore: true, | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  |     compileAnimations: false, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('text bindings', () => { | 
					
						
							|  |  |  |     it('should generate interpolation instruction', () => { | 
					
						
							|  |  |  |       const files: MockDirectory = { | 
					
						
							|  |  |  |         app: { | 
					
						
							|  |  |  |           'example.ts': `
 | 
					
						
							|  |  |  |           import {Component, NgModule} from '@angular/core'; | 
					
						
							|  |  |  |           @Component({ | 
					
						
							|  |  |  |             selector: 'my-component', | 
					
						
							|  |  |  |             template: \`
 | 
					
						
							|  |  |  |               <div>Hello {{ name }}</div>\`
 | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class MyComponent { | 
					
						
							|  |  |  |             name = 'World'; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           @NgModule({declarations: [MyComponent]}) | 
					
						
							|  |  |  |           export class MyModule {} | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const template = `
 | 
					
						
							| 
									
										
										
										
											2018-07-12 15:10:55 -07:00
										 |  |  |       template:function MyComponent_Template(rf, $ctx$){ | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  |         if (rf & 1) { | 
					
						
							| 
									
										
										
										
											2018-08-14 16:48:58 -07:00
										 |  |  |           $i0$.ɵelementStart(0, "div"); | 
					
						
							|  |  |  |           $i0$.ɵtext(1); | 
					
						
							|  |  |  |           $i0$.ɵelementEnd(); | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (rf & 2) { | 
					
						
							| 
									
										
										
										
											2018-08-14 16:48:58 -07:00
										 |  |  |           $i0$.ɵtextBinding(1, $i0$.ɵinterpolation1("Hello ", $ctx$.name, "")); | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |       }`;
 | 
					
						
							|  |  |  |       const result = compile(files, angularFiles); | 
					
						
							|  |  |  |       expectEmit(result.source, template, 'Incorrect interpolated text binding'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('property bindings', () => { | 
					
						
							|  |  |  |     it('should generate bind instruction', () => { | 
					
						
							|  |  |  |       const files: MockDirectory = { | 
					
						
							|  |  |  |         app: { | 
					
						
							|  |  |  |           'example.ts': `
 | 
					
						
							|  |  |  |           import {Component, NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @Component({ | 
					
						
							|  |  |  |             selector: 'my-app', | 
					
						
							|  |  |  |             template: '<a [title]="title"></a>' | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class MyComponent { | 
					
						
							|  |  |  |             title = 'Hello World'; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule({declarations: [MyComponent]}) | 
					
						
							|  |  |  |           export class MyModule {}`
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const template = `
 | 
					
						
							| 
									
										
										
										
											2018-08-20 15:20:12 +02:00
										 |  |  |       const $e0_attrs$ = [${AttributeMarker.SelectOnly}, "title"]; | 
					
						
							|  |  |  |       … | 
					
						
							| 
									
										
										
										
											2018-07-12 15:10:55 -07:00
										 |  |  |       template:function MyComponent_Template(rf, $ctx$){ | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  |         if (rf & 1) { | 
					
						
							| 
									
										
										
										
											2018-08-20 15:20:12 +02:00
										 |  |  |           $i0$.ɵelement(0, "a", $e0_attrs$); | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (rf & 2) { | 
					
						
							| 
									
										
										
										
											2018-08-14 16:48:58 -07:00
										 |  |  |           $i0$.ɵelementProperty(0, "title", $i0$.ɵbind($ctx$.title)); | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |       }`;
 | 
					
						
							|  |  |  |       const result = compile(files, angularFiles); | 
					
						
							|  |  |  |       expectEmit(result.source, template, 'Incorrect property binding'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should generate interpolation instruction for {{...}} bindings', () => { | 
					
						
							|  |  |  |       const files: MockDirectory = { | 
					
						
							|  |  |  |         app: { | 
					
						
							|  |  |  |           'example.ts': `
 | 
					
						
							|  |  |  |           import {Component, NgModule} from '@angular/core'; | 
					
						
							|  |  |  |           @Component({ | 
					
						
							|  |  |  |             selector: 'my-component', | 
					
						
							|  |  |  |             template: \`
 | 
					
						
							|  |  |  |               <a title="Hello {{name}}"></a>\`
 | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class MyComponent { | 
					
						
							|  |  |  |             name = 'World'; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           @NgModule({declarations: [MyComponent]}) | 
					
						
							|  |  |  |           export class MyModule {} | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const template = `
 | 
					
						
							| 
									
										
										
										
											2018-08-20 15:20:12 +02:00
										 |  |  |       const $e0_attrs$ = [${AttributeMarker.SelectOnly}, "title"]; | 
					
						
							|  |  |  |       … | 
					
						
							| 
									
										
										
										
											2018-07-12 15:10:55 -07:00
										 |  |  |       template:function MyComponent_Template(rf, $ctx$){ | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  |         if (rf & 1) { | 
					
						
							| 
									
										
										
										
											2018-08-20 15:20:12 +02:00
										 |  |  |           $i0$.ɵelement(0, "a", $e0_attrs$); | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (rf & 2) { | 
					
						
							| 
									
										
										
										
											2018-08-14 16:48:58 -07:00
										 |  |  |           $i0$.ɵelementProperty(0, "title", $i0$.ɵinterpolation1("Hello ", $ctx$.name, "")); | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |       }`;
 | 
					
						
							|  |  |  |       const result = compile(files, angularFiles); | 
					
						
							|  |  |  |       expectEmit(result.source, template, 'Incorrect interpolated property binding'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-26 13:34:42 -07:00
										 |  |  |   describe('non bindable behavior', () => { | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |     const getAppFiles = (template: string = ''): MockDirectory => ({ | 
					
						
							|  |  |  |       app: { | 
					
						
							|  |  |  |         'example.ts': `
 | 
					
						
							|  |  |  |           import {Component, NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @Component({ | 
					
						
							|  |  |  |             selector: 'my-app', | 
					
						
							|  |  |  |             template: \`${template}\`
 | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class MyComponent { | 
					
						
							|  |  |  |             name = 'John Doe'; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule({declarations: [MyComponent]}) | 
					
						
							|  |  |  |           export class MyModule {}`
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should keep local ref for host element', () => { | 
					
						
							|  |  |  |       const files: MockDirectory = getAppFiles(`
 | 
					
						
							|  |  |  |         <b ngNonBindable #myRef id="my-id"> | 
					
						
							|  |  |  |           <i>Hello {{ name }}!</i> | 
					
						
							|  |  |  |         </b> | 
					
						
							|  |  |  |         {{ myRef.id }} | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const template = `
 | 
					
						
							|  |  |  |         const $_c0$ = ["id", "my-id"]; | 
					
						
							|  |  |  |         const $_c1$ = ["myRef", ""]; | 
					
						
							|  |  |  |         … | 
					
						
							|  |  |  |         template:function MyComponent_Template(rf, $ctx$){ | 
					
						
							|  |  |  |           if (rf & 1) { | 
					
						
							|  |  |  |             $i0$.ɵelementStart(0, "b", $_c0$, $_c1$); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |             $i0$.ɵdisableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |             $i0$.ɵelementStart(2, "i"); | 
					
						
							|  |  |  |             $i0$.ɵtext(3, "Hello {{ name }}!"); | 
					
						
							|  |  |  |             $i0$.ɵelementEnd(); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |             $i0$.ɵenableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |             $i0$.ɵelementEnd(); | 
					
						
							|  |  |  |             $i0$.ɵtext(4); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (rf & 2) { | 
					
						
							|  |  |  |             const $_r0$ = $i0$.ɵreference(1); | 
					
						
							|  |  |  |             $i0$.ɵtextBinding(4, $i0$.ɵinterpolation1(" ", $_r0$.id, " ")); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `;
 | 
					
						
							|  |  |  |       const result = compile(files, angularFiles); | 
					
						
							| 
									
										
										
										
											2018-09-26 14:33:48 -07:00
										 |  |  |       expectEmit(result.source, template, 'Incorrect handling of local refs for host element'); | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not have local refs for nested elements', () => { | 
					
						
							|  |  |  |       const files: MockDirectory = getAppFiles(`
 | 
					
						
							|  |  |  |        <div ngNonBindable> | 
					
						
							|  |  |  |          <input value="one" #myInput> {{ myInput.value }} | 
					
						
							|  |  |  |        </div> | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const template = `
 | 
					
						
							|  |  |  |         const $_c0$ = ["value", "one", "#myInput", ""]; | 
					
						
							|  |  |  |         … | 
					
						
							|  |  |  |         template:function MyComponent_Template(rf, $ctx$){ | 
					
						
							|  |  |  |           if (rf & 1) { | 
					
						
							|  |  |  |             $i0$.ɵelementStart(0, "div"); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |             $i0$.ɵdisableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |             $i0$.ɵelement(1, "input", $_c0$); | 
					
						
							|  |  |  |             $i0$.ɵtext(2, " {{ myInput.value }} "); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |             $i0$.ɵenableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |             $i0$.ɵelementEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `;
 | 
					
						
							|  |  |  |       const result = compile(files, angularFiles); | 
					
						
							| 
									
										
										
										
											2018-09-26 14:33:48 -07:00
										 |  |  |       expectEmit(result.source, template, 'Incorrect handling of local refs for nested elements'); | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-09-26 15:15:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should not process property bindings and listeners', () => { | 
					
						
							|  |  |  |       const files: MockDirectory = getAppFiles(`
 | 
					
						
							|  |  |  |         <div ngNonBindable> | 
					
						
							|  |  |  |           <div [id]="my-id" (click)="onclick"></div> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const template = `
 | 
					
						
							|  |  |  |         const $_c0$ = ["[id]", "my-id", "(click)", "onclick"]; | 
					
						
							|  |  |  |         … | 
					
						
							|  |  |  |         template:function MyComponent_Template(rf, $ctx$){ | 
					
						
							|  |  |  |           if (rf & 1) { | 
					
						
							|  |  |  |             $i0$.ɵelementStart(0, "div"); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |             $i0$.ɵdisableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 15:15:06 -07:00
										 |  |  |             $i0$.ɵelement(1, "div", $_c0$); | 
					
						
							| 
									
										
										
										
											2018-09-26 21:09:03 -07:00
										 |  |  |             $i0$.ɵenableBindings(); | 
					
						
							| 
									
										
										
										
											2018-09-26 15:15:06 -07:00
										 |  |  |             $i0$.ɵelementEnd(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `;
 | 
					
						
							|  |  |  |       const result = compile(files, angularFiles); | 
					
						
							| 
									
										
										
										
											2018-09-26 16:02:40 -07:00
										 |  |  |       expectEmit(result.source, template, 'Incorrect handling of property bindings and listeners'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not generate extra instructions for elements with no children', () => { | 
					
						
							|  |  |  |       const files: MockDirectory = getAppFiles(`
 | 
					
						
							|  |  |  |         <div ngNonBindable></div> | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const template = `
 | 
					
						
							|  |  |  |         template:function MyComponent_Template(rf, $ctx$){ | 
					
						
							|  |  |  |           if (rf & 1) { | 
					
						
							|  |  |  |             $i0$.ɵelement(0, "div"); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `;
 | 
					
						
							|  |  |  |       const result = compile(files, angularFiles); | 
					
						
							|  |  |  |       expectEmit(result.source, template, 'Incorrect handling of elements with no children'); | 
					
						
							| 
									
										
										
										
											2018-09-26 15:15:06 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-09-26 16:02:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-26 13:19:04 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-15 21:07:59 +02:00
										 |  |  | }); |