/** * @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"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 1, vars: 0, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelement(0, "div"); } }, encapsulation: 2 }); `; const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); }); 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"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 1, vars: 0, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelement(0, "div"); } }, encapsulation: 2 }); `; const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); }); 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 = ` … const _c0 = [${AttributeMarker.Bindings}, "someDirective"]; … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelement(0, "div", _c0); } if (rf & 2) { $r3$.ɵɵselect(0); $r3$.ɵɵelementProperty(0, "someDirective", $r3$.ɵɵbind(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 = ` … const $_c0$ = ["directiveA", ""]; function MyComponent_ng_template_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtext(0, "Some content"); } } … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtemplate(0, MyComponent_ng_template_0_Template, 1, 0, "ng-template", $_c0$); } }, … 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 = ` … const $_c0$ = ["directiveA", "", ${AttributeMarker.Template}, "ngIf"]; const $_c1$ = ["directiveA", ""]; function MyComponent_ng_container_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelementContainerStart(0, $_c1$); $r3$.ɵɵtext(1, "Some content"); $r3$.ɵɵelementContainerEnd(); } } … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtemplate(0, MyComponent_ng_container_0_Template, 2, 0, "ng-container", $_c0$); } if (rf & 2) { $r3$.ɵɵselect(0); $r3$.ɵɵelementProperty(0, "ngIf", $r3$.ɵɵbind(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 = ` … const $c0_a0$ = [${AttributeMarker.Bindings}, "someDirective"]; … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtemplate(0, MyComponent_ng_template_0_Template, 0, 0, "ng-template", $c0_a0$); } if (rf & 2) { $r3$.ɵɵselect(0); $r3$.ɵɵelementProperty(0, "someDirective", $r3$.ɵɵbind(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 = ` … const $c0_a0$ = [${AttributeMarker.Template}, "someDirective"]; … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtemplate(0, MyComponent_div_0_Template, 1, 0, "div", $c0_a0$); } }, … 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 = ` … const $c0_a0$ = [${AttributeMarker.Bindings}, "someDirective"]; … MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelementStart(0, "div", $c0_a0$); $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'); }); }); });