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:
parent
5b2408f0a6
commit
f00bb85b58
|
@ -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
Loading…
Reference in New Issue