
committed by
Misko Hevery

parent
ede9cb7c2f
commit
1278cca883
@ -7,11 +7,11 @@
|
||||
*/
|
||||
|
||||
import {ViewEncapsulation} from '../../src/core';
|
||||
import {E, T, b, defineComponent, e, markDirty, r, t} from '../../src/render3/index';
|
||||
import {C, E, T, V, b, cR, cr, defineComponent, e, markDirty, p, r, t, v} from '../../src/render3/index';
|
||||
import {createRendererType2} from '../../src/view/index';
|
||||
|
||||
import {getRendererFactory2} from './imported_renderer2';
|
||||
import {containerEl, renderComponent, requestAnimationFrame, toHtml} from './render_util';
|
||||
import {containerEl, renderComponent, renderToHtml, requestAnimationFrame, toHtml} from './render_util';
|
||||
|
||||
describe('component', () => {
|
||||
class CounterComponent {
|
||||
@ -59,6 +59,70 @@ describe('component', () => {
|
||||
|
||||
});
|
||||
|
||||
describe('component with a container', () => {
|
||||
|
||||
function showItems(ctx: {items: string[]}, cm: boolean) {
|
||||
if (cm) {
|
||||
C(0);
|
||||
}
|
||||
cR(0);
|
||||
{
|
||||
for (const item of ctx.items) {
|
||||
const cm0 = V(0);
|
||||
{
|
||||
if (cm0) {
|
||||
T(0);
|
||||
}
|
||||
t(0, b(item));
|
||||
}
|
||||
v();
|
||||
}
|
||||
}
|
||||
cr();
|
||||
}
|
||||
|
||||
class WrapperComponent {
|
||||
items: string[];
|
||||
static ngComponentDef = defineComponent({
|
||||
type: WrapperComponent,
|
||||
tag: 'wrapper',
|
||||
template: function ChildComponentTemplate(ctx: {items: string[]}, cm: boolean) {
|
||||
if (cm) {
|
||||
C(0);
|
||||
}
|
||||
cR(0);
|
||||
{
|
||||
const cm0 = V(0);
|
||||
{ showItems({items: ctx.items}, cm0); }
|
||||
v();
|
||||
}
|
||||
cr();
|
||||
},
|
||||
factory: () => new WrapperComponent,
|
||||
inputs: {items: 'items'}
|
||||
});
|
||||
}
|
||||
|
||||
function template(ctx: {items: string[]}, cm: boolean) {
|
||||
if (cm) {
|
||||
E(0, WrapperComponent);
|
||||
e();
|
||||
}
|
||||
p(0, 'items', b(ctx.items));
|
||||
WrapperComponent.ngComponentDef.h(1, 0);
|
||||
r(1, 0);
|
||||
}
|
||||
|
||||
it('should re-render on input change', () => {
|
||||
const ctx: {items: string[]} = {items: ['a']};
|
||||
expect(renderToHtml(template, ctx)).toEqual('<wrapper>a</wrapper>');
|
||||
|
||||
ctx.items = [...ctx.items, 'b'];
|
||||
expect(renderToHtml(template, ctx)).toEqual('<wrapper>ab</wrapper>');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// TODO: add tests with Native once tests are run in real browser (domino doesn't support shadow
|
||||
// root)
|
||||
describe('encapsulation', () => {
|
||||
|
@ -377,6 +377,61 @@ describe('content projection', () => {
|
||||
expect(toHtml(parent)).toEqual('<child><div></div></child>');
|
||||
});
|
||||
|
||||
it('should support projection in embedded views when ng-content is a root node of an embedded view, with other nodes after',
|
||||
() => {
|
||||
let childCmptInstance: any;
|
||||
|
||||
/**
|
||||
* <div>
|
||||
* % if (!skipContent) {
|
||||
* before-<ng-content></ng-content>-after
|
||||
* % }
|
||||
* </div>
|
||||
*/
|
||||
const Child = createComponent('child', function(ctx: any, cm: boolean) {
|
||||
if (cm) {
|
||||
pD(0);
|
||||
E(1, 'div');
|
||||
{ C(2); }
|
||||
e();
|
||||
}
|
||||
cR(2);
|
||||
{
|
||||
if (!ctx.skipContent) {
|
||||
if (V(0)) {
|
||||
T(0, 'before-');
|
||||
P(1, 0);
|
||||
T(2, '-after');
|
||||
}
|
||||
v();
|
||||
}
|
||||
}
|
||||
cr();
|
||||
});
|
||||
|
||||
/**
|
||||
* <child>content</child>
|
||||
*/
|
||||
const Parent = createComponent('parent', function(ctx: any, cm: boolean) {
|
||||
if (cm) {
|
||||
E(0, Child);
|
||||
{
|
||||
childCmptInstance = m(1);
|
||||
T(2, 'content');
|
||||
}
|
||||
e();
|
||||
}
|
||||
Child.ngComponentDef.h(1, 0);
|
||||
r(1, 0);
|
||||
});
|
||||
const parent = renderComponent(Parent);
|
||||
expect(toHtml(parent)).toEqual('<child><div>before-content-after</div></child>');
|
||||
|
||||
childCmptInstance.skipContent = true;
|
||||
detectChanges(parent);
|
||||
expect(toHtml(parent)).toEqual('<child><div></div></child>');
|
||||
});
|
||||
|
||||
it('should project nodes into the last ng-content', () => {
|
||||
/**
|
||||
* <div><ng-content></ng-content></div>
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {C, E, NC, T, V, a, b, b1, b2, b3, b4, b5, b6, b7, b8, bV, cR, cr, defineComponent, e, k, m, p, r, s, t, v} from '../../src/render3/index';
|
||||
import {C, E, NC, P, T, V, a, b, b1, b2, b3, b4, b5, b6, b7, b8, bV, cR, cr, defineComponent, e, k, m, p, pD, r, s, t, v} from '../../src/render3/index';
|
||||
import {NO_CHANGE} from '../../src/render3/instructions';
|
||||
|
||||
import {containerEl, renderToHtml} from './render_util';
|
||||
@ -393,6 +393,142 @@ describe('render3 integration test', () => {
|
||||
|
||||
});
|
||||
|
||||
describe('tree', () => {
|
||||
interface Tree {
|
||||
beforeLabel?: string;
|
||||
subTrees?: Tree[];
|
||||
afterLabel?: string;
|
||||
}
|
||||
|
||||
interface ParentCtx {
|
||||
beforeTree: Tree;
|
||||
projectedTree: Tree;
|
||||
afterTree: Tree;
|
||||
}
|
||||
|
||||
function showLabel(ctx: {label: string | undefined}, cm: boolean) {
|
||||
if (cm) {
|
||||
C(0);
|
||||
}
|
||||
cR(0);
|
||||
{
|
||||
if (ctx.label != null) {
|
||||
if (V(0)) {
|
||||
T(0);
|
||||
}
|
||||
t(0, b(ctx.label));
|
||||
v();
|
||||
}
|
||||
}
|
||||
cr();
|
||||
}
|
||||
|
||||
function showTree(ctx: {tree: Tree}, cm: boolean) {
|
||||
if (cm) {
|
||||
C(0);
|
||||
C(1);
|
||||
C(2);
|
||||
}
|
||||
cR(0);
|
||||
{
|
||||
const cm0 = V(0);
|
||||
{ showLabel({label: ctx.tree.beforeLabel}, cm0); }
|
||||
v();
|
||||
}
|
||||
cr();
|
||||
cR(1);
|
||||
{
|
||||
for (let subTree of ctx.tree.subTrees || []) {
|
||||
const cm0 = V(0);
|
||||
{ showTree({tree: subTree}, cm0); }
|
||||
v();
|
||||
}
|
||||
}
|
||||
cr();
|
||||
cR(2);
|
||||
{
|
||||
const cm0 = V(0);
|
||||
{ showLabel({label: ctx.tree.afterLabel}, cm0); }
|
||||
v();
|
||||
}
|
||||
cr();
|
||||
}
|
||||
|
||||
class ChildComponent {
|
||||
beforeTree: Tree;
|
||||
afterTree: Tree;
|
||||
static ngComponentDef = defineComponent({
|
||||
tag: 'child',
|
||||
type: ChildComponent,
|
||||
template: function ChildComponentTemplate(
|
||||
ctx: {beforeTree: Tree, afterTree: Tree}, cm: boolean) {
|
||||
if (cm) {
|
||||
pD(0);
|
||||
C(1);
|
||||
P(2, 0);
|
||||
C(3);
|
||||
}
|
||||
cR(1);
|
||||
{
|
||||
const cm0 = V(0);
|
||||
{ showTree({tree: ctx.beforeTree}, cm0); }
|
||||
v();
|
||||
}
|
||||
cr();
|
||||
cR(3);
|
||||
{
|
||||
const cm0 = V(0);
|
||||
{ showTree({tree: ctx.afterTree}, cm0); }
|
||||
v();
|
||||
}
|
||||
cr();
|
||||
},
|
||||
factory: () => new ChildComponent,
|
||||
inputs: {beforeTree: 'beforeTree', afterTree: 'afterTree'}
|
||||
});
|
||||
}
|
||||
|
||||
function parentTemplate(ctx: ParentCtx, cm: boolean) {
|
||||
if (cm) {
|
||||
E(0, ChildComponent);
|
||||
{ C(2); }
|
||||
e();
|
||||
}
|
||||
p(0, 'beforeTree', b(ctx.beforeTree));
|
||||
p(0, 'afterTree', b(ctx.afterTree));
|
||||
cR(2);
|
||||
{
|
||||
const cm0 = V(0);
|
||||
{ showTree({tree: ctx.projectedTree}, cm0); }
|
||||
v();
|
||||
}
|
||||
cr();
|
||||
ChildComponent.ngComponentDef.h(1, 0);
|
||||
r(1, 0);
|
||||
}
|
||||
|
||||
it('should work with a tree', () => {
|
||||
|
||||
const ctx: ParentCtx = {
|
||||
beforeTree: {subTrees: [{beforeLabel: 'a'}]},
|
||||
projectedTree: {beforeLabel: 'p'},
|
||||
afterTree: {afterLabel: 'z'}
|
||||
};
|
||||
expect(renderToHtml(parentTemplate, ctx)).toEqual('<child>apz</child>');
|
||||
ctx.projectedTree = {subTrees: [{}, {}, {subTrees: [{}, {}]}, {}]};
|
||||
ctx.beforeTree.subTrees !.push({afterLabel: 'b'});
|
||||
expect(renderToHtml(parentTemplate, ctx)).toEqual('<child>abz</child>');
|
||||
ctx.projectedTree.subTrees ![1].afterLabel = 'h';
|
||||
expect(renderToHtml(parentTemplate, ctx)).toEqual('<child>abhz</child>');
|
||||
ctx.beforeTree.subTrees !.push({beforeLabel: 'c'});
|
||||
expect(renderToHtml(parentTemplate, ctx)).toEqual('<child>abchz</child>');
|
||||
|
||||
// To check the context easily:
|
||||
// console.log(JSON.stringify(ctx));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('element bindings', () => {
|
||||
|
||||
describe('elementAttribute', () => {
|
||||
|
@ -296,7 +296,7 @@ describe('query', () => {
|
||||
expect(isViewContainerRef(query.first)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should read ElementRef with a native element pointing to comment DOM node from containers',
|
||||
it('should no longer read ElementRef with a native element pointing to comment DOM node from containers',
|
||||
() => {
|
||||
/**
|
||||
* <ng-template #foo></ng-template>
|
||||
@ -316,8 +316,7 @@ describe('query', () => {
|
||||
const cmptInstance = renderComponent(Cmpt);
|
||||
const query = (cmptInstance.query as QueryList<any>);
|
||||
expect(query.length).toBe(1);
|
||||
expect(isElementRef(query.first)).toBeTruthy();
|
||||
expect(query.first.nativeElement.nodeType).toBe(8); // Node.COMMENT_NODE = 8
|
||||
expect(query.first.nativeElement).toBe(null);
|
||||
});
|
||||
|
||||
it('should read TemplateRef from container nodes by default', () => {
|
||||
|
Reference in New Issue
Block a user