/** * @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 */ import {AttributeMarker} from '@angular/compiler/src/core'; import {setup} from '@angular/compiler/test/aot/test_util'; import {compile, expectEmit} from './mock_compile'; describe('compiler compliance: directives', () => { const angularFiles = setup({ compileAngular: false, compileAnimations: false, compileFakeCore: true, }); describe('matching', () => { it('should not match directives on i18n attribute', () => { const files = { app: { 'spec.ts': ` import {Component, Directive, NgModule} from '@angular/core'; @Directive({selector: '[i18n]'}) export class I18nDirective {} @Component({selector: 'my-component', template: '
'}) export class MyComponent {} @NgModule({declarations: [I18nDirective, MyComponent]}) export class MyModule{}` } }; // MyComponent definition should be: const MyComponentDefinition = ` MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], decls: 1, vars: 0, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelement(0, "div"); } }, encapsulation: 2 }); `; const MyComponentFactory = ` MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }; `; const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); expectEmit(source, MyComponentFactory, 'Incorrect ChildComponent.ngFactoryDef'); }); it('should not match directives on i18n-prefixed attributes', () => { const files = { app: { 'spec.ts': ` import {Component, Directive, NgModule} from '@angular/core'; @Directive({selector: '[i18n]'}) export class I18nDirective {} @Directive({selector: '[i18n-foo]'}) export class I18nFooDirective {} @Directive({selector: '[foo]'}) export class FooDirective {} @Component({selector: 'my-component', template: '
'}) export class MyComponent {} @NgModule({declarations: [I18nDirective, I18nFooDirective, FooDirective, MyComponent]}) export class MyModule{}` } }; // MyComponent definition should be: const MyComponentDefinition = ` MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], decls: 1, vars: 0, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelement(0, "div"); } }, encapsulation: 2 }); `; const MyComponentFactory = ` MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }; `; const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); expectEmit(source, MyComponentFactory, 'Incorrect ChildComponent.ngFactoryDef'); }); it('should match directives on element bindings', () => { const files = { app: { 'spec.ts': ` import {Component, Directive, Input, NgModule} from '@angular/core'; @Directive({selector: '[someDirective]'}) export class SomeDirective { @Input() someDirective; } @Component({selector: 'my-component', template: '
'}) export class MyComponent {} @NgModule({declarations: [SomeDirective, MyComponent]}) export class MyModule{} ` } }; // MyComponent definition should be: const MyComponentDefinition = ` … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … consts: [[${AttributeMarker.Bindings}, "someDirective"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelement(0, "div", 0); } if (rf & 2) { $r3$.ɵɵproperty("someDirective", true); } }, … directives: [SomeDirective], encapsulation: 2 }); `; const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); }); it('should match directives on ng-templates', () => { const files = { app: { 'spec.ts': ` import {Component, Directive, NgModule, TemplateRef} from '@angular/core'; @Directive({ selector: 'ng-template[directiveA]' }) export class DirectiveA { constructor(public templateRef: TemplateRef) {} } @Component({ selector: 'my-component', template: \` Some content \` }) export class MyComponent {} @NgModule({declarations: [DirectiveA, MyComponent]}) export class MyModule{} ` } }; const MyComponentDefinition = ` … function MyComponent_ng_template_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtext(0, "Some content"); } } … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … consts: [["directiveA", ""]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtemplate(0, MyComponent_ng_template_0_Template, 1, 0, "ng-template", 0); } }, … directives: [DirectiveA], … }); `; const result = compile(files, angularFiles); expectEmit(result.source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); }); it('should match directives on ng-container', () => { const files = { app: { 'spec.ts': ` import {Component, Directive, NgModule, TemplateRef} from '@angular/core'; @Directive({ selector: 'ng-container[directiveA]' }) export class DirectiveA { constructor(public templateRef: TemplateRef) {} } @Component({ selector: 'my-component', template: \` Some content \` }) export class MyComponent {} @NgModule({declarations: [DirectiveA, MyComponent]}) export class MyModule{} ` } }; const MyComponentDefinition = ` … function MyComponent_ng_container_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelementContainerStart(0, 1); $r3$.ɵɵtext(1, "Some content"); $r3$.ɵɵelementContainerEnd(); } } … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … consts: [["directiveA", "", ${AttributeMarker.Template}, "ngIf"], ["directiveA", ""]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtemplate(0, MyComponent_ng_container_0_Template, 2, 0, "ng-container", 0); } if (rf & 2) { $r3$.ɵɵproperty("ngIf", ctx.showing); } }, … directives: [DirectiveA], … }); `; const result = compile(files, angularFiles); expectEmit(result.source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); }); it('should match directives on ng-template bindings', () => { const files = { app: { 'spec.ts': ` import {Component, Directive, Input, NgModule} from '@angular/core'; @Directive({selector: '[someDirective]'}) export class SomeDirective { @Input() someDirective; } @Component({selector: 'my-component', template: ''}) export class MyComponent {} @NgModule({declarations: [SomeDirective, MyComponent]}) export class MyModule{} ` } }; // MyComponent definition should be: const MyComponentDefinition = ` … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … consts: [[${AttributeMarker.Bindings}, "someDirective"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtemplate(0, MyComponent_ng_template_0_Template, 0, 0, "ng-template", 0); } if (rf & 2) { $r3$.ɵɵproperty("someDirective", true); } }, … directives: [SomeDirective], encapsulation: 2 }); `; const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); }); it('should match structural directives', () => { const files = { app: { 'spec.ts': ` import {Component, Directive, Input, NgModule} from '@angular/core'; @Directive({selector: '[someDirective]'}) export class SomeDirective { @Input() someDirective; } @Component({selector: 'my-component', template: '
'}) export class MyComponent {} @NgModule({declarations: [SomeDirective, MyComponent]}) export class MyModule{} ` } }; // MyComponent definition should be: const MyComponentDefinition = ` … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … consts: [[${AttributeMarker.Template}, "someDirective"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtemplate(0, MyComponent_div_0_Template, 1, 0, "div", 0); } }, … directives: [SomeDirective], encapsulation: 2 }); `; const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); }); it('should match directives on element outputs', () => { const files = { app: { 'spec.ts': ` import {Component, Directive, Output, EventEmitter, NgModule} from '@angular/core'; @Directive({selector: '[someDirective]'}) export class SomeDirective { @Output() someDirective = new EventEmitter(); } @Component({selector: 'my-component', template: '
'}) export class MyComponent { noop() {} } @NgModule({declarations: [SomeDirective, MyComponent]}) export class MyModule{} ` } }; // MyComponent definition should be: const MyComponentDefinition = ` … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … consts: [[${AttributeMarker.Bindings}, "someDirective"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelementStart(0, "div", 0); $r3$.ɵɵlistener("someDirective", function MyComponent_Template_div_someDirective_0_listener($event) { return ctx.noop(); }); $r3$.ɵɵelementEnd(); } }, … directives: [SomeDirective], encapsulation: 2 }); `; const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); }); }); });