From 1f2b39ad7d982819e025baa7060f5dfd7cfda358 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 9 May 2019 19:48:19 +0200 Subject: [PATCH] test(ivy): move content projection tests to acceptance (#30357) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moves all manual `render3` content projection tests that use the `ɵɵelementProperty` to acceptance tests. Additionally a few other content projection tests were moved over to acceptance. Eventually we'll be able to move all remaining content projection tests to acceptance. PR Close #30357 --- packages/core/test/acceptance/content_spec.ts | 384 +++++++++- packages/core/test/render3/content_spec.ts | 708 +----------------- 2 files changed, 385 insertions(+), 707 deletions(-) diff --git a/packages/core/test/acceptance/content_spec.ts b/packages/core/test/acceptance/content_spec.ts index dff0702576..c84aa1d5fc 100644 --- a/packages/core/test/acceptance/content_spec.ts +++ b/packages/core/test/acceptance/content_spec.ts @@ -6,11 +6,393 @@ * found in the LICENSE file at https://angular.io/license */ -import {ChangeDetectorRef, Component, Directive} from '@angular/core'; +import {CommonModule} from '@angular/common'; +import {ChangeDetectorRef, Component, Directive, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core'; +import {Input} from '@angular/core/src/metadata'; import {TestBed} from '@angular/core/testing'; +import {By} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; describe('projection', () => { + + function getElementHtml(element: HTMLElement) { + return element.innerHTML.replace(//g, '') + .replace(/\sng-reflect-\S*="[^"]*"/g, ''); + } + + it('should project content', () => { + @Component({selector: 'child', template: `
`}) + class Child { + } + + @Component({selector: 'parent', template: 'content'}) + class Parent { + } + + TestBed.configureTestingModule({declarations: [Parent, Child]}); + const fixture = TestBed.createComponent(Parent); + fixture.detectChanges(); + + expect(fixture.nativeElement.innerHTML).toBe(`
content
`); + }); + + it('should project content when is at a template root', () => { + @Component({ + selector: 'child', + template: '', + }) + class Child { + } + + @Component({ + selector: 'parent', + template: 'content', + }) + class Parent { + } + + TestBed.configureTestingModule({declarations: [Parent, Child]}); + const fixture = TestBed.createComponent(Parent); + fixture.detectChanges(); + + expect(fixture.nativeElement.innerHTML).toBe(`content`); + }); + + it('should project content with siblings', () => { + @Component({selector: 'child', template: ''}) + class Child { + } + + @Component({selector: 'parent', template: `before
content
after
`}) + class Parent { + } + + + TestBed.configureTestingModule({declarations: [Parent, Child]}); + const fixture = TestBed.createComponent(Parent); + fixture.detectChanges(); + + expect(fixture.nativeElement.innerHTML).toBe(`before
content
after
`); + }); + + it('should be able to re-project content', () => { + @Component({selector: 'grand-child', template: `
`}) + class GrandChild { + } + + @Component( + {selector: 'child', template: ``}) + class Child { + } + + @Component({ + selector: 'parent', + template: `HelloWorld!`, + }) + class Parent { + } + + TestBed.configureTestingModule({declarations: [Parent, Child, GrandChild]}); + const fixture = TestBed.createComponent(Parent); + fixture.detectChanges(); + + expect(fixture.nativeElement.innerHTML) + .toBe('
HelloWorld!
'); + }); + + it('should project components', () => { + @Component({ + selector: 'child', + template: `
`, + }) + class Child { + } + + @Component({ + selector: 'projected-comp', + template: 'content', + }) + class ProjectedComp { + } + + @Component({selector: 'parent', template: ``}) + class Parent { + } + + TestBed.configureTestingModule({declarations: [Parent, Child, ProjectedComp]}); + const fixture = TestBed.createComponent(Parent); + fixture.detectChanges(); + + expect(fixture.nativeElement.innerHTML) + .toBe('
content
'); + }); + + it('should project components that have their own projection', () => { + @Component({selector: 'child', template: `
`}) + class Child { + } + + @Component({selector: 'projected-comp', template: `

`}) + class ProjectedComp { + } + + @Component({ + selector: 'parent', + template: ` + +
Some content
Other content
+
`, + }) + class Parent { + } + + TestBed.configureTestingModule({declarations: [Parent, Child, ProjectedComp]}); + const fixture = TestBed.createComponent(Parent); + fixture.detectChanges(); + + expect(fixture.nativeElement.innerHTML) + .toBe( + `

Some content
Other content

`); + }); + + it('should project into dynamic views (with createEmbeddedView)', () => { + @Component({ + selector: 'child', + template: `Before--After` + }) + class Child { + showing = false; + } + + @Component({selector: 'parent', template: `
A
Some text
`}) + class Parent { + } + + TestBed.configureTestingModule({declarations: [Parent, Child], imports: [CommonModule]}); + + const fixture = TestBed.createComponent(Parent); + const childDebugEl = fixture.debugElement.query(By.directive(Child)); + const childInstance = childDebugEl.injector.get(Child); + const childElement = childDebugEl.nativeElement as HTMLElement; + + childInstance.showing = true; + fixture.detectChanges(); + + expect(getElementHtml(childElement)).toBe(`Before-
A
Some text-After`); + + childInstance.showing = false; + fixture.detectChanges(); + + expect(getElementHtml(childElement)).toBe(`Before--After`); + + childInstance.showing = true; + fixture.detectChanges(); + expect(getElementHtml(childElement)).toBe(`Before-
A
Some text-After`); + }); + + it('should project into dynamic views with specific selectors', () => { + @Component({ + selector: 'child', + template: ` + + Before- + + + + -After` + }) + class Child { + showing = false; + } + + @Component({ + selector: 'parent', + template: ` + +
A
+ B +
+ ` + }) + class Parent { + } + + TestBed.configureTestingModule({declarations: [Parent, Child], imports: [CommonModule]}); + + const fixture = TestBed.createComponent(Parent); + const childDebugEl = fixture.debugElement.query(By.directive(Child)); + const childInstance = childDebugEl.injector.get(Child); + + childInstance.showing = true; + fixture.detectChanges(); + + expect(getElementHtml(fixture.nativeElement)) + .toBe('B Before-
A
-After
'); + + childInstance.showing = false; + fixture.detectChanges(); + expect(getElementHtml(fixture.nativeElement)) + .toBe('B Before- -After'); + + childInstance.showing = true; + fixture.detectChanges(); + expect(getElementHtml(fixture.nativeElement)) + .toBe('B Before-
A
-After
'); + }); + + it('should project if is in a template that has different declaration/insertion points', + () => { + @Component( + {selector: 'comp', template: ``}) + class Comp { + @ViewChild(TemplateRef) template !: TemplateRef; + } + + @Directive({selector: '[trigger]'}) + class Trigger { + @Input() trigger !: Comp; + + constructor(public vcr: ViewContainerRef) {} + + open() { this.vcr.createEmbeddedView(this.trigger.template); } + } + + @Component({ + selector: 'parent', + template: ` + + Some content + ` + }) + class Parent { + } + + TestBed.configureTestingModule({declarations: [Parent, Trigger, Comp]}); + + const fixture = TestBed.createComponent(Parent); + const trigger = fixture.debugElement.query(By.directive(Trigger)).injector.get(Trigger); + fixture.detectChanges(); + + expect(getElementHtml(fixture.nativeElement)).toBe(``); + + trigger.open(); + expect(getElementHtml(fixture.nativeElement)) + .toBe(`Some content`); + }); + + // https://stackblitz.com/edit/angular-ceqmnw?file=src%2Fapp%2Fapp.component.ts + it('should project nodes into the last ng-content unrolled by ngFor', () => { + @Component({ + selector: 'child', + template: + `
({{i}}):
` + }) + class Child { + } + + @Component({selector: 'parent', template: `content`}) + class Parent { + } + + TestBed.configureTestingModule({declarations: [Parent, Child], imports: [CommonModule]}); + const fixture = TestBed.createComponent(Parent); + fixture.detectChanges(); + + expect(getElementHtml(fixture.nativeElement)) + .toBe('
(0):
(1):content
'); + }); + + it('should handle projected containers inside other containers', () => { + @Component({selector: 'nested-comp', template: `
Child content
`}) + class NestedComp { + } + + @Component({ + selector: 'root-comp', + template: ``, + }) + class RootComp { + } + + @Component({ + selector: 'my-app', + template: ` + + + + + + ` + }) + class MyApp { + items = [1, 2]; + } + + TestBed.configureTestingModule( + {declarations: [MyApp, RootComp, NestedComp], imports: [CommonModule]}); + const fixture = TestBed.createComponent(MyApp); + fixture.detectChanges(); + + // expecting # of divs to be (items.length - 1), since last element is filtered out by *ngIf, + // this applies to all other assertions below + expect(fixture.nativeElement.querySelectorAll('div').length).toBe(1); + + fixture.componentInstance.items = [3, 4, 5]; + fixture.detectChanges(); + expect(fixture.nativeElement.querySelectorAll('div').length).toBe(2); + + fixture.componentInstance.items = [6, 7, 8, 9]; + fixture.detectChanges(); + expect(fixture.nativeElement.querySelectorAll('div').length).toBe(3); + }); + + describe('with selectors', () => { + // https://stackblitz.com/edit/angular-psokum?file=src%2Fapp%2Fapp.module.ts + it('should project nodes where attribute selector matches a binding', () => { + @Component({ + selector: 'child', + template: ``, + }) + class Child { + } + + @Component({ + selector: 'parent', + template: `Has title` + }) + class Parent { + } + + TestBed.configureTestingModule({declarations: [Child, Parent]}); + const fixture = TestBed.createComponent(Parent); + fixture.detectChanges(); + + expect(getElementHtml(fixture.nativeElement)) + .toEqual('Has title'); + + }); + + it('should match selectors against projected containers', () => { + @Component( + {selector: 'child', template: ``}) + class Child { + } + + @Component({template: `
content
`}) + class Parent { + value = false; + } + TestBed.configureTestingModule({declarations: [Child, Parent]}); + const fixture = TestBed.createComponent(Parent); + + fixture.componentInstance.value = true; + fixture.detectChanges(); + + expect(getElementHtml(fixture.nativeElement)) + .toEqual('
content
'); + }); + }); + it('should handle projected containers inside other containers', () => { @Component({ selector: 'child-comp', // diff --git a/packages/core/test/render3/content_spec.ts b/packages/core/test/render3/content_spec.ts index f2109372eb..49aa362f8f 100644 --- a/packages/core/test/render3/content_spec.ts +++ b/packages/core/test/render3/content_spec.ts @@ -6,231 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {QueryList, TemplateRef, ViewContainerRef} from '@angular/core'; import {SelectorFlags} from '@angular/core/src/render3/interfaces/projection'; -import {AttributeMarker, detectChanges, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵloadViewQuery, ɵɵqueryRefresh, ɵɵreference, ɵɵtemplateRefExtractor, ɵɵviewQuery} from '../../src/render3/index'; -import {ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵinterpolation1, ɵɵprojection, ɵɵprojectionDef, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all'; +import {AttributeMarker, detectChanges} from '../../src/render3/index'; +import {ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵtext} from '../../src/render3/instructions/all'; import {RenderFlags} from '../../src/render3/interfaces/definition'; - -import {NgForOf, NgIf} from './common_with_def'; import {ComponentFixture, createComponent, getDirectiveOnNode, renderComponent, toHtml} from './render_util'; describe('content projection', () => { - it('should project content', () => { - - /** - *
- */ - const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵelementStart(0, 'div'); - { ɵɵprojection(1); } - ɵɵelementEnd(); - } - }, 2); - - /** - * content - */ - const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { ɵɵtext(1, 'content'); } - ɵɵelementEnd(); - } - }, 2, 0, [Child]); - - const parent = renderComponent(Parent); - expect(toHtml(parent)).toEqual('
content
'); - }); - - it('should project content when is at a template root', () => { - /** */ - const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵprojection(0); - } - }, 1); - - /** content */ - const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { ɵɵtext(1, 'content'); } - ɵɵelementEnd(); - } - }, 2, 0, [Child]); - - const parent = renderComponent(Parent); - expect(toHtml(parent)).toEqual('content'); - }); - - it('should project content with siblings', () => { - /** */ - const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵprojection(0); - } - }, 1); - - /** - * - * before - *
content
- * after - *
- */ - const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { - ɵɵtext(1, 'before'); - ɵɵelementStart(2, 'div'); - { ɵɵtext(3, 'content'); } - ɵɵelementEnd(); - ɵɵtext(4, 'after'); - } - ɵɵelementEnd(); - } - }, 5, 0, [Child]); - - const parent = renderComponent(Parent); - expect(toHtml(parent)).toEqual('before
content
after
'); - }); - - it('should re-project content when root.', () => { - /**
*/ - const GrandChild = createComponent('grand-child', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵelementStart(0, 'div'); - { ɵɵprojection(1); } - ɵɵelementEnd(); - } - }, 2); - - /** */ - const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵelementStart(0, 'grand-child'); - { ɵɵprojection(1); } - ɵɵelementEnd(); - } - }, 2, 0, [GrandChild]); - - /** HelloWorld! */ - const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { - ɵɵelementStart(1, 'b'); - ɵɵtext(2, 'Hello'); - ɵɵelementEnd(); - ɵɵtext(3, 'World!'); - } - ɵɵelementEnd(); - } - }, 4, 0, [Child]); - - const parent = renderComponent(Parent); - expect(toHtml(parent)) - .toEqual('
HelloWorld!
'); - }); - - it('should project components', () => { - - /**
*/ - const Child = createComponent('child', (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵelementStart(0, 'div'); - { ɵɵprojection(1); } - ɵɵelementEnd(); - } - }, 2); - - const ProjectedComp = createComponent('projected-comp', (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0, 'content'); - } - }, 1); - - /** - * - * - * - */ - const Parent = createComponent('parent', (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { ɵɵelement(1, 'projected-comp'); } - ɵɵelementEnd(); - } - }, 2, 0, [Child, ProjectedComp]); - - const parent = renderComponent(Parent); - expect(toHtml(parent)) - .toEqual('
content
'); - }); - - it('should project components that have their own projection', () => { - /**
*/ - const Child = createComponent('child', (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵelementStart(0, 'div'); - { ɵɵprojection(1); } - ɵɵelementEnd(); - } - }, 2); - - /**

*/ - const ProjectedComp = createComponent('projected-comp', (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵelementStart(0, 'p'); - ɵɵprojection(1); - ɵɵelementEnd(); - } - }, 2); - - /** - * - * - *
Some content
- * Other content - *
- *
- */ - const Parent = createComponent('parent', (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { - ɵɵelementStart(1, 'projected-comp'); - { - ɵɵelementStart(2, 'div'); - ɵɵtext(3, 'Some content'); - ɵɵelementEnd(); - ɵɵtext(4, 'Other content'); - } - - ɵɵelementEnd(); - } - ɵɵelementEnd(); - } - }, 5, 0, [Child, ProjectedComp]); - - const parent = renderComponent(Parent); - expect(toHtml(parent)) - .toEqual( - '

Some content
Other content

'); - }); - it('should project containers', () => { /**
*/ const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { @@ -802,280 +585,6 @@ describe('content projection', () => { expect(toHtml(parent)).toEqual('
'); }); - it('should project into dynamic views (with createEmbeddedView)', () => { - /** - * Before- - * - * - * - * -After - */ - const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵtext(0, 'Before-'); - ɵɵtemplate(1, IfTemplate, 1, 0, 'ng-template', [AttributeMarker.Bindings, 'ngIf']); - ɵɵtext(2, '-After'); - } - if (rf & RenderFlags.Update) { - ɵɵelementProperty(1, 'ngIf', ɵɵbind(ctx.showing)); - } - - }, 3, 1, [NgIf]); - - function IfTemplate(rf1: RenderFlags, ctx: any) { - if (rf1 & RenderFlags.Create) { - ɵɵprojection(0); - } - } - - let child: {showing: boolean}; - /** - * - *
A
- * Some text - *
- */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { - ɵɵelementStart(1, 'div'); - { ɵɵtext(2, 'A'); } - ɵɵelementEnd(); - ɵɵtext(3, 'Some text'); - } - ɵɵelementEnd(); - - // testing - child = getDirectiveOnNode(0); - } - }, 4, 0, [Child]); - - const fixture = new ComponentFixture(App); - child !.showing = true; - fixture.update(); - expect(fixture.html).toEqual('Before-
A
Some text-After
'); - - child !.showing = false; - fixture.update(); - expect(fixture.html).toEqual('Before--After'); - - child !.showing = true; - fixture.update(); - expect(fixture.html).toEqual('Before-
A
Some text-After
'); - }); - - it('should project into dynamic views (with insertion)', () => { - /** - * Before- - * - * - * - * -After - */ - const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵtext(0, 'Before-'); - ɵɵtemplate(1, IfTemplate, 1, 0, 'ng-template', [AttributeMarker.Bindings, 'ngIf']); - ɵɵtext(2, '-After'); - } - if (rf & RenderFlags.Update) { - ɵɵelementProperty(1, 'ngIf', ɵɵbind(ctx.showing)); - } - - }, 3, 1, [NgIf]); - - function IfTemplate(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojection(0); - } - } - - let child: {showing: boolean}; - /** - * - *
A
- * Some text - *
- */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { - ɵɵelementStart(1, 'div'); - { ɵɵtext(2, 'A'); } - ɵɵelementEnd(); - ɵɵtext(3, 'Some text'); - } - ɵɵelementEnd(); - - // testing - child = getDirectiveOnNode(0); - } - }, 4, 0, [Child]); - - const fixture = new ComponentFixture(App); - child !.showing = true; - fixture.update(); - expect(fixture.html).toEqual('Before-
A
Some text-After
'); - - child !.showing = false; - fixture.update(); - expect(fixture.html).toEqual('Before--After'); - - child !.showing = true; - fixture.update(); - expect(fixture.html).toEqual('Before-
A
Some text-After
'); - }); - - it('should project into dynamic views with specific selectors', () => { - /** - * - * Before- - * - * - * - * -After - */ - const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef([[['div']]]); - ɵɵprojection(0); - ɵɵtext(1, 'Before-'); - ɵɵtemplate(2, IfTemplate, 1, 0, 'ng-template', [AttributeMarker.Bindings, 'ngIf']); - ɵɵtext(3, '-After'); - } - if (rf & RenderFlags.Update) { - ɵɵelementProperty(2, 'ngIf', ɵɵbind(ctx.showing)); - } - - }, 4, 1, [NgIf]); - - function IfTemplate(rf1: RenderFlags) { - if (rf1 & RenderFlags.Create) { - ɵɵprojection(0, 1); - } - } - - let child: {showing: boolean}; - /** - * - *
A
- * B - *
- */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { - ɵɵelementStart(1, 'div'); - { ɵɵtext(2, 'A'); } - ɵɵelementEnd(); - ɵɵelementStart(3, 'span'); - { ɵɵtext(4, 'B'); } - ɵɵelementEnd(); - } - ɵɵelementEnd(); - - // testing - child = getDirectiveOnNode(0); - } - }, 5, 0, [Child]); - - const fixture = new ComponentFixture(App); - child !.showing = true; - fixture.update(); - expect(fixture.html).toEqual('BBefore-
A
-After
'); - - child !.showing = false; - fixture.update(); - expect(fixture.html).toEqual('BBefore--After'); - - child !.showing = true; - fixture.update(); - expect(fixture.html).toEqual('BBefore-
A
-After
'); - }); - - it('should project if is in a template that has different declaration/insertion points', - () => { - let triggerDir !: Trigger; - - function NgTemplate(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojection(0); - } - } - - /** - * - * - * - */ - const Comp = createComponent( - 'comp', - (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵtemplate(1, NgTemplate, 1, 0, 'ng-template', null, null, ɵɵtemplateRefExtractor); - } - }, - 2, 0, [], [], - function(rf: RenderFlags, ctx: any) { - /** @ViewChild(TemplateRef) template: TemplateRef */ - if (rf & RenderFlags.Create) { - ɵɵviewQuery(TemplateRef as any, true, null); - } - if (rf & RenderFlags.Update) { - let tmp: any; - ɵɵqueryRefresh(tmp = ɵɵloadViewQuery>()) && - (ctx.template = tmp.first); - } - }); - - class Trigger { - // @Input() - trigger: any; - - constructor(public vcr: ViewContainerRef) {} - - open() { this.vcr.createEmbeddedView(this.trigger.template); } - - static ngComponentDef = ɵɵdefineDirective({ - type: Trigger, - selectors: [['', 'trigger', '']], - factory: () => triggerDir = new Trigger(ɵɵdirectiveInject(ViewContainerRef as any)), - inputs: {trigger: 'trigger'} - }); - } - - /** - * - * - * Some content - * - */ - const App = createComponent('app', (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'button', [AttributeMarker.Bindings, 'trigger']); - ɵɵelementStart(1, 'comp', null, ['comp', '']); - { ɵɵtext(3, 'Some content'); } - ɵɵelementEnd(); - } - if (rf & RenderFlags.Update) { - const comp = ɵɵreference(2); - ɵɵelementProperty(0, 'trigger', ɵɵbind(comp)); - } - }, 4, 1, [Comp, Trigger]); - - const fixture = new ComponentFixture(App); - expect(fixture.html).toEqual(``); - - triggerDir.open(); - expect(fixture.html).toEqual(`Some content`); - }); - it('should project nodes into the last ng-content', () => { /** *
@@ -1172,52 +681,6 @@ describe('content projection', () => { expect(toHtml(parent)).toEqual('
content
'); }); - // https://stackblitz.com/edit/angular-ceqmnw?file=src%2Fapp%2Fapp.component.ts - it('should project nodes into the last ng-content unrolled by ngFor', () => { - const items = [1, 2]; - - /** -
- ({{index}}): -
- */ - const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - { ɵɵtemplate(0, ForTemplate, 3, 1, 'div', [AttributeMarker.Template, 'ngFor', 'ngForOf']); } - } - if (rf & RenderFlags.Update) { - ɵɵelementProperty(0, 'ngForOf', ɵɵbind(items)); - } - }, 1, 1, [NgForOf]); - - function ForTemplate(rf1: RenderFlags, ctx: {index: number}) { - if (rf1 & RenderFlags.Create) { - ɵɵelementStart(0, 'div'); - ɵɵtext(1); - ɵɵprojection(2); - ɵɵelementEnd(); - } - if (rf1 & RenderFlags.Update) { - ɵɵtextBinding(1, ɵɵinterpolation1('(', ctx.index, '):')); - } - } - - /** - * content - */ - const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { ɵɵtext(1, 'content'); } - ɵɵelementEnd(); - } - }, 2, 0, [Child]); - - const parent = renderComponent(Parent); - expect(toHtml(parent)).toEqual('
(0):
(1):content
'); - }); - it('should project with multiple instances of a component with projection', () => { const ProjectionComp = createComponent('projection-comp', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -1441,88 +904,6 @@ describe('content projection', () => { expect(toHtml(parent)).toEqual('content'); }); - it('should handle projected containers inside other containers', () => { - //
Child content
- const NestedComp = createComponent('nested-comp', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'div'); - ɵɵtext(1, 'Child content'); - ɵɵelementEnd(); - } - }, 2, 0, []); - - // - const RootComp = createComponent('root-comp', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵprojection(0); - } - }, 1, 0, []); - - // - // - // - // - // - function MyApp_ng_container_1_child_comp_1_Template(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'nested-comp'); - } - } - function MyApp_ng_container_1_Template(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementContainerStart(0); - ɵɵtemplate( - 1, MyApp_ng_container_1_child_comp_1_Template, 1, 0, 'nested-comp', - [AttributeMarker.Template, 'ngIf']); - ɵɵelementContainerEnd(); - } - if (rf & RenderFlags.Update) { - const last_r2 = ctx.last; - ɵɵelementProperty(1, 'ngIf', ɵɵbind(!last_r2)); - } - } - let myAppInstance: MyApp; - class MyApp { - items = [1, 2]; - - static ngComponentDef = ɵɵdefineComponent({ - type: MyApp, - selectors: [['', 'my-app', '']], - factory: () => myAppInstance = new MyApp(), - consts: 2, - vars: 1, - template: function MyApp_Template(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'root-comp'); - ɵɵtemplate( - 1, MyApp_ng_container_1_Template, 2, 1, 'ng-container', - [AttributeMarker.Template, 'ngFor', 'ngForOf']); - ɵɵelementEnd(); - } - if (rf & RenderFlags.Update) { - ɵɵelementProperty(1, 'ngForOf', ɵɵbind(ctx.items)); - } - }, - directives: [NgForOf, NgIf, NestedComp, RootComp] - }); - } - const fixture = new ComponentFixture(MyApp); - fixture.update(); - - // expecting # of divs to be (items.length - 1), since last element is filtered out by *ngIf, - // this applies to all other assertions below - expect(fixture.hostElement.querySelectorAll('div').length).toBe(1); - - myAppInstance !.items = [3, 4, 5]; - fixture.update(); - expect(fixture.hostElement.querySelectorAll('div').length).toBe(2); - - myAppInstance !.items = [6, 7, 8, 9]; - fixture.update(); - expect(fixture.hostElement.querySelectorAll('div').length).toBe(3); - }); - describe('with selectors', () => { it('should project nodes using attribute selectors', () => { @@ -1569,43 +950,6 @@ describe('content projection', () => { '
1
2
'); }); - // https://stackblitz.com/edit/angular-psokum?file=src%2Fapp%2Fapp.module.ts - it('should project nodes where attribute selector matches a binding', () => { - /** - * - */ - const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef([[['', 'title', '']]]); - { ɵɵprojection(0, 1); } - } - }, 1); - - /** - * - * Has title - * - */ - const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { - ɵɵelementStart(1, 'span', [AttributeMarker.Bindings, 'title']); - { ɵɵtext(2, 'Has title'); } - ɵɵelementEnd(); - } - ɵɵelementEnd(); - } - if (rf & RenderFlags.Update) { - ɵɵelementProperty(1, 'title', ɵɵbind('Some title')); - } - }, 3, 1, [Child]); - - const fixture = new ComponentFixture(Parent); - expect(fixture.html).toEqual('Has title'); - - }); - it('should project nodes using class selectors', () => { /** *
@@ -1991,54 +1335,6 @@ describe('content projection', () => { const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('
should project
'); }); - - it('should match selectors against projected containers', () => { - - /** - * - * - * - */ - const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef([[['div']]]); - ɵɵelementStart(0, 'span'); - { ɵɵprojection(1, 1); } - ɵɵelementEnd(); - } - }, 2); - - function IfTemplate(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'div'); - { ɵɵtext(1, 'content'); } - ɵɵelementEnd(); - } - } - - /** - * - *
content
- *
- */ - const Parent = createComponent('parent', function(rf: RenderFlags, ctx: {value: any}) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'child'); - { ɵɵtemplate(1, IfTemplate, 2, 0, 'div', [AttributeMarker.Template, 'ngIf']); } - ɵɵelementEnd(); - } - if (rf & RenderFlags.Update) { - ɵɵelementProperty(1, 'ngIf', ɵɵbind(ctx.value)); - } - }, 2, 1, [Child, NgIf]); - - - const fixture = new ComponentFixture(Parent); - fixture.component.value = true; - fixture.update(); - expect(fixture.html).toEqual('
content
'); - }); - }); });