/** * @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 {ChangeDetectorRef, Component, Directive} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; describe('projection', () => { it('should handle projected containers inside other containers', () => { @Component({ selector: 'child-comp', // template: '' }) class ChildComp { } @Component({ selector: 'root-comp', // template: '' }) class RootComp { } @Component({ selector: 'my-app', template: ` {{ item }}| ` }) class MyApp { items: number[] = [1, 2, 3]; } TestBed.configureTestingModule({declarations: [ChildComp, RootComp, MyApp]}); const fixture = TestBed.createComponent(MyApp); fixture.detectChanges(); // expecting # of elements to be (items.length - 1), since last element is filtered out by // *ngIf, this applies to all other assertions below expect(fixture.nativeElement).toHaveText('1|2|'); fixture.componentInstance.items = [4, 5]; fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('4|'); fixture.componentInstance.items = [6, 7, 8, 9]; fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('6|7|8|'); }); it('should project content if the change detector has been detached', () => { @Component({selector: 'my-comp', template: ''}) class MyComp { constructor(changeDetectorRef: ChangeDetectorRef) { changeDetectorRef.detach(); } } @Component({ selector: 'my-app', template: `

hello

` }) class MyApp { } TestBed.configureTestingModule({declarations: [MyComp, MyApp]}); const fixture = TestBed.createComponent(MyApp); fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('hello'); }); it('should support ngProjectAs on elements (including )', () => { @Component({ selector: 'card', template: ` --- ` }) class Card { } @Component({ selector: 'card-with-title', template: `

Title

` }) class CardWithTitle { } @Component({ selector: 'app', template: ` content ` }) class App { } TestBed.configureTestingModule({declarations: [Card, CardWithTitle, App]}); const fixture = TestBed.createComponent(App); fixture.detectChanges(); // Compare the text output, because Ivy and ViewEngine produce slightly different HTML. expect(fixture.nativeElement.textContent).toContain('Title --- content'); }); it('should not match multiple selectors in ngProjectAs', () => { @Component({ selector: 'card', template: ` content ` }) class Card { } @Component({ template: `

Title

` }) class App { } TestBed.configureTestingModule({declarations: [Card, App]}); const fixture = TestBed.createComponent(App); fixture.detectChanges(); // Compare the text output, because Ivy and ViewEngine produce slightly different HTML. expect(fixture.nativeElement.textContent).not.toContain('Title content'); }); describe('on inline templates (e.g. *ngIf)', () => { it('should work when matching the element name', () => { let divDirectives = 0; @Component({selector: 'selector-proj', template: ''}) class SelectedNgContentComp { } @Directive({selector: 'div'}) class DivDirective { constructor() { divDirectives++; } } @Component({ selector: 'main-selector', template: '
Hello world!
' }) class SelectorMainComp { } TestBed.configureTestingModule( {declarations: [DivDirective, SelectedNgContentComp, SelectorMainComp]}); const fixture = TestBed.createComponent(SelectorMainComp); fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('Hello world!'); expect(divDirectives).toEqual(1); }); it('should work when matching attributes', () => { let xDirectives = 0; @Component({selector: 'selector-proj', template: ''}) class SelectedNgContentComp { } @Directive({selector: '[x]'}) class XDirective { constructor() { xDirectives++; } } @Component({ selector: 'main-selector', template: '
Hello world!
' }) class SelectorMainComp { } TestBed.configureTestingModule( {declarations: [XDirective, SelectedNgContentComp, SelectorMainComp]}); const fixture = TestBed.createComponent(SelectorMainComp); fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('Hello world!'); expect(xDirectives).toEqual(1); }); it('should work when matching classes', () => { let xDirectives = 0; @Component({selector: 'selector-proj', template: ''}) class SelectedNgContentComp { } @Directive({selector: '.x'}) class XDirective { constructor() { xDirectives++; } } @Component({ selector: 'main-selector', template: '
Hello world!
' }) class SelectorMainComp { } TestBed.configureTestingModule( {declarations: [XDirective, SelectedNgContentComp, SelectorMainComp]}); const fixture = TestBed.createComponent(SelectorMainComp); fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('Hello world!'); expect(xDirectives).toEqual(1); }); it('should ignore synthesized attributes (e.g. ngTrackBy)', () => { @Component( {selector: 'selector-proj', template: ''}) class SelectedNgContentComp { } @Component({ selector: 'main-selector', template: 'inline(
{{item.name}}
)' + 'ng-template(
{{item.name}}
)' }) class SelectorMainComp { items = [ {id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 3, name: 'three'}, ]; getItemId(item: {id: number}) { return item.id; } } TestBed.configureTestingModule({declarations: [SelectedNgContentComp, SelectorMainComp]}); const fixture = TestBed.createComponent(SelectorMainComp); fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('inline()ng-template(onetwothree)'); }); describe('on containers', () => { it('should work when matching attributes', () => { let xDirectives = 0; @Component({selector: 'selector-proj', template: ''}) class SelectedNgContentComp { } @Directive({selector: '[x]'}) class XDirective { constructor() { xDirectives++; } } @Component({ selector: 'main-selector', template: 'Hello world!' }) class SelectorMainComp { } TestBed.configureTestingModule( {declarations: [XDirective, SelectedNgContentComp, SelectorMainComp]}); const fixture = TestBed.createComponent(SelectorMainComp); fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('Hello world!'); expect(xDirectives).toEqual(1); }); it('should work when matching classes', () => { let xDirectives = 0; @Component({selector: 'selector-proj', template: ''}) class SelectedNgContentComp { } @Directive({selector: '.x'}) class XDirective { constructor() { xDirectives++; } } @Component({ selector: 'main-selector', template: 'Hello world!' }) class SelectorMainComp { } TestBed.configureTestingModule( {declarations: [XDirective, SelectedNgContentComp, SelectorMainComp]}); const fixture = TestBed.createComponent(SelectorMainComp); fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('Hello world!'); expect(xDirectives).toEqual(1); }); }); }); });