refactor(ivy): migrate content spec from render3 (#32474)

Migrate the remaining `render3/content_spec.ts` to `acceptance` (some JS block ones were already migrated with `ngIf`).

PR Close #32474
This commit is contained in:
cexbrayat 2019-08-16 15:46:06 +02:00 committed by Matias Niemelä
parent 5b2408f0a6
commit f00bb85b58
2 changed files with 397 additions and 1345 deletions

View File

@ -155,6 +155,84 @@ describe('projection', () => {
`<child><div><projected-comp><p><div>Some content</div>Other content</p></projected-comp></div></child>`); `<child><div><projected-comp><p><div>Some content</div>Other content</p></projected-comp></div></child>`);
}); });
it('should project with multiple instances of a component with projection', () => {
@Component({selector: 'child', template: `<div><ng-content></ng-content></div>`})
class Child {
}
@Component({selector: 'projected-comp', template: `Before<ng-content></ng-content>After`})
class ProjectedComp {
}
@Component({
selector: 'parent',
template: `
<child>
<projected-comp><div>A</div><p>123</p></projected-comp>
<projected-comp><div>B</div><p>456</p></projected-comp>
</child>`,
})
class Parent {
}
TestBed.configureTestingModule({declarations: [Parent, Child, ProjectedComp]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toBe(
'<child><div>' +
'<projected-comp>Before<div>A</div><p>123</p>After</projected-comp>' +
'<projected-comp>Before<div>B</div><p>456</p>After</projected-comp>' +
'</div></child>');
});
it('should re-project with multiple instances of a component with projection', () => {
@Component({selector: 'child', template: `<div><ng-content></ng-content></div>`})
class Child {
}
@Component({selector: 'projected-comp', template: `Before<ng-content></ng-content>After`})
class ProjectedComp {
}
@Component({
selector: 'parent',
template: `
<child>
<projected-comp><div>A</div><ng-content></ng-content><p>123</p></projected-comp>
<projected-comp><div>B</div><p>456</p></projected-comp>
</child>`,
})
class Parent {
}
@Component({
selector: 'app',
template: `
<parent>**ABC**</parent>
<parent>**DEF**</parent>
`,
})
class App {
}
TestBed.configureTestingModule({declarations: [App, Parent, Child, ProjectedComp]});
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toBe(
'<parent><child><div>' +
'<projected-comp>Before<div>A</div>**ABC**<p>123</p>After</projected-comp>' +
'<projected-comp>Before<div>B</div><p>456</p>After</projected-comp>' +
'</div></child></parent>' +
'<parent><child><div>' +
'<projected-comp>Before<div>A</div>**DEF**<p>123</p>After</projected-comp>' +
'<projected-comp>Before<div>B</div><p>456</p>After</projected-comp>' +
'</div></child></parent>');
});
it('should project into dynamic views (with createEmbeddedView)', () => { it('should project into dynamic views (with createEmbeddedView)', () => {
@Component({ @Component({
selector: 'child', selector: 'child',
@ -280,6 +358,27 @@ describe('projection', () => {
.toBe(`<button></button>Some content<comp></comp>`); .toBe(`<button></button>Some content<comp></comp>`);
}); });
it('should project nodes into the last ng-content', () => {
@Component({
selector: 'child',
template: `<div><ng-content></ng-content></div>
<span><ng-content></ng-content></span>`
})
class Child {
}
@Component({selector: 'parent', template: `<child>content</child>`})
class Parent {
}
TestBed.configureTestingModule({declarations: [Parent, Child], imports: [CommonModule]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement))
.toBe('<child><div></div><span>content</span></child>');
});
// https://stackblitz.com/edit/angular-ceqmnw?file=src%2Fapp%2Fapp.component.ts // https://stackblitz.com/edit/angular-ceqmnw?file=src%2Fapp%2Fapp.component.ts
it('should project nodes into the last ng-content unrolled by ngFor', () => { it('should project nodes into the last ng-content unrolled by ngFor', () => {
@Component({ @Component({
@ -408,6 +507,64 @@ describe('projection', () => {
expect(fixture.nativeElement.querySelectorAll('div').length).toBe(0); expect(fixture.nativeElement.querySelectorAll('div').length).toBe(0);
}); });
it('should project ng-container at the content root', () => {
@Component({selector: 'child', template: `<ng-content></ng-content>`})
class Child {
}
@Component({
selector: 'parent',
template: `<child>
<ng-container>
<ng-container>content</ng-container>
</ng-container>
</child>
`
})
class Parent {
}
TestBed.configureTestingModule({declarations: [Parent, Child]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement)).toBe('<child>content</child>');
});
it('should re-project ng-container at the content root', () => {
@Component({selector: 'grand-child', template: `<ng-content></ng-content>`})
class GrandChild {
}
@Component({
selector: 'child',
template: `<grand-child>
<ng-content></ng-content>
</grand-child>`
})
class Child {
}
@Component({
selector: 'parent',
template: `<child>
<ng-container>
<ng-container>content</ng-container>
</ng-container>
</child>
`
})
class Parent {
}
TestBed.configureTestingModule({declarations: [Parent, Child, GrandChild]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement))
.toBe('<child><grand-child>content</grand-child></child>');
});
it('should handle re-projection at the root of an embedded view', () => { it('should handle re-projection at the root of an embedded view', () => {
@Component({ @Component({
selector: 'child-comp', selector: 'child-comp',
@ -442,6 +599,246 @@ describe('projection', () => {
}); });
describe('with selectors', () => { describe('with selectors', () => {
it('should project nodes using attribute selectors', () => {
@Component({
selector: 'child',
template: `<div id="first"><ng-content select="span[title=toFirst]"></ng-content></div>
<div id="second"><ng-content select="span[title=toSecond]"></ng-content></div>`,
})
class Child {
}
@Component({
selector: 'parent',
template: `<child><span title="toFirst">1</span><span title="toSecond">2</span></child>`
})
class Parent {
}
TestBed.configureTestingModule({declarations: [Child, Parent]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement))
.toEqual(
'<child><div id="first"><span title="toFirst">1</span></div><div id="second"><span title="toSecond">2</span></div></child>');
});
it('should project nodes using class selectors', () => {
@Component({
selector: 'child',
template: `<div id="first"><ng-content select="span.toFirst"></ng-content></div>
<div id="second"><ng-content select="span.toSecond"></ng-content></div>`,
})
class Child {
}
@Component({
selector: 'parent',
template: `<child><span class="toFirst">1</span><span class="toSecond">2</span></child>`
})
class Parent {
}
TestBed.configureTestingModule({declarations: [Child, Parent]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement))
.toEqual(
'<child><div id="first"><span class="toFirst">1</span></div><div id="second"><span class="toSecond">2</span></div></child>');
});
it('should project nodes using class selectors when element has multiple classes', () => {
@Component({
selector: 'child',
template: `<div id="first"><ng-content select="span.toFirst"></ng-content></div>
<div id="second"><ng-content select="span.toSecond"></ng-content></div>`
})
class Child {
}
@Component({
selector: 'parent',
template:
`<child><span class="other toFirst">1</span><span class="noise toSecond">2</span></child>`
})
class Parent {
}
TestBed.configureTestingModule({declarations: [Child, Parent]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement))
.toEqual(
'<child><div id="first"><span class="other toFirst">1</span></div><div id="second"><span class="noise toSecond">2</span></div></child>');
});
it('should project nodes into the first matching selector', () => {
@Component({
selector: 'child',
template: `<div id="first"><ng-content select="span"></ng-content></div>
<div id="second"><ng-content select="span.toSecond"></ng-content></div>`
})
class Child {
}
@Component({
selector: 'parent',
template: `<child><span class="toFirst">1</span><span class="toSecond">2</span></child>`
})
class Parent {
}
TestBed.configureTestingModule({declarations: [Child, Parent]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement))
.toEqual(
'<child><div id="first"><span class="toFirst">1</span><span class="toSecond">2</span></div><div id="second"></div></child>');
});
it('should allow mixing ng-content with and without selectors', () => {
@Component({
selector: 'child',
template: `<div id="first"><ng-content select="span.toFirst"></ng-content></div>
<div id="second"><ng-content></ng-content></div>`
})
class Child {
}
@Component({
selector: 'parent',
template:
`<child><span class="toFirst">1</span><span>remaining</span>more remaining</child>`
})
class Parent {
}
TestBed.configureTestingModule({declarations: [Child, Parent]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement))
.toEqual(
'<child><div id="first"><span class="toFirst">1</span></div><div id="second"><span>remaining</span>more remaining</div></child>');
});
it('should allow mixing ng-content with and without selectors - ng-content first', () => {
@Component({
selector: 'child',
template: `<div id="first"><ng-content></ng-content></div>
<div id="second"><ng-content select="span.toSecond"></ng-content></div>`
})
class Child {
}
@Component({
selector: 'parent',
template: `<child><span>1</span><span class="toSecond">2</span>remaining</child>`
})
class Parent {
}
TestBed.configureTestingModule({declarations: [Child, Parent]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement))
.toEqual(
'<child><div id="first"><span>1</span>remaining</div><div id="second"><span class="toSecond">2</span></div></child>');
});
/**
* Descending into projected content for selector-matching purposes is not supported
* today: http://plnkr.co/edit/MYQcNfHSTKp9KvbzJWVQ?p=preview
*/
it('should not descend into re-projected content', () => {
@Component({
selector: 'grand-child',
template: `<ng-content select="span"></ng-content><hr><ng-content></ng-content>`
})
class GrandChild {
}
@Component({
selector: 'child',
template: `<grand-child>
<ng-content></ng-content>
<span>in child template</span>
</grand-child>`
})
class Child {
}
@Component({selector: 'parent', template: `<child><span>parent content</span></child>`})
class Parent {
}
TestBed.configureTestingModule({declarations: [GrandChild, Child, Parent]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement))
.toEqual(
'<child><grand-child><span>in child template</span><hr><span>parent content</span></grand-child></child>');
});
it('should not descend into re-projected content', () => {
@Component({
selector: 'card',
template:
`<ng-content select="[card-title]"></ng-content><hr><ng-content select="[card-content]"></ng-content>`
})
class Card {
}
@Component({
selector: 'card-with-title',
template: `<card>
<h1 card-title>Title</h1>
<ng-content card-content></ng-content>
</card>`
})
class CardWithTitle {
}
@Component({selector: 'parent', template: `<card-with-title>content</card-with-title>`})
class Parent {
}
TestBed.configureTestingModule({declarations: [Card, CardWithTitle, Parent]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement))
.toEqual(
'<card-with-title><card><h1 card-title="">Title</h1><hr>content</card></card-with-title>');
});
it('should not match selectors against node having ngProjectAs attribute', () => {
@Component({selector: 'child', template: `<ng-content select="div"></ng-content>`})
class Child {
}
@Component({
selector: 'parent',
template:
`<child><div ngProjectAs="span">should not project</div><div>should project</div></child>`
})
class Parent {
}
TestBed.configureTestingModule({declarations: [Child, Parent]});
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(getElementHtml(fixture.nativeElement))
.toEqual('<child><div>should project</div></child>');
});
// https://stackblitz.com/edit/angular-psokum?file=src%2Fapp%2Fapp.module.ts // https://stackblitz.com/edit/angular-psokum?file=src%2Fapp%2Fapp.module.ts
it('should project nodes where attribute selector matches a binding', () => { it('should project nodes where attribute selector matches a binding', () => {
@Component({ @Component({

File diff suppressed because it is too large Load Diff