test(ivy): tests for view insertion before another view (#33627)

PR Close #33627
This commit is contained in:
Pawel Kozlowski 2019-11-06 15:28:28 +01:00 committed by Kara Erickson
parent a33162bb66
commit c57759f191
1 changed files with 243 additions and 1 deletions

View File

@ -7,7 +7,7 @@
*/ */
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {ChangeDetectorRef, Component, EmbeddedViewRef, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core'; import {ChangeDetectorRef, Component, ComponentFactoryResolver, Directive, EmbeddedViewRef, Injector, NgModule, TemplateRef, ViewChild, ViewContainerRef, ViewRef} from '@angular/core';
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser'; import {By} from '@angular/platform-browser';
@ -249,4 +249,246 @@ describe('view insertion', () => {
expect(fixture.debugElement.queryAll(By.css('div.dynamic')).length).toBe(4); expect(fixture.debugElement.queryAll(By.css('div.dynamic')).length).toBe(4);
}); });
}); });
describe('before another view', () => {
@Directive({selector: '[viewInserting]', exportAs: 'vi'})
class ViewInsertingDir {
constructor(private _vcRef: ViewContainerRef) {}
insert(beforeView: ViewRef, insertTpl: TemplateRef<{}>) {
this._vcRef.insert(beforeView, 0);
this._vcRef.createEmbeddedView(insertTpl, {}, 0);
}
}
describe('before embedded view', () => {
@Component({
selector: 'test-cmpt',
template: `
<ng-template #insert>insert</ng-template>
<ng-template #before>|before</ng-template>
<div><ng-template #vi="vi" viewInserting></ng-template></div>
`
})
class TestCmpt {
@ViewChild('before', {static: true}) beforeTpl !: TemplateRef<{}>;
@ViewChild('insert', {static: true}) insertTpl !: TemplateRef<{}>;
@ViewChild('vi', {static: true}) viewInsertingDir !: ViewInsertingDir;
minutes = 10;
insert() {
const beforeView = this.beforeTpl.createEmbeddedView({});
// change-detect the "before view" to create all child views
beforeView.detectChanges();
this.viewInsertingDir.insert(beforeView, this.insertTpl);
}
}
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestCmpt, ViewInsertingDir],
imports: [CommonModule],
});
});
function createAndInsertViews(beforeTpl: string): any {
TestBed.overrideTemplate(TestCmpt, `
<ng-template #insert>insert</ng-template>
<ng-template #before>${beforeTpl}</ng-template>
<div><ng-template #vi="vi" viewInserting></ng-template></div>
`);
const fixture = TestBed.createComponent(TestCmpt);
fixture.detectChanges();
fixture.componentInstance.insert();
fixture.detectChanges();
return fixture.nativeElement;
}
it('should insert before a view with the text node as the first root node',
() => { expect(createAndInsertViews('|before').textContent).toBe('insert|before'); });
it('should insert before a view with the element as the first root node', () => {
expect(createAndInsertViews('<span>|before</span>').textContent).toBe('insert|before');
});
it('should insert before a view with the ng-container as the first root node', () => {
expect(createAndInsertViews(`
<ng-container>
<ng-container>|before</ng-container>
</ng-container>
`).textContent)
.toBe('insert|before');
});
it('should insert before a view with ICU container inside a ng-container as the first root node',
() => {
expect(
createAndInsertViews(
`<ng-container i18n>{minutes, plural, =0 {just now} =1 {one minute ago} other {|before}}</ng-container>`)
.textContent)
.toBe('insert|before');
});
it('should insert before a view with a container as the first root node', () => {
expect(createAndInsertViews(`<ng-template [ngIf]="true">|before</ng-template>`).textContent)
.toBe('insert|before');
});
it('should insert before a view with an empty container as the first root node', () => {
expect(createAndInsertViews(`<ng-template [ngIf]="true"></ng-template>`).textContent)
.toBe('insert');
});
it('should insert before a view with an empty projection as the first root node', () => {
expect(createAndInsertViews(`<ng-content></ng-content>|before`).textContent)
.toBe('insert|before');
});
it('should insert before a view with complex node structure', () => {
expect(createAndInsertViews(`
<ng-template [ngIf]="true">
<ng-container>
<ng-container>
<ng-template [ngIf]="true">|before</ng-template>
</ng-container>
</ng-container>
</ng-template>
`).textContent)
.toBe('insert|before');
});
});
describe('before embedded view with projection', () => {
@Component({
selector: 'with-content',
template: `
<ng-template #insert>insert</ng-template>
<ng-template #before><ng-content></ng-content></ng-template>
<div><ng-template #vi="vi" viewInserting></ng-template></div>
`
})
class WithContentCmpt {
@ViewChild('insert', {static: true}) insertTpl !: TemplateRef<{}>;
@ViewChild('before', {static: true}) beforeTpl !: TemplateRef<{}>;
@ViewChild('vi', {static: true}) viewInsertingDir !: ViewInsertingDir;
insert() {
const beforeView = this.beforeTpl.createEmbeddedView({});
// change-detect the "before view" to create all child views
beforeView.detectChanges();
this.viewInsertingDir.insert(beforeView, this.insertTpl);
}
}
@Component({selector: 'test-cmpt', template: ''})
class TestCmpt {
@ViewChild('wc', {static: true}) withContentCmpt !: WithContentCmpt;
}
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ViewInsertingDir, WithContentCmpt, TestCmpt],
imports: [CommonModule],
});
});
it('should insert before a view with projected text nodes', () => {
TestBed.overrideTemplate(TestCmpt, `<with-content #wc>|before</with-content>`);
const fixture = TestBed.createComponent(TestCmpt);
fixture.detectChanges();
fixture.componentInstance.withContentCmpt.insert();
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toBe('insert|before');
});
it('should insert before a view with projected container', () => {
TestBed.overrideTemplate(
TestCmpt,
`<with-content #wc><ng-template [ngIf]="true">|before</ng-template></with-content>`);
const fixture = TestBed.createComponent(TestCmpt);
fixture.detectChanges();
fixture.componentInstance.withContentCmpt.insert();
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toBe('insert|before');
});
});
describe('before component view', () => {
@Directive({selector: '[viewInserting]', exportAs: 'vi'})
class ViewInsertingDir {
constructor(private _vcRef: ViewContainerRef) {}
insert(beforeView: ViewRef, insertTpl: TemplateRef<{}>) {
this._vcRef.insert(beforeView, 0);
this._vcRef.createEmbeddedView(insertTpl, {}, 0);
}
}
@Component({selector: 'dynamic-cmpt', template: '|before'})
class DynamicComponent {
}
it('should insert in front a dynamic component view', () => {
@Component({
selector: 'test-cmpt',
template: `
<ng-template #insert>insert</ng-template>
<div><ng-template #vi="vi" viewInserting></ng-template></div>
`
})
class TestCmpt {
@ViewChild('insert', {static: true}) insertTpl !: TemplateRef<{}>;
@ViewChild('vi', {static: true}) viewInsertingDir !: ViewInsertingDir;
constructor(private _cfr: ComponentFactoryResolver, private _injector: Injector) {}
insert() {
// create a dynamic component view to act as an "insert before" view
const componentFactory = this._cfr.resolveComponentFactory(DynamicComponent);
const beforeView = componentFactory.create(this._injector).hostView;
// change-detect the "before view" to create all child views
beforeView.detectChanges();
this.viewInsertingDir.insert(beforeView, this.insertTpl);
}
}
@NgModule({
declarations: [TestCmpt, ViewInsertingDir, DynamicComponent],
imports: [CommonModule],
entryComponents: [DynamicComponent]
})
class TestModule {
}
TestBed.configureTestingModule({imports: [TestModule]});
const fixture = TestBed.createComponent(TestCmpt);
fixture.detectChanges();
fixture.componentInstance.insert();
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toBe('insert|before');
});
});
});
}); });