diff --git a/modules/benchmarks/src/largetable/render3/table.ts b/modules/benchmarks/src/largetable/render3/table.ts index 65998e56dc..7df84ed974 100644 --- a/modules/benchmarks/src/largetable/render3/table.ts +++ b/modules/benchmarks/src/largetable/render3/table.ts @@ -19,6 +19,7 @@ export class LargeTableComponent { static ngComponentDef: ComponentDefInternal = ɵdefineComponent({ type: LargeTableComponent, selectors: [['largetable']], + consts: 3, template: function(rf: ɵRenderFlags, ctx: LargeTableComponent) { if (rf & ɵRenderFlags.Create) { ɵelementStart(0, 'table'); @@ -33,7 +34,7 @@ export class LargeTableComponent { ɵcontainerRefreshStart(2); { for (let row of ctx.data) { - let rf1 = ɵembeddedViewStart(1); + let rf1 = ɵembeddedViewStart(1, 2); { if (rf1 & ɵRenderFlags.Create) { ɵelementStart(0, 'tr'); @@ -44,7 +45,7 @@ export class LargeTableComponent { ɵcontainerRefreshStart(1); { for (let cell of row) { - let rf2 = ɵembeddedViewStart(2); + let rf2 = ɵembeddedViewStart(2, 2); { if (rf2 & ɵRenderFlags.Create) { ɵelementStart(0, 'td'); diff --git a/modules/benchmarks/src/tree/render3/tree.ts b/modules/benchmarks/src/tree/render3/tree.ts index 3d1933ebd0..9503bd0789 100644 --- a/modules/benchmarks/src/tree/render3/tree.ts +++ b/modules/benchmarks/src/tree/render3/tree.ts @@ -38,6 +38,7 @@ export class TreeComponent { static ngComponentDef = ɵdefineComponent({ type: TreeComponent, selectors: [['tree']], + consts: 4, template: function(rf: ɵRenderFlags, ctx: TreeComponent) { if (rf & ɵRenderFlags.Create) { ɵelementStart(0, 'span'); @@ -53,7 +54,7 @@ export class TreeComponent { ɵcontainerRefreshStart(2); { if (ctx.data.left != null) { - let rf0 = ɵembeddedViewStart(0); + let rf0 = ɵembeddedViewStart(0, 1); { if (rf0 & ɵRenderFlags.Create) { ɵelementStart(0, 'tree'); @@ -70,7 +71,7 @@ export class TreeComponent { ɵcontainerRefreshStart(3); { if (ctx.data.right != null) { - let rf0 = ɵembeddedViewStart(0); + let rf0 = ɵembeddedViewStart(0, 1); { if (rf0 & ɵRenderFlags.Create) { ɵelementStart(0, 'tree'); @@ -99,6 +100,7 @@ export class TreeFunction { static ngComponentDef = ɵdefineComponent({ type: TreeFunction, selectors: [['tree']], + consts: 5, template: function(rf: ɵRenderFlags, ctx: TreeFunction) { // bit of a hack TreeTpl(rf, ctx.data); @@ -128,7 +130,7 @@ export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) { ɵcontainerRefreshStart(3); { if (ctx.left != null) { - let rf0 = ɵembeddedViewStart(0); + let rf0 = ɵembeddedViewStart(0, 5); { TreeTpl(rf0, ctx.left); } ɵembeddedViewEnd(); } @@ -137,7 +139,7 @@ export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) { ɵcontainerRefreshStart(4); { if (ctx.right != null) { - let rf0 = ɵembeddedViewStart(0); + let rf0 = ɵembeddedViewStart(0, 5); { TreeTpl(rf0, ctx.right); } ɵembeddedViewEnd(); } diff --git a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts index 258edfeea2..a34998a663 100644 --- a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts @@ -414,6 +414,7 @@ describe('compiler compliance', () => { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 1, template:function MyComponent_Template(rf,ctx){ if (rf & 1) { $r3$.ɵelementStart(0, "div"); @@ -467,6 +468,7 @@ describe('compiler compliance', () => { selectors: [["child"]], factory: function ChildComponent_Factory(t) { return new (t || ChildComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 1, template: function ChildComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵtext(0, "child-view"); @@ -493,6 +495,7 @@ describe('compiler compliance', () => { selectors: [["my-component"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 2, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "child", $c1$); @@ -645,10 +648,11 @@ describe('compiler compliance', () => { selectors: [["my-component"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 3, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "ul", null, $c1$); - $r3$.ɵtemplate(2, MyComponent_li_Template_2, null, $c2$); + $r3$.ɵtemplate(2, MyComponent_li_Template_2, 2, null, $c2$); $r3$.ɵelementEnd(); } }, @@ -705,6 +709,7 @@ describe('compiler compliance', () => { selectors: [["my-app"]], factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, features: [$r3$.ɵPublicFeature], + consts: 1, template: function MyApp_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "my-comp"); @@ -785,6 +790,7 @@ describe('compiler compliance', () => { selectors: [["my-app"]], factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, features: [$r3$.ɵPublicFeature], + consts: 1, template: function MyApp_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "my-comp"); @@ -847,6 +853,7 @@ describe('compiler compliance', () => { selectors: [["my-app"]], factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, features: [$r3$.ɵPublicFeature], + consts: 1, template: function MyApp_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "object-comp"); @@ -913,6 +920,7 @@ describe('compiler compliance', () => { selectors: [["my-app"]], factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, features: [$r3$.ɵPublicFeature], + consts: 1, template: function MyApp_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "nested-comp"); @@ -971,6 +979,7 @@ describe('compiler compliance', () => { selectors: [["simple"]], factory: function SimpleComponent_Factory(t) { return new (t || SimpleComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 2, template: function SimpleComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵprojectionDef(); @@ -992,6 +1001,7 @@ describe('compiler compliance', () => { selectors: [["complex"]], factory: function ComplexComponent_Factory(t) { return new (t || ComplexComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 4, template: function ComplexComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵprojectionDef($c1$, $c2$); @@ -1067,6 +1077,7 @@ describe('compiler compliance', () => { ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(0))) && (ctx.someDir = $tmp$.first)); } }, + consts: 2, template: function ViewQueryComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(1, "div", $e0_attrs$); @@ -1134,6 +1145,7 @@ describe('compiler compliance', () => { ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && ($instance$.someDirList = $tmp$)); }, features: [$r3$.ɵPublicFeature], + consts: 2, template: function ContentQueryComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵprojectionDef(); @@ -1219,6 +1231,7 @@ describe('compiler compliance', () => { selectors: [["my-app"]], factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, features: [$r3$.ɵPublicFeature], + consts: 6, template: function MyApp_Template(rf, ctx) { if (rf & 1) { $r3$.ɵtext(0); @@ -1270,6 +1283,7 @@ describe('compiler compliance', () => { selectors: [["my-component"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 3, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "input", null, $c1$); @@ -1345,7 +1359,7 @@ describe('compiler compliance', () => { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵtext(1); - $r3$.ɵtemplate(2, MyComponent_div_span_Template_2, null, $c2$); + $r3$.ɵtemplate(2, MyComponent_div_span_Template_2, 2, null, $c2$); $r3$.ɵelement(3, "span", null, $c4$); $r3$.ɵelementEnd(); } @@ -1362,11 +1376,12 @@ describe('compiler compliance', () => { selectors: [["my-component"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 6, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "div", null, $c1$); $r3$.ɵtext(2); - $r3$.ɵtemplate(3, MyComponent_div_Template_3, null, $c2$); + $r3$.ɵtemplate(3, MyComponent_div_Template_3, 5, null, $c2$); $r3$.ɵelement(4, "div", null, $c3$); } if (rf & 2) { @@ -1430,7 +1445,7 @@ describe('compiler compliance', () => { if (rf & 1) { $i0$.ɵelementStart(0, "div"); $i0$.ɵelement(1, "div", null, $c1$); - $i0$.ɵtemplate(3, MyComponent_div_span_Template_3, null, $c2$); + $i0$.ɵtemplate(3, MyComponent_div_span_Template_3, 2, null, $c2$); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -1442,7 +1457,7 @@ describe('compiler compliance', () => { // ... template:function MyComponent_Template(rf, ctx){ if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_div_Template_0, null, $c0$); + $i0$.ɵtemplate(0, MyComponent_div_Template_0, 4, null, $c0$); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items)); @@ -1506,6 +1521,7 @@ describe('compiler compliance', () => { factory: function LifecycleComp_Factory(t) { return new (t || LifecycleComp)(); }, inputs: {nameMin: "name"}, features: [$r3$.ɵPublicFeature, $r3$.ɵNgOnChangesFeature], + consts: 0, template: function LifecycleComp_Template(rf, ctx) {} });`; @@ -1515,6 +1531,7 @@ describe('compiler compliance', () => { selectors: [["simple-layout"]], factory: function SimpleLayout_Factory(t) { return new (t || SimpleLayout)(); }, features: [$r3$.ɵPublicFeature], + consts: 2, template: function SimpleLayout_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "lifecycle-comp"); @@ -1643,11 +1660,12 @@ describe('compiler compliance', () => { selectors: [["my-component"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 2, template: function MyComponent_Template(rf, ctx){ if (rf & 1) { $r3$.ɵnamespaceSVG(); $r3$.ɵelementStart(0,"svg"); - $r3$.ɵtemplate(1,MyComponent__svg_g_Template_1,null,$_c0$); + $r3$.ɵtemplate(1, MyComponent__svg_g_Template_1, 2, null, $_c0$); $r3$.ɵelementEnd(); } if (rf & 2) { $r3$.ɵelementProperty(1,"forOf",$r3$.ɵbind(ctx.items)); } @@ -1720,10 +1738,11 @@ describe('compiler compliance', () => { selectors: [["my-component"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 2, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "ul"); - $r3$.ɵtemplate(1, MyComponent_li_Template_1, null, $_c0$); + $r3$.ɵtemplate(1, MyComponent_li_Template_1, 2, null, $_c0$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -1801,7 +1820,7 @@ describe('compiler compliance', () => { $r3$.ɵtext(2); $r3$.ɵelementEnd(); $r3$.ɵelementStart(3, "ul"); - $r3$.ɵtemplate(4, MyComponent_li_li_Template_4, null, $c1$); + $r3$.ɵtemplate(4, MyComponent_li_li_Template_4, 2, null, $c1$); $r3$.ɵelementEnd(); $r3$.ɵelementEnd(); } @@ -1818,10 +1837,11 @@ describe('compiler compliance', () => { selectors: [["my-component"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 2, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "ul"); - $r3$.ɵtemplate(1, MyComponent_li_Template_1, null, $c1$); + $r3$.ɵtemplate(1, MyComponent_li_Template_1, 5, null, $c1$); $r3$.ɵelementEnd(); } if (rf & 2) { diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts index 38115f50a9..ddcd7e011e 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts @@ -112,7 +112,7 @@ describe('compiler compliance: listen()', () => { // ... template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_div_Template_0, null, $c0$); + $r3$.ɵtemplate(0, MyComponent_div_Template_0, 3, null, $c0$); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngIf", $i0$.ɵbind(ctx.showing)); @@ -154,6 +154,7 @@ describe('compiler compliance: listen()', () => { selectors: [["my-component"]], factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 4, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "button"); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts index 8ef0cfff8a..94589381cd 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts @@ -94,6 +94,7 @@ describe('compiler compliance: styling', () => { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 1, template: function MyComponent_Template(rf, $ctx$) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); @@ -151,6 +152,7 @@ describe('compiler compliance: styling', () => { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 1, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); @@ -246,6 +248,7 @@ describe('compiler compliance: styling', () => { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 1, template: function MyComponent_Template(rf, $ctx$) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); @@ -300,6 +303,7 @@ describe('compiler compliance: styling', () => { return new (t || MyComponent)(); }, features: [$r3$.ɵPublicFeature], + consts: 1, template: function MyComponent_Template(rf, $ctx$) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts index cb928552d7..eb4099712f 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts @@ -81,7 +81,7 @@ describe('compiler compliance: template', () => { function MyComponent_ul_li_Template_1(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "li"); - $i0$.ɵtemplate(1, MyComponent_ul_li_div_Template_1, null, _c0); + $i0$.ɵtemplate(1, MyComponent_ul_li_div_Template_1, 2, null, _c0); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -93,7 +93,7 @@ describe('compiler compliance: template', () => { function MyComponent_ul_Template_0(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "ul"); - $i0$.ɵtemplate(1, MyComponent_ul_li_Template_1, null, _c0); + $i0$.ɵtemplate(1, MyComponent_ul_li_Template_1, 2, null, _c0); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -104,7 +104,7 @@ describe('compiler compliance: template', () => { // ... template:function MyComponent_Template(rf, ctx){ if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_ul_Template_0, null, _c0); + $i0$.ɵtemplate(0, MyComponent_ul_Template_0, 2, null, _c0); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items)); @@ -155,7 +155,7 @@ describe('compiler compliance: template', () => { // ... template:function MyComponent_Template(rf, ctx){ if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_span_Template_0, null, _c0); + $i0$.ɵtemplate(0, MyComponent_span_Template_0, 2, null, _c0); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items)); @@ -211,7 +211,7 @@ describe('compiler compliance: template', () => { function MyComponent_div_Template_0(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "div"); - $i0$.ɵtemplate(1, MyComponent_div_span_Template_1, null, $c1$); + $i0$.ɵtemplate(1, MyComponent_div_span_Template_1, 2, null, $c1$); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -223,7 +223,7 @@ describe('compiler compliance: template', () => { // ... template:function MyComponent_Template(rf, ctx){ if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_div_Template_0, null, $c0$); + $i0$.ɵtemplate(0, MyComponent_div_Template_0, 2, null, $c0$); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items)); @@ -279,7 +279,7 @@ describe('compiler compliance: template', () => { function MyComponent_div_div_Template_1(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "div"); - $i0$.ɵtemplate(1, MyComponent_div_div_div_Template_1, null, _c0); + $i0$.ɵtemplate(1, MyComponent_div_div_div_Template_1, 2, null, _c0); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -291,7 +291,7 @@ describe('compiler compliance: template', () => { function MyComponent_div_Template_0(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "div"); - $i0$.ɵtemplate(1, MyComponent_div_div_Template_1, null, _c0); + $i0$.ɵtemplate(1, MyComponent_div_div_Template_1, 2, null, _c0); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -302,7 +302,7 @@ describe('compiler compliance: template', () => { // ... template:function MyComponent_Template(rf, ctx){ if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_div_Template_0, null, _c0); + $i0$.ɵtemplate(0, MyComponent_div_Template_0, 2, null, _c0); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items)); @@ -348,7 +348,7 @@ describe('compiler compliance: template', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $i0$.ɵtemplate(0, Template_0, null, $c0$); + $i0$.ɵtemplate(0, Template_0, 1, null, $c0$); } if (rf & 2) { $i0$.ɵelementProperty(0, "boundAttr", $i0$.ɵbind(ctx.b)); diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index 2615cda505..5d016fd429 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -189,13 +189,15 @@ export function compileComponentFromMetadata( const pipesUsed = new Set(); const template = meta.template; - const templateFunctionExpression = - new TemplateDefinitionBuilder( - constantPool, BindingScope.ROOT_SCOPE, 0, templateTypeName, templateName, - meta.viewQueries, directiveMatcher, directivesUsed, meta.pipes, pipesUsed, - R3.namespaceHTML) - .buildTemplateFunction( - template.nodes, [], template.hasNgContent, template.ngContentSelectors); + const templateBuilder = new TemplateDefinitionBuilder( + constantPool, BindingScope.ROOT_SCOPE, 0, templateTypeName, templateName, meta.viewQueries, + directiveMatcher, directivesUsed, meta.pipes, pipesUsed, R3.namespaceHTML); + + const templateFunctionExpression = templateBuilder.buildTemplateFunction( + template.nodes, [], template.hasNgContent, template.ngContentSelectors); + + // e.g. `consts: 2` + definitionMap.set('consts', o.literal(templateBuilder.getSlotCount())); definitionMap.set('template', templateFunctionExpression); diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index 5b166f397d..50c931414d 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -171,6 +171,10 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver // resolving bindings. t.visitAll(this, nodes); + // Nested templates must be processed before creation instructions so template() + // instructions can be generated with the correct internal const count. + this._nestedTemplateFns.forEach(buildTemplateFn => buildTemplateFn()); + // Generate all the creation mode instructions (e.g. resolve bindings in listeners) const creationStatements = this._creationCodeFns.map((fn: () => o.Statement) => fn()); @@ -208,8 +212,6 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver } } - this._nestedTemplateFns.forEach(buildTemplateFn => buildTemplateFn()); - return o.fn( // i.e. (rf: RenderFlags, ctx: any) [new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null)], @@ -727,9 +729,6 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver parameters.push(this.constantPool.getConstLiteral(o.literalArr(attributeNames), true)); } - // e.g. template(1, MyComp_Template_1) - this.creationInstruction(template.sourceSpan, R3.templateCreate, trimTrailingNulls(parameters)); - // e.g. p(1, 'forOf', ɵbind(ctx.items)); const context = o.variable(CONTEXT_NAME); template.inputs.forEach(input => { @@ -756,6 +755,12 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver templateVisitor.buildTemplateFunction(template.children, template.variables); this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName, null)); }); + + // e.g. template(1, MyComp_Template_1) + this.creationInstruction(template.sourceSpan, R3.templateCreate, () => { + parameters.splice(2, 0, o.literal(templateVisitor.getSlotCount())); + return trimTrailingNulls(parameters); + }); } // These should be handled in the template or element directly. @@ -801,6 +806,9 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver } private allocateDataSlot() { return this._dataIndex++; } + + getSlotCount() { return this._dataIndex; } + private bindingContext() { return `${this._bindingContext++}`; } // Bindings must only be resolved after all local refs have been visited, so all diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index 13fbb9d9fa..fb29742060 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -18,7 +18,7 @@ import {CLEAN_PROMISE, ROOT_DIRECTIVE_INDICES, _getComponentHostLElementNode, ba import {ComponentDef, ComponentDefInternal, ComponentType} from './interfaces/definition'; import {LElementNode} from './interfaces/node'; import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; -import {LViewData, LViewFlags, RootContext, INJECTOR, CONTEXT, TVIEW} from './interfaces/view'; +import {LViewData, LViewFlags, RootContext, BINDING_INDEX, INJECTOR, CONTEXT, TVIEW} from './interfaces/view'; import {stringify} from './util'; @@ -107,11 +107,12 @@ export function renderComponent( const rootView: LViewData = createLViewData( rendererFactory.createRenderer(hostNode, componentDef), - createTView(-1, null, null, null, null), rootContext, + createTView(-1, null, 1, null, null, null), rootContext, componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways); rootView[INJECTOR] = opts.injector || null; const oldView = enterView(rootView, null !); + rootView[BINDING_INDEX] = rootView[TVIEW].bindingStartIndex; let elementNode: LElementNode; let component: T; try { diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index 4b6a52ee60..9029571aab 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -22,7 +22,7 @@ import {baseDirectiveCreate, createLNode, createLViewData, createTView, elementC import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition'; import {LElementNode, TNode, TNodeType} from './interfaces/node'; import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; -import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view'; +import {BINDING_INDEX, CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view'; import {RootViewRef, ViewRef} from './view_ref'; export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver { @@ -121,12 +121,13 @@ export class ComponentFactory extends viewEngine_ComponentFactory { // Create the root view. Uses empty TView and ContentTemplate. const rootView: LViewData = createLViewData( rendererFactory.createRenderer(hostNode, this.componentDef), - createTView(-1, null, null, null, null), rootContext, + createTView(-1, null, 1, null, null, null), rootContext, this.componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways); rootView[INJECTOR] = ngModule && ngModule.injector || null; // rootView is the parent when bootstrapping const oldView = enterView(rootView, null !); + rootView[BINDING_INDEX] = rootView[TVIEW].bindingStartIndex; let component: T; let elementNode: LElementNode; diff --git a/packages/core/src/render3/definition.ts b/packages/core/src/render3/definition.ts index 373b05bbb6..b4c3542cb4 100644 --- a/packages/core/src/render3/definition.ts +++ b/packages/core/src/render3/definition.ts @@ -53,6 +53,15 @@ export function defineComponent(componentDefinition: { */ factory: () => T; + /** + * The number of nodes, local refs, and pipes in this component template. + * + * Used to calculate the length of the component's LViewData array, so we + * can pre-fill the array and set the binding start index. + */ + // TODO(kara): remove queries from this count + consts: number; + /** * Static attributes to set on host element. * @@ -245,6 +254,7 @@ export function defineComponent(componentDefinition: { const def: ComponentDefInternal = { type: type, diPublic: null, + consts: componentDefinition.consts, factory: componentDefinition.factory, template: componentDefinition.template || null !, hostBindings: componentDefinition.hostBindings || null, diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index fbf3866358..d5ce437c39 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -7,7 +7,7 @@ */ import {assertEqual, assertLessThan} from './assert'; -import {NO_CHANGE, _getViewData, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createLNode, getPreviousOrParentNode, getRenderer, initBindings, load, resetApplicationState} from './instructions'; +import {NO_CHANGE, _getViewData, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createLNode, getPreviousOrParentNode, getRenderer, load, resetApplicationState} from './instructions'; import {RENDER_PARENT} from './interfaces/container'; import {LContainerNode, LNode, TContainerNode, TElementNode, TNodeType} from './interfaces/node'; import {BINDING_INDEX, HEADER_OFFSET, TVIEW} from './interfaces/view'; @@ -293,7 +293,9 @@ function appendI18nNode(node: LNode, parentNode: LNode, previousNode: LNode) { export function i18nApply(startIndex: number, instructions: I18nInstruction[]): void { const viewData = _getViewData(); if (ngDevMode) { - assertEqual(viewData[BINDING_INDEX], -1, 'i18nApply should be called before any binding'); + assertEqual( + viewData[BINDING_INDEX], viewData[TVIEW].bindingStartIndex, + 'i18nApply should be called before any binding'); } if (!instructions) { @@ -383,7 +385,6 @@ export function i18nExpMapping( * @returns The concatenated string when any of the arguments changes, `NO_CHANGE` otherwise. */ export function i18nInterpolation1(instructions: I18nExpInstruction[], v0: any): string|NO_CHANGE { - initBindings(); const different = bindingUpdated(_getViewData()[BINDING_INDEX]++, v0); if (!different) { @@ -415,7 +416,6 @@ export function i18nInterpolation1(instructions: I18nExpInstruction[], v0: any): */ export function i18nInterpolation2(instructions: I18nExpInstruction[], v0: any, v1: any): string| NO_CHANGE { - initBindings(); const viewData = _getViewData(); const different = bindingUpdated2(viewData[BINDING_INDEX], v0, v1); viewData[BINDING_INDEX] += 2; @@ -456,7 +456,6 @@ export function i18nInterpolation2(instructions: I18nExpInstruction[], v0: any, */ export function i18nInterpolation3( instructions: I18nExpInstruction[], v0: any, v1: any, v2: any): string|NO_CHANGE { - initBindings(); const viewData = _getViewData(); const different = bindingUpdated3(viewData[BINDING_INDEX], v0, v1, v2); viewData[BINDING_INDEX] += 3; @@ -499,7 +498,6 @@ export function i18nInterpolation3( */ export function i18nInterpolation4( instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any): string|NO_CHANGE { - initBindings(); const viewData = _getViewData(); const different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); viewData[BINDING_INDEX] += 4; @@ -544,7 +542,6 @@ export function i18nInterpolation4( export function i18nInterpolation5( instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any): string| NO_CHANGE { - initBindings(); const viewData = _getViewData(); let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); different = bindingUpdated(viewData[BINDING_INDEX] + 4, v4) || different; @@ -592,7 +589,6 @@ export function i18nInterpolation5( i18nInterpolation6( instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any): string|NO_CHANGE { - initBindings(); const viewData = _getViewData(); let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); different = bindingUpdated2(viewData[BINDING_INDEX] + 4, v4, v5) || different; @@ -641,7 +637,6 @@ i18nInterpolation6( export function i18nInterpolation7( instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any): string|NO_CHANGE { - initBindings(); const viewData = _getViewData(); let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); different = bindingUpdated3(viewData[BINDING_INDEX] + 4, v4, v5, v6) || different; @@ -691,7 +686,6 @@ export function i18nInterpolation7( export function i18nInterpolation8( instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any): string|NO_CHANGE { - initBindings(); const viewData = _getViewData(); let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); different = bindingUpdated4(viewData[BINDING_INDEX] + 4, v4, v5, v6, v7) || different; @@ -733,7 +727,6 @@ export function i18nInterpolation8( */ export function i18nInterpolationV(instructions: I18nExpInstruction[], values: any[]): string| NO_CHANGE { - initBindings(); const viewData = _getViewData(); let different = false; for (let i = 0; i < values.length; i++) { diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 3b9c127458..fc83ff28f6 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -518,6 +518,7 @@ export function resetApplicationState() { * * @param hostNode Existing node to render into. * @param templateFn Template function with the instructions. + * @param consts The number of nodes, local refs, and pipes in this template * @param context to pass into the template. * @param providedRendererFactory renderer factory to use * @param host The host element node to use @@ -525,14 +526,14 @@ export function resetApplicationState() { * @param pipes Pipe defs that should be used for matching */ export function renderTemplate( - hostNode: RElement, templateFn: ComponentTemplate, context: T, + hostNode: RElement, templateFn: ComponentTemplate, consts: number, context: T, providedRendererFactory: RendererFactory3, host: LElementNode | null, directives?: DirectiveDefListOrFactory | null, pipes?: PipeDefListOrFactory | null, sanitizer?: Sanitizer | null): LElementNode { if (host == null) { resetApplicationState(); rendererFactory = providedRendererFactory; - const tView = getOrCreateTView(templateFn, directives || null, pipes || null, null); + const tView = getOrCreateTView(templateFn, consts, directives || null, pipes || null, null); host = createLNode( -1, TNodeType.Element, hostNode, null, null, createLViewData( @@ -598,6 +599,7 @@ export function renderEmbeddedTemplate( oldView = enterView(viewNode.data !, viewNode); namespaceHTML(); + viewData[BINDING_INDEX] = tView.bindingStartIndex; tView.template !(rf, context); if (rf & RenderFlags.Update) { refreshDescendantViews(); @@ -641,6 +643,7 @@ export function renderComponentOrTemplate( } if (templateFn) { namespaceHTML(); + viewData[BINDING_INDEX] = tView.bindingStartIndex; templateFn(getRenderFlags(hostView), componentOrContext !); refreshDescendantViews(); } else { @@ -723,8 +726,9 @@ export function element( */ export function elementContainerStart( index: number, attrs?: TAttributes | null, localRefs?: string[] | null): void { - ngDevMode && - assertEqual(viewData[BINDING_INDEX], -1, 'elements should be created before any bindings'); + ngDevMode && assertEqual( + viewData[BINDING_INDEX], tView.bindingStartIndex, + 'element containers should be created before any bindings'); ngDevMode && ngDevMode.rendererCreateComment++; const native = renderer.createComment(ngDevMode ? 'ng-container' : ''); @@ -768,8 +772,9 @@ export function elementContainerEnd(): void { */ export function elementStart( index: number, name: string, attrs?: TAttributes | null, localRefs?: string[] | null): void { - ngDevMode && - assertEqual(viewData[BINDING_INDEX], -1, 'elements should be created before any bindings'); + ngDevMode && assertEqual( + viewData[BINDING_INDEX], tView.bindingStartIndex, + 'elements should be created before any bindings '); ngDevMode && ngDevMode.rendererCreateElement++; @@ -1005,8 +1010,9 @@ function saveResolvedLocalsInData( * @returns TView */ function getOrCreateTView( - templateFn: ComponentTemplate, directives: DirectiveDefListOrFactory | null, - pipes: PipeDefListOrFactory | null, viewQuery: ComponentQuery| null): TView { + templateFn: ComponentTemplate, consts: number, + directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null, + viewQuery: ComponentQuery| null): TView { // TODO(misko): reading `ngPrivateData` here is problematic for two reasons // 1. It is a megamorphic call on each invocation. // 2. For nested embedded views (ngFor inside ngFor) the template instance is per @@ -1014,19 +1020,22 @@ function getOrCreateTView( // Correct solution is to only put `ngPrivateData` on the Component template // and not on embedded templates. - return templateFn.ngPrivateData || (templateFn.ngPrivateData = createTView( - -1, templateFn, directives, pipes, viewQuery) as never); + return templateFn.ngPrivateData || + (templateFn.ngPrivateData = + createTView(-1, templateFn, consts, directives, pipes, viewQuery) as never); } /** * Creates a TView instance * * @param viewIndex The viewBlockId for inline views, or -1 if it's a component/dynamic + * @param templateFn Template function + * @param consts The number of nodes, local refs, and pipes in this template * @param directives Registry of directives for this view * @param pipes Registry of pipes for this view */ export function createTView( - viewIndex: number, templateFn: ComponentTemplate| null, + viewIndex: number, templateFn: ComponentTemplate| null, consts: number, directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null, viewQuery: ComponentQuery| null): TView { ngDevMode && ngDevMode.tView++; @@ -1037,7 +1046,7 @@ export function createTView( node: null !, data: HEADER_FILLER.slice(), // Fill in to match HEADER_OFFSET in LViewData childIndex: -1, // Children set in addToViewTree(), if any - bindingStartIndex: -1, // Set in initBindings() + bindingStartIndex: HEADER_OFFSET + consts, directives: null, firstTemplatePass: true, initHooks: null, @@ -1137,7 +1146,8 @@ export function hostElement( const node = createLNode( 0, TNodeType.Element, rNode, null, null, createLViewData( - renderer, getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs, def.viewQuery), + renderer, getOrCreateTView( + def.template, def.consts, def.directiveDefs, def.pipeDefs, def.viewQuery), null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer)); if (firstTemplatePass) { @@ -1590,8 +1600,9 @@ export function elementStylingMap( * @param value Value to write. This value will be stringified. */ export function text(index: number, value?: any): void { - ngDevMode && - assertEqual(viewData[BINDING_INDEX], -1, 'text nodes should be created before bindings'); + ngDevMode && assertEqual( + viewData[BINDING_INDEX], tView.bindingStartIndex, + 'text nodes should be created before any bindings'); ngDevMode && ngDevMode.rendererCreateTextNode++; const textNode = createTextNode(value, renderer); const node = createLNode(index, TNodeType.Element, textNode, null, null); @@ -1667,7 +1678,8 @@ export function directiveCreate( function addComponentLogic( directiveIndex: number, instance: T, def: ComponentDefInternal): void { - const tView = getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs, def.viewQuery); + const tView = + getOrCreateTView(def.template, def.consts, def.directiveDefs, def.pipeDefs, def.viewQuery); // Only component views should be added to the view tree directly. Embedded views are // accessed through their containers because they may be removed / re-added later. @@ -1696,8 +1708,9 @@ function addComponentLogic( export function baseDirectiveCreate( index: number, directive: T, directiveDef: DirectiveDefInternal| ComponentDefInternal): T { - ngDevMode && - assertEqual(viewData[BINDING_INDEX], -1, 'directives should be created before any bindings'); + ngDevMode && assertEqual( + viewData[BINDING_INDEX], tView.bindingStartIndex, + 'directives should be created before any bindings'); ngDevMode && assertPreviousIsParent(); Object.defineProperty( @@ -1843,6 +1856,7 @@ export function createLContainer( * * @param index The index of the container in the data array * @param templateFn Inline template + * @param consts The number of nodes, local refs, and pipes for this template * @param tagName The name of the container element, if applicable * @param attrs The attrs attached to the container, if applicable * @param localRefs A set of local reference bindings on the element. @@ -1850,14 +1864,15 @@ export function createLContainer( * Defaults to the current element associated with the local-ref. */ export function template( - index: number, templateFn: ComponentTemplate| null, tagName?: string | null, - attrs?: TAttributes | null, localRefs?: string[] | null, + index: number, templateFn: ComponentTemplate| null, consts: number, + tagName?: string | null, attrs?: TAttributes | null, localRefs?: string[] | null, localRefExtractor?: LocalRefExtractor) { // TODO: consider a separate node type for templates const node = containerInternal(index, tagName || null, attrs || null, localRefs || null); + if (firstTemplatePass) { node.tNode.tViews = - createTView(-1, templateFn, tView.directiveRegistry, tView.pipeRegistry, null); + createTView(-1, templateFn, consts, tView.directiveRegistry, tView.pipeRegistry, null); } createDirectivesAndLocals(node, localRefs, localRefExtractor); @@ -1884,9 +1899,9 @@ export function container(index: number): void { function containerInternal( index: number, tagName: string | null, attrs: TAttributes | null, localRefs: string[] | null): LContainerNode { - ngDevMode && - assertEqual( - viewData[BINDING_INDEX], -1, 'container nodes should be created before any bindings'); + ngDevMode && assertEqual( + viewData[BINDING_INDEX], tView.bindingStartIndex, + 'container nodes should be created before any bindings'); const currentParent = isParent ? previousOrParentNode : getParentLNode(previousOrParentNode) !; const lContainer = createLContainer(currentParent, viewData); @@ -2010,7 +2025,7 @@ function scanForView( * @param viewBlockId The ID of this view * @return boolean Whether or not this view is in creation mode */ -export function embeddedViewStart(viewBlockId: number): RenderFlags { +export function embeddedViewStart(viewBlockId: number, consts: number): RenderFlags { const container = (isParent ? previousOrParentNode : getParentLNode(previousOrParentNode)) as LContainerNode; ngDevMode && assertNodeType(container, TNodeType.Container); @@ -2025,8 +2040,8 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags { } else { // When we create a new LView, we always reset the state of the instructions. const newView = createLViewData( - renderer, getOrCreateEmbeddedTView(viewBlockId, container), null, LViewFlags.CheckAlways, - getCurrentSanitizer()); + renderer, getOrCreateEmbeddedTView(viewBlockId, consts, container), null, + LViewFlags.CheckAlways, getCurrentSanitizer()); if (lContainer[QUERIES]) { newView[QUERIES] = lContainer[QUERIES] !.createView(); @@ -2042,6 +2057,7 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags { } lContainer[ACTIVE_INDEX] !++; } + viewData[BINDING_INDEX] = tView.bindingStartIndex; return getRenderFlags(viewNode.data); } @@ -2053,17 +2069,19 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags { * it with the same index (since it's in the same template). * * @param viewIndex The index of the TView in TNode.tViews + * @param consts The number of nodes, local refs, and pipes in this template * @param parent The parent container in which to look for the view's static data * @returns TView */ -function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TView { +function getOrCreateEmbeddedTView( + viewIndex: number, consts: number, parent: LContainerNode): TView { ngDevMode && assertNodeType(parent, TNodeType.Container); const containerTViews = (parent !.tNode as TContainerNode).tViews as TView[]; ngDevMode && assertDefined(containerTViews, 'TView expected'); ngDevMode && assertEqual(Array.isArray(containerTViews), true, 'TViews should be in an array'); if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) { containerTViews[viewIndex] = - createTView(viewIndex, null, tView.directiveRegistry, tView.pipeRegistry, null); + createTView(viewIndex, null, consts, tView.directiveRegistry, tView.pipeRegistry, null); } return containerTViews[viewIndex]; } @@ -2443,6 +2461,7 @@ export function detectChangesInternal( const hostTView = hostView[TVIEW]; const templateFn = hostTView.template !; const viewQuery = hostTView.viewQuery; + viewData[BINDING_INDEX] = tView.bindingStartIndex; try { namespaceHTML(); @@ -2501,43 +2520,17 @@ export interface NO_CHANGE { /** A special value which designates that a value has not changed. */ export const NO_CHANGE = {} as NO_CHANGE; -/** - * Initializes the binding start index. Will get inlined. - * - * This function must be called before any binding related function is called - * (ie `bind()`, `interpolationX()`, `pureFunctionX()`) - */ -export function initBindings() { - // TODO(kara): remove this check when we have pre-filled array - if (tView.bindingStartIndex === -1) { - tView.bindingStartIndex = viewData.length; - } - if (viewData[BINDING_INDEX] === -1) { - viewData[BINDING_INDEX] = tView.bindingStartIndex; - } -} - /** * Creates a single value binding. * * @param value Value to diff */ export function bind(value: T): T|NO_CHANGE { - initBindings(); return bindingUpdated(viewData[BINDING_INDEX]++, value) ? value : NO_CHANGE; } // TODO(kara): Remove this when updating the compiler (cannot remove without breaking JIT test) -export function reserveSlots(numSlots: number) { - // Init the slots with a unique `NO_CHANGE` value so that the first change is always detected - // whether it happens or not during the first change detection pass - pure functions checks - // might be skipped when short-circuited. - viewData.length += numSlots; - viewData.fill(NO_CHANGE, -numSlots); - // We need to initialize the binding in case a `pureFunctionX` kind of binding instruction is - // called first in the update section. - initBindings(); -} +export function reserveSlots(numSlots: number) {} /** * Create interpolation bindings with a variable number of expressions. @@ -2554,7 +2547,6 @@ export function reserveSlots(numSlots: number) { export function interpolationV(values: any[]): string|NO_CHANGE { ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values'); ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values'); - initBindings(); let different = false; for (let i = 1; i < values.length; i += 2) { @@ -2583,7 +2575,6 @@ export function interpolationV(values: any[]): string|NO_CHANGE { * @param suffix static value used for concatenation only. */ export function interpolation1(prefix: string, v0: any, suffix: string): string|NO_CHANGE { - initBindings(); const different = bindingUpdated(viewData[BINDING_INDEX]++, v0); return different ? prefix + stringify(v0) + suffix : NO_CHANGE; } @@ -2591,7 +2582,6 @@ export function interpolation1(prefix: string, v0: any, suffix: string): string| /** Creates an interpolation binding with 2 expressions. */ export function interpolation2( prefix: string, v0: any, i0: string, v1: any, suffix: string): string|NO_CHANGE { - initBindings(); const different = bindingUpdated2(viewData[BINDING_INDEX], v0, v1); viewData[BINDING_INDEX] += 2; @@ -2602,7 +2592,6 @@ export function interpolation2( export function interpolation3( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): string| NO_CHANGE { - initBindings(); const different = bindingUpdated3(viewData[BINDING_INDEX], v0, v1, v2); viewData[BINDING_INDEX] += 3; @@ -2614,7 +2603,6 @@ export function interpolation3( export function interpolation4( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string): string|NO_CHANGE { - initBindings(); const different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); viewData[BINDING_INDEX] += 4; @@ -2628,7 +2616,6 @@ export function interpolation4( export function interpolation5( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, suffix: string): string|NO_CHANGE { - initBindings(); let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); different = bindingUpdated(viewData[BINDING_INDEX] + 4, v4) || different; viewData[BINDING_INDEX] += 5; @@ -2643,7 +2630,6 @@ export function interpolation5( export function interpolation6( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string): string|NO_CHANGE { - initBindings(); let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); different = bindingUpdated2(viewData[BINDING_INDEX] + 4, v4, v5) || different; viewData[BINDING_INDEX] += 6; @@ -2659,7 +2645,6 @@ export function interpolation7( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string): string| NO_CHANGE { - initBindings(); let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); different = bindingUpdated3(viewData[BINDING_INDEX] + 4, v4, v5, v6) || different; viewData[BINDING_INDEX] += 7; @@ -2675,7 +2660,6 @@ export function interpolation8( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any, suffix: string): string|NO_CHANGE { - initBindings(); let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); different = bindingUpdated4(viewData[BINDING_INDEX] + 4, v4, v5, v6, v7) || different; viewData[BINDING_INDEX] += 8; diff --git a/packages/core/src/render3/interfaces/definition.ts b/packages/core/src/render3/interfaces/definition.ts index c6bb7890ce..21bb13aa1a 100644 --- a/packages/core/src/render3/interfaces/definition.ts +++ b/packages/core/src/render3/interfaces/definition.ts @@ -201,6 +201,15 @@ export interface ComponentDef extends DirectiveDef(slotOffset: number, pureFn: () => T, thisArg?: any): T { - initBindings(); // TODO(kara): remove this check when we have pre-filled array + // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getTView().bindingStartIndex + slotOffset; return getCreationMode() ? updateBinding(bindingIndex, thisArg ? pureFn.call(thisArg) : pureFn()) : @@ -51,7 +51,7 @@ export function pureFunction0(slotOffset: number, pureFn: () => T, thisArg?: */ export function pureFunction1( slotOffset: number, pureFn: (v: any) => any, exp: any, thisArg?: any): any { - initBindings(); // TODO(kara): remove this check when we have pre-filled array + // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getTView().bindingStartIndex + slotOffset; return bindingUpdated(bindingIndex, exp) ? updateBinding(bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) : @@ -72,7 +72,7 @@ export function pureFunction1( export function pureFunction2( slotOffset: number, pureFn: (v1: any, v2: any) => any, exp1: any, exp2: any, thisArg?: any): any { - initBindings(); // TODO(kara): remove this check when we have pre-filled array + // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getTView().bindingStartIndex + slotOffset; return bindingUpdated2(bindingIndex, exp1, exp2) ? updateBinding( @@ -95,7 +95,7 @@ export function pureFunction2( export function pureFunction3( slotOffset: number, pureFn: (v1: any, v2: any, v3: any) => any, exp1: any, exp2: any, exp3: any, thisArg?: any): any { - initBindings(); // TODO(kara): remove this check when we have pre-filled array + // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getTView().bindingStartIndex + slotOffset; return bindingUpdated3(bindingIndex, exp1, exp2, exp3) ? updateBinding( @@ -120,7 +120,7 @@ export function pureFunction3( export function pureFunction4( slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any) => any, exp1: any, exp2: any, exp3: any, exp4: any, thisArg?: any): any { - initBindings(); // TODO(kara): remove this check when we have pre-filled array + // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getTView().bindingStartIndex + slotOffset; return bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4) ? updateBinding( @@ -146,7 +146,7 @@ export function pureFunction4( export function pureFunction5( slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any) => any, exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, thisArg?: any): any { - initBindings(); // TODO(kara): remove this check when we have pre-filled array + // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getTView().bindingStartIndex + slotOffset; const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4); return bindingUpdated(bindingIndex + 4, exp5) || different ? @@ -174,7 +174,7 @@ export function pureFunction5( export function pureFunction6( slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any) => any, exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, thisArg?: any): any { - initBindings(); // TODO(kara): remove this check when we have pre-filled array + // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getTView().bindingStartIndex + slotOffset; const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4); return bindingUpdated2(bindingIndex + 4, exp5, exp6) || different ? @@ -204,7 +204,7 @@ export function pureFunction7( slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any) => any, exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any, thisArg?: any): any { - initBindings(); // TODO(kara): remove this check when we have pre-filled array + // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getTView().bindingStartIndex + slotOffset; let different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4); return bindingUpdated3(bindingIndex + 4, exp5, exp6, exp7) || different ? @@ -237,7 +237,7 @@ export function pureFunction8( pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, v8: any) => any, exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any, exp8: any, thisArg?: any): any { - initBindings(); // TODO(kara): remove this check when we have pre-filled array + // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getTView().bindingStartIndex + slotOffset; const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4); return bindingUpdated4(bindingIndex + 4, exp5, exp6, exp7, exp8) || different ? @@ -263,7 +263,7 @@ export function pureFunction8( */ export function pureFunctionV( slotOffset: number, pureFn: (...v: any[]) => any, exps: any[], thisArg?: any): any { - initBindings(); // TODO(kara): remove this check when we have pre-filled array + // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings let bindingIndex = getTView().bindingStartIndex + slotOffset; let different = false; for (let i = 0; i < exps.length; i++) { diff --git a/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json b/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json index fcccc10fc6..324aafc61e 100644 --- a/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json @@ -2349,7 +2349,7 @@ "name": "camelCaseToDashCase" }, { - "name": "checkAndUpdateBinding$1" + "name": "checkAndUpdateBinding" }, { "name": "checkAndUpdateDirectiveDynamic" diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 12ba180c9c..230ba05d08 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -641,9 +641,6 @@ { "name": "hostElement" }, - { - "name": "initBindings" - }, { "name": "initChangeDetectorIfExisting" }, diff --git a/packages/core/test/render3/Inherit_definition_feature_spec.ts b/packages/core/test/render3/Inherit_definition_feature_spec.ts index a39437b603..f9dc0519a8 100644 --- a/packages/core/test/render3/Inherit_definition_feature_spec.ts +++ b/packages/core/test/render3/Inherit_definition_feature_spec.ts @@ -314,6 +314,7 @@ describe('InheritDefinitionFeature', () => { type: SuperComponent, template: () => {}, selectors: [['', 'superDir', '']], + consts: 0, factory: () => new SuperComponent() }); } diff --git a/packages/core/test/render3/basic_perf.ts b/packages/core/test/render3/basic_perf.ts index b809ef7a4a..b515ea6e04 100644 --- a/packages/core/test/render3/basic_perf.ts +++ b/packages/core/test/render3/basic_perf.ts @@ -35,6 +35,7 @@ describe('iv perf test', () => { static ngComponentDef = defineComponent({ type: Component, selectors: [['div']], + consts: 1, template: function Template(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); @@ -43,7 +44,7 @@ describe('iv perf test', () => { containerRefreshStart(0); { for (let i = 0; i < count; i++) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 2); { if (rf0 & RenderFlags.Create) { elementStart(0, 'div'); diff --git a/packages/core/test/render3/change_detection_spec.ts b/packages/core/test/render3/change_detection_spec.ts index bde9dd461b..662193086a 100644 --- a/packages/core/test/render3/change_detection_spec.ts +++ b/packages/core/test/render3/change_detection_spec.ts @@ -29,6 +29,7 @@ describe('change detection', () => { type: MyComponent, selectors: [['my-comp']], factory: () => new MyComponent(), + consts: 2, template: (rf: RenderFlags, ctx: MyComponent) => { if (rf & RenderFlags.Create) { elementStart(0, 'span'); @@ -102,6 +103,7 @@ describe('change detection', () => { type: MyComponent, selectors: [['my-comp']], factory: () => comp = new MyComponent(), + consts: 2, /** * {{ doCheckCount }} - {{ name }} * @@ -129,6 +131,7 @@ describe('change detection', () => { type: MyApp, selectors: [['my-app']], factory: () => new MyApp(), + consts: 1, /** */ template: (rf: RenderFlags, ctx: MyApp) => { if (rf & RenderFlags.Create) { @@ -207,7 +210,7 @@ describe('change detection', () => { { listener('click', () => noop()); } elementEnd(); } - }, [MyComponent]); + }, 2, [MyComponent]); const buttonParent = renderComponent(ButtonParent); expect(getRenderedText(buttonParent)).toEqual('1 - Nancy'); @@ -229,6 +232,7 @@ describe('change detection', () => { type: ButtonParent, selectors: [['button-parent']], factory: () => parent = new ButtonParent(), + consts: 2, /** {{ doCheckCount }} - */ template: (rf: RenderFlags, ctx: ButtonParent) => { if (rf & RenderFlags.Create) { @@ -248,7 +252,7 @@ describe('change detection', () => { if (rf & RenderFlags.Create) { element(0, 'button-parent'); } - }, [ButtonParent]); + }, 1, [ButtonParent]); const myButtonApp = renderComponent(MyButtonApp); expect(parent !.doCheckCount).toEqual(1); @@ -288,6 +292,7 @@ describe('change detection', () => { type: MyComp, selectors: [['my-comp']], factory: () => myComp = new MyComp(injectChangeDetectorRef()), + consts: 1, /** {{ name }} */ template: (rf: RenderFlags, ctx: MyComp) => { if (rf & RenderFlags.Create) { @@ -312,6 +317,7 @@ describe('change detection', () => { type: ParentComp, selectors: [['parent-comp']], factory: () => new ParentComp(injectChangeDetectorRef()), + consts: 2, /** * {{ doCheckCount}} - * @@ -399,7 +405,7 @@ describe('change detection', () => { if (rf & RenderFlags.Create) { element(0, 'my-comp', ['dir', '']); } - }, [MyComp, Dir]); + }, 1, [MyComp, Dir]); const app = renderComponent(MyApp); expect(getRenderedText(app)).toEqual('Nancy'); @@ -422,7 +428,7 @@ describe('change detection', () => { if (rf & RenderFlags.Update) { textBinding(1, bind(ctx.value)); } - }, [Dir]); + }, 2, [Dir]); const app = renderComponent(MyApp); app.value = 'Frank'; @@ -445,6 +451,7 @@ describe('change detection', () => { type: MyApp, selectors: [['my-app']], factory: () => new MyApp(injectChangeDetectorRef()), + consts: 2, /** * {{ name}} * % if (showing) { @@ -461,7 +468,7 @@ describe('change detection', () => { containerRefreshStart(1); { if (ctx.showing) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { element(0, 'div', ['dir', '']); } @@ -498,6 +505,7 @@ describe('change detection', () => { type: DetectChangesComp, selectors: [['detect-changes-comp']], factory: () => new DetectChangesComp(injectChangeDetectorRef()), + consts: 1, /** {{ value }} */ template: (rf: RenderFlags, ctx: DetectChangesComp) => { if (rf & RenderFlags.Create) { @@ -529,6 +537,7 @@ describe('change detection', () => { type: DetectChangesComp, selectors: [['detect-changes-comp']], factory: () => new DetectChangesComp(injectChangeDetectorRef()), + consts: 1, /** {{ doCheckCount }} */ template: (rf: RenderFlags, ctx: DetectChangesComp) => { if (rf & RenderFlags.Create) { @@ -557,6 +566,7 @@ describe('change detection', () => { type: MyApp, selectors: [['my-app']], factory: () => new MyApp(injectChangeDetectorRef()), + consts: 1, /** */ template: (rf: RenderFlags, ctx: MyApp) => { if (rf & RenderFlags.Create) { @@ -579,6 +589,7 @@ describe('change detection', () => { type: DetachedComp, selectors: [['detached-comp']], factory: () => comp = new DetachedComp(injectChangeDetectorRef()), + consts: 1, /** {{ value }} */ template: (rf: RenderFlags, ctx: DetachedComp) => { if (rf & RenderFlags.Create) { @@ -678,6 +689,7 @@ describe('change detection', () => { type: OnPushComp, selectors: [['on-push-comp']], factory: () => onPushComp = new OnPushComp(injectChangeDetectorRef()), + consts: 1, /** {{ value }} */ template: (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { @@ -700,7 +712,7 @@ describe('change detection', () => { if (rf & RenderFlags.Update) { elementProperty(0, 'value', bind(ctx.value)); } - }, [OnPushComp]); + }, 1, [OnPushComp]); const app = renderComponent(OnPushApp); app.value = 'one'; @@ -737,6 +749,7 @@ describe('change detection', () => { type: OnPushComp, selectors: [['on-push-comp']], factory: () => comp = new OnPushComp(injectChangeDetectorRef()), + consts: 1, /** {{ value }} */ template: (rf: RenderFlags, ctx: OnPushComp) => { if (rf & RenderFlags.Create) { @@ -757,6 +770,7 @@ describe('change detection', () => { type: OnPushParent, selectors: [['on-push-parent']], factory: () => new OnPushParent(), + consts: 2, /** * {{ value }} - * @@ -825,6 +839,7 @@ describe('change detection', () => { type: EmbeddedViewParent, selectors: [['embedded-view-parent']], factory: () => new EmbeddedViewParent(), + consts: 2, /** * {{ value }} - * % if (ctx.showing) { @@ -841,7 +856,7 @@ describe('change detection', () => { containerRefreshStart(1); { if (ctx.showing) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { element(0, 'on-push-comp'); } @@ -900,6 +915,7 @@ describe('change detection', () => { type: NoChangesComp, selectors: [['no-changes-comp']], factory: () => comp = new NoChangesComp(injectChangeDetectorRef()), + consts: 1, template: (rf: RenderFlags, ctx: NoChangesComp) => { if (rf & RenderFlags.Create) { text(0); @@ -920,6 +936,7 @@ describe('change detection', () => { type: AppComp, selectors: [['app-comp']], factory: () => new AppComp(injectChangeDetectorRef()), + consts: 2, /** * {{ value }} - * @@ -981,6 +998,7 @@ describe('change detection', () => { type: EmbeddedViewApp, selectors: [['embedded-view-app']], factory: () => new EmbeddedViewApp(injectChangeDetectorRef()), + consts: 1, /** * % if (showing) { * {{ value }} @@ -994,7 +1012,7 @@ describe('change detection', () => { containerRefreshStart(0); { if (ctx.showing) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { text(0); } @@ -1064,6 +1082,7 @@ describe('change detection', () => { type: MyComponent, selectors: [['my-comp']], factory: () => new MyComponent(), + consts: 1, template: (rf: RenderFlags, ctx: MyComponent) => { if (rf & RenderFlags.Create) { text(0); diff --git a/packages/core/test/render3/common_integration_spec.ts b/packages/core/test/render3/common_integration_spec.ts index c91a51e38d..58b02fc998 100644 --- a/packages/core/test/render3/common_integration_spec.ts +++ b/packages/core/test/render3/common_integration_spec.ts @@ -38,13 +38,14 @@ describe('@angular/common integration', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 2, //
    //
  • {{item}}
  • //
template: (rf: RenderFlags, ctx: MyApp) => { if (rf & RenderFlags.Create) { elementStart(0, 'ul'); - { template(1, liTemplate, undefined, ['ngForOf', '']); } + { template(1, liTemplate, 2, undefined, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -98,6 +99,7 @@ describe('@angular/common integration', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 2, //
    //
  • {{index}} of // {{count}}: {{item}}
  • @@ -105,7 +107,7 @@ describe('@angular/common integration', () => { template: (rf: RenderFlags, ctx: MyApp) => { if (rf & RenderFlags.Create) { elementStart(0, 'ul'); - { template(1, liTemplate, undefined, ['ngForOf', '']); } + { template(1, liTemplate, 2, undefined, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -157,6 +159,7 @@ describe('@angular/common integration', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 4, // //
      //
    • {{index}}
    • @@ -170,7 +173,7 @@ describe('@angular/common integration', () => { } elementEnd(); elementStart(2, 'ul'); - { template(3, liTemplate, undefined, ['ngForOf', '']); } + { template(3, liTemplate, 2, undefined, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -220,10 +223,11 @@ describe('@angular/common integration', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 2, template: (rf: RenderFlags, ctx: MyApp) => { if (rf & RenderFlags.Create) { elementStart(0, 'ul'); - { template(1, liTemplate, null, ['ngForOf', '']); } + { template(1, liTemplate, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -238,7 +242,7 @@ describe('@angular/common integration', () => { function liTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'li'); - { template(1, spanTemplate, null, ['ngForOf', '']); } + { template(1, spanTemplate, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -309,9 +313,10 @@ describe('@angular/common integration', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 1, template: (rf: RenderFlags, ctx: MyApp) => { if (rf & RenderFlags.Create) { - template(0, divTemplate, null, ['ngForOf', '']); + template(0, divTemplate, 2, null, ['ngForOf', '']); } if (rf & RenderFlags.Update) { elementProperty(0, 'ngForOf', bind(ctx.items)); @@ -325,7 +330,7 @@ describe('@angular/common integration', () => { function divTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); - { template(1, pTemplate, null, ['ngForOf', '']); } + { template(1, pTemplate, 3, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -401,9 +406,10 @@ describe('@angular/common integration', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 1, template: (rf: RenderFlags, ctx: MyApp) => { if (rf & RenderFlags.Create) { - template(0, divTemplate, null, ['ngForOf', '']); + template(0, divTemplate, 2, null, ['ngForOf', '']); } if (rf & RenderFlags.Update) { elementProperty(0, 'ngForOf', bind(ctx.items)); @@ -417,7 +423,7 @@ describe('@angular/common integration', () => { function divTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); - { template(1, innerDivTemplate, null, ['ngForOf', '']); } + { template(1, innerDivTemplate, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -429,7 +435,7 @@ describe('@angular/common integration', () => { function innerDivTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); - { template(1, spanTemplate, null, ['ngForOf', '']); } + { template(1, spanTemplate, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -567,9 +573,10 @@ describe('@angular/common integration', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 1, template: (rf: RenderFlags, ctx: MyApp) => { if (rf & RenderFlags.Create) { - template(0, itemTemplate0, null, ['ngForOf', '']); + template(0, itemTemplate0, 2, null, ['ngForOf', '']); } if (rf & RenderFlags.Update) { elementProperty(0, 'ngForOf', bind(ctx.items)); @@ -583,7 +590,7 @@ describe('@angular/common integration', () => { function itemTemplate0(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); - { template(1, itemTemplate1, null, ['ngForOf', '']); } + { template(1, itemTemplate1, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -595,7 +602,7 @@ describe('@angular/common integration', () => { function itemTemplate1(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); - { template(1, itemTemplate2, null, ['ngForOf', '']); } + { template(1, itemTemplate2, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -607,7 +614,7 @@ describe('@angular/common integration', () => { function itemTemplate2(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); - { template(1, itemTemplate3, null, ['ngForOf', '']); } + { template(1, itemTemplate3, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -619,7 +626,7 @@ describe('@angular/common integration', () => { function itemTemplate3(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); - { template(1, itemTemplate4, null, ['ngForOf', '']); } + { template(1, itemTemplate4, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -631,7 +638,7 @@ describe('@angular/common integration', () => { function itemTemplate4(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); - { template(1, itemTemplate5, null, ['ngForOf', '']); } + { template(1, itemTemplate5, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -643,7 +650,7 @@ describe('@angular/common integration', () => { function itemTemplate5(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); - { template(1, itemTemplate6, null, ['ngForOf', '']); } + { template(1, itemTemplate6, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -655,7 +662,7 @@ describe('@angular/common integration', () => { function itemTemplate6(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); - { template(1, itemTemplate7, null, ['ngForOf', '']); } + { template(1, itemTemplate7, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -667,7 +674,7 @@ describe('@angular/common integration', () => { function itemTemplate7(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); - { template(1, itemTemplate8, null, ['ngForOf', '']); } + { template(1, itemTemplate8, 2, null, ['ngForOf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -729,14 +736,15 @@ describe('@angular/common integration', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 2, /** *
      {{ valueOne }}
      *
      {{ valueTwo }}
      */ template: (rf: RenderFlags, ctx: MyApp) => { if (rf & RenderFlags.Create) { - template(0, templateOne, undefined, ['ngIf', '']); - template(1, templateTwo, undefined, ['ngIf', '']); + template(0, templateOne, 2, undefined, ['ngIf', '']); + template(1, templateTwo, 2, undefined, ['ngIf', '']); } if (rf & RenderFlags.Update) { elementProperty(0, 'ngIf', bind(ctx.showing)); @@ -801,9 +809,10 @@ describe('@angular/common integration', () => { type: AppComponent, factory: () => new AppComponent(), selectors: [['my-app']], + consts: 1, template: (rf: RenderFlags, ctx: AppComponent) => { if (rf & RenderFlags.Create) { - template(0, divTemplate, undefined, ['ngIf', '']); + template(0, divTemplate, 2, undefined, ['ngIf', '']); } if (rf & RenderFlags.Update) { elementProperty(0, 'ngIf', bind(ctx.showing)); @@ -817,7 +826,7 @@ describe('@angular/common integration', () => { function divTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); - { template(1, outerDivTemplate, undefined, ['ngIf', '']); } + { template(1, outerDivTemplate, 2, undefined, ['ngIf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -829,7 +838,7 @@ describe('@angular/common integration', () => { function outerDivTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); - { template(1, innerDivTemplate, undefined, ['ngIf', '']); } + { template(1, innerDivTemplate, 2, undefined, ['ngIf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { @@ -870,6 +879,7 @@ describe('@angular/common integration', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 3, /** * from tpl * @@ -880,8 +890,8 @@ describe('@angular/common integration', () => { if (rf1 & RenderFlags.Create) { text(0, 'from tpl'); } - }, undefined, undefined, ['tpl', ''], templateRefExtractor); - template(2, null, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']); + }, 1, undefined, undefined, ['tpl', ''], templateRefExtractor); + template(2, null, 0, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']); } if (rf & RenderFlags.Update) { const tplRef = load(1); diff --git a/packages/core/test/render3/compiler_canonical/component_directives_spec.ts b/packages/core/test/render3/compiler_canonical/component_directives_spec.ts index 5e9f03d931..c82176c84d 100644 --- a/packages/core/test/render3/compiler_canonical/component_directives_spec.ts +++ b/packages/core/test/render3/compiler_canonical/component_directives_spec.ts @@ -32,6 +32,7 @@ describe('components & directives', () => { type: ChildComponent, selectors: [['child']], factory: function ChildComponent_Factory() { return new ChildComponent(); }, + consts: 1, template: function ChildComponent_Template(rf: $RenderFlags$, ctx: $ChildComponent$) { if (rf & 1) { $r3$.ɵtext(0, 'child-view'); @@ -67,6 +68,7 @@ describe('components & directives', () => { type: MyComponent, selectors: [['my-component']], factory: () => new MyComponent(), + consts: 2, template: function(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelement(0, 'child', $e0_attrs$); @@ -120,6 +122,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelement(0, 'div', $e0_attrs$); @@ -171,6 +174,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 2, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelementStart(0, 'button', $e0_attrs$); @@ -218,6 +222,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelement(0, 'div', $e0_attrs$); @@ -268,6 +273,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelement(0, 'div', $e0_attrs$); @@ -304,6 +310,7 @@ describe('components & directives', () => { type: MyComp, selectors: [['my-comp']], factory: function MyComp_Factory() { return new MyComp(); }, + consts: 1, template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) { if (rf & 1) { $r3$.ɵtext(0); @@ -329,6 +336,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelement(0, 'my-comp'); @@ -393,10 +401,11 @@ describe('components & directives', () => { type: MyComponent, selectors: [['my-component']], factory: () => new MyComponent(), + consts: 3, template: function(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelementStart(0, 'ul', null, $e0_locals$); - $r3$.ɵtemplate(2, C1, '', ['if', '']); + $r3$.ɵtemplate(2, C1, 2, '', ['if', '']); $r3$.ɵelementEnd(); } } @@ -425,6 +434,7 @@ describe('components & directives', () => { type: MyArrayComp, selectors: [['my-array-comp']], factory: function MyArrayComp_Factory() { return new MyArrayComp(); }, + consts: 1, template: function MyArrayComp_Template(rf: $RenderFlags$, ctx: $MyArrayComp$) { if (rf & 1) { $r3$.ɵtext(0); @@ -456,6 +466,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelement(0, 'my-array-comp'); @@ -500,6 +511,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelement(0, 'my-array-comp'); @@ -534,6 +546,7 @@ describe('components & directives', () => { type: MyComp, selectors: [['my-comp']], factory: function MyComp_Factory() { return new MyComp(); }, + consts: 1, template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) { if (rf & 1) { $r3$.ɵtext(0); @@ -566,6 +579,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelement(0, 'my-comp'); @@ -609,6 +623,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelement(0, 'my-array-comp'); @@ -657,6 +672,7 @@ describe('components & directives', () => { type: MyComp, selectors: [['my-comp']], factory: function MyComp_Factory() { return new MyComp(); }, + consts: 12, template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) { if (rf & 1) { $r3$.ɵtext(0); @@ -720,6 +736,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, template: function MyApp_Template(rf: $RenderFlags$, c: $any$) { if (rf & 1) { $r3$.ɵelement(0, 'my-comp'); @@ -762,6 +779,7 @@ describe('components & directives', () => { type: ObjectComp, selectors: [['object-comp']], factory: function ObjectComp_Factory() { return new ObjectComp(); }, + consts: 4, template: function ObjectComp_Template(rf: $RenderFlags$, ctx: $ObjectComp$) { if (rf & 1) { $r3$.ɵelementStart(0, 'p'); @@ -798,6 +816,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelement(0, 'object-comp'); @@ -839,6 +858,7 @@ describe('components & directives', () => { type: NestedComp, selectors: [['nested-comp']], factory: function NestedComp_Factory() { return new NestedComp(); }, + consts: 6, template: function NestedComp_Template(rf: $RenderFlags$, ctx: $NestedComp$) { if (rf & 1) { $r3$.ɵelementStart(0, 'p'); @@ -884,6 +904,7 @@ describe('components & directives', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelement(0, 'nested-comp'); diff --git a/packages/core/test/render3/compiler_canonical/content_projection_spec.ts b/packages/core/test/render3/compiler_canonical/content_projection_spec.ts index 40ad035d22..3a33469b2c 100644 --- a/packages/core/test/render3/compiler_canonical/content_projection_spec.ts +++ b/packages/core/test/render3/compiler_canonical/content_projection_spec.ts @@ -25,6 +25,7 @@ describe('content projection', () => { type: SimpleComponent, selectors: [['simple']], factory: () => new SimpleComponent(), + consts: 1, template: function(rf: $RenderFlags$, ctx: $SimpleComponent$) { if (rf & 1) { $r3$.ɵprojectionDef(); @@ -54,6 +55,7 @@ describe('content projection', () => { type: ComplexComponent, selectors: [['complex']], factory: () => new ComplexComponent(), + consts: 4, template: function(rf: $RenderFlags$, ctx: $ComplexComponent$) { if (rf & 1) { $r3$.ɵprojectionDef($pD_0P$, $pD_0R$); @@ -77,6 +79,7 @@ describe('content projection', () => { type: MyApp, selectors: [['my-app']], factory: () => new MyApp(), + consts: 2, template: function(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelementStart(0, 'simple'); diff --git a/packages/core/test/render3/compiler_canonical/elements_spec.ts b/packages/core/test/render3/compiler_canonical/elements_spec.ts index 90a1cfd3f9..85f1a038f6 100644 --- a/packages/core/test/render3/compiler_canonical/elements_spec.ts +++ b/packages/core/test/render3/compiler_canonical/elements_spec.ts @@ -37,6 +37,7 @@ describe('elements', () => { type: MyComponent, selectors: [['my-component']], factory: () => new MyComponent(), + consts: 5, template: function(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelementStart(0, 'div', $e0_attrs$); @@ -88,6 +89,7 @@ describe('elements', () => { type: LocalRefComp, selectors: [['local-ref-comp']], factory: function LocalRefComp_Factory() { return new LocalRefComp(); }, + consts: 4, template: function LocalRefComp_Template(rf: $RenderFlags$, ctx: $LocalRefComp$) { let $tmp$: any; let $tmp_2$: any; @@ -133,6 +135,7 @@ describe('elements', () => { type: ListenerComp, selectors: [['listener-comp']], factory: function ListenerComp_Factory() { return new ListenerComp(); }, + consts: 1, template: function ListenerComp_Template(rf: $RenderFlags$, ctx: $ListenerComp$) { if (rf & 1) { $r3$.ɵelementStart(0, 'button'); @@ -188,6 +191,7 @@ describe('elements', () => { type: MyComponent, selectors: [['my-component']], factory: () => new MyComponent(), + consts: 5, template: function(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelementStart(0, 'div', $e0_attrs$); @@ -220,6 +224,7 @@ describe('elements', () => { type: MyComponent, selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, + consts: 1, template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelement(0, 'div'); @@ -251,6 +256,7 @@ describe('elements', () => { type: MyComponent, selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, + consts: 1, template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelement(0, 'div'); @@ -283,6 +289,7 @@ describe('elements', () => { type: MyComponent, selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, + consts: 1, template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelementStart(0, 'div'); @@ -322,6 +329,7 @@ describe('elements', () => { type: MyComponent, selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, + consts: 1, template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelementStart(0, 'div'); @@ -373,6 +381,7 @@ describe('elements', () => { type: MyComponent, selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, + consts: 1, template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelementStart(0, 'div'); @@ -411,6 +420,7 @@ describe('elements', () => { type: StyleComponent, selectors: [['style-comp']], factory: function StyleComponent_Factory() { return new StyleComponent(); }, + consts: 1, template: function StyleComponent_Template(rf: $RenderFlags$, ctx: $StyleComponent$) { if (rf & 1) { $r3$.ɵelementStart(0, 'div'); diff --git a/packages/core/test/render3/compiler_canonical/i18n_spec.ts b/packages/core/test/render3/compiler_canonical/i18n_spec.ts index 5b4cab0ffc..7aed96f14a 100644 --- a/packages/core/test/render3/compiler_canonical/i18n_spec.ts +++ b/packages/core/test/render3/compiler_canonical/i18n_spec.ts @@ -26,6 +26,7 @@ describe('i18n', () => { type: MyApp, selectors: [['my-app']], factory: () => new MyApp(), + consts: 2, template: function(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelementStart(0, 'div'); @@ -51,6 +52,7 @@ describe('i18n', () => { type: MyApp, selectors: [['my-app']], factory: () => new MyApp(), + consts: 2, template: function(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelementStart(0, 'div'); @@ -78,6 +80,7 @@ describe('i18n', () => { type: MyApp, selectors: [['my-app']], factory: () => new MyApp(), + consts: 2, template: function(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelementStart(0, 'div'); @@ -99,6 +102,18 @@ describe('i18n', () => { const $i18n_1$ = $r3$.ɵi18nMapping( $msg_1$, [{START_LI: 1}, {START_LI: 0}], [null, {EXP_1: 1}], ['START_LI']); + function liTemplate(rf1: $RenderFlags$, row: NgForOfContext) { + if (rf1 & 1) { + $r3$.ɵelementStart(0, 'li'); + $r3$.ɵtext(1); + $r3$.ɵelementEnd(); + $r3$.ɵi18nApply(0, $i18n_1$[1]); + } + if (rf1 & 2) { + $r3$.ɵtextBinding(1, $r3$.ɵbind(row.$implicit)); + } + } + @Component({ selector: 'my-app', template: `
      • value: {{item}}
      ` @@ -109,28 +124,17 @@ describe('i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 2, template: (rf: $RenderFlags$, myApp: $MyApp$) => { if (rf & 1) { $r3$.ɵelementStart(0, 'ul'); - $r3$.ɵtemplate(1, liTemplate, null, ['ngForOf', '']); + $r3$.ɵtemplate(1, liTemplate, 2, null, ['ngForOf', '']); $r3$.ɵelementEnd(); $r3$.ɵi18nApply(1, $i18n_1$[0]); } if (rf & 2) { $r3$.ɵelementProperty(1, 'ngForOf', $r3$.ɵbind(myApp.items)); } - - function liTemplate(rf1: $RenderFlags$, row: NgForOfContext) { - if (rf1 & 1) { - $r3$.ɵelementStart(0, 'li'); - $r3$.ɵtext(1); - $r3$.ɵelementEnd(); - $r3$.ɵi18nApply(0, $i18n_1$[1]); - } - if (rf1 & 2) { - $r3$.ɵtextBinding(1, $r3$.ɵbind(row.$implicit)); - } - } }, directives: () => [NgForOf] }); diff --git a/packages/core/test/render3/compiler_canonical/injection_spec.ts b/packages/core/test/render3/compiler_canonical/injection_spec.ts index 6ce6345c8e..0aebb6faca 100644 --- a/packages/core/test/render3/compiler_canonical/injection_spec.ts +++ b/packages/core/test/render3/compiler_canonical/injection_spec.ts @@ -34,6 +34,7 @@ describe('injection', () => { factory: function MyComp_Factory() { return new MyComp($r3$.ɵinjectChangeDetectorRef()); }, + consts: 1, template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) { if (rf & 1) { $r3$.ɵtext(0); @@ -51,6 +52,7 @@ describe('injection', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, /** */ template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { @@ -80,6 +82,7 @@ describe('injection', () => { type: MyComp, selectors: [['my-comp']], factory: function MyComp_Factory() { return new MyComp($r3$.ɵinjectAttribute('title')); }, + consts: 1, template: function MyComp_Template(rf: $RenderFlags$, ctx: $MyComp$) { if (rf & 1) { $r3$.ɵtext(0); @@ -97,6 +100,7 @@ describe('injection', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 1, /** */ template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { @@ -149,6 +153,7 @@ describe('injection', () => { return new MyApp( $r3$.ɵdirectiveInject(ServiceA), $r3$.ɵdirectiveInject(ServiceB), inject(INJECTOR)); }, + consts: 0, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {}, providers: [ServiceA], viewProviders: [ServiceB], diff --git a/packages/core/test/render3/compiler_canonical/life_cycle_spec.ts b/packages/core/test/render3/compiler_canonical/life_cycle_spec.ts index bc20719008..0e7f361a08 100644 --- a/packages/core/test/render3/compiler_canonical/life_cycle_spec.ts +++ b/packages/core/test/render3/compiler_canonical/life_cycle_spec.ts @@ -46,6 +46,7 @@ describe('lifecycle hooks', () => { type: LifecycleComp, selectors: [['lifecycle-comp']], factory: function LifecycleComp_Factory() { return new LifecycleComp(); }, + consts: 0, template: function LifecycleComp_Template(rf: $RenderFlags$, ctx: $LifecycleComp$) {}, inputs: {nameMin: ['name', 'nameMin']}, features: [$r3$.ɵNgOnChangesFeature] @@ -69,6 +70,7 @@ describe('lifecycle hooks', () => { type: SimpleLayout, selectors: [['simple-layout']], factory: function SimpleLayout_Factory() { return simpleLayout = new SimpleLayout(); }, + consts: 2, template: function SimpleLayout_Template(rf: $RenderFlags$, ctx: $SimpleLayout$) { if (rf & 1) { $r3$.ɵelement(0, 'lifecycle-comp'); diff --git a/packages/core/test/render3/compiler_canonical/local_reference_spec.ts b/packages/core/test/render3/compiler_canonical/local_reference_spec.ts index db20cb1001..0b3c5da093 100644 --- a/packages/core/test/render3/compiler_canonical/local_reference_spec.ts +++ b/packages/core/test/render3/compiler_canonical/local_reference_spec.ts @@ -25,6 +25,7 @@ describe('local references', () => { type: MyComponent, selectors: [['my-component']], factory: () => new MyComponent, + consts: 3, template: function(rf: $RenderFlags$, ctx: $MyComponent$) { let l1_user: any; if (rf & 1) { @@ -60,11 +61,12 @@ describe('local references', () => { type: MyComponent, selectors: [['my-component']], factory: () => new MyComponent, + consts: 3, template: function(rf: $RenderFlags$, ctx: $MyComponent$) { let l1_tpl: any; if (rf & 1) { $r3$.ɵtemplate( - 0, MyComponent_Template_0, null, null, ['tpl', ''], $r3$.ɵtemplateRefExtractor); + 0, MyComponent_Template_0, 0, null, null, ['tpl', ''], $r3$.ɵtemplateRefExtractor); $r3$.ɵtext(2); } if (rf & 2) { diff --git a/packages/core/test/render3/compiler_canonical/pipes_spec.ts b/packages/core/test/render3/compiler_canonical/pipes_spec.ts index d680ac642a..8ce45f614c 100644 --- a/packages/core/test/render3/compiler_canonical/pipes_spec.ts +++ b/packages/core/test/render3/compiler_canonical/pipes_spec.ts @@ -83,6 +83,7 @@ describe('pipes', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 3, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵtext(0); @@ -155,12 +156,11 @@ describe('pipes', () => { $r3$.ɵtext(1); $r3$.ɵpipe(2, 'myPurePipe'); $r3$.ɵelementEnd(); - $r3$.ɵreserveSlots(3); } if (rf & 2) { const $comp$ = $r3$.ɵnextContext(); $r3$.ɵtextBinding( - 1, $r3$.ɵinterpolation1('', $r3$.ɵpipeBind2(2, 3, $comp$.name, $comp$.size), '')); + 1, $r3$.ɵinterpolation1('', $r3$.ɵpipeBind2(2, 3, $comp$.name, $comp$.size), '')); } } @@ -178,14 +178,14 @@ describe('pipes', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 5, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵtext(0); $r3$.ɵpipe(1, 'myPurePipe'); $r3$.ɵtext(2); $r3$.ɵpipe(3, 'myPurePipe'); - $r3$.ɵtemplate(4, MyApp_div_Template_4, '', ['oneTimeIf', '']); - $r3$.ɵreserveSlots(6); + $r3$.ɵtemplate(4, MyApp_div_Template_4, 3, '', ['oneTimeIf', '']); } if (rf & 2) { $r3$.ɵtextBinding( diff --git a/packages/core/test/render3/compiler_canonical/query_spec.ts b/packages/core/test/render3/compiler_canonical/query_spec.ts index 9046ac1a6a..263e5211eb 100644 --- a/packages/core/test/render3/compiler_canonical/query_spec.ts +++ b/packages/core/test/render3/compiler_canonical/query_spec.ts @@ -54,6 +54,7 @@ describe('queries', () => { type: ViewQueryComponent, selectors: [['view-query-component']], factory: function ViewQueryComponent_Factory() { return new ViewQueryComponent(); }, + consts: 3, template: function ViewQueryComponent_Template( rf: $RenderFlags$, ctx: $ViewQueryComponent$) { if (rf & 1) { @@ -110,6 +111,7 @@ describe('queries', () => { type: ContentQueryComponent, selectors: [['content-query-component']], factory: function ContentQueryComponent_Factory() { return new ContentQueryComponent(); }, + consts: 2, contentQueries: function ContentQueryComponent_ContentQueries() { $r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false)); $r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false)); @@ -152,6 +154,7 @@ describe('queries', () => { type: MyApp, selectors: [['my-app']], factory: function MyApp_Factory() { return new MyApp(); }, + consts: 2, template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) { if (rf & 1) { $r3$.ɵelementStart(0, 'content-query-component'); diff --git a/packages/core/test/render3/compiler_canonical/sanitize_spec.ts b/packages/core/test/render3/compiler_canonical/sanitize_spec.ts index b8915f65dd..ebabff1356 100644 --- a/packages/core/test/render3/compiler_canonical/sanitize_spec.ts +++ b/packages/core/test/render3/compiler_canonical/sanitize_spec.ts @@ -41,6 +41,7 @@ describe('compiler sanitization', () => { type: MyComponent, selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, + consts: 2, template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelementStart(0, 'div'); diff --git a/packages/core/test/render3/compiler_canonical/small_app_spec.ts b/packages/core/test/render3/compiler_canonical/small_app_spec.ts index 06c7e0fb07..496e086a92 100644 --- a/packages/core/test/render3/compiler_canonical/small_app_spec.ts +++ b/packages/core/test/render3/compiler_canonical/small_app_spec.ts @@ -38,6 +38,19 @@ class AppState { // /NORMATIVE } +const ToDoAppComponent_NgForOf_Template = function ToDoAppComponent_NgForOf_Template( + rf: $RenderFlags$, ctx1: NgForOfContext) { + if (rf & 1) { + const $comp$ = r3.nextContext(); + r3.elementStart(0, 'todo'); + r3.listener('archive', $comp$.onArchive.bind($comp$)); + r3.elementEnd(); + } + if (rf & 2) { + r3.elementProperty(0, 'todo', r3.bind(ctx1.$implicit)); + } +}; + @Component({ selector: 'todo-app', template: ` @@ -64,24 +77,14 @@ class ToDoAppComponent { factory: function ToDoAppComponent_Factory() { return new ToDoAppComponent(r3.directiveInject(AppState)); }, + consts: 6, template: function ToDoAppComponent_Template(rf: $RenderFlags$, ctx: ToDoAppComponent) { if (rf & 1) { - const ToDoAppComponent_NgForOf_Template = function ToDoAppComponent_NgForOf_Template( - rf: $RenderFlags$, ctx1: NgForOfContext) { - if (rf & 1) { - r3.elementStart(0, 'todo'); - r3.listener('archive', ctx.onArchive.bind(ctx)); - r3.elementEnd(); - } - if (rf & 2) { - r3.elementProperty(0, 'todo', r3.bind(ctx1.$implicit)); - } - }; r3.elementStart(0, 'h1'); r3.text(1, 'ToDo Application'); r3.elementEnd(); r3.elementStart(2, 'div'); - r3.template(3, ToDoAppComponent_NgForOf_Template, '', ['ngForOf', '']); + r3.template(3, ToDoAppComponent_NgForOf_Template, 1, '', ['ngForOf', '']); r3.elementEnd(); r3.elementStart(4, 'span'); r3.text(5); @@ -131,6 +134,7 @@ class ToDoItemComponent { type: ToDoItemComponent, selectors: [['todo']], factory: function ToDoItemComponent_Factory() { return new ToDoItemComponent(); }, + consts: 6, template: function ToDoItemComponent_Template(rf: $RenderFlags$, ctx: ToDoItemComponent) { if (rf & 1) { r3.elementStart(0, 'div'); diff --git a/packages/core/test/render3/compiler_canonical/template_variables_spec.ts b/packages/core/test/render3/compiler_canonical/template_variables_spec.ts index a8a606925e..68f834fde9 100644 --- a/packages/core/test/render3/compiler_canonical/template_variables_spec.ts +++ b/packages/core/test/render3/compiler_canonical/template_variables_spec.ts @@ -85,6 +85,18 @@ describe('template variables', () => { name: string; } + function MyComponent_ForOfDirective_Template_1(rf: $RenderFlags$, ctx1: $any$) { + if (rf & 1) { + $r3$.ɵelementStart(0, 'li'); + $r3$.ɵtext(1); + $r3$.ɵelementEnd(); + } + if (rf & 2) { + const $l0_item$ = ctx1.$implicit; + $r3$.ɵtextBinding(1, $r3$.ɵinterpolation1('', $l0_item$.name, '')); + } + } + @Component({ selector: 'my-component', template: `
      • {{item.name}}
      ` @@ -97,29 +109,15 @@ describe('template variables', () => { type: MyComponent, selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, + consts: 2, template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelementStart(0, 'ul'); - $r3$.ɵtemplate(1, MyComponent_ForOfDirective_Template_1, '', ['forOf', '']); + $r3$.ɵtemplate(1, MyComponent_ForOfDirective_Template_1, 2, '', ['forOf', '']); $r3$.ɵelementEnd(); } if (rf & 2) { $r3$.ɵelementProperty(1, 'forOf', $r3$.ɵbind(ctx.items)); - $r3$.ɵcontainerRefreshStart(1); - $r3$.ɵcontainerRefreshEnd(); - } - - function MyComponent_ForOfDirective_Template_1(rf: $RenderFlags$, ctx1: $any$) { - if (rf & 1) { - $r3$.ɵelementStart(0, 'li'); - $r3$.ɵtext(1); - $r3$.ɵelementEnd(); - } - let $l0_item$: any; - if (rf & 2) { - $l0_item$ = ctx1.$implicit; - $r3$.ɵtextBinding(1, $r3$.ɵinterpolation1('', $l0_item$.name, '')); - } } } }); @@ -146,6 +144,39 @@ describe('template variables', () => { infos: Info[]; } + function MyComponent_ForOfDirective_Template_1(rf: $RenderFlags$, ctx1: $any$) { + if (rf & 1) { + $r3$.ɵelementStart(0, 'li'); + $r3$.ɵelementStart(1, 'div'); + $r3$.ɵtext(2); + $r3$.ɵelementEnd(); + $r3$.ɵelementStart(3, 'ul'); + $r3$.ɵtemplate( + 4, MyComponent_ForOfDirective_ForOfDirective_Template_3, 2, '', ['forOf', '']); + $r3$.ɵelementEnd(); + $r3$.ɵelementEnd(); + } + if (rf & 2) { + const $l0_item$ = ctx1.$implicit; + $r3$.ɵelementProperty(4, 'forOf', $r3$.ɵbind($l0_item$.infos)); + $r3$.ɵtextBinding(2, $r3$.ɵinterpolation1('', $l0_item$.name, '')); + } + } + + function MyComponent_ForOfDirective_ForOfDirective_Template_3(rf: $number$, ctx2: $any$) { + if (rf & 1) { + $r3$.ɵelementStart(0, 'li'); + $r3$.ɵtext(1); + $r3$.ɵelementEnd(); + } + if (rf & 2) { + const $l0_info$ = ctx2.$implicit; + const $l0_item$ = $r3$.ɵnextContext(); + $r3$.ɵtextBinding( + 1, $r3$.ɵinterpolation2(' ', $l0_item$.name, ': ', $l0_info$.description, ' ')); + } + } + @Component({ selector: 'my-component', template: ` @@ -171,10 +202,11 @@ describe('template variables', () => { type: MyComponent, selectors: [['my-component']], factory: function MyComponent_Factory() { return new MyComponent(); }, + consts: 2, template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) { if (rf & 1) { $r3$.ɵelementStart(0, 'ul'); - $r3$.ɵtemplate(1, MyComponent_ForOfDirective_Template_1, '', ['forOf', '']); + $r3$.ɵtemplate(1, MyComponent_ForOfDirective_Template_1, 5, '', ['forOf', '']); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -182,43 +214,6 @@ describe('template variables', () => { $r3$.ɵcontainerRefreshStart(1); $r3$.ɵcontainerRefreshEnd(); } - - function MyComponent_ForOfDirective_Template_1(rf1: $RenderFlags$, ctx1: $any$) { - if (rf & 1) { - $r3$.ɵelementStart(0, 'li'); - $r3$.ɵelementStart(1, 'div'); - $r3$.ɵtext(2); - $r3$.ɵelementEnd(); - $r3$.ɵelementStart(3, 'ul'); - $r3$.ɵtemplate( - 4, MyComponent_ForOfDirective_ForOfDirective_Template_3, '', ['forOf', '']); - $r3$.ɵelementEnd(); - $r3$.ɵelementEnd(); - } - let $l0_item$: any; - if (rf & 2) { - $l0_item$ = ctx1.$implicit; - $r3$.ɵelementProperty(4, 'forOf', $r3$.ɵbind($l0_item$.infos)); - $r3$.ɵtextBinding(2, $r3$.ɵinterpolation1('', $l0_item$.name, '')); - $r3$.ɵcontainerRefreshStart(4); - $r3$.ɵcontainerRefreshEnd(); - } - - function MyComponent_ForOfDirective_ForOfDirective_Template_3( - rf2: $number$, ctx2: $any$) { - if (rf & 1) { - $r3$.ɵelementStart(0, 'li'); - $r3$.ɵtext(1); - $r3$.ɵelementEnd(); - } - let $l0_info$: any; - if (rf & 2) { - $l0_info$ = ctx2.$implicit; - $r3$.ɵtextBinding( - 1, $r3$.ɵinterpolation2(' ', $l0_item$.name, ': ', $l0_info$.description, ' ')); - } - } - } } }); // /NORMATIVE diff --git a/packages/core/test/render3/component_spec.ts b/packages/core/test/render3/component_spec.ts index fe0a787c05..c7b185f512 100644 --- a/packages/core/test/render3/component_spec.ts +++ b/packages/core/test/render3/component_spec.ts @@ -27,6 +27,7 @@ describe('component', () => { static ngComponentDef = defineComponent({ type: CounterComponent, selectors: [['counter']], + consts: 1, template: function(rf: RenderFlags, ctx: CounterComponent) { if (rf & RenderFlags.Create) { text(0); @@ -72,6 +73,7 @@ describe('component', () => { type: MyComponent, selectors: [['my-component']], factory: () => new MyComponent(directiveInject(MyService)), + consts: 1, template: function(fs: RenderFlags, ctx: MyComponent) { if (fs & RenderFlags.Create) { text(0); @@ -114,7 +116,7 @@ describe('component with a container', () => { containerRefreshStart(0); { for (const item of ctx.items) { - const rf0 = embeddedViewStart(0); + const rf0 = embeddedViewStart(0, 1); { if (rf0 & RenderFlags.Create) { text(0); @@ -136,6 +138,7 @@ describe('component with a container', () => { static ngComponentDef = defineComponent({ type: WrapperComponent, selectors: [['wrapper']], + consts: 1, template: function ChildComponentTemplate(rf: RenderFlags, ctx: {items: string[]}) { if (rf & RenderFlags.Create) { container(0); @@ -143,7 +146,7 @@ describe('component with a container', () => { if (rf & RenderFlags.Update) { containerRefreshStart(0); { - const rf0 = embeddedViewStart(0); + const rf0 = embeddedViewStart(0, 1); { showItems(rf0, {items: ctx.items}); } embeddedViewEnd(); } @@ -168,10 +171,10 @@ describe('component with a container', () => { it('should re-render on input change', () => { const ctx: {items: string[]} = {items: ['a']}; - expect(renderToHtml(template, ctx, defs)).toEqual('a'); + expect(renderToHtml(template, ctx, 1, defs)).toEqual('a'); ctx.items = [...ctx.items, 'b']; - expect(renderToHtml(template, ctx, defs)).toEqual('ab'); + expect(renderToHtml(template, ctx, 1, defs)).toEqual('ab'); }); }); @@ -183,6 +186,7 @@ describe('encapsulation', () => { static ngComponentDef = defineComponent({ type: WrapperComponent, selectors: [['wrapper']], + consts: 1, template: function(rf: RenderFlags, ctx: WrapperComponent) { if (rf & RenderFlags.Create) { element(0, 'encapsulated'); @@ -197,6 +201,7 @@ describe('encapsulation', () => { static ngComponentDef = defineComponent({ type: EncapsulatedComponent, selectors: [['encapsulated']], + consts: 2, template: function(rf: RenderFlags, ctx: EncapsulatedComponent) { if (rf & RenderFlags.Create) { text(0, 'foo'); @@ -215,6 +220,7 @@ describe('encapsulation', () => { static ngComponentDef = defineComponent({ type: LeafComponent, selectors: [['leaf']], + consts: 2, template: function(rf: RenderFlags, ctx: LeafComponent) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); @@ -245,6 +251,7 @@ describe('encapsulation', () => { static ngComponentDef = defineComponent({ type: WrapperComponentWith, selectors: [['wrapper']], + consts: 1, template: function(rf: RenderFlags, ctx: WrapperComponentWith) { if (rf & RenderFlags.Create) { element(0, 'leaf'); @@ -262,6 +269,7 @@ describe('encapsulation', () => { static ngComponentDef = defineComponent({ type: LeafComponentwith, selectors: [['leaf']], + consts: 1, template: function(rf: RenderFlags, ctx: LeafComponentwith) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); @@ -320,6 +328,7 @@ describe('recursive components', () => { type: TreeComponent, selectors: [['tree-comp']], factory: () => new TreeComponent(), + consts: 3, template: (rf: RenderFlags, ctx: TreeComponent) => { if (rf & RenderFlags.Create) { text(0); @@ -331,7 +340,7 @@ describe('recursive components', () => { containerRefreshStart(1); { if (ctx.data.left != null) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { element(0, 'tree-comp'); } @@ -345,7 +354,7 @@ describe('recursive components', () => { containerRefreshStart(2); { if (ctx.data.right != null) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { element(0, 'tree-comp'); } @@ -379,12 +388,13 @@ describe('recursive components', () => { type: NgIfTree, selectors: [['ng-if-tree']], factory: () => new NgIfTree(), + consts: 3, template: (rf: RenderFlags, ctx: NgIfTree) => { if (rf & RenderFlags.Create) { text(0); - template(1, IfTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']); - template(2, IfTemplate2, '', [AttributeMarker.SelectOnly, 'ngIf']); + template(1, IfTemplate, 1, '', [AttributeMarker.SelectOnly, 'ngIf']); + template(2, IfTemplate2, 1, '', [AttributeMarker.SelectOnly, 'ngIf']); } if (rf & RenderFlags.Update) { textBinding(0, bind(ctx.data.value)); @@ -453,7 +463,7 @@ describe('recursive components', () => { if (rf & RenderFlags.Update) { containerRefreshStart(0); if (!ctx.skipContent) { - const rf0 = embeddedViewStart(0); + const rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { elementStart(0, 'tree-comp'); elementEnd(); @@ -462,7 +472,7 @@ describe('recursive components', () => { } containerRefreshEnd(); } - }, [TreeComponent]); + }, 1, [TreeComponent]); const fixture = new ComponentFixture(App); expect(getRenderedText(fixture.component)).toEqual('6201534'); @@ -487,7 +497,7 @@ describe('recursive components', () => { if (rf & RenderFlags.Update) { containerRefreshStart(0); if (!ctx.skipContent) { - const rf0 = embeddedViewStart(0); + const rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { elementStart(0, 'ng-if-tree'); elementEnd(); @@ -496,7 +506,7 @@ describe('recursive components', () => { } containerRefreshEnd(); } - }, [NgIfTree]); + }, 1, [NgIfTree]); const fixture = new ComponentFixture(App); expect(getRenderedText(fixture.component)).toEqual('6201534'); @@ -516,6 +526,7 @@ describe('recursive components', () => { type: TestInputsComponent, selectors: [['test-inputs']], inputs: {minifiedName: 'unminifiedName'}, + consts: 0, factory: () => new TestInputsComponent(), template: function(rf: RenderFlags, ctx: TestInputsComponent): void { // Template not needed for this test diff --git a/packages/core/test/render3/content_spec.ts b/packages/core/test/render3/content_spec.ts index 21920733b8..490e9bcfcf 100644 --- a/packages/core/test/render3/content_spec.ts +++ b/packages/core/test/render3/content_spec.ts @@ -31,7 +31,7 @@ describe('content projection', () => { { projection(1); } elementEnd(); } - }); + }, 2); /** * content @@ -42,7 +42,7 @@ describe('content projection', () => { { text(1, 'content'); } elementEnd(); } - }, [Child]); + }, 2, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('
      content
      '); @@ -55,7 +55,7 @@ describe('content projection', () => { projectionDef(); projection(0); } - }); + }, 1); /** content */ const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { @@ -64,7 +64,7 @@ describe('content projection', () => { { text(1, 'content'); } elementEnd(); } - }, [Child]); + }, 2, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('content'); @@ -77,7 +77,7 @@ describe('content projection', () => { projectionDef(); projection(0); } - }); + }, 1); /** * @@ -98,7 +98,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 5, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('before
      content
      after
      '); @@ -113,7 +113,7 @@ describe('content projection', () => { { projection(1); } elementEnd(); } - }); + }, 2); /** */ const Child = createComponent('child', function(rf: RenderFlags, ctx: any) { @@ -123,7 +123,7 @@ describe('content projection', () => { { projection(1); } elementEnd(); } - }, [GrandChild]); + }, 2, [GrandChild]); /** HelloWorld! */ const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { @@ -137,7 +137,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 4, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)) @@ -154,13 +154,13 @@ describe('content projection', () => { { projection(1); } elementEnd(); } - }); + }, 2); const ProjectedComp = createComponent('projected-comp', (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { text(0, 'content'); } - }); + }, 1); /** * @@ -173,7 +173,7 @@ describe('content projection', () => { { element(1, 'projected-comp'); } elementEnd(); } - }, [Child, ProjectedComp]); + }, 2, [Child, ProjectedComp]); const parent = renderComponent(Parent); expect(toHtml(parent)) @@ -189,7 +189,7 @@ describe('content projection', () => { { projection(1); } elementEnd(); } - }); + }, 2); /**

      */ const ProjectedComp = createComponent('projected-comp', (rf: RenderFlags, ctx: any) => { @@ -199,7 +199,7 @@ describe('content projection', () => { projection(1); elementEnd(); } - }); + }, 2); /** * @@ -225,7 +225,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child, ProjectedComp]); + }, 5, [Child, ProjectedComp]); const parent = renderComponent(Parent); expect(toHtml(parent)) @@ -242,7 +242,7 @@ describe('content projection', () => { { projection(1); } elementEnd(); } - }); + }, 2); /** * @@ -267,7 +267,7 @@ describe('content projection', () => { containerRefreshStart(2); { if (ctx.value) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { text(0, 'content'); } @@ -276,7 +276,7 @@ describe('content projection', () => { } containerRefreshEnd(); } - }, [Child]); + }, 4, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('
      ()
      '); @@ -297,7 +297,7 @@ describe('content projection', () => { projectionDef(); projection(0); } - }); + }, 1); /** * @@ -316,7 +316,7 @@ describe('content projection', () => { containerRefreshStart(1); { if (ctx.value) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { text(0, 'content'); } @@ -325,7 +325,7 @@ describe('content projection', () => { } containerRefreshEnd(); } - }, [Child]); + }, 2, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual(''); @@ -348,7 +348,7 @@ describe('content projection', () => { { projection(1); } elementEnd(); } - }); + }, 2); /** * @@ -375,13 +375,13 @@ describe('content projection', () => { containerRefreshStart(2); { if (ctx.value) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { text(0, 'content'); } embeddedViewEnd(); } else { - if (embeddedViewStart(1)) { + if (embeddedViewStart(1, 1)) { text(0, 'else'); } embeddedViewEnd(); @@ -389,7 +389,7 @@ describe('content projection', () => { } containerRefreshEnd(); } - }, [Child]); + }, 4, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('
      (else)
      '); @@ -424,7 +424,7 @@ describe('content projection', () => { containerRefreshStart(1); { if (!ctx.skipContent) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 2); if (rf0 & RenderFlags.Create) { elementStart(0, 'span'); projection(1); @@ -457,7 +457,7 @@ describe('content projection', () => { // testing childCmptInstance = loadDirective(0); } - }, [Child]); + }, 4, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('
      text
      content
      '); @@ -489,7 +489,7 @@ describe('content projection', () => { containerRefreshStart(1); { if (!ctx.skipContent) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 2); if (rf0 & RenderFlags.Create) { projection(0); text(1, 'text'); @@ -499,7 +499,7 @@ describe('content projection', () => { } containerRefreshEnd(); } - }); + }, 2); /** */ const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) { @@ -509,7 +509,7 @@ describe('content projection', () => { // testing childCmptInstance = loadDirective(0); } - }, [Child]); + }, 1, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('
      text
      '); @@ -541,7 +541,7 @@ describe('content projection', () => { containerRefreshStart(1); { if (!ctx.skipContent) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { projection(0); } @@ -550,7 +550,7 @@ describe('content projection', () => { } containerRefreshEnd(); } - }); + }, 2); /** * content @@ -564,7 +564,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 2, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('
      content
      '); @@ -599,7 +599,7 @@ describe('content projection', () => { containerRefreshStart(2); { if (!ctx.skipContent) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { projection(0); } @@ -608,7 +608,7 @@ describe('content projection', () => { } containerRefreshEnd(); } - }); + }, 4); /** * @@ -633,7 +633,7 @@ describe('content projection', () => { containerRefreshStart(2); { if (!ctx.skipContent) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { text(0, 'content'); } @@ -642,7 +642,7 @@ describe('content projection', () => { } containerRefreshEnd(); } - }, [Child]); + }, 4, [Child]); const fixture = new ComponentFixture(Parent); expect(fixture.html) @@ -675,7 +675,7 @@ describe('content projection', () => { containerRefreshStart(1); { if (!ctx.skipContent) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { projection(0); } @@ -684,7 +684,7 @@ describe('content projection', () => { } containerRefreshEnd(); } - }); + }, 2); /** * @@ -710,7 +710,7 @@ describe('content projection', () => { containerRefreshStart(2); { if (!ctx.skipContent) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { projection(0); } @@ -719,7 +719,7 @@ describe('content projection', () => { } containerRefreshEnd(); } - }, [Child]); + }, 4, [Child]); let parent: any; /**

      text

      */ @@ -735,7 +735,7 @@ describe('content projection', () => { // testing parent = loadDirective(0); } - }, [Parent]); + }, 3, [Parent]); const fixture = new ComponentFixture(App); expect(fixture.html) @@ -769,7 +769,7 @@ describe('content projection', () => { containerRefreshStart(1); { if (!ctx.skipContent) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 3); if (rf0 & RenderFlags.Create) { text(0, 'before-'); projection(1); @@ -780,7 +780,7 @@ describe('content projection', () => { } containerRefreshEnd(); } - }); + }, 2); /** * content @@ -794,7 +794,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 2, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('
      before-content-after
      '); @@ -816,14 +816,14 @@ describe('content projection', () => { if (rf & RenderFlags.Create) { projectionDef(); text(0, 'Before-'); - template(1, IfTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']); + template(1, IfTemplate, 1, '', [AttributeMarker.SelectOnly, 'ngIf']); text(2, '-After'); } if (rf & RenderFlags.Update) { elementProperty(1, 'ngIf', bind(ctx.showing)); } - }, [NgIf]); + }, 3, [NgIf]); function IfTemplate(rf1: RenderFlags, ctx: any) { if (rf1 & RenderFlags.Create) { @@ -853,7 +853,7 @@ describe('content projection', () => { // testing child = loadDirective(0); } - }, [Child]); + }, 4, [Child]); const fixture = new ComponentFixture(App); child !.showing = true; @@ -881,14 +881,14 @@ describe('content projection', () => { if (rf & RenderFlags.Create) { projectionDef(); text(0, 'Before-'); - template(1, IfTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']); + template(1, IfTemplate, 1, '', [AttributeMarker.SelectOnly, 'ngIf']); text(2, '-After'); } if (rf & RenderFlags.Update) { elementProperty(1, 'ngIf', bind(ctx.showing)); } - }, [NgIf]); + }, 3, [NgIf]); function IfTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -918,7 +918,7 @@ describe('content projection', () => { // testing child = loadDirective(0); } - }, [Child]); + }, 4, [Child]); const fixture = new ComponentFixture(App); child !.showing = true; @@ -949,7 +949,7 @@ describe('content projection', () => { { projection(3); } elementEnd(); } - }); + }, 4); /** * content @@ -960,7 +960,7 @@ describe('content projection', () => { { text(1, 'content'); } elementEnd(); } - }, [Child]); + }, 2, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('
      content
      '); @@ -997,7 +997,7 @@ describe('content projection', () => { containerRefreshStart(2); { if (ctx.show) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { projection(0); } @@ -1006,7 +1006,7 @@ describe('content projection', () => { } containerRefreshEnd(); } - }); + }, 3); /** * content @@ -1020,7 +1020,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 2, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('content
      '); @@ -1038,7 +1038,7 @@ describe('content projection', () => { projection(1); text(2, 'After'); } - }); + }, 3); /** * @@ -1073,7 +1073,7 @@ describe('content projection', () => { } elementEnd(); } - }, [ProjectionComp]); + }, 10, [ProjectionComp]); const fixture = new ComponentFixture(AppComp); fixture.update(); @@ -1096,7 +1096,7 @@ describe('content projection', () => { projection(1); text(2, 'After'); } - }); + }, 3); /** * @@ -1134,7 +1134,7 @@ describe('content projection', () => { } elementEnd(); } - }, [ProjectionComp]); + }, 11, [ProjectionComp]); /** * @@ -1153,7 +1153,7 @@ describe('content projection', () => { { text(3, '**DEF**'); } elementEnd(); } - }, [ProjectionParent]); + }, 4, [ProjectionParent]); const fixture = new ComponentFixture(AppComp); fixture.update(); @@ -1175,7 +1175,7 @@ describe('content projection', () => { projectionDef(); projection(0); } - }); + }, 1); ` @@ -1198,7 +1198,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 4, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('content'); @@ -1212,7 +1212,7 @@ describe('content projection', () => { projectionDef(); projection(0); } - }); + }, 1); ` @@ -1224,7 +1224,7 @@ describe('content projection', () => { { projection(1); } elementEnd(); } - }, [GrandChild]); + }, 2, [GrandChild]); ` @@ -1247,7 +1247,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 4, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('content'); @@ -1272,7 +1272,7 @@ describe('content projection', () => { { projection(3, 2); } elementEnd(); } - }); + }, 4); /** * @@ -1293,7 +1293,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 5, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)) @@ -1311,7 +1311,7 @@ describe('content projection', () => { projectionDef([[['', 'title', '']]], ['[title]']); { projection(0, 1); } } - }); + }, 1); /** * @@ -1331,7 +1331,7 @@ describe('content projection', () => { if (rf & RenderFlags.Update) { elementProperty(1, 'title', bind('Some title')); } - }, [Child]); + }, 3, [Child]); const fixture = new ComponentFixture(Parent); expect(fixture.html).toEqual('Has title'); @@ -1358,7 +1358,7 @@ describe('content projection', () => { { projection(3, 2); } elementEnd(); } - }); + }, 4); /** * @@ -1379,7 +1379,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 5, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)) @@ -1407,7 +1407,7 @@ describe('content projection', () => { { projection(3, 2); } elementEnd(); } - }); + }, 4); /** * @@ -1428,7 +1428,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 5, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)) @@ -1452,7 +1452,7 @@ describe('content projection', () => { { projection(3, 2); } elementEnd(); } - }); + }, 4); /** * @@ -1473,7 +1473,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 5, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)) @@ -1496,7 +1496,7 @@ describe('content projection', () => { { projection(3); } elementEnd(); } - }); + }, 4); /** * @@ -1518,7 +1518,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 6, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)) @@ -1541,7 +1541,7 @@ describe('content projection', () => { { projection(3, 1); } elementEnd(); } - }); + }, 4); /** * @@ -1564,7 +1564,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 6, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)) @@ -1590,7 +1590,7 @@ describe('content projection', () => { element(1, 'hr'); projection(2); } - }); + }, 3); /** * @@ -1610,7 +1610,7 @@ describe('content projection', () => { } elementEnd(); } - }, [GrandChild]); + }, 4, [GrandChild]); /** * @@ -1629,7 +1629,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 3, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)) @@ -1653,7 +1653,7 @@ describe('content projection', () => { element(1, 'hr'); projection(2, 2); } - }); + }, 3); /** * @@ -1673,7 +1673,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Card]); + }, 4, [Card]); /** * @@ -1686,7 +1686,7 @@ describe('content projection', () => { { text(1, 'content'); } elementEnd(); } - }, [CardWithTitle]); + }, 2, [CardWithTitle]); const app = renderComponent(App); expect(toHtml(app)) @@ -1711,7 +1711,7 @@ describe('content projection', () => { element(1, 'hr'); projection(2, 2); } - }); + }, 3); /** * @@ -1731,7 +1731,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Card]); + }, 4, [Card]); /** * @@ -1744,7 +1744,7 @@ describe('content projection', () => { { text(1, 'content'); } elementEnd(); } - }, [CardWithTitle]); + }, 2, [CardWithTitle]); const app = renderComponent(App); expect(toHtml(app)) @@ -1762,7 +1762,7 @@ describe('content projection', () => { projectionDef([[['div']]], ['div']); projection(0, 1); } - }); + }, 1); /** * @@ -1783,7 +1783,7 @@ describe('content projection', () => { } elementEnd(); } - }, [Child]); + }, 5, [Child]); const parent = renderComponent(Parent); expect(toHtml(parent)).toEqual('
      should project
      '); @@ -1803,7 +1803,7 @@ describe('content projection', () => { { projection(1, 1); } elementEnd(); } - }); + }, 2); function IfTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -1821,13 +1821,13 @@ describe('content projection', () => { const Parent = createComponent('parent', function(rf: RenderFlags, ctx: {value: any}) { if (rf & RenderFlags.Create) { elementStart(0, 'child'); - { template(1, IfTemplate, 'div', [AttributeMarker.SelectOnly, 'ngIf']); } + { template(1, IfTemplate, 2, 'div', [AttributeMarker.SelectOnly, 'ngIf']); } elementEnd(); } if (rf & RenderFlags.Update) { elementProperty(1, 'ngIf', bind(ctx.value)); } - }, [Child, NgIf]); + }, 2, [Child, NgIf]); const fixture = new ComponentFixture(Parent); diff --git a/packages/core/test/render3/control_flow_spec.ts b/packages/core/test/render3/control_flow_spec.ts index 09c8528ffd..7e9993aa77 100644 --- a/packages/core/test/render3/control_flow_spec.ts +++ b/packages/core/test/render3/control_flow_spec.ts @@ -14,9 +14,7 @@ import {ComponentFixture, TemplateFixture, createComponent, renderToHtml} from ' describe('JS control flow', () => { it('should work with if block', () => { - const ctx: {message: string | null, condition: boolean} = {message: 'Hello', condition: true}; - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); { container(1); } @@ -26,7 +24,7 @@ describe('JS control flow', () => { containerRefreshStart(1); { if (ctx.condition) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { elementStart(0, 'span'); @@ -42,21 +40,25 @@ describe('JS control flow', () => { } } containerRefreshEnd(); - } + }, 2); - expect(renderToHtml(Template, ctx)).toEqual('
      Hello
      '); + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.component.message = 'Hello'; + fixture.update(); + expect(fixture.html).toEqual('
      Hello
      '); - ctx.condition = false; - ctx.message = 'Hi!'; - expect(renderToHtml(Template, ctx)).toEqual('
      '); + fixture.component.condition = false; + fixture.component.message = 'Hi!'; + fixture.update(); + expect(fixture.html).toEqual('
      '); - ctx.condition = true; - expect(renderToHtml(Template, ctx)).toEqual('
      Hi!
      '); + fixture.component.condition = true; + fixture.update(); + expect(fixture.html).toEqual('
      Hi!
      '); }); it('should work with nested if blocks', () => { - const ctx: {condition: boolean, condition2: boolean} = {condition: true, condition2: true}; - /** *
      * % if(ctx.condition) { @@ -68,7 +70,7 @@ describe('JS control flow', () => { * % } *
      */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); { container(1); } @@ -78,7 +80,7 @@ describe('JS control flow', () => { containerRefreshStart(1); { if (ctx.condition) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { elementStart(0, 'span'); @@ -89,7 +91,7 @@ describe('JS control flow', () => { containerRefreshStart(1); { if (ctx.condition2) { - let rf2 = embeddedViewStart(2); + let rf2 = embeddedViewStart(2, 1); { if (rf2 & RenderFlags.Create) { text(0, 'Hello'); @@ -106,33 +108,45 @@ describe('JS control flow', () => { } containerRefreshEnd(); } - } + }, 2); - expect(renderToHtml(Template, ctx)).toEqual('
      Hello
      '); + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.component.condition2 = true; + fixture.update(); + expect(fixture.html).toEqual('
      Hello
      '); - ctx.condition = false; - expect(renderToHtml(Template, ctx)).toEqual('
      '); + fixture.component.condition = false; + fixture.update(); + expect(fixture.html).toEqual('
      '); - ctx.condition = true; - expect(renderToHtml(Template, ctx)).toEqual('
      Hello
      '); + fixture.component.condition = true; + fixture.update(); + expect(fixture.html).toEqual('
      Hello
      '); - ctx.condition2 = false; - expect(renderToHtml(Template, ctx)).toEqual('
      '); + fixture.component.condition2 = false; + fixture.update(); + expect(fixture.html).toEqual('
      '); - ctx.condition2 = true; - expect(renderToHtml(Template, ctx)).toEqual('
      Hello
      '); + fixture.component.condition2 = true; + fixture.update(); + expect(fixture.html).toEqual('
      Hello
      '); - ctx.condition2 = false; - expect(renderToHtml(Template, ctx)).toEqual('
      '); + fixture.component.condition2 = false; + fixture.update(); + expect(fixture.html).toEqual('
      '); - ctx.condition = false; - expect(renderToHtml(Template, ctx)).toEqual('
      '); + fixture.component.condition = false; + fixture.update(); + expect(fixture.html).toEqual('
      '); - ctx.condition = true; - expect(renderToHtml(Template, ctx)).toEqual('
      '); + fixture.component.condition = true; + fixture.update(); + expect(fixture.html).toEqual('
      '); - ctx.condition2 = true; - expect(renderToHtml(Template, ctx)).toEqual('
      Hello
      '); + fixture.component.condition2 = true; + fixture.update(); + expect(fixture.html).toEqual('
      Hello
      '); }); it('should work with nested adjacent if blocks', () => { @@ -156,7 +170,7 @@ describe('JS control flow', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { { container(0); } @@ -166,7 +180,7 @@ describe('JS control flow', () => { containerRefreshStart(0); { if (ctx.condition2) { - let rf2 = embeddedViewStart(2); + let rf2 = embeddedViewStart(2, 1); { if (rf2 & RenderFlags.Create) { text(0, 'Hello'); @@ -179,7 +193,7 @@ describe('JS control flow', () => { containerRefreshStart(1); { if (ctx.condition3) { - let rf2 = embeddedViewStart(2); + let rf2 = embeddedViewStart(2, 1); { if (rf2 & RenderFlags.Create) { text(0, 'World'); @@ -197,7 +211,7 @@ describe('JS control flow', () => { containerRefreshEnd(); } - const fixture = new TemplateFixture(createTemplate, updateTemplate); + const fixture = new TemplateFixture(createTemplate, updateTemplate, 1); expect(fixture.html).toEqual('World'); ctx.condition2 = true; @@ -206,9 +220,6 @@ describe('JS control flow', () => { }); it('should work with adjacent if blocks managing views in the same container', () => { - - const ctx = {condition1: true, condition2: true, condition3: true}; - /** * % if(ctx.condition1) { * 1 @@ -218,28 +229,28 @@ describe('JS control flow', () => { * 3 * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } if (rf & RenderFlags.Update) { containerRefreshStart(0); if (ctx.condition1) { - const rf1 = embeddedViewStart(1); + const rf1 = embeddedViewStart(1, 1); if (rf1 & RenderFlags.Create) { text(0, '1'); } embeddedViewEnd(); } // can't have ; here due linting rules if (ctx.condition2) { - const rf2 = embeddedViewStart(2); + const rf2 = embeddedViewStart(2, 1); if (rf2 & RenderFlags.Create) { text(0, '2'); } embeddedViewEnd(); } // can't have ; here due linting rules if (ctx.condition3) { - const rf3 = embeddedViewStart(3); + const rf3 = embeddedViewStart(3, 1); if (rf3 & RenderFlags.Create) { text(0, '3'); } @@ -247,16 +258,22 @@ describe('JS control flow', () => { } containerRefreshEnd(); } - } + }, 1); - expect(renderToHtml(Template, ctx)).toEqual('123'); + const fixture = new ComponentFixture(App); + fixture.component.condition1 = true; + fixture.component.condition2 = true; + fixture.component.condition3 = true; + fixture.update(); + expect(fixture.html).toEqual('123'); - ctx.condition2 = false; - expect(renderToHtml(Template, ctx)).toEqual('13'); + fixture.component.condition2 = false; + fixture.update(); + expect(fixture.html).toEqual('13'); }); it('should work with containers with views as parents', () => { - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); { text(1, 'hello'); } @@ -267,7 +284,7 @@ describe('JS control flow', () => { containerRefreshStart(2); { if (ctx.condition1) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); { if (rf0 & RenderFlags.Create) { container(0); @@ -276,7 +293,7 @@ describe('JS control flow', () => { containerRefreshStart(0); { if (ctx.condition2) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); { if (rf0 & RenderFlags.Create) { text(0, 'world'); @@ -293,19 +310,23 @@ describe('JS control flow', () => { } containerRefreshEnd(); } - } + }, 3); - expect(renderToHtml(Template, {condition1: true, condition2: true})) - .toEqual('
      hello
      world'); - expect(renderToHtml(Template, {condition1: false, condition2: false})) - .toEqual('
      hello
      '); + const fixture = new ComponentFixture(App); + fixture.component.condition1 = true; + fixture.component.condition2 = true; + fixture.update(); + expect(fixture.html).toEqual('
      hello
      world'); + fixture.component.condition1 = false; + fixture.component.condition2 = false; + fixture.update(); + expect(fixture.html).toEqual('
      hello
      '); }); it('should work with loop block', () => { - const ctx: {data: string[] | null} = {data: ['a', 'b', 'c']}; - - function Template(rf: RenderFlags, ctx: any) { + let data: string[] = ['a', 'b', 'c']; + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'ul'); { container(1); } @@ -314,8 +335,8 @@ describe('JS control flow', () => { if (rf & RenderFlags.Update) { containerRefreshStart(1); { - for (let i = 0; i < ctx.data.length; i++) { - let rf1 = embeddedViewStart(1); + for (let i = 0; i < data.length; i++) { + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { elementStart(0, 'li'); @@ -323,7 +344,7 @@ describe('JS control flow', () => { elementEnd(); } if (rf1 & RenderFlags.Update) { - textBinding(1, bind(ctx.data[i])); + textBinding(1, bind(data[i])); } } embeddedViewEnd(); @@ -331,31 +352,37 @@ describe('JS control flow', () => { } containerRefreshEnd(); } - } + }, 2); - expect(renderToHtml(Template, ctx)).toEqual('
      • a
      • b
      • c
      '); + const fixture = new ComponentFixture(App); + fixture.update(); + expect(fixture.html).toEqual('
      • a
      • b
      • c
      '); - ctx.data = ['e', 'f']; - expect(renderToHtml(Template, ctx)).toEqual('
      • e
      • f
      '); + data = ['e', 'f']; + fixture.update(); + expect(fixture.html).toEqual('
      • e
      • f
      '); - ctx.data = []; - expect(renderToHtml(Template, ctx)).toEqual('
        '); + data = []; + fixture.update(); + expect(fixture.html).toEqual('
          '); - ctx.data = ['a', 'b', 'c']; - expect(renderToHtml(Template, ctx)).toEqual('
          • a
          • b
          • c
          '); + data = ['a', 'b', 'c']; + fixture.update(); + expect(fixture.html).toEqual('
          • a
          • b
          • c
          '); - ctx.data.push('d'); - expect(renderToHtml(Template, ctx)) - .toEqual('
          • a
          • b
          • c
          • d
          '); + data.push('d'); + fixture.update(); + expect(fixture.html).toEqual('
          • a
          • b
          • c
          • d
          '); - ctx.data = ['e']; - expect(renderToHtml(Template, ctx)).toEqual('
          • e
          '); + data = ['e']; + fixture.update(); + expect(fixture.html).toEqual('
          • e
          '); }); it('should work with nested loop blocks', () => { - const ctx: {data: string[][] | null} = {data: [['a', 'b', 'c'], ['m', 'n']]}; + let data: string[][] = [['a', 'b', 'c'], ['m', 'n']]; - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'ul'); { container(1); } @@ -364,8 +391,8 @@ describe('JS control flow', () => { if (rf & RenderFlags.Update) { containerRefreshStart(1); { - for (let i = 0; i < ctx.data[0].length; i++) { - let rf1 = embeddedViewStart(1); + for (let i = 0; i < data[0].length; i++) { + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { elementStart(0, 'li'); @@ -375,13 +402,13 @@ describe('JS control flow', () => { if (rf1 & RenderFlags.Update) { containerRefreshStart(1); { - ctx.data[1].forEach((value: string, ind: number) => { - let rf2 = embeddedViewStart(2); + data[1].forEach((value: string, ind: number) => { + let rf2 = embeddedViewStart(2, 1); if (rf2 & RenderFlags.Create) { text(0); } if (rf2 & RenderFlags.Update) { - textBinding(0, bind(ctx.data[0][i] + value)); + textBinding(0, bind(data[0][i] + value)); } embeddedViewEnd(); }); @@ -394,15 +421,22 @@ describe('JS control flow', () => { } containerRefreshEnd(); } - } + }, 2); - expect(renderToHtml(Template, ctx)).toEqual('
          • aman
          • bmbn
          • cmcn
          '); + const fixture = new ComponentFixture(App); + fixture.update(); + expect(fixture.html).toEqual('
          • aman
          • bmbn
          • cmcn
          '); - ctx.data = [[], []]; - expect(renderToHtml(Template, ctx)).toEqual('
            '); + data = [[], []]; + fixture.update(); + expect(fixture.html).toEqual('
              '); }); it('should work with nested loop blocks where nested container is a root node', () => { + let cafes = [ + {name: '1', entrees: ['a', 'b', 'c']}, {name: '2', entrees: ['d', 'e', 'f']}, + {name: '3', entrees: ['g', 'h', 'i']} + ]; /** *
              @@ -417,7 +451,7 @@ describe('JS control flow', () => { * After *
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); { @@ -430,8 +464,8 @@ describe('JS control flow', () => { if (rf & RenderFlags.Update) { containerRefreshStart(2); { - for (let i = 0; i < ctx.cafes.length; i++) { - let rf1 = embeddedViewStart(1); + for (let i = 0; i < cafes.length; i++) { + let rf1 = embeddedViewStart(1, 4); { if (rf1 & RenderFlags.Create) { elementStart(0, 'h2'); @@ -441,16 +475,16 @@ describe('JS control flow', () => { text(3, '-'); } if (rf1 & RenderFlags.Update) { - textBinding(1, bind(ctx.cafes[i].name)); + textBinding(1, bind(cafes[i].name)); containerRefreshStart(2); { - for (let j = 0; j < ctx.cafes[i].entrees.length; j++) { - let rf2 = embeddedViewStart(2); + for (let j = 0; j < cafes[i].entrees.length; j++) { + let rf2 = embeddedViewStart(2, 1); if (rf2 & RenderFlags.Create) { text(0); } if (rf2 & RenderFlags.Update) { - textBinding(0, bind(ctx.cafes[i].entrees[j])); + textBinding(0, bind(cafes[i].entrees[j])); } embeddedViewEnd(); } @@ -463,30 +497,38 @@ describe('JS control flow', () => { } containerRefreshEnd(); } - } + }, 4); - const ctx = { - cafes: [ - {name: '1', entrees: ['a', 'b', 'c']}, {name: '2', entrees: ['d', 'e', 'f']}, - {name: '3', entrees: ['g', 'h', 'i']} - ] - }; - - expect(renderToHtml(Template, ctx)) + const fixture = new ComponentFixture(App); + fixture.update(); + expect(fixture.html) .toEqual('
              Before

              1

              abc-

              2

              def-

              3

              ghi-After
              '); - ctx.cafes = []; - expect(renderToHtml(Template, ctx)).toEqual('
              BeforeAfter
              '); + cafes = []; + fixture.update(); + expect(fixture.html).toEqual('
              BeforeAfter
              '); - ctx.cafes = [ + cafes = [ {name: '1', entrees: ['a', 'c']}, {name: '2', entrees: ['d', 'e']}, ]; - expect(renderToHtml(Template, ctx)).toEqual('
              Before

              1

              ac-

              2

              de-After
              '); - + fixture.update(); + expect(fixture.html).toEqual('
              Before

              1

              ac-

              2

              de-After
              '); }); it('should work with loop blocks nested three deep', () => { + let cafes = [ + { + name: '1', + entrees: + [{name: 'a', foods: [1, 2]}, {name: 'b', foods: [3, 4]}, {name: 'c', foods: [5, 6]}] + }, + { + name: '2', + entrees: + [{name: 'd', foods: [1, 2]}, {name: 'e', foods: [3, 4]}, {name: 'f', foods: [5, 6]}] + } + ]; /** *
              @@ -504,7 +546,7 @@ describe('JS control flow', () => { * After *
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); { @@ -517,8 +559,8 @@ describe('JS control flow', () => { if (rf & RenderFlags.Update) { containerRefreshStart(2); { - for (let i = 0; i < ctx.cafes.length; i++) { - let rf1 = embeddedViewStart(1); + for (let i = 0; i < cafes.length; i++) { + let rf1 = embeddedViewStart(1, 4); { if (rf1 & RenderFlags.Create) { elementStart(0, 'h2'); @@ -528,11 +570,11 @@ describe('JS control flow', () => { text(3, '-'); } if (rf1 & RenderFlags.Update) { - textBinding(1, bind(ctx.cafes[i].name)); + textBinding(1, bind(cafes[i].name)); containerRefreshStart(2); { - for (let j = 0; j < ctx.cafes[i].entrees.length; j++) { - let rf1 = embeddedViewStart(1); + for (let j = 0; j < cafes[i].entrees.length; j++) { + let rf1 = embeddedViewStart(1, 3); { if (rf1 & RenderFlags.Create) { elementStart(0, 'h3'); @@ -541,16 +583,16 @@ describe('JS control flow', () => { container(2); } if (rf1 & RenderFlags.Update) { - textBinding(1, bind(ctx.cafes[i].entrees[j].name)); + textBinding(1, bind(cafes[i].entrees[j].name)); containerRefreshStart(2); { - for (let k = 0; k < ctx.cafes[i].entrees[j].foods.length; k++) { - let rf2 = embeddedViewStart(1); + for (let k = 0; k < cafes[i].entrees[j].foods.length; k++) { + let rf2 = embeddedViewStart(1, 1); if (rf2 & RenderFlags.Create) { text(0); } if (rf2 & RenderFlags.Update) { - textBinding(0, bind(ctx.cafes[i].entrees[j].foods[k])); + textBinding(0, bind(cafes[i].entrees[j].foods[k])); } embeddedViewEnd(); } @@ -569,25 +611,11 @@ describe('JS control flow', () => { } containerRefreshEnd(); } - } + }, 4); - const ctx = { - cafes: [ - { - name: '1', - entrees: - [{name: 'a', foods: [1, 2]}, {name: 'b', foods: [3, 4]}, {name: 'c', foods: [5, 6]}] - }, - { - name: '2', - entrees: [ - {name: 'd', foods: [1, 2]}, {name: 'e', foods: [3, 4]}, {name: 'f', foods: [5, 6]} - ] - } - ] - }; - - expect(renderToHtml(Template, ctx)) + const fixture = new ComponentFixture(App); + fixture.update(); + expect(fixture.html) .toEqual( '
              ' + 'Before' + @@ -596,14 +624,13 @@ describe('JS control flow', () => { 'After' + '
              '); - ctx.cafes = []; - expect(renderToHtml(Template, ctx)).toEqual('
              BeforeAfter
              '); + cafes = []; + fixture.update(); + expect(fixture.html).toEqual('
              BeforeAfter
              '); }); it('should work with if/else blocks', () => { - const ctx: {message: string | null, condition: boolean} = {message: 'Hello', condition: true}; - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); { container(1); } @@ -613,7 +640,7 @@ describe('JS control flow', () => { containerRefreshStart(1); { if (ctx.condition) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { elementStart(0, 'span'); @@ -623,7 +650,7 @@ describe('JS control flow', () => { } embeddedViewEnd(); } else { - let rf2 = embeddedViewStart(2); + let rf2 = embeddedViewStart(2, 2); { if (rf2) { elementStart(0, 'div'); @@ -636,15 +663,20 @@ describe('JS control flow', () => { } containerRefreshEnd(); } - } + }, 2); - expect(renderToHtml(Template, ctx)).toEqual('
              Hello
              '); + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.update(); + expect(fixture.html).toEqual('
              Hello
              '); - ctx.condition = false; - expect(renderToHtml(Template, ctx)).toEqual('
              Goodbye
              '); + fixture.component.condition = false; + fixture.update(); + expect(fixture.html).toEqual('
              Goodbye
              '); - ctx.condition = true; - expect(renderToHtml(Template, ctx)).toEqual('
              Hello
              '); + fixture.component.condition = true; + fixture.update(); + expect(fixture.html).toEqual('
              Hello
              '); }); it('should work with sibling if blocks with children', () => { @@ -656,6 +688,7 @@ describe('JS control flow', () => { static ngComponentDef = defineComponent({ type: Comp, selectors: [['comp']], + consts: 0, factory: () => { log.push('comp!'); return new Comp(); @@ -672,6 +705,7 @@ describe('JS control flow', () => { type: App, selectors: [['app']], factory: () => new App(), + consts: 3, template: function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div'); @@ -682,7 +716,7 @@ describe('JS control flow', () => { containerRefreshStart(1); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -693,7 +727,7 @@ describe('JS control flow', () => { containerRefreshStart(2); { if (ctx.condition2) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -720,6 +754,7 @@ describe('JS control flow', () => { static ngComponentDef = defineComponent({ type: Comp, selectors: [['comp']], + consts: 0, factory: () => { log.push('comp!'); return new Comp(); @@ -736,6 +771,7 @@ describe('JS control flow', () => { type: App, selectors: [['app']], factory: () => new App(), + consts: 3, template: function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div'); @@ -746,7 +782,7 @@ describe('JS control flow', () => { containerRefreshStart(1); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -757,7 +793,7 @@ describe('JS control flow', () => { containerRefreshStart(2); { if (ctx.condition2) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -782,8 +818,7 @@ describe('JS control flow', () => { describe('JS for loop', () => { it('should work with sibling for blocks', () => { - const ctx: {data1: string[] | null, - data2: number[] | null} = {data1: ['a', 'b', 'c'], data2: [1, 2]}; + const config: {data1: string[], data2: number[]} = {data1: ['a', 'b', 'c'], data2: [1, 2]}; /** *
              @@ -794,7 +829,7 @@ describe('JS for loop', () => { * % } *
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); { container(1); } @@ -803,47 +838,51 @@ describe('JS for loop', () => { if (rf & RenderFlags.Update) { containerRefreshStart(1); { - for (let i = 0; i < ctx.data1.length; i++) { - let rf2 = embeddedViewStart(1); + for (let i = 0; i < config.data1.length; i++) { + let rf2 = embeddedViewStart(1, 1); if (rf2 & RenderFlags.Create) { text(0); } if (rf2 & RenderFlags.Update) { - textBinding(0, bind(ctx.data1[i])); + textBinding(0, bind(config.data1[i])); } embeddedViewEnd(); } - for (let j = 0; j < ctx.data2.length; j++) { - let rf2 = embeddedViewStart(1); + for (let j = 0; j < config.data2.length; j++) { + let rf2 = embeddedViewStart(1, 1); if (rf2 & RenderFlags.Create) { text(0); } if (rf2 & RenderFlags.Update) { - textBinding(0, bind(ctx.data2[j])); + textBinding(0, bind(config.data2[j])); } embeddedViewEnd(); } } containerRefreshEnd(); } - } + }, 2); - expect(renderToHtml(Template, ctx)).toEqual('
              abc12
              '); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('
              abc12
              '); - ctx.data1 = ['e', 'f']; - expect(renderToHtml(Template, ctx)).toEqual('
              ef12
              '); + config.data1 = ['e', 'f']; + fixture.update(); + expect(fixture.html).toEqual('
              ef12
              '); - ctx.data2 = [8]; - expect(renderToHtml(Template, ctx)).toEqual('
              ef8
              '); + config.data2 = [8]; + fixture.update(); + expect(fixture.html).toEqual('
              ef8
              '); - ctx.data1 = ['x', 'y']; - expect(renderToHtml(Template, ctx)).toEqual('
              xy8
              '); + config.data1 = ['x', 'y']; + fixture.update(); + expect(fixture.html).toEqual('
              xy8
              '); }); }); describe('function calls', () => { it('should work', () => { - const ctx: {data: string[]} = {data: ['foo', 'bar']}; + let data: string[] = ['foo', 'bar']; function spanify(rf: RenderFlags, ctx: {message: string | null}) { const message = ctx.message; @@ -857,7 +896,7 @@ describe('function calls', () => { } } - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); { @@ -871,26 +910,27 @@ describe('function calls', () => { if (rf & RenderFlags.Update) { containerRefreshStart(2); { - let rf0 = embeddedViewStart(0); - { spanify(rf0, {message: ctx.data[0]}); } + let rf0 = embeddedViewStart(0, 2); + { spanify(rf0, {message: data[0]}); } embeddedViewEnd(); } containerRefreshEnd(); containerRefreshStart(3); { - let rf0 = embeddedViewStart(0); - { spanify(rf0, {message: ctx.data[1]}); } + let rf0 = embeddedViewStart(0, 2); + { spanify(rf0, {message: data[1]}); } embeddedViewEnd(); } containerRefreshEnd(); } - } + }, 5); - expect(renderToHtml(Template, ctx)) - .toEqual('
              BeforefoobarAfter
              '); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('
              BeforefoobarAfter
              '); - ctx.data = []; - expect(renderToHtml(Template, ctx)).toEqual('
              BeforeAfter
              '); + data = []; + fixture.update(); + expect(fixture.html).toEqual('
              BeforeAfter
              '); }); }); diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index a66f262c15..94d193841c 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -34,7 +34,7 @@ describe('di', () => { } /**
              {{ dir.value }}
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div', ['dir', ''], ['dir', 'dir']); { text(2); } @@ -44,9 +44,10 @@ describe('di', () => { const tmp = reference(1) as any; textBinding(2, bind(tmp.value)); } - } + }, 3, [Directive]); - expect(renderToHtml(Template, {}, [Directive])).toEqual('
              Created
              '); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('
              Created
              '); }); }); @@ -94,7 +95,7 @@ describe('di', () => { * {{ dir.value }} *
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div', ['dirA', '']); { @@ -108,11 +109,10 @@ describe('di', () => { const tmp = reference(2) as any; textBinding(3, bind(tmp.value)); } - } + }, 4, [DirA, DirB, DirC]); - const defs = [DirA, DirB, DirC]; - expect(renderToHtml(Template, {}, defs)) - .toEqual('
              DirADirB
              '); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('
              DirADirB
              '); }); it('should instantiate injected directives in dependency order', () => { @@ -131,7 +131,7 @@ describe('di', () => { if (rf & RenderFlags.Create) { element(0, 'div', ['dirA', '', 'dirB', '']); } - }, [DirA, DirB]); + }, 1, [DirA, DirB]); new ComponentFixture(App); expect(log).toEqual(['DirB', 'DirA (dep: DirB)']); @@ -157,7 +157,7 @@ describe('di', () => { element(0, 'div', ['dirB', '']); element(1, 'div', ['dirA', '']); } - }, [DirA, DirB]); + }, 2, [DirA, DirB]); const fakeModuleInjector: any = { get: function(token: any) { @@ -177,6 +177,7 @@ describe('di', () => { static ngComponentDef = defineComponent({ selectors: [['comp']], type: Comp, + consts: 0, factory: () => new Comp(directiveInject(DirB)), template: (ctx: any, fm: boolean) => {} }); @@ -187,7 +188,7 @@ describe('di', () => { if (rf & RenderFlags.Create) { element(0, 'comp', ['dirB', '']); } - }, [Comp, DirB]); + }, 1, [Comp, DirB]); new ComponentFixture(App); expect(log).toEqual(['DirB', 'Comp (dep: DirB)']); @@ -216,14 +217,14 @@ describe('di', () => { containerRefreshStart(0); { for (let i = 0; i < 3; i++) { - if (embeddedViewStart(0)) { + if (embeddedViewStart(0, 1)) { element(0, 'div', ['dirA', '', 'dirB', '']); } embeddedViewEnd(); } } containerRefreshEnd(); - }, [DirA, DirB]); + }, 1, [DirA, DirB]); new ComponentFixture(App); expect(log).toEqual( @@ -272,7 +273,7 @@ describe('di', () => { if (rf & RenderFlags.Create) { element(0, 'div', ['dirA', '', 'dirB', '', 'dirC', '']); } - }, [DirA, DirB, DirC]); + }, 1, [DirA, DirB, DirC]); new ComponentFixture(App); expect(log).toEqual(['DirA', 'DirC', 'DirB (deps: DirA and DirC)']); @@ -285,6 +286,7 @@ describe('di', () => { static ngComponentDef = defineComponent({ selectors: [['comp']], type: Comp, + consts: 0, factory: () => new Comp(directiveInject(DirD)), template: (ctx: any, fm: boolean) => {} }); @@ -331,7 +333,7 @@ describe('di', () => { if (rf & RenderFlags.Create) { element(0, 'comp', ['dirA', '', 'dirB', '', 'dirC', '', 'dirD', '']); } - }, [Comp, DirA, DirB, DirC, DirD]); + }, 1, [Comp, DirA, DirB, DirC, DirD]); new ComponentFixture(App); expect(log).toEqual( @@ -358,6 +360,7 @@ describe('di', () => { selectors: [['app']], type: App, factory: () => new App(), + consts: 1, /**
              */ template: (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { @@ -407,14 +410,14 @@ describe('di', () => { if (rf & RenderFlags.Create) { element(0, 'div', ['dirA', '', 'dirB', '']); } - }, [DirA, DirB]); + }, 1, [DirA, DirB]); /** */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent', ['dirB', '']); } - }, [Parent, DirB]); + }, 1, [Parent, DirB]); new ComponentFixture(App); expect(log).toEqual(['DirB', 'DirB', 'DirA (dep: DirB - 2)']); @@ -432,6 +435,7 @@ describe('di', () => { static ngComponentDef = defineComponent({ type: MyComponent, selectors: [['my-component']], + consts: 1, factory: () => new MyComponent(directiveInject(MyService)), template: function(rf: RenderFlags, ctx: MyComponent) { if (rf & RenderFlags.Create) { @@ -475,7 +479,7 @@ describe('di', () => { if (rf & RenderFlags.Create) { element(0, 'div', ['dir', '']); } - }, [Dir, OtherDir]); + }, 1, [Dir, OtherDir]); expect(() => new ComponentFixture(App)).toThrowError(/Injector: NOT_FOUND \[OtherDir\]/); }); @@ -510,7 +514,7 @@ describe('di', () => { element(0, 'div', ['other', '']); element(1, 'div', ['dir', '']); } - }, [Dir, OtherDir]); + }, 2, [Dir, OtherDir]); expect(() => new ComponentFixture(App)).toThrowError(/Injector: NOT_FOUND \[OtherDir\]/); }); @@ -544,7 +548,7 @@ describe('di', () => { if (rf & RenderFlags.Create) { element(0, 'div', ['dirA', '', 'dirB', '']); } - }, [DirA, DirB]); + }, 1, [DirA, DirB]); expect(() => new ComponentFixture(App)).toThrowError(/Cannot instantiate cyclic dependency!/); }); @@ -566,7 +570,7 @@ describe('di', () => { if (rf & RenderFlags.Create) { element(0, 'div', ['dir', '']); } - }, [Dir]); + }, 1, [Dir]); expect(() => new ComponentFixture(App)).toThrowError(/Cannot instantiate cyclic dependency!/); }); @@ -604,7 +608,7 @@ describe('di', () => { if (rf & RenderFlags.Create) { element(0, 'div', ['dirA', '']); } - }, [DirA, DirB]); + }, 1, [DirA, DirB]); expect(() => { new ComponentFixture(App); @@ -634,7 +638,7 @@ describe('di', () => { element(0, 'div', ['dirB', '']); element(1, 'div', ['dirA', '']); } - }, [DirA, DirB]); + }, 2, [DirA, DirB]); expect(() => { new ComponentFixture(App); @@ -660,14 +664,14 @@ describe('di', () => { if (rf & RenderFlags.Create) { element(0, 'div', ['dirA', '', 'dirB', 'self']); } - }, [DirA, DirB]); + }, 1, [DirA, DirB]); /* */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp', ['dirB', 'parent']); } - }, [Comp, DirB]); + }, 1, [Comp, DirB]); new ComponentFixture(App); expect(dirA !.dirB.value).toEqual('parent'); @@ -697,7 +701,7 @@ describe('di', () => { element(1, 'div', ['dirA', '']); elementEnd(); } - }, [DirA, DirB]); + }, 2, [DirA, DirB]); expect(() => { new ComponentFixture(App); }).toThrowError(/Injector: NOT_FOUND \[DirB\]/); }); @@ -728,7 +732,7 @@ describe('di', () => { element(1, 'div', ['dirA', '', 'dirC', '']); elementEnd(); } - }, [DirA, DirB, DirC]); + }, 2, [DirA, DirB, DirC]); expect(() => { (DirA as any)['__NG_ELEMENT_ID__'] = 1; @@ -755,14 +759,14 @@ describe('di', () => { if (rf & RenderFlags.Create) { element(0, 'div', ['dirA', '']); } - }, [DirA, DirB]); + }, 1, [DirA, DirB]); /* */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp', ['dirB', '']); } - }, [Comp, DirB]); + }, 1, [Comp, DirB]); expect(() => { new ComponentFixture(App); }).toThrowError(/Injector: NOT_FOUND \[DirB\]/); @@ -806,7 +810,7 @@ describe('di', () => { * {{ dir.value }} - {{ dirSame.value }} *
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dirSame', 'dirSame', 'dir', 'dir']); { text(3); } @@ -818,11 +822,10 @@ describe('di', () => { const tmp2 = reference(2) as any; textBinding(3, interpolation2('', tmp2.value, '-', tmp1.value, '')); } - } + }, 4, [Directive, DirectiveSameInstance]); - const defs = [Directive, DirectiveSameInstance]; - expect(renderToHtml(Template, {}, defs)) - .toEqual('
              ElementRef-true
              '); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('
              ElementRef-true
              '); }); }); @@ -860,10 +863,10 @@ describe('di', () => { * {{ dir.value }} - {{ dirSame.value }} * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { template(0, function() { - }, undefined, ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']); + }, 0, undefined, ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']); text(3); } if (rf & RenderFlags.Update) { @@ -871,10 +874,10 @@ describe('di', () => { const tmp2 = reference(2) as any; textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, '')); } - } + }, 4, [Directive, DirectiveSameInstance]); - const defs = [Directive, DirectiveSameInstance]; - expect(renderToHtml(Template, {}, defs)).toEqual('TemplateRef-true'); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('TemplateRef-true'); }); }); @@ -913,7 +916,7 @@ describe('di', () => { * {{ dir.value }} - {{ dirSame.value }} *
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']); { text(3); } @@ -924,11 +927,10 @@ describe('di', () => { const tmp2 = reference(2) as any; textBinding(3, interpolation2('', tmp1.value, '-', tmp2.value, '')); } - } + }, 4, [Directive, DirectiveSameInstance]); - const defs = [Directive, DirectiveSameInstance]; - expect(renderToHtml(Template, {}, defs)) - .toEqual('
              ViewContainerRef-true
              '); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('
              ViewContainerRef-true
              '); }); }); @@ -944,6 +946,7 @@ describe('di', () => { type: MyComp, selectors: [['my-comp']], factory: () => comp = new MyComp(injectChangeDetectorRef()), + consts: 1, template: function(rf: RenderFlags, ctx: MyComp) { if (rf & RenderFlags.Create) { projectionDef(); @@ -1012,7 +1015,7 @@ describe('di', () => { const tmp = reference(1) as any; textBinding(2, bind(tmp.value)); } - }, directives); + }, 3, directives); const app = renderComponent(MyApp); // ChangeDetectorRef is the token, ViewRef has historically been the constructor @@ -1031,6 +1034,7 @@ describe('di', () => { static ngComponentDef = defineComponent({ type: MyApp, selectors: [['my-app']], + consts: 3, factory: () => new MyApp(injectChangeDetectorRef()), /**
              {{ dir.value }}
              */ template: function(rf: RenderFlags, ctx: any) { @@ -1063,6 +1067,7 @@ describe('di', () => { static ngComponentDef = defineComponent({ type: MyApp, selectors: [['my-app']], + consts: 4, factory: () => new MyApp(injectChangeDetectorRef()), /** * @@ -1105,6 +1110,7 @@ describe('di', () => { type: MyApp, selectors: [['my-app']], factory: () => new MyApp(injectChangeDetectorRef()), + consts: 1, /** * % if (showing) { *
              {{ dir.value }}
              @@ -1118,7 +1124,7 @@ describe('di', () => { containerRefreshStart(0); { if (ctx.showing) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 3); if (rf1 & RenderFlags.Create) { elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']); { text(2); } @@ -1147,6 +1153,18 @@ describe('di', () => { }); it('should inject host component ChangeDetectorRef into directives on containers', () => { + function C1(rf1: RenderFlags, ctx1: any) { + if (rf1 & RenderFlags.Create) { + elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']); + { text(2); } + elementEnd(); + } + if (rf1 & RenderFlags.Update) { + const tmp = reference(1) as any; + textBinding(2, bind(tmp.value)); + } + } + class MyApp { showing = true; @@ -1156,27 +1174,16 @@ describe('di', () => { type: MyApp, selectors: [['my-app']], factory: () => new MyApp(injectChangeDetectorRef()), + consts: 1, /**
              {{ dir.value }}
              */ template: function(rf: RenderFlags, ctx: MyApp) { if (rf & RenderFlags.Create) { - template(0, C1, null, ['myIf', 'showing']); + template(0, C1, 3, null, ['myIf', 'showing']); } if (rf & RenderFlags.Update) { containerRefreshStart(0); containerRefreshEnd(); } - - function C1(rf1: RenderFlags, ctx1: any) { - if (rf1 & RenderFlags.Create) { - elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']); - { text(2); } - elementEnd(); - } - if (rf1 & RenderFlags.Update) { - const tmp = reference(1) as any; - textBinding(2, bind(tmp.value)); - } - } }, directives: directives }); @@ -1221,7 +1228,7 @@ describe('di', () => { exist = injectAttribute('exist'); nonExist = injectAttribute('nonExist'); } - }); + }, 1); new ComponentFixture(MyApp); expect(exist).toEqual('existValue'); @@ -1240,7 +1247,7 @@ describe('di', () => { exist = injectAttribute('exist'); nonExist = injectAttribute('nonExist'); } - }); + }, 1); new ComponentFixture(MyApp); expect(exist).toEqual('existValue'); @@ -1353,7 +1360,7 @@ describe('di', () => { * *
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div', ['parentDir', '']); { container(1); } @@ -1362,7 +1369,7 @@ describe('di', () => { if (rf & RenderFlags.Update) { containerRefreshStart(1); { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 4); if (rf1 & RenderFlags.Create) { elementStart( 0, 'span', ['childDir', '', 'child2Dir', ''], @@ -1379,10 +1386,10 @@ describe('di', () => { } containerRefreshEnd(); } - } + }, 2, [ChildDirective, Child2Directive, ParentDirective]); - const defs = [ChildDirective, Child2Directive, ParentDirective]; - expect(renderToHtml(Template, {}, defs)) + const fixture = new ComponentFixture(App); + expect(fixture.html) .toEqual('
              Directive-true
              '); }); @@ -1394,7 +1401,7 @@ describe('di', () => { describe('getOrCreateNodeInjector', () => { it('should handle initial undefined state', () => { const contentView = createLViewData( - null !, createTView(-1, null, null, null, null), null, LViewFlags.CheckAlways); + null !, createTView(-1, null, 0, null, null, null), null, LViewFlags.CheckAlways); const oldView = enterView(contentView, null !); try { const parent = createLNode(0, TNodeType.Element, null, null, null, null); diff --git a/packages/core/test/render3/directive_spec.ts b/packages/core/test/render3/directive_spec.ts index 5880a5f587..e7b7ede494 100644 --- a/packages/core/test/render3/directive_spec.ts +++ b/packages/core/test/render3/directive_spec.ts @@ -35,7 +35,7 @@ describe('directive', () => { function Template() { element(0, 'span', [AttributeMarker.SelectOnly, 'dir']); } - const fixture = new TemplateFixture(Template, () => {}, [Directive]); + const fixture = new TemplateFixture(Template, () => {}, 1, [Directive]); expect(fixture.html).toEqual(''); directiveInstance !.klass = 'bar'; @@ -86,7 +86,7 @@ describe('directive', () => { function updateTemplate() { elementProperty(0, 'test', bind(false)); } - const fixture = new TemplateFixture(createTemplate, updateTemplate, [Directive]); + const fixture = new TemplateFixture(createTemplate, updateTemplate, 1, [Directive]); // the "test" attribute should not be reflected in the DOM as it is here only for directive // matching purposes @@ -142,7 +142,7 @@ describe('directive', () => { elementProperty(0, 'prop2', bind(true)); } - const fixture = new TemplateFixture(createTemplate, updateTemplate, [Directive]); + const fixture = new TemplateFixture(createTemplate, updateTemplate, 1, [Directive]); // the "test" attribute should not be reflected in the DOM as it is here only for directive // matching purposes @@ -173,7 +173,7 @@ describe('directive', () => { elementEnd(); } - const fixture = new TemplateFixture(createTemplate, () => {}, [Directive]); + const fixture = new TemplateFixture(createTemplate, () => {}, 1, [Directive]); // "out" should not be part of reflected attributes expect(fixture.html).toEqual(''); diff --git a/packages/core/test/render3/exports_spec.ts b/packages/core/test/render3/exports_spec.ts index fe948beaa6..51813bc1b9 100644 --- a/packages/core/test/render3/exports_spec.ts +++ b/packages/core/test/render3/exports_spec.ts @@ -17,7 +17,7 @@ describe('exports', () => { it('should support export of DOM element', () => { /** {{ myInput.value }} */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'input', ['value', 'one'], ['myInput', '']); text(2); @@ -26,15 +26,27 @@ describe('exports', () => { const tmp = reference(1) as any; textBinding(2, tmp.value); } - } + }, 3); - expect(renderToHtml(Template, {})).toEqual('one'); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('one'); }); it('should support basic export of component', () => { + class MyComponent { + name = 'Nancy'; + + static ngComponentDef = defineComponent({ + type: MyComponent, + selectors: [['comp']], + consts: 0, + template: function() {}, + factory: () => new MyComponent + }); + } /** {{ myComp.name }} */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp', null, ['myComp', '']); text(2); @@ -43,20 +55,10 @@ describe('exports', () => { const tmp = reference(1) as any; textBinding(2, tmp.name); } - } + }, 3, [MyComponent]); - class MyComponent { - name = 'Nancy'; - - static ngComponentDef = defineComponent({ - type: MyComponent, - selectors: [['comp']], - template: function() {}, - factory: () => new MyComponent - }); - } - - expect(renderToHtml(Template, {}, [MyComponent])).toEqual('Nancy'); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('Nancy'); }); it('should support component instance fed into directive', () => { @@ -68,6 +70,7 @@ describe('exports', () => { static ngComponentDef = defineComponent({ type: MyComponent, selectors: [['comp']], + consts: 0, template: function() {}, factory: () => new MyComponent }); @@ -88,7 +91,7 @@ describe('exports', () => { const defs = [MyComponent, MyDir]; /**
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp', null, ['myComp', '']); element(2, 'div', ['myDir', '']); @@ -97,26 +100,13 @@ describe('exports', () => { const tmp = reference(1) as any; elementProperty(2, 'myDir', bind(tmp)); } - } + }, 3, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(myDir !.myDir).toEqual(myComponent !); }); it('should work with directives with exportAs set', () => { - - /**
              {{ myDir.name }} */ - function Template(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - element(0, 'div', ['someDir', ''], ['myDir', 'someDir']); - text(2); - } - if (rf & RenderFlags.Update) { - const tmp = reference(1) as any; - textBinding(2, tmp.name); - } - } - class SomeDir { name = 'Drew'; static ngDirectiveDef = defineDirective({ @@ -127,7 +117,20 @@ describe('exports', () => { }); } - expect(renderToHtml(Template, {}, [SomeDir])).toEqual('
              Drew'); + /**
              {{ myDir.name }} */ + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + element(0, 'div', ['someDir', ''], ['myDir', 'someDir']); + text(2); + } + if (rf & RenderFlags.Update) { + const tmp = reference(1) as any; + textBinding(2, tmp.name); + } + }, 3, [SomeDir]); + + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('
              Drew'); }); it('should throw if export name is not found', () => { @@ -137,7 +140,7 @@ describe('exports', () => { if (rf & RenderFlags.Create) { element(0, 'div', null, ['myDir', 'someDir']); } - }); + }, 1); expect(() => { const fixture = new ComponentFixture(App); @@ -147,7 +150,7 @@ describe('exports', () => { describe('forward refs', () => { it('should work with basic text bindings', () => { /** {{ myInput.value}} */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { text(0); element(1, 'input', ['value', 'one'], ['myInput', '']); @@ -156,15 +159,16 @@ describe('exports', () => { const tmp = reference(2) as any; textBinding(0, bind(tmp.value)); } - } + }, 3); - expect(renderToHtml(Template, {})).toEqual('one'); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('one'); }); it('should work with element properties', () => { /**
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div'); element(1, 'input', ['value', 'one'], ['myInput', '']); @@ -173,14 +177,15 @@ describe('exports', () => { const tmp = reference(2) as any; elementProperty(0, 'title', bind(tmp.value)); } - } + }, 3); - expect(renderToHtml(Template, {})).toEqual('
              '); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('
              '); }); it('should work with element attrs', () => { /**
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div'); element(1, 'input', ['value', 'one'], ['myInput', '']); @@ -189,14 +194,15 @@ describe('exports', () => { const tmp = reference(2) as any; elementAttribute(0, 'aria-label', bind(tmp.value)); } - } + }, 3); - expect(renderToHtml(Template, {})).toEqual('
              '); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('
              '); }); it('should work with element classes', () => { /**
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); elementStyling([InitialStylingFlags.VALUES_MODE, 'red', true]); @@ -208,10 +214,10 @@ describe('exports', () => { elementClassProp(0, 0, tmp.checked); elementStylingApply(0); } - } + }, 3); - expect(renderToHtml(Template, {})) - .toEqual('
              '); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('
              '); }); it('should work with component refs', () => { @@ -225,6 +231,7 @@ describe('exports', () => { static ngComponentDef = defineComponent({ type: MyComponent, selectors: [['comp']], + consts: 0, template: function(rf: RenderFlags, ctx: MyComponent) {}, factory: () => new MyComponent }); @@ -245,7 +252,7 @@ describe('exports', () => { } /**
              */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['myDir', '']); element(1, 'comp', null, ['myComp', '']); @@ -254,16 +261,32 @@ describe('exports', () => { const tmp = reference(2) as any; elementProperty(0, 'myDir', bind(tmp)); } - } + }, 3, [MyComponent, MyDir]); - renderToHtml(Template, {}, [MyComponent, MyDir]); + const fixture = new ComponentFixture(App); expect(myDir !.myDir).toEqual(myComponent !); }); it('should work with multiple forward refs', () => { + let myComponent: MyComponent; + + class MyComponent { + name = 'Nancy'; + + constructor() { myComponent = this; } + + static ngComponentDef = defineComponent({ + type: MyComponent, + selectors: [['comp']], + consts: 0, + template: function() {}, + factory: () => new MyComponent + }); + } + /** {{ myInput.value }} {{ myComp.name }} */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { text(0); text(1); @@ -276,28 +299,14 @@ describe('exports', () => { textBinding(0, bind(tmp2.value)); textBinding(1, bind(tmp1.name)); } - } + }, 6, [MyComponent]); - let myComponent: MyComponent; - - class MyComponent { - name = 'Nancy'; - - constructor() { myComponent = this; } - - static ngComponentDef = defineComponent({ - type: MyComponent, - selectors: [['comp']], - template: function() {}, - factory: () => new MyComponent - }); - } - expect(renderToHtml(Template, {}, [MyComponent])) - .toEqual('oneNancy'); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('oneNancy'); }); it('should work inside a view container', () => { - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); { container(1); } @@ -307,7 +316,7 @@ describe('exports', () => { containerRefreshStart(1); { if (ctx.condition) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { text(0); @@ -323,12 +332,16 @@ describe('exports', () => { } containerRefreshEnd(); } - } + }, 2); - expect(renderToHtml(Template, { - condition: true - })).toEqual('
              one
              '); - expect(renderToHtml(Template, {condition: false})).toEqual('
              '); + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.update(); + expect(fixture.html).toEqual('
              one
              '); + + fixture.component.condition = false; + fixture.update(); + expect(fixture.html).toEqual('
              '); }); it('should support local refs in nested dynamic views', () => { @@ -348,12 +361,12 @@ describe('exports', () => { if (rf & RenderFlags.Create) { elementStart(0, 'input', ['value', 'one'], ['outerInput', '']); elementEnd(); - template(2, outerTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']); + template(2, outerTemplate, 5, '', [AttributeMarker.SelectOnly, 'ngIf']); } if (rf & RenderFlags.Update) { elementProperty(2, 'ngIf', bind(app.outer)); } - }, [NgIf]); + }, 3, [NgIf]); function outerTemplate(rf: RenderFlags, outer: any) { if (rf & RenderFlags.Create) { @@ -362,7 +375,7 @@ describe('exports', () => { text(1); elementStart(2, 'input', ['value', 'two'], ['innerInput', '']); elementEnd(); - template(4, innerTemplate, '', [AttributeMarker.SelectOnly, 'ngIf']); + template(4, innerTemplate, 2, '', [AttributeMarker.SelectOnly, 'ngIf']); } elementEnd(); } diff --git a/packages/core/test/render3/i18n_spec.ts b/packages/core/test/render3/i18n_spec.ts index 532b14d9d7..cea1ee41c7 100644 --- a/packages/core/test/render3/i18n_spec.ts +++ b/packages/core/test/render3/i18n_spec.ts @@ -10,7 +10,7 @@ import {NgForOfContext} from '@angular/common'; import {Component} from '../../src/core'; import {defineComponent} from '../../src/render3/definition'; import {I18nExpInstruction, I18nInstruction, i18nApply, i18nExpMapping, i18nInterpolation1, i18nInterpolation2, i18nInterpolation3, i18nInterpolation4, i18nInterpolation5, i18nInterpolation6, i18nInterpolation7, i18nInterpolation8, i18nInterpolationV, i18nMapping} from '../../src/render3/i18n'; -import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, projection, projectionDef, template, text, textBinding} from '../../src/render3/instructions'; +import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, nextContext, projection, projectionDef, template, text, textBinding} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {NgForOf} from './common_with_def'; import {ComponentFixture, TemplateFixture} from './render_util'; @@ -60,7 +60,7 @@ describe('Runtime i18n', () => { i18nApply(1, i18n_1[0]); } - const fixture = new TemplateFixture(createTemplate); + const fixture = new TemplateFixture(createTemplate, () => {}, 5); expect(fixture.html).toEqual(''); }); @@ -76,6 +76,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 3, // Initial template: //
              // {{exp1}} {{exp2}} @@ -134,6 +135,7 @@ describe('Runtime i18n', () => { static ngComponentDef = defineComponent({ type: MyApp, factory: () => new MyApp(), + consts: 2, selectors: [['my-app']], // Initial template: //
              @@ -191,6 +193,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 1, // Initial template: //
              @@ -236,6 +239,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 8, // Initial template: //
              // {{exp1}} @@ -332,6 +336,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 6, // Initial template: //
              // @@ -426,6 +431,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 3, // Initial template: // before ( // % if (condition) { // with i18n @@ -452,7 +458,7 @@ describe('Runtime i18n', () => { if (rf & RenderFlags.Update) { containerRefreshStart(1); { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { // Start of translated section 1 text(0); // EXP_1 @@ -523,7 +529,7 @@ describe('Runtime i18n', () => { i18nApply(2, i18n_1[0]); } - const fixture = new TemplateFixture(createTemplate); + const fixture = new TemplateFixture(createTemplate, () => {}, 5); expect(fixture.html).toEqual('
              '); }); @@ -531,6 +537,22 @@ describe('Runtime i18n', () => { const MSG_DIV_SECTION_1 = `{$START_LI}valeur: {$EXP_1}!{$END_LI}`; // The indexes are based on each template function let i18n_1: I18nInstruction[][]; + + function liTemplate(rf1: RenderFlags, row: NgForOfContext) { + if (rf1 & RenderFlags.Create) { + // This is a container so the whole template is a translated section + // Start of translated section 2 + elementStart(0, 'li'); // START_LI + { text(1); } // EXP_1 + elementEnd(); + // End of translated section 2 + i18nApply(0, i18n_1[1]); + } + if (rf1 & RenderFlags.Update) { + textBinding(1, bind(row.$implicit)); + } + } + class MyApp { items: string[] = ['1', '2']; @@ -538,6 +560,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 2, // Initial template: //
                //
              • value: {{item}}
              • @@ -558,7 +581,7 @@ describe('Runtime i18n', () => { elementStart(0, 'ul'); { // Start of translated section 1 - template(1, liTemplate, null, ['ngForOf', '']); // START_LI + template(1, liTemplate, 2, null, ['ngForOf', '']); // START_LI // End of translated section 1 } elementEnd(); @@ -567,21 +590,6 @@ describe('Runtime i18n', () => { if (rf & RenderFlags.Update) { elementProperty(1, 'ngForOf', bind(myApp.items)); } - - function liTemplate(rf1: RenderFlags, row: NgForOfContext) { - if (rf1 & RenderFlags.Create) { - // This is a container so the whole template is a translated section - // Start of translated section 2 - elementStart(0, 'li'); // START_LI - { text(1); } // EXP_1 - elementEnd(); - // End of translated section 2 - i18nApply(0, i18n_1[1]); - } - if (rf1 & RenderFlags.Update) { - textBinding(1, bind(row.$implicit)); - } - } }, directives: () => [NgForOf] }); @@ -615,6 +623,37 @@ describe('Runtime i18n', () => { `{$START_LI_0}valeur: {$EXP_1}!{$END_LI_0}{$START_LI_1}valeur bis: {$EXP_2}!{$END_LI_1}`; // The indexes are based on each template function let i18n_1: I18nInstruction[][]; + + function liTemplate(rf1: RenderFlags, row: NgForOfContext) { + if (rf1 & RenderFlags.Create) { + // This is a container so the whole template is a translated section + // Start of translated section 2 + elementStart(0, 'li'); // START_LI_0 + { text(1); } // EXP_1 + elementEnd(); + // End of translated section 2 + i18nApply(0, i18n_1[1]); + } + if (rf1 & RenderFlags.Update) { + textBinding(1, bind(row.$implicit)); + } + } + + function liTemplateBis(rf1: RenderFlags, row: NgForOfContext) { + if (rf1 & RenderFlags.Create) { + // This is a container so the whole template is a translated section + // Start of translated section 3 + elementStart(0, 'li'); // START_LI_1 + { text(1); } // EXP_2 + elementEnd(); + // End of translated section 3 + i18nApply(0, i18n_1[2]); + } + if (rf1 & RenderFlags.Update) { + textBinding(1, bind(row.$implicit)); + } + } + class MyApp { items: string[] = ['1', '2']; @@ -622,6 +661,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 3, // Initial template: //
                  //
                • value: {{item}}
                • @@ -645,8 +685,8 @@ describe('Runtime i18n', () => { elementStart(0, 'ul'); { // Start of translated section 1 - template(1, liTemplate, null, ['ngForOf', '']); // START_LI_0 - template(2, liTemplateBis, null, ['ngForOf', '']); // START_LI_1 + template(1, liTemplate, 2, null, ['ngForOf', '']); // START_LI_0 + template(2, liTemplateBis, 2, null, ['ngForOf', '']); // START_LI_1 // End of translated section 1 } elementEnd(); @@ -656,36 +696,6 @@ describe('Runtime i18n', () => { elementProperty(1, 'ngForOf', bind(myApp.items)); elementProperty(2, 'ngForOf', bind(myApp.items)); } - - function liTemplate(rf1: RenderFlags, row: NgForOfContext) { - if (rf1 & RenderFlags.Create) { - // This is a container so the whole template is a translated section - // Start of translated section 2 - elementStart(0, 'li'); // START_LI_0 - { text(1); } // EXP_1 - elementEnd(); - // End of translated section 2 - i18nApply(0, i18n_1[1]); - } - if (rf1 & RenderFlags.Update) { - textBinding(1, bind(row.$implicit)); - } - } - - function liTemplateBis(rf1: RenderFlags, row: NgForOfContext) { - if (rf1 & RenderFlags.Create) { - // This is a container so the whole template is a translated section - // Start of translated section 3 - elementStart(0, 'li'); // START_LI_1 - { text(1); } // EXP_2 - elementEnd(); - // End of translated section 3 - i18nApply(0, i18n_1[2]); - } - if (rf1 & RenderFlags.Update) { - textBinding(1, bind(row.$implicit)); - } - } }, directives: () => [NgForOf] }); @@ -725,6 +735,37 @@ describe('Runtime i18n', () => { `{$START_LI_1}valeur bis: {$EXP_2}!{$END_LI_1}{$START_LI_0}valeur: {$EXP_1}!{$END_LI_0}`; // The indexes are based on each template function let i18n_1: I18nInstruction[][]; + + function liTemplate(rf1: RenderFlags, row: NgForOfContext) { + if (rf1 & RenderFlags.Create) { + // This is a container so the whole template is a translated section + // Start of translated section 2 + elementStart(0, 'li'); // START_LI_0 + { text(1); } // EXP_1 + elementEnd(); + // End of translated section 2 + i18nApply(0, i18n_1[1]); + } + if (rf1 & RenderFlags.Update) { + textBinding(1, bind(row.$implicit)); + } + } + + function liTemplateBis(rf1: RenderFlags, row: NgForOfContext) { + if (rf1 & RenderFlags.Create) { + // This is a container so the whole template is a translated section + // Start of translated section 3 + elementStart(0, 'li'); // START_LI_1 + { text(1); } // EXP_2 + elementEnd(); + // End of translated section 3 + i18nApply(0, i18n_1[2]); + } + if (rf1 & RenderFlags.Update) { + textBinding(1, bind(row.$implicit)); + } + } + class MyApp { items: string[] = ['1', '2']; @@ -732,6 +773,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 3, // Initial template: //
                    //
                  • value: {{item}}
                  • @@ -755,8 +797,8 @@ describe('Runtime i18n', () => { elementStart(0, 'ul'); { // Start of translated section 1 - template(1, liTemplate, null, ['ngForOf', '']); // START_LI_0 - template(2, liTemplateBis, null, ['ngForOf', '']); // START_LI_1 + template(1, liTemplate, 2, null, ['ngForOf', '']); // START_LI_0 + template(2, liTemplateBis, 2, null, ['ngForOf', '']); // START_LI_1 // End of translated section 1 } elementEnd(); @@ -766,36 +808,6 @@ describe('Runtime i18n', () => { elementProperty(1, 'ngForOf', bind(myApp.items)); elementProperty(2, 'ngForOf', bind(myApp.items)); } - - function liTemplate(rf1: RenderFlags, row: NgForOfContext) { - if (rf1 & RenderFlags.Create) { - // This is a container so the whole template is a translated section - // Start of translated section 2 - elementStart(0, 'li'); // START_LI_0 - { text(1); } // EXP_1 - elementEnd(); - // End of translated section 2 - i18nApply(0, i18n_1[1]); - } - if (rf1 & RenderFlags.Update) { - textBinding(1, bind(row.$implicit)); - } - } - - function liTemplateBis(rf1: RenderFlags, row: NgForOfContext) { - if (rf1 & RenderFlags.Create) { - // This is a container so the whole template is a translated section - // Start of translated section 3 - elementStart(0, 'li'); // START_LI_1 - { text(1); } // EXP_2 - elementEnd(); - // End of translated section 3 - i18nApply(0, i18n_1[2]); - } - if (rf1 & RenderFlags.Update) { - textBinding(1, bind(row.$implicit)); - } - } }, directives: () => [NgForOf] }); @@ -834,6 +846,40 @@ describe('Runtime i18n', () => { const MSG_DIV_SECTION_1 = `{$START_LI}{$START_SPAN}valeur: {$EXP_1}!{$END_SPAN}{$END_LI}`; // The indexes are based on each template function let i18n_1: I18nInstruction[][]; + + function liTemplate(rf1: RenderFlags, row: NgForOfContext) { + if (rf1 & RenderFlags.Create) { + // This is a container so the whole template is a translated section + // Start of translated section 2 + elementStart(0, 'li'); // START_LI + { + template(1, spanTemplate, 2, null, ['ngForOf', '']); // START_SPAN + } + elementEnd(); + // End of translated section 2 + i18nApply(0, i18n_1[1]); + } + if (rf1 & RenderFlags.Update) { + const myApp = nextContext(); + elementProperty(1, 'ngForOf', bind(myApp.items)); + } + } + + function spanTemplate(rf1: RenderFlags, row: NgForOfContext) { + if (rf1 & RenderFlags.Create) { + // This is a container so the whole template is a translated section + // Start of translated section 3 + elementStart(0, 'span'); // START_SPAN + { text(1); } // EXP_1 + elementEnd(); + // End of translated section 3 + i18nApply(0, i18n_1[2]); + } + if (rf1 & RenderFlags.Update) { + textBinding(1, bind(row.$implicit)); + } + } + class MyApp { items: string[] = ['1', '2']; @@ -841,6 +887,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 2, // Initial template: //
                      //
                    • @@ -866,7 +913,7 @@ describe('Runtime i18n', () => { elementStart(0, 'ul'); { // Start of translated section 1 - template(1, liTemplate, null, ['ngForOf', '']); // START_LI + template(1, liTemplate, 2, null, ['ngForOf', '']); // START_LI // End of translated section 1 } elementEnd(); @@ -875,38 +922,6 @@ describe('Runtime i18n', () => { if (rf & RenderFlags.Update) { elementProperty(1, 'ngForOf', bind(myApp.items)); } - - function liTemplate(rf1: RenderFlags, row: NgForOfContext) { - if (rf1 & RenderFlags.Create) { - // This is a container so the whole template is a translated section - // Start of translated section 2 - elementStart(0, 'li'); // START_LI - { - template(1, spanTemplate, null, ['ngForOf', '']); // START_SPAN - } - elementEnd(); - // End of translated section 2 - i18nApply(0, i18n_1[1]); - } - if (rf1 & RenderFlags.Update) { - elementProperty(1, 'ngForOf', bind(myApp.items)); - } - } - - function spanTemplate(rf1: RenderFlags, row: NgForOfContext) { - if (rf1 & RenderFlags.Create) { - // This is a container so the whole template is a translated section - // Start of translated section 3 - elementStart(0, 'span'); // START_SPAN - { text(1); } // EXP_1 - elementEnd(); - // End of translated section 3 - i18nApply(0, i18n_1[2]); - } - if (rf1 & RenderFlags.Update) { - textBinding(1, bind(row.$implicit)); - } - } }, directives: () => [NgForOf] }); @@ -947,6 +962,21 @@ describe('Runtime i18n', () => { // The indexes are based on each template function let i18n_1: I18nInstruction[][]; + function liTemplate(rf1: RenderFlags, row: NgForOfContext) { + if (rf1 & RenderFlags.Create) { + // This is a container so the whole template is a translated section + // Start of translated section 2 + elementStart(0, 'li'); // START_LI_1 + { text(1); } // EXP_1 + elementEnd(); + // End of translated section 2 + i18nApply(0, i18n_1[1]); + } + if (rf1 & RenderFlags.Update) { + textBinding(1, bind(row.$implicit)); + } + } + class MyApp { items: string[] = ['first', 'second']; @@ -954,6 +984,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 5, // Initial template: //
                        //
                      • start
                      • @@ -979,9 +1010,9 @@ describe('Runtime i18n', () => { elementStart(0, 'ul'); { // Start of translated section 1 - element(1, 'li'); // START_LI_0 - template(2, liTemplate, null, ['ngForOf', '']); // START_LI_1 - elementStart(3, 'li'); // START_LI_2 + element(1, 'li'); // START_LI_0 + template(2, liTemplate, 2, null, ['ngForOf', '']); // START_LI_1 + elementStart(3, 'li'); // START_LI_2 { text(4, 'delete me'); } elementEnd(); // End of translated section 1 @@ -992,21 +1023,6 @@ describe('Runtime i18n', () => { if (rf & RenderFlags.Update) { elementProperty(2, 'ngForOf', bind(myApp.items)); } - - function liTemplate(rf1: RenderFlags, row: NgForOfContext) { - if (rf1 & RenderFlags.Create) { - // This is a container so the whole template is a translated section - // Start of translated section 2 - elementStart(0, 'li'); // START_LI_1 - { text(1); } // EXP_1 - elementEnd(); - // End of translated section 2 - i18nApply(0, i18n_1[1]); - } - if (rf1 & RenderFlags.Update) { - textBinding(1, bind(row.$implicit)); - } - } }, directives: () => [NgForOf] }); @@ -1042,6 +1058,20 @@ describe('Runtime i18n', () => { const MSG_DIV_SECTION_1 = `loop`; // The indexes are based on each template function let i18n_1: I18nInstruction[][]; + function liTemplate(rf1: RenderFlags, row: NgForOfContext) { + if (rf1 & RenderFlags.Create) { + // This is a container so the whole template is a translated section + // Start of translated section 2 + elementStart(0, 'li'); // START_LI + { text(1); } // EXP_1 + elementEnd(); + // End of translated section 2 + i18nApply(0, i18n_1[1]); + } + if (rf1 & RenderFlags.Update) { + textBinding(1, bind(row.$implicit)); + } + } class MyApp { items: string[] = ['first', 'second']; @@ -1050,6 +1080,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 2, // Initial template: //
                          //
                        • value: {{item}}
                        • @@ -1070,7 +1101,7 @@ describe('Runtime i18n', () => { elementStart(0, 'ul'); { // Start of translated section 1 - template(1, liTemplate, undefined, ['ngForOf', '']); // START_LI + template(1, liTemplate, 2, undefined, ['ngForOf', '']); // START_LI // End of translated section 1 } elementEnd(); @@ -1079,21 +1110,6 @@ describe('Runtime i18n', () => { if (rf & RenderFlags.Update) { elementProperty(1, 'ngForOf', bind(myApp.items)); } - - function liTemplate(rf1: RenderFlags, row: NgForOfContext) { - if (rf1 & RenderFlags.Create) { - // This is a container so the whole template is a translated section - // Start of translated section 2 - elementStart(0, 'li'); // START_LI - { text(1); } // EXP_1 - elementEnd(); - // End of translated section 2 - i18nApply(0, i18n_1[1]); - } - if (rf1 & RenderFlags.Update) { - textBinding(1, bind(row.$implicit)); - } - } }, directives: () => [NgForOf] }); @@ -1131,6 +1147,7 @@ describe('Runtime i18n', () => { type: Child, selectors: [['child']], factory: () => new Child(), + consts: 2, template: (rf: RenderFlags, cmp: Child) => { if (rf & RenderFlags.Create) { projectionDef(); @@ -1169,6 +1186,7 @@ describe('Runtime i18n', () => { selectors: [['parent']], directives: [Child], factory: () => new Parent(), + consts: 4, template: (rf: RenderFlags, cmp: Parent) => { if (rf & RenderFlags.Create) { if (!i18n_1) { @@ -1227,6 +1245,7 @@ describe('Runtime i18n', () => { type: Child, selectors: [['child']], factory: () => new Child(), + consts: 2, template: (rf: RenderFlags, cmp: Child) => { if (rf & RenderFlags.Create) { projectionDef(); @@ -1265,6 +1284,7 @@ describe('Runtime i18n', () => { selectors: [['parent']], directives: [Child], factory: () => new Parent(), + consts: 6, template: (rf: RenderFlags, cmp: Parent) => { if (rf & RenderFlags.Create) { if (!i18n_1) { @@ -1314,6 +1334,7 @@ describe('Runtime i18n', () => { type: GrandChild, selectors: [['grand-child']], factory: () => new GrandChild(), + consts: 2, template: (rf: RenderFlags, cmp: Child) => { if (rf & RenderFlags.Create) { projectionDef(); @@ -1333,6 +1354,7 @@ describe('Runtime i18n', () => { selectors: [['child']], directives: [GrandChild], factory: () => new Child(), + consts: 2, template: (rf: RenderFlags, cmp: Child) => { if (rf & RenderFlags.Create) { projectionDef(); @@ -1360,6 +1382,7 @@ describe('Runtime i18n', () => { selectors: [['parent']], directives: [Child], factory: () => new Parent(), + consts: 2, template: (rf: RenderFlags, cmp: Parent) => { if (rf & RenderFlags.Create) { if (!i18n_1) { @@ -1396,6 +1419,7 @@ describe('Runtime i18n', () => { type: Child, selectors: [['child']], factory: () => new Child(), + consts: 1, template: (rf: RenderFlags, cmp: Child) => { if (rf & RenderFlags.Create) { projectionDef([[['span']]], ['span']); @@ -1425,6 +1449,7 @@ describe('Runtime i18n', () => { selectors: [['parent']], directives: [Child], factory: () => new Parent(), + consts: 3, template: (rf: RenderFlags, cmp: Parent) => { if (rf & RenderFlags.Create) { if (!i18n_1) { @@ -1465,6 +1490,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 1, // Initial template: //
                          @@ -1501,6 +1527,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 1, // Initial template: //
                          @@ -1536,6 +1563,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 1, // Initial template: //
                          @@ -1573,6 +1601,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 1, // Initial template: //
                          @@ -1615,6 +1644,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 1, // Initial template: //
                          @@ -1659,6 +1689,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 1, // Initial template: //
                          @@ -1712,6 +1743,7 @@ describe('Runtime i18n', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 1, // Initial template: //
                          diff --git a/packages/core/test/render3/instructions_spec.ts b/packages/core/test/render3/instructions_spec.ts index da72e6e398..0f96339130 100644 --- a/packages/core/test/render3/instructions_spec.ts +++ b/packages/core/test/render3/instructions_spec.ts @@ -40,7 +40,7 @@ describe('instructions', () => { describe('bind', () => { it('should update bindings when value changes', () => { - const t = new TemplateFixture(createAnchor); + const t = new TemplateFixture(createAnchor, () => {}, 1); t.update(() => elementProperty(0, 'title', bind('Hello'))); expect(t.html).toEqual(''); @@ -58,7 +58,7 @@ describe('instructions', () => { it('should not update bindings when value does not change', () => { const idempotentUpdate = () => elementProperty(0, 'title', bind('Hello')); - const t = new TemplateFixture(createAnchor, idempotentUpdate); + const t = new TemplateFixture(createAnchor, idempotentUpdate, 1); t.update(); expect(t.html).toEqual(''); @@ -77,7 +77,9 @@ describe('instructions', () => { describe('element', () => { it('should create an element', () => { - const t = new TemplateFixture(() => { element(0, 'div', ['id', 'test', 'title', 'Hello']); }); + const t = new TemplateFixture(() => { + element(0, 'div', ['id', 'test', 'title', 'Hello']); + }, () => {}, 1); const div = (t.hostNode.native as HTMLElement).querySelector('div') !; expect(div.id).toEqual('test'); @@ -105,7 +107,7 @@ describe('instructions', () => { 'title', 'Hello', ]); - }); + }, () => {}, 1); const div = (t.hostNode.native as HTMLElement).querySelector('div') !; const attrs: any = div.attributes; @@ -134,7 +136,7 @@ describe('instructions', () => { describe('elementAttribute', () => { it('should use sanitizer function', () => { - const t = new TemplateFixture(createDiv); + const t = new TemplateFixture(createDiv, () => {}, 1); t.update(() => elementAttribute(0, 'title', 'javascript:true', sanitizeUrl)); expect(t.html).toEqual('
                          '); @@ -155,7 +157,7 @@ describe('instructions', () => { describe('elementProperty', () => { it('should use sanitizer function when available', () => { - const t = new TemplateFixture(createDiv); + const t = new TemplateFixture(createDiv, () => {}, 1); t.update(() => elementProperty(0, 'title', 'javascript:true', sanitizeUrl)); expect(t.html).toEqual('
                          '); @@ -173,7 +175,7 @@ describe('instructions', () => { }); it('should not stringify non string values', () => { - const t = new TemplateFixture(createDiv); + const t = new TemplateFixture(createDiv, () => {}, 1); t.update(() => elementProperty(0, 'hidden', false)); // The hidden property would be true if `false` was stringified into `"false"`. @@ -191,7 +193,7 @@ describe('instructions', () => { describe('elementStyleProp', () => { it('should automatically sanitize unless a bypass operation is applied', () => { const t = new TemplateFixture( - () => { return createDiv(['background-image'], defaultStyleSanitizer); }); + () => { return createDiv(['background-image'], defaultStyleSanitizer); }, () => {}, 1); t.update(() => { elementStyleProp(0, 0, 'url("http://server")'); elementStylingApply(0); @@ -210,7 +212,7 @@ describe('instructions', () => { it('should not re-apply the style value even if it is a newly bypassed again', () => { const sanitizerInterceptor = new MockSanitizerInterceptor(); const t = createTemplateFixtureWithSanitizer( - () => createDiv(['background-image'], sanitizerInterceptor.getStyleSanitizer()), + () => createDiv(['background-image'], sanitizerInterceptor.getStyleSanitizer()), 1, sanitizerInterceptor); t.update(() => { @@ -237,7 +239,7 @@ describe('instructions', () => { } it('should add style', () => { - const fixture = new TemplateFixture(createDivWithStyle); + const fixture = new TemplateFixture(createDivWithStyle, () => {}, 1); fixture.update(() => { elementStylingMap(0, null, {'background-color': 'red'}); elementStylingApply(0); @@ -250,7 +252,7 @@ describe('instructions', () => { const sanitizerInterceptor = new MockSanitizerInterceptor(value => { detectedValues.push(value); }); const fixture = createTemplateFixtureWithSanitizer( - () => createDiv([], sanitizerInterceptor.getStyleSanitizer()), sanitizerInterceptor); + () => createDiv([], sanitizerInterceptor.getStyleSanitizer()), 1, sanitizerInterceptor); fixture.update(() => { elementStylingMap(0, null, { @@ -280,7 +282,7 @@ describe('instructions', () => { } it('should add class', () => { - const fixture = new TemplateFixture(createDivWithStyling); + const fixture = new TemplateFixture(createDivWithStyling, () => {}, 1); fixture.update(() => { elementStylingMap(0, 'multiple classes'); elementStylingApply(0); @@ -292,6 +294,32 @@ describe('instructions', () => { describe('performance counters', () => { it('should create tViews only once for each nested level', () => { const _c0 = ['ngFor', '', 'ngForOf', '']; + + function ToDoAppComponent_NgForOf_Template_0(rf: RenderFlags, ctx0: NgForOfContext) { + if (rf & RenderFlags.Create) { + elementStart(0, 'ul'); + template(1, ToDoAppComponent_NgForOf_NgForOf_Template_1, 2, null, _c0); + elementEnd(); + } + if (rf & RenderFlags.Update) { + const row_r2 = ctx0.$implicit; + elementProperty(1, 'ngForOf', bind(row_r2)); + } + } + + function ToDoAppComponent_NgForOf_NgForOf_Template_1( + rf: RenderFlags, ctx1: NgForOfContext) { + if (rf & RenderFlags.Create) { + elementStart(0, 'li'); + text(1); + elementEnd(); + } + if (rf & RenderFlags.Update) { + const col_r3 = ctx1.$implicit; + textBinding(1, interpolation1('', col_r3, '')); + } + } + /** *
                            *
                          • {{col}}
                          • @@ -304,37 +332,14 @@ describe('instructions', () => { type: NestedLoops, selectors: [['nested-loops']], factory: function ToDoAppComponent_Factory() { return new NestedLoops(); }, + consts: 1, template: function ToDoAppComponent_Template(rf: RenderFlags, ctx: NestedLoops) { if (rf & RenderFlags.Create) { - template(0, ToDoAppComponent_NgForOf_Template_0, null, _c0); + template(0, ToDoAppComponent_NgForOf_Template_0, 2, null, _c0); } if (rf & RenderFlags.Update) { elementProperty(0, 'ngForOf', bind(ctx.rows)); } - function ToDoAppComponent_NgForOf_Template_0( - rf: RenderFlags, ctx0: NgForOfContext) { - if (rf & RenderFlags.Create) { - elementStart(0, 'ul'); - template(1, ToDoAppComponent_NgForOf_NgForOf_Template_1, null, _c0); - elementEnd(); - } - if (rf & RenderFlags.Update) { - const row_r2 = ctx0.$implicit; - elementProperty(1, 'ngForOf', bind(row_r2)); - } - function ToDoAppComponent_NgForOf_NgForOf_Template_1( - rf: RenderFlags, ctx1: NgForOfContext) { - if (rf & RenderFlags.Create) { - elementStart(0, 'li'); - text(1); - elementEnd(); - } - if (rf & RenderFlags.Update) { - const col_r3 = ctx1.$implicit; - textBinding(1, interpolation1('', col_r3, '')); - } - } - } }, directives: [NgForOf] }); @@ -351,7 +356,7 @@ describe('instructions', () => { describe('sanitization injection compatibility', () => { it('should work for url sanitization', () => { const s = new LocalMockSanitizer(value => `${value}-sanitized`); - const t = new TemplateFixture(createAnchor, undefined, null, null, s); + const t = new TemplateFixture(createAnchor, undefined, 1, null, null, s); const inputValue = 'http://foo'; const outputValue = 'http://foo-sanitized'; @@ -362,7 +367,7 @@ describe('instructions', () => { it('should bypass url sanitization if marked by the service', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createAnchor, undefined, null, null, s); + const t = new TemplateFixture(createAnchor, undefined, 1, null, null, s); const inputValue = s.bypassSecurityTrustUrl('http://foo'); const outputValue = 'http://foo'; @@ -373,7 +378,7 @@ describe('instructions', () => { it('should bypass ivy-level url sanitization if a custom sanitizer is used', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createAnchor, undefined, null, null, s); + const t = new TemplateFixture(createAnchor, undefined, 1, null, null, s); const inputValue = bypassSanitizationTrustUrl('http://foo'); const outputValue = 'http://foo-ivy'; @@ -384,7 +389,7 @@ describe('instructions', () => { it('should work for style sanitization', () => { const s = new LocalMockSanitizer(value => `color:blue`); - const t = new TemplateFixture(createDiv, undefined, null, null, s); + const t = new TemplateFixture(createDiv, undefined, 1, null, null, s); const inputValue = 'color:red'; const outputValue = 'color:blue'; @@ -395,7 +400,7 @@ describe('instructions', () => { it('should bypass style sanitization if marked by the service', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createDiv, undefined, null, null, s); + const t = new TemplateFixture(createDiv, undefined, 1, null, null, s); const inputValue = s.bypassSecurityTrustStyle('color:maroon'); const outputValue = 'color:maroon'; @@ -406,7 +411,7 @@ describe('instructions', () => { it('should bypass ivy-level style sanitization if a custom sanitizer is used', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createDiv, undefined, null, null, s); + const t = new TemplateFixture(createDiv, undefined, 1, null, null, s); const inputValue = bypassSanitizationTrustStyle('font-family:foo'); const outputValue = 'font-family:foo-ivy'; @@ -417,7 +422,7 @@ describe('instructions', () => { it('should work for resourceUrl sanitization', () => { const s = new LocalMockSanitizer(value => `${value}-sanitized`); - const t = new TemplateFixture(createScript, undefined, null, null, s); + const t = new TemplateFixture(createScript, undefined, 1, null, null, s); const inputValue = 'http://resource'; const outputValue = 'http://resource-sanitized'; @@ -428,7 +433,7 @@ describe('instructions', () => { it('should bypass resourceUrl sanitization if marked by the service', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createScript, undefined, null, null, s); + const t = new TemplateFixture(createScript, undefined, 1, null, null, s); const inputValue = s.bypassSecurityTrustResourceUrl('file://all-my-secrets.pdf'); const outputValue = 'file://all-my-secrets.pdf'; @@ -439,7 +444,7 @@ describe('instructions', () => { it('should bypass ivy-level resourceUrl sanitization if a custom sanitizer is used', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createScript, undefined, null, null, s); + const t = new TemplateFixture(createScript, undefined, 1, null, null, s); const inputValue = bypassSanitizationTrustResourceUrl('file://all-my-secrets.pdf'); const outputValue = 'file://all-my-secrets.pdf-ivy'; @@ -450,7 +455,7 @@ describe('instructions', () => { it('should work for script sanitization', () => { const s = new LocalMockSanitizer(value => `${value} //sanitized`); - const t = new TemplateFixture(createScript, undefined, null, null, s); + const t = new TemplateFixture(createScript, undefined, 1, null, null, s); const inputValue = 'fn();'; const outputValue = 'fn(); //sanitized'; @@ -461,7 +466,7 @@ describe('instructions', () => { it('should bypass script sanitization if marked by the service', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createScript, undefined, null, null, s); + const t = new TemplateFixture(createScript, undefined, 1, null, null, s); const inputValue = s.bypassSecurityTrustScript('alert("bar")'); const outputValue = 'alert("bar")'; @@ -472,7 +477,7 @@ describe('instructions', () => { it('should bypass ivy-level script sanitization if a custom sanitizer is used', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createScript, undefined, null, null, s); + const t = new TemplateFixture(createScript, undefined, 1, null, null, s); const inputValue = bypassSanitizationTrustScript('alert("bar")'); const outputValue = 'alert("bar")-ivy'; @@ -483,7 +488,7 @@ describe('instructions', () => { it('should work for html sanitization', () => { const s = new LocalMockSanitizer(value => `${value} `); - const t = new TemplateFixture(createDiv, undefined, null, null, s); + const t = new TemplateFixture(createDiv, undefined, 1, null, null, s); const inputValue = '
                            '; const outputValue = '
                            '; @@ -494,7 +499,7 @@ describe('instructions', () => { it('should bypass html sanitization if marked by the service', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createDiv, undefined, null, null, s); + const t = new TemplateFixture(createDiv, undefined, 1, null, null, s); const inputValue = s.bypassSecurityTrustHtml('
                            '); const outputValue = '
                            '; @@ -505,7 +510,7 @@ describe('instructions', () => { it('should bypass ivy-level script sanitization if a custom sanitizer is used', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createDiv, undefined, null, null, s); + const t = new TemplateFixture(createDiv, undefined, 1, null, null, s); const inputValue = bypassSanitizationTrustHtml('
                            '); const outputValue = '
                            -ivy'; @@ -568,6 +573,7 @@ function stripStyleWsCharacters(value: string): string { return value.replace(/;/g, '').replace(/:\s+/g, ':'); } -function createTemplateFixtureWithSanitizer(buildFn: () => any, sanitizer: Sanitizer) { - return new TemplateFixture(buildFn, () => {}, null, null, sanitizer); +function createTemplateFixtureWithSanitizer( + buildFn: () => any, consts: number, sanitizer: Sanitizer) { + return new TemplateFixture(buildFn, () => {}, consts, null, null, sanitizer); } diff --git a/packages/core/test/render3/integration_spec.ts b/packages/core/test/render3/integration_spec.ts index ab183cbe32..621d3b2971 100644 --- a/packages/core/test/render3/integration_spec.ts +++ b/packages/core/test/render3/integration_spec.ts @@ -25,7 +25,7 @@ describe('render3 integration test', () => { describe('render', () => { it('should render basic template', () => { - expect(renderToHtml(Template, {})).toEqual('Greetings'); + expect(renderToHtml(Template, {}, 2)).toEqual('Greetings'); function Template(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -43,19 +43,25 @@ describe('render3 integration test', () => { }); it('should render and update basic "Hello, World" template', () => { - expect(renderToHtml(Template, 'World')).toEqual('

                            Hello, World!

                            '); - expect(renderToHtml(Template, 'New World')).toEqual('

                            Hello, New World!

                            '); - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'h1'); { text(1); } elementEnd(); } if (rf & RenderFlags.Update) { - textBinding(1, interpolation1('Hello, ', ctx, '!')); + textBinding(1, interpolation1('Hello, ', ctx.name, '!')); } - } + }, 2); + + const fixture = new ComponentFixture(App); + fixture.component.name = 'World'; + fixture.update(); + expect(fixture.html).toEqual('

                            Hello, World!

                            '); + + fixture.component.name = 'New World'; + fixture.update(); + expect(fixture.html).toEqual('

                            Hello, New World!

                            '); }); }); @@ -70,8 +76,8 @@ describe('render3 integration test', () => { } } - expect(renderToHtml(Template, 'benoit')).toEqual('benoit'); - expect(renderToHtml(Template, undefined)).toEqual(''); + expect(renderToHtml(Template, 'benoit', 1)).toEqual('benoit'); + expect(renderToHtml(Template, undefined, 1)).toEqual(''); expect(ngDevMode).toHaveProperties({ firstTemplatePass: 0, tNode: 2, @@ -90,8 +96,8 @@ describe('render3 integration test', () => { } } - expect(renderToHtml(Template, 'benoit')).toEqual('benoit'); - expect(renderToHtml(Template, null)).toEqual(''); + expect(renderToHtml(Template, 'benoit', 1)).toEqual('benoit'); + expect(renderToHtml(Template, null, 1)).toEqual(''); expect(ngDevMode).toHaveProperties({ firstTemplatePass: 0, tNode: 2, @@ -109,8 +115,8 @@ describe('render3 integration test', () => { textBinding(0, rf & RenderFlags.Create ? value : NO_CHANGE); } } - expect(renderToHtml(Template, 'once')).toEqual('once'); - expect(renderToHtml(Template, 'twice')).toEqual('once'); + expect(renderToHtml(Template, 'once', 1)).toEqual('once'); + expect(renderToHtml(Template, 'twice', 1)).toEqual('once'); expect(ngDevMode).toHaveProperties({ firstTemplatePass: 0, tNode: 2, @@ -123,22 +129,29 @@ describe('render3 integration test', () => { describe('Siblings update', () => { it('should handle a flat list of static/bound text nodes', () => { - function Template(rf: RenderFlags, name: string) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { text(0, 'Hello '); text(1); text(2, '!'); } if (rf & RenderFlags.Update) { - textBinding(1, bind(name)); + textBinding(1, bind(ctx.name)); } - } - expect(renderToHtml(Template, 'world')).toEqual('Hello world!'); - expect(renderToHtml(Template, 'monde')).toEqual('Hello monde!'); + }, 3); + + const fixture = new ComponentFixture(App); + fixture.component.name = 'world'; + fixture.update(); + expect(fixture.html).toEqual('Hello world!'); + + fixture.component.name = 'monde'; + fixture.update(); + expect(fixture.html).toEqual('Hello monde!'); }); it('should handle a list of static/bound text nodes as element children', () => { - function Template(rf: RenderFlags, name: string) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'b'); { @@ -149,15 +162,22 @@ describe('render3 integration test', () => { elementEnd(); } if (rf & RenderFlags.Update) { - textBinding(2, bind(name)); + textBinding(2, bind(ctx.name)); } - } - expect(renderToHtml(Template, 'world')).toEqual('Hello world!'); - expect(renderToHtml(Template, 'mundo')).toEqual('Hello mundo!'); + }, 4); + + const fixture = new ComponentFixture(App); + fixture.component.name = 'world'; + fixture.update(); + expect(fixture.html).toEqual('Hello world!'); + + fixture.component.name = 'mundo'; + fixture.update(); + expect(fixture.html).toEqual('Hello mundo!'); }); it('should render/update text node as a child of a deep list of elements', () => { - function Template(rf: RenderFlags, name: string) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'b'); { @@ -176,15 +196,22 @@ describe('render3 integration test', () => { elementEnd(); } if (rf & RenderFlags.Update) { - textBinding(4, interpolation1('Hello ', name, '!')); + textBinding(4, interpolation1('Hello ', ctx.name, '!')); } - } - expect(renderToHtml(Template, 'world')).toEqual('Hello world!'); - expect(renderToHtml(Template, 'mundo')).toEqual('Hello mundo!'); + }, 5); + + const fixture = new ComponentFixture(App); + fixture.component.name = 'world'; + fixture.update(); + expect(fixture.html).toEqual('Hello world!'); + + fixture.component.name = 'mundo'; + fixture.update(); + expect(fixture.html).toEqual('Hello mundo!'); }); it('should update 2 sibling elements', () => { - function Template(rf: RenderFlags, id: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'b'); { @@ -196,26 +223,32 @@ describe('render3 integration test', () => { elementEnd(); } if (rf & RenderFlags.Update) { - elementAttribute(2, 'id', bind(id)); + elementAttribute(2, 'id', bind(ctx.id)); } - } - expect(renderToHtml(Template, 'foo')) - .toEqual(''); - expect(renderToHtml(Template, 'bar')) - .toEqual(''); + }, 3); + + const fixture = new ComponentFixture(App); + fixture.component.id = 'foo'; + fixture.update(); + expect(fixture.html).toEqual(''); + + fixture.component.id = 'bar'; + fixture.update(); + expect(fixture.html).toEqual(''); }); it('should handle sibling text node after element with child text node', () => { - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'p'); { text(1, 'hello'); } elementEnd(); text(2, 'world'); } - } + }, 3); - expect(renderToHtml(Template, null)).toEqual('

                            hello

                            world'); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('

                            hello

                            world'); }); }); @@ -227,6 +260,7 @@ describe('render3 integration test', () => { static ngComponentDef = defineComponent({ type: TodoComponent, selectors: [['todo']], + consts: 3, template: function TodoTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'p'); @@ -247,23 +281,26 @@ describe('render3 integration test', () => { const defs = [TodoComponent]; it('should support a basic component template', () => { - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'todo'); } - } + }, 1, defs); - expect(renderToHtml(Template, null, defs)).toEqual('

                            Todo one

                            '); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('

                            Todo one

                            '); }); it('should support a component template with sibling', () => { - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'todo'); text(1, 'two'); } - } - expect(renderToHtml(Template, null, defs)).toEqual('

                            Todo one

                            two'); + }, 2, defs); + + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('

                            Todo one

                            two'); }); it('should support a component template with component sibling', () => { @@ -271,14 +308,15 @@ describe('render3 integration test', () => { * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'todo'); element(1, 'todo'); } - } - expect(renderToHtml(Template, null, defs)) - .toEqual('

                            Todo one

                            Todo one

                            '); + }, 2, defs); + + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('

                            Todo one

                            Todo one

                            '); }); it('should support a component with binding on host element', () => { @@ -289,6 +327,7 @@ describe('render3 integration test', () => { static ngComponentDef = defineComponent({ type: TodoComponentHostBinding, selectors: [['todo']], + consts: 1, template: function TodoComponentHostBindingTemplate( rf: RenderFlags, ctx: TodoComponentHostBinding) { if (rf & RenderFlags.Create) { @@ -308,16 +347,18 @@ describe('render3 integration test', () => { }); } - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'todo'); } - } + }, 1, [TodoComponentHostBinding]); + + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('one'); - const defs = [TodoComponentHostBinding]; - expect(renderToHtml(Template, {}, defs)).toEqual('one'); cmptInstance !.title = 'two'; - expect(renderToHtml(Template, {}, defs)).toEqual('two'); + fixture.update(); + expect(fixture.html).toEqual('two'); }); it('should support root component with host attribute', () => { @@ -326,6 +367,7 @@ describe('render3 integration test', () => { type: HostAttributeComp, selectors: [['host-attr-comp']], factory: () => new HostAttributeComp(), + consts: 0, template: (rf: RenderFlags, ctx: HostAttributeComp) => {}, attributes: ['role', 'button'] }); @@ -342,6 +384,7 @@ describe('render3 integration test', () => { static ngComponentDef = defineComponent({ type: MyComp, selectors: [['comp']], + consts: 2, template: function MyCompTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'p'); @@ -356,13 +399,14 @@ describe('render3 integration test', () => { }); } - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); } - } + }, 1, [MyComp]); - expect(renderToHtml(Template, null, [MyComp])).toEqual('

                            Bess

                            '); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual('

                            Bess

                            '); }); it('should support a component with sub-views', () => { @@ -377,6 +421,7 @@ describe('render3 integration test', () => { static ngComponentDef = defineComponent({ type: MyComp, selectors: [['comp']], + consts: 1, template: function MyCompTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); @@ -385,7 +430,7 @@ describe('render3 integration test', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 2); if (rf1 & RenderFlags.Create) { elementStart(0, 'div'); { text(1, 'text'); } @@ -403,20 +448,23 @@ describe('render3 integration test', () => { } /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); } if (rf & RenderFlags.Update) { elementProperty(0, 'condition', bind(ctx.condition)); } - } + }, 1, [MyComp]); - const defs = [MyComp]; - expect(renderToHtml(Template, {condition: true}, defs)) - .toEqual('
                            text
                            '); - expect(renderToHtml(Template, {condition: false}, defs)).toEqual(''); + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.update(); + expect(fixture.html).toEqual('
                            text
                            '); + fixture.component.condition = false; + fixture.update(); + expect(fixture.html).toEqual(''); }); }); @@ -424,7 +472,6 @@ describe('render3 integration test', () => { describe('ng-container', () => { it('should insert as a child of a regular element', () => { - /** *
                            before|Greetings|after
                            */ @@ -443,7 +490,7 @@ describe('render3 integration test', () => { elementEnd(); } - const fixture = new TemplateFixture(Template); + const fixture = new TemplateFixture(Template, () => {}, 6); expect(fixture.html).toEqual('
                            before|Greetings|after
                            '); }); @@ -462,7 +509,7 @@ describe('render3 integration test', () => { if (rf & RenderFlags.Update) { containerRefreshStart(0); if (ctx.value) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 3); { if (rf1 & RenderFlags.Create) { elementStart(0, 'div'); @@ -478,7 +525,7 @@ describe('render3 integration test', () => { } containerRefreshEnd(); } - }); + }, 1); const fixture = new ComponentFixture(TestCmpt); expect(fixture.html).toEqual(''); @@ -507,7 +554,7 @@ describe('render3 integration test', () => { if (rf & RenderFlags.Update) { containerRefreshStart(0); if (ctx.value) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 2); { if (rf1 & RenderFlags.Create) { elementContainerStart(0); @@ -519,7 +566,7 @@ describe('render3 integration test', () => { } containerRefreshEnd(); } - }); + }, 1); const fixture = new ComponentFixture(TestCmpt); expect(fixture.html).toEqual(''); @@ -558,12 +605,12 @@ describe('render3 integration test', () => { const TestCmpt = createComponent('test-cmpt', function(rf: RenderFlags, ctx: {value: any}) { if (rf & RenderFlags.Create) { - template(0, ngIfTemplate, null, [AttributeMarker.SelectOnly, 'ngIf']); + template(0, ngIfTemplate, 2, null, [AttributeMarker.SelectOnly, 'ngIf']); } if (rf & RenderFlags.Update) { elementProperty(0, 'ngIf', bind(ctx.value)); } - }, [NgIf]); + }, 1, [NgIf]); const fixture = new ComponentFixture(TestCmpt); expect(fixture.html).toEqual(''); @@ -614,12 +661,12 @@ describe('render3 integration test', () => { `; const TestCmpt = createComponent('test-cmpt', function(rf: RenderFlags) { if (rf & RenderFlags.Create) { - template(0, embeddedTemplate, null, [AttributeMarker.SelectOnly, 'testDirective']); + template(0, embeddedTemplate, 2, null, [AttributeMarker.SelectOnly, 'testDirective']); } if (rf & RenderFlags.Update) { testDirective = loadDirective(0); } - }, [TestDirective]); + }, 1, [TestDirective]); const fixture = new ComponentFixture(TestCmpt); expect(fixture.html).toEqual(''); @@ -643,11 +690,11 @@ describe('render3 integration test', () => { { text(1, 'component template'); } elementContainerEnd(); } - }); + }, 2); function App() { element(0, 'test-cmpt'); } - const fixture = new TemplateFixture(App, () => {}, [TestCmpt]); + const fixture = new TemplateFixture(App, () => {}, 1, [TestCmpt]); expect(fixture.html).toEqual('component template'); }); @@ -675,11 +722,11 @@ describe('render3 integration test', () => { } elementContainerEnd(); } - }); + }, 4); function App() { element(0, 'test-cmpt'); } - const fixture = new TemplateFixture(App, () => {}, [TestCmpt]); + const fixture = new TemplateFixture(App, () => {}, 1, [TestCmpt]); expect(fixture.html).toEqual('content'); }); @@ -717,23 +764,25 @@ describe('render3 integration test', () => { } } - ` - - - - content - - - - `; + /** + * + * + * + * + * content + * + * + * + * + */ const TestCmpt = createComponent('test-cmpt', function(rf: RenderFlags) { if (rf & RenderFlags.Create) { - template(0, embeddedTemplate, null, [AttributeMarker.SelectOnly, 'testDirective']); + template(0, embeddedTemplate, 4, null, [AttributeMarker.SelectOnly, 'testDirective']); } if (rf & RenderFlags.Update) { testDirective = loadDirective(0); } - }, [TestDirective]); + }, 1, [TestDirective]); function App() { element(0, 'test-cmpt'); } @@ -780,13 +829,12 @@ describe('render3 integration test', () => { elementEnd(); } - const fixture = new TemplateFixture(Template, () => {}, [Directive]); + const fixture = new TemplateFixture(Template, () => {}, 2, [Directive]); expect(fixture.html).toEqual('
                            '); expect(directive !.elRef.nativeElement.nodeType).toBe(Node.COMMENT_NODE); }); it('should not set any attributes', () => { - /** *
                            */ @@ -799,12 +847,11 @@ describe('render3 integration test', () => { elementEnd(); } - const fixture = new TemplateFixture(Template); + const fixture = new TemplateFixture(Template, () => {}, 2); expect(fixture.html).toEqual('
                            '); }); it('should throw when trying to add event listener', () => { - /** *
                            */ @@ -820,7 +867,7 @@ describe('render3 integration test', () => { elementEnd(); } - expect(() => { new TemplateFixture(Template); }).toThrow(); + expect(() => { new TemplateFixture(Template, () => {}, 2); }).toThrow(); }); }); @@ -846,7 +893,7 @@ describe('render3 integration test', () => { containerRefreshStart(0); { if (ctx.label != null) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { text(0); } @@ -868,7 +915,7 @@ describe('render3 integration test', () => { } containerRefreshStart(0); { - const rf0 = embeddedViewStart(0); + const rf0 = embeddedViewStart(0, 1); { showLabel(rf0, {label: ctx.tree.beforeLabel}); } embeddedViewEnd(); } @@ -876,7 +923,7 @@ describe('render3 integration test', () => { containerRefreshStart(1); { for (let subTree of ctx.tree.subTrees || []) { - const rf0 = embeddedViewStart(0); + const rf0 = embeddedViewStart(0, 1); { showTree(rf0, {tree: subTree}); } embeddedViewEnd(); } @@ -884,7 +931,7 @@ describe('render3 integration test', () => { containerRefreshEnd(); containerRefreshStart(2); { - const rf0 = embeddedViewStart(0); + const rf0 = embeddedViewStart(0, 1); { showLabel(rf0, {label: ctx.tree.afterLabel}); } embeddedViewEnd(); } @@ -899,6 +946,7 @@ describe('render3 integration test', () => { static ngComponentDef = defineComponent({ selectors: [['child']], type: ChildComponent, + consts: 3, template: function ChildComponentTemplate( rf: RenderFlags, ctx: {beforeTree: Tree, afterTree: Tree}) { if (rf & RenderFlags.Create) { @@ -909,14 +957,14 @@ describe('render3 integration test', () => { } containerRefreshStart(0); { - const rf0 = embeddedViewStart(0); + const rf0 = embeddedViewStart(0, 1); { showTree(rf0, {tree: ctx.beforeTree}); } embeddedViewEnd(); } containerRefreshEnd(); containerRefreshStart(2); { - const rf0 = embeddedViewStart(0); + const rf0 = embeddedViewStart(0, 1); { showTree(rf0, {tree: ctx.afterTree}); } embeddedViewEnd(); } @@ -938,7 +986,7 @@ describe('render3 integration test', () => { elementProperty(0, 'afterTree', bind(ctx.afterTree)); containerRefreshStart(1); { - const rf0 = embeddedViewStart(0); + const rf0 = embeddedViewStart(0, 1); { showTree(rf0, {tree: ctx.projectedTree}); } embeddedViewEnd(); } @@ -954,14 +1002,14 @@ describe('render3 integration test', () => { afterTree: {afterLabel: 'z'} }; const defs = [ChildComponent]; - expect(renderToHtml(parentTemplate, ctx, defs)).toEqual('apz'); + expect(renderToHtml(parentTemplate, ctx, 2, defs)).toEqual('apz'); ctx.projectedTree = {subTrees: [{}, {}, {subTrees: [{}, {}]}, {}]}; ctx.beforeTree.subTrees !.push({afterLabel: 'b'}); - expect(renderToHtml(parentTemplate, ctx, defs)).toEqual('abz'); + expect(renderToHtml(parentTemplate, ctx, 2, defs)).toEqual('abz'); ctx.projectedTree.subTrees ![1].afterLabel = 'h'; - expect(renderToHtml(parentTemplate, ctx, defs)).toEqual('abhz'); + expect(renderToHtml(parentTemplate, ctx, 2, defs)).toEqual('abhz'); ctx.beforeTree.subTrees !.push({beforeLabel: 'c'}); - expect(renderToHtml(parentTemplate, ctx, defs)).toEqual('abchz'); + expect(renderToHtml(parentTemplate, ctx, 2, defs)).toEqual('abchz'); // To check the context easily: // console.log(JSON.stringify(ctx)); @@ -973,45 +1021,50 @@ describe('render3 integration test', () => { describe('elementAttribute', () => { it('should support attribute bindings', () => { - const ctx: {title: string | null} = {title: 'Hello'}; - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'span'); } if (rf & RenderFlags.Update) { elementAttribute(0, 'title', bind(ctx.title)); } - } + }, 1); + const fixture = new ComponentFixture(App); + fixture.component.title = 'Hello'; + fixture.update(); // initial binding - expect(renderToHtml(Template, ctx)).toEqual(''); + expect(fixture.html).toEqual(''); // update binding - ctx.title = 'Hi!'; - expect(renderToHtml(Template, ctx)).toEqual(''); + fixture.component.title = 'Hi!'; + fixture.update(); + expect(fixture.html).toEqual(''); // remove attribute - ctx.title = null; - expect(renderToHtml(Template, ctx)).toEqual(''); + fixture.component.title = null; + fixture.update(); + expect(fixture.html).toEqual(''); }); it('should stringify values used attribute bindings', () => { - const ctx: {title: any} = {title: NaN}; - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'span'); } if (rf & RenderFlags.Update) { elementAttribute(0, 'title', bind(ctx.title)); } - } + }, 1); - expect(renderToHtml(Template, ctx)).toEqual(''); + const fixture = new ComponentFixture(App); + fixture.component.title = NaN; + fixture.update(); + expect(fixture.html).toEqual(''); - ctx.title = {toString: () => 'Custom toString'}; - expect(renderToHtml(Template, ctx)).toEqual(''); + fixture.component.title = {toString: () => 'Custom toString'}; + fixture.update(); + expect(fixture.html).toEqual(''); }); it('should update bindings', () => { @@ -1045,15 +1098,15 @@ describe('render3 integration test', () => { } } let args = ['(', 0, 'a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 6, 'g', 7, ')']; - expect(renderToHtml(Template, args)) + expect(renderToHtml(Template, args, 1)) .toEqual( ''); args = args.reverse(); - expect(renderToHtml(Template, args)) + expect(renderToHtml(Template, args, 1)) .toEqual( ''); args = args.reverse(); - expect(renderToHtml(Template, args)) + expect(renderToHtml(Template, args, 1)) .toEqual( ''); }); @@ -1061,7 +1114,7 @@ describe('render3 integration test', () => { it('should not update DOM if context has not changed', () => { const ctx: {title: string | null} = {title: 'Hello'}; - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); container(1); @@ -1072,7 +1125,7 @@ describe('render3 integration test', () => { containerRefreshStart(1); { if (true) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 1); { if (rf1 & RenderFlags.Create) { elementStart(0, 'b'); @@ -1086,19 +1139,23 @@ describe('render3 integration test', () => { } containerRefreshEnd(); } - } + }, 2); + const fixture = new ComponentFixture(App); + fixture.component.title = 'Hello'; + fixture.update(); // initial binding - expect(renderToHtml(Template, ctx)) - .toEqual(''); + expect(fixture.html).toEqual(''); // update DOM manually - containerEl.querySelector('b') !.setAttribute('title', 'Goodbye'); + fixture.hostElement.querySelector('b') !.setAttribute('title', 'Goodbye'); + // refresh with same binding - expect(renderToHtml(Template, ctx)) - .toEqual(''); + fixture.update(); + expect(fixture.html).toEqual(''); + // refresh again with same binding - expect(renderToHtml(Template, ctx)) - .toEqual(''); + fixture.update(); + expect(fixture.html).toEqual(''); }); it('should support host attribute bindings', () => { @@ -1121,91 +1178,123 @@ describe('render3 integration test', () => { }); } - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['hostBindingDir', '']); } - } + }, 1, [HostBindingDir]); - const defs = [HostBindingDir]; - expect(renderToHtml(Template, {}, defs)) - .toEqual(`
                            `); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual(`
                            `); hostBindingDir !.label = 'other label'; - expect(renderToHtml(Template, {}, defs)) - .toEqual(`
                            `); + fixture.update(); + expect(fixture.html).toEqual(`
                            `); }); }); describe('elementStyle', () => { it('should support binding to styles', () => { - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); elementStyling(null, ['border-color']); elementEnd(); } if (rf & RenderFlags.Update) { - elementStyleProp(0, 0, ctx); + elementStyleProp(0, 0, ctx.color); elementStylingApply(0); } - } + }, 1); - expect(renderToHtml(Template, 'red')).toEqual(''); - expect(renderToHtml(Template, 'green')) - .toEqual(''); - expect(renderToHtml(Template, null)).toEqual(''); + const fixture = new ComponentFixture(App); + fixture.component.color = 'red'; + fixture.update(); + expect(fixture.html).toEqual(''); + + fixture.component.color = 'green'; + fixture.update(); + expect(fixture.html).toEqual(''); + + fixture.component.color = null; + fixture.update(); + expect(fixture.html).toEqual(''); }); it('should support binding to styles with suffix', () => { - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); elementStyling(null, ['font-size']); elementEnd(); } if (rf & RenderFlags.Update) { - elementStyleProp(0, 0, ctx, 'px'); + elementStyleProp(0, 0, ctx.time, 'px'); elementStylingApply(0); } - } + }, 1); - expect(renderToHtml(Template, '100')).toEqual(''); - expect(renderToHtml(Template, 200)).toEqual(''); - expect(renderToHtml(Template, null)).toEqual(''); + const fixture = new ComponentFixture(App); + fixture.component.time = '100'; + fixture.update(); + expect(fixture.html).toEqual(''); + + fixture.component.time = 200; + fixture.update(); + expect(fixture.html).toEqual(''); + + fixture.component.time = null; + fixture.update(); + expect(fixture.html).toEqual(''); }); }); describe('elementClass', () => { it('should support CSS class toggle', () => { - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); elementStyling(['active']); elementEnd(); } if (rf & RenderFlags.Update) { - elementClassProp(0, 0, ctx); + elementClassProp(0, 0, ctx.class); elementStylingApply(0); } - } + }, 1); - expect(renderToHtml(Template, true)).toEqual(''); - expect(renderToHtml(Template, false)).toEqual(''); + const fixture = new ComponentFixture(App); + fixture.component.class = true; + fixture.update(); + expect(fixture.html).toEqual(''); + + fixture.component.class = false; + fixture.update(); + expect(fixture.html).toEqual(''); // truthy values - expect(renderToHtml(Template, 'a_string')).toEqual(''); - expect(renderToHtml(Template, 10)).toEqual(''); + fixture.component.class = 'a_string'; + fixture.update(); + expect(fixture.html).toEqual(''); + + fixture.component.class = 10; + fixture.update(); + expect(fixture.html).toEqual(''); // falsy values - expect(renderToHtml(Template, '')).toEqual(''); - expect(renderToHtml(Template, 0)).toEqual(''); + fixture.component.class = ''; + fixture.update(); + expect(fixture.html).toEqual(''); + + fixture.component.class = 0; + fixture.update(); + expect(fixture.html).toEqual(''); }); it('should work correctly with existing static classes', () => { - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'span'); elementStyling( @@ -1213,13 +1302,19 @@ describe('render3 integration test', () => { elementEnd(); } if (rf & RenderFlags.Update) { - elementClassProp(0, 1, ctx); + elementClassProp(0, 1, ctx.class); elementStylingApply(0); } - } + }, 1); - expect(renderToHtml(Template, true)).toEqual(''); - expect(renderToHtml(Template, false)).toEqual(''); + const fixture = new ComponentFixture(App); + fixture.component.class = true; + fixture.update(); + expect(fixture.html).toEqual(''); + + fixture.component.class = false; + fixture.update(); + expect(fixture.html).toEqual(''); }); }); }); @@ -1240,7 +1335,7 @@ describe('render3 integration test', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'div'); } @@ -1253,7 +1348,7 @@ describe('render3 integration test', () => { expect((Template as any).ngPrivateData).toBeUndefined(); - renderToHtml(Template, {condition: true}); + renderToHtml(Template, {condition: true}, 1); const oldTemplateData = (Template as any).ngPrivateData; const oldContainerData = (oldTemplateData as any).data[HEADER_OFFSET]; @@ -1261,8 +1356,8 @@ describe('render3 integration test', () => { expect(oldContainerData).not.toBeNull(); expect(oldElementData).not.toBeNull(); - renderToHtml(Template, {condition: false}); - renderToHtml(Template, {condition: true}); + renderToHtml(Template, {condition: false}, 1); + renderToHtml(Template, {condition: true}, 1); const newTemplateData = (Template as any).ngPrivateData; const newContainerData = (oldTemplateData as any).data[HEADER_OFFSET]; @@ -1281,6 +1376,7 @@ describe('render3 integration test', () => { type: SanitizationComp, selectors: [['sanitize-this']], factory: () => new SanitizationComp(), + consts: 1, template: (rf: RenderFlags, ctx: SanitizationComp) => { if (rf & RenderFlags.Create) { element(0, 'a'); diff --git a/packages/core/test/render3/lifecycle_spec.ts b/packages/core/test/render3/lifecycle_spec.ts index 5152225a14..e34629c787 100644 --- a/packages/core/test/render3/lifecycle_spec.ts +++ b/packages/core/test/render3/lifecycle_spec.ts @@ -39,23 +39,27 @@ describe('lifecycles', () => { { projection(1); } elementEnd(); } - }); - let Parent = createOnInitComponent('parent', getParentTemplate('comp'), [Comp]); + }, 2); + let Parent = createOnInitComponent('parent', getParentTemplate('comp'), 1, [Comp]); let ProjectedComp = createOnInitComponent('projected', (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { text(0, 'content'); } - }); + }, 1); function createOnInitComponent( - name: string, template: ComponentTemplate, directives: any[] = []) { + name: string, template: ComponentTemplate, consts: number, directives: any[] = []) { return class Component { val: string = ''; - ngOnInit() { events.push(`${name}${this.val}`); } + ngOnInit() { + if (!this.val) this.val = ''; + events.push(`${name}${this.val}`); + } static ngComponentDef = defineComponent({ type: Component, selectors: [[name]], + consts: consts, factory: () => new Component(), inputs: {val: 'val'}, template, directives: directives @@ -75,20 +79,22 @@ describe('lifecycles', () => { it('should call onInit method after inputs are set in creation mode (and not in update mode)', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); } if (rf & RenderFlags.Update) { elementProperty(0, 'val', bind(ctx.val)); } - } + }, 1, directives); - renderToHtml(Template, {val: '1'}, directives); - expect(events).toEqual(['comp1']); + const fixture = new ComponentFixture(App); + fixture.update(); + expect(events).toEqual(['comp']); - renderToHtml(Template, {val: '2'}, directives); - expect(events).toEqual(['comp1']); + fixture.component.val = '2'; + fixture.update(); + expect(events).toEqual(['comp']); }); it('should be called on root component in creation mode', () => { @@ -105,14 +111,13 @@ describe('lifecycles', () => { * * parent temp: */ - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); } - } + }, 1, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['parent', 'comp']); }); @@ -123,8 +128,7 @@ describe('lifecycles', () => { * * parent temp: */ - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); element(1, 'parent'); @@ -133,29 +137,28 @@ describe('lifecycles', () => { elementProperty(0, 'val', 1); elementProperty(1, 'val', 2); } - } + }, 2, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['parent1', 'parent2', 'comp1', 'comp2']); }); it('should call onInit every time a new view is created (if block)', () => { /** - * % if (condition) { + * % if (!skip) { * * % } */ - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } if (rf & RenderFlags.Update) { containerRefreshStart(0); { - if (ctx.condition) { - let rf1 = embeddedViewStart(0); + if (!ctx.skip) { + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -164,15 +167,17 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, directives); - renderToHtml(Template, {condition: true}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp']); - renderToHtml(Template, {condition: false}, directives); + fixture.component.skip = true; + fixture.update(); expect(events).toEqual(['comp']); - renderToHtml(Template, {condition: true}, directives); + fixture.component.skip = false; + fixture.update(); expect(events).toEqual(['comp', 'comp']); }); @@ -182,15 +187,15 @@ describe('lifecycles', () => { * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'comp'); { elementStart(1, 'projected'); } elementEnd(); } - } + }, 2, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp', 'projected']); }); @@ -203,7 +208,7 @@ describe('lifecycles', () => { * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'comp'); { elementStart(1, 'projected'); } @@ -218,40 +223,39 @@ describe('lifecycles', () => { elementProperty(2, 'val', 2); elementProperty(3, 'val', 2); } - } + }, 4, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp1', 'projected1', 'comp2', 'projected2']); }); it('should be called on directives after component', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp', ['dir', '']); } - } + }, 1, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp', 'dir']); - renderToHtml(Template, {}, directives); + fixture.update(); expect(events).toEqual(['comp', 'dir']); - }); it('should be called on directives on an element', () => { /**
                            */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['dir', '']); } - } + }, 1, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['dir']); - renderToHtml(Template, {}, directives); + fixture.update(); expect(events).toEqual(['dir']); }); @@ -263,8 +267,7 @@ describe('lifecycles', () => { * % } * */ - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); container(1); @@ -276,7 +279,7 @@ describe('lifecycles', () => { containerRefreshStart(1); { for (let j = 2; j < 5; j++) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -288,10 +291,9 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } - - renderToHtml(Template, {}, directives); + }, 3, directives); + const fixture = new ComponentFixture(App); // onInit is called top to bottom, so top level comps (1 and 5) are called // before the comps inside the for loop's embedded view (2, 3, and 4) expect(events).toEqual(['comp1', 'comp5', 'comp2', 'comp3', 'comp4']); @@ -305,8 +307,7 @@ describe('lifecycles', () => { * % } * */ - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); container(1); @@ -318,7 +319,7 @@ describe('lifecycles', () => { containerRefreshStart(1); { for (let j = 2; j < 5; j++) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'parent'); } @@ -330,10 +331,9 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } - - renderToHtml(Template, {}, directives); + }, 3, directives); + const fixture = new ComponentFixture(App); // onInit is called top to bottom, so top level comps (1 and 5) are called // before the comps inside the for loop's embedded view (2, 3, and 4) expect(events).toEqual([ @@ -354,10 +354,11 @@ describe('lifecycles', () => { }); let Comp = createDoCheckComponent('comp', (rf: RenderFlags, ctx: any) => {}); - let Parent = createDoCheckComponent('parent', getParentTemplate('comp'), [Comp]); + let Parent = createDoCheckComponent('parent', getParentTemplate('comp'), 1, [Comp]); function createDoCheckComponent( - name: string, template: ComponentTemplate, directives: any[] = []) { + name: string, template: ComponentTemplate, consts: number = 0, + directives: any[] = []) { return class Component { ngDoCheck() { events.push(name); @@ -370,6 +371,7 @@ describe('lifecycles', () => { type: Component, selectors: [[name]], factory: () => new Component(), template, + consts: consts, directives: directives }); }; @@ -386,16 +388,16 @@ describe('lifecycles', () => { it('should call doCheck on every refresh', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); } - } + }, 1, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp']); - renderToHtml(Template, {}, directives); + fixture.update(); expect(events).toEqual(['comp', 'comp']); }); @@ -413,60 +415,58 @@ describe('lifecycles', () => { * * parent temp: */ - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); } - } + }, 1, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['parent', 'comp']); }); it('should call ngOnInit before ngDoCheck if creation mode', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); } - } + }, 1, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(allEvents).toEqual(['init comp', 'check comp']); - renderToHtml(Template, {}, directives); + fixture.update(); expect(allEvents).toEqual(['init comp', 'check comp', 'check comp']); }); it('should be called on directives after component', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp', ['dir', '']); } - } + }, 1, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp', 'dir']); - renderToHtml(Template, {}, directives); + fixture.update(); expect(events).toEqual(['comp', 'dir', 'comp', 'dir']); - }); it('should be called on directives on an element', () => { /**
                            */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['dir', '']); } - } + }, 1, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['dir']); - renderToHtml(Template, {}, directives); + fixture.update(); expect(events).toEqual(['dir', 'dir']); }); @@ -486,7 +486,7 @@ describe('lifecycles', () => { projectionDef(); projection(0); } - }); + }, 1); let Parent = createAfterContentInitComp('parent', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -498,17 +498,18 @@ describe('lifecycles', () => { if (rf & RenderFlags.Update) { elementProperty(0, 'val', bind(ctx.val)); } - }, [Comp]); + }, 2, [Comp]); let ProjectedComp = createAfterContentInitComp('projected', (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { projectionDef(); projection(0); } - }); + }, 1); function createAfterContentInitComp( - name: string, template: ComponentTemplate, directives: any[] = []) { + name: string, template: ComponentTemplate, consts: number = 0, + directives: any[] = []) { return class Component { val: string = ''; ngAfterContentInit() { @@ -521,6 +522,7 @@ describe('lifecycles', () => { type: Component, selectors: [[name]], factory: () => new Component(), + consts: consts, inputs: {val: 'val'}, template: template, directives: directives @@ -552,7 +554,7 @@ describe('lifecycles', () => { containerRefreshStart(2); { for (let i = 2; i < 4; i++) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 2); if (rf1 & RenderFlags.Create) { elementStart(0, 'parent'); { text(1, 'content'); } @@ -572,18 +574,18 @@ describe('lifecycles', () => { it('should be called only in creation mode', () => { /** content */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'comp'); { text(1, 'content'); } elementEnd(); } - } + }, 2, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp']); - renderToHtml(Template, {}, directives); + fixture.update(); expect(events).toEqual(['comp']); }); @@ -598,19 +600,19 @@ describe('lifecycles', () => { it('should be called on every init (if blocks)', () => { /** - * % if (condition) { + * % if (!skip) { * content * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } if (rf & RenderFlags.Update) { containerRefreshStart(0); { - if (ctx.condition) { - let rf1 = embeddedViewStart(0); + if (!ctx.skip) { + let rf1 = embeddedViewStart(0, 2); if (rf1 & RenderFlags.Create) { elementStart(0, 'comp'); { text(1, 'content'); } @@ -621,15 +623,17 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, directives); - renderToHtml(Template, {condition: true}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp']); - renderToHtml(Template, {condition: false}, directives); + fixture.component.skip = true; + fixture.update(); expect(events).toEqual(['comp']); - renderToHtml(Template, {condition: true}, directives); + fixture.component.skip = false; + fixture.update(); expect(events).toEqual(['comp', 'comp']); }); @@ -639,15 +643,15 @@ describe('lifecycles', () => { * * parent template: */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'parent'); { text(1, 'content'); } elementEnd(); } - } + }, 2, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['parent', 'comp']); }); @@ -658,7 +662,7 @@ describe('lifecycles', () => { * * parent template: */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'parent'); { text(1, 'content'); } @@ -671,9 +675,9 @@ describe('lifecycles', () => { elementProperty(0, 'val', 1); elementProperty(2, 'val', 2); } - } + }, 4, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['parent1', 'parent2', 'comp1', 'comp2']); }); @@ -688,7 +692,7 @@ describe('lifecycles', () => { * * projected comp: */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'parent'); { @@ -698,9 +702,9 @@ describe('lifecycles', () => { } elementEnd(); } - } + }, 3, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['projected', 'parent', 'comp']); }); @@ -718,7 +722,7 @@ describe('lifecycles', () => { * * projected comp: */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'parent'); { @@ -741,9 +745,9 @@ describe('lifecycles', () => { elementProperty(3, 'val', 2); elementProperty(4, 'val', 2); } - } + }, 6, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['projected1', 'parent1', 'projected2', 'parent2', 'comp1', 'comp2']); }); @@ -755,7 +759,7 @@ describe('lifecycles', () => { * % } * content */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'comp'); { text(1, 'content'); } @@ -771,7 +775,7 @@ describe('lifecycles', () => { containerRefreshStart(2); { for (let i = 2; i < 4; i++) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 2); if (rf1 & RenderFlags.Create) { elementStart(0, 'comp'); { text(1, 'content'); } @@ -785,9 +789,9 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 5, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp2', 'comp3', 'comp1', 'comp4']); }); @@ -800,7 +804,7 @@ describe('lifecycles', () => { * content */ - renderToHtml(ForLoopWithChildrenTemplate, {}, directives); + renderToHtml(ForLoopWithChildrenTemplate, {}, 5, directives); expect(events).toEqual( ['parent2', 'comp2', 'parent3', 'comp3', 'parent1', 'parent4', 'comp1', 'comp4']); }); @@ -809,20 +813,19 @@ describe('lifecycles', () => { it('should be called every change detection run after afterContentInit', () => { /** content */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'comp'); { text(1, 'content'); } elementEnd(); } - } + }, 2, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(allEvents).toEqual(['comp init', 'comp check']); - renderToHtml(Template, {}, directives); + fixture.update(); expect(allEvents).toEqual(['comp init', 'comp check', 'comp check']); - }); it('should be called on root component', () => { @@ -839,25 +842,25 @@ describe('lifecycles', () => { describe('directives', () => { it('should be called on directives after component', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp', ['dir', '']); } - } + }, 1, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp', 'init', 'check']); }); it('should be called on directives on an element', () => { /**
                            */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['dir', '']); } - } + }, 1, directives); - renderToHtml(Template, {}, directives); + const fixture = new ComponentFixture(App); expect(events).toEqual(['init', 'check']); }); }); @@ -879,20 +882,21 @@ describe('lifecycles', () => { { projection(1); } elementEnd(); } - }); - let Parent = createAfterViewInitComponent('parent', getParentTemplate('comp'), [Comp]); + }, 2); + let Parent = createAfterViewInitComponent('parent', getParentTemplate('comp'), 1, [Comp]); let ProjectedComp = createAfterViewInitComponent('projected', (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { text(0, 'content'); } - }); + }, 1); function createAfterViewInitComponent( - name: string, template: ComponentTemplate, directives: any[] = []) { + name: string, template: ComponentTemplate, consts: number, directives: any[] = []) { return class Component { val: string = ''; ngAfterViewInit() { + if (!this.val) this.val = ''; events.push(`${name}${this.val}`); allEvents.push(`${name}${this.val} init`); } @@ -901,6 +905,7 @@ describe('lifecycles', () => { static ngComponentDef = defineComponent({ type: Component, selectors: [[name]], + consts: consts, factory: () => new Component(), inputs: {val: 'val'}, template: template, @@ -921,16 +926,16 @@ describe('lifecycles', () => { it('should be called on init and not in update mode', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); } - } + }, 1, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp']); - renderToHtml(Template, {}, defs); + fixture.update(); expect(events).toEqual(['comp']); }); @@ -945,19 +950,19 @@ describe('lifecycles', () => { it('should be called every time a view is initialized (if block)', () => { /* - * % if (condition) { + * % if (!skip) { * * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } if (rf & RenderFlags.Update) { containerRefreshStart(0); { - if (ctx.condition) { - let rf1 = embeddedViewStart(0); + if (!ctx.skip) { + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -966,15 +971,17 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, defs); - renderToHtml(Template, {condition: true}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp']); - renderToHtml(Template, {condition: false}, defs); + fixture.component.skip = true; + fixture.update(); expect(events).toEqual(['comp']); - renderToHtml(Template, {condition: true}, defs); + fixture.component.skip = false; + fixture.update(); expect(events).toEqual(['comp', 'comp']); }); @@ -985,15 +992,14 @@ describe('lifecycles', () => { * * parent temp: */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); } - } + }, 1, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp', 'parent']); - }); it('should be called for entire subtree before being called in any parent view comps', () => { @@ -1003,7 +1009,7 @@ describe('lifecycles', () => { * * parent temp: */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); element(1, 'parent'); @@ -1012,8 +1018,9 @@ describe('lifecycles', () => { elementProperty(0, 'val', 1); elementProperty(1, 'val', 2); } - } - renderToHtml(Template, {}, defs); + }, 2, defs); + + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp1', 'comp2', 'parent1', 'parent2']); }); @@ -1024,15 +1031,15 @@ describe('lifecycles', () => { * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'comp'); { element(1, 'projected'); } elementEnd(); } - } + }, 2, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual(['projected', 'comp']); }); @@ -1045,7 +1052,7 @@ describe('lifecycles', () => { * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'comp'); { element(1, 'projected'); } @@ -1060,9 +1067,9 @@ describe('lifecycles', () => { elementProperty(2, 'val', 2); elementProperty(3, 'val', 2); } - } + }, 4, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual(['projected1', 'comp1', 'projected2', 'comp2']); }); @@ -1082,13 +1089,13 @@ describe('lifecycles', () => { elementProperty(0, 'val', bind(ctx.val)); elementProperty(1, 'val', bind(ctx.val)); } - }, [Comp, ProjectedComp]); + }, 2, [Comp, ProjectedComp]); /** * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); element(1, 'parent'); @@ -1097,9 +1104,9 @@ describe('lifecycles', () => { elementProperty(0, 'val', 1); elementProperty(1, 'val', 2); } - } + }, 2, [ParentComp]); - renderToHtml(Template, {}, [ParentComp]); + const fixture = new ComponentFixture(App); expect(events).toEqual(['projected1', 'comp1', 'projected2', 'comp2', 'parent1', 'parent2']); }); @@ -1111,7 +1118,7 @@ describe('lifecycles', () => { * % } * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); container(1); @@ -1123,7 +1130,7 @@ describe('lifecycles', () => { containerRefreshStart(1); { for (let i = 2; i < 4; i++) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -1135,9 +1142,9 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 3, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp2', 'comp3', 'comp1', 'comp4']); }); @@ -1150,7 +1157,7 @@ describe('lifecycles', () => { * % } * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); container(1); @@ -1162,7 +1169,7 @@ describe('lifecycles', () => { containerRefreshStart(1); { for (let i = 2; i < 4; i++) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'parent'); } @@ -1174,9 +1181,9 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 3, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual( ['comp2', 'parent2', 'comp3', 'parent3', 'comp1', 'comp4', 'parent1', 'parent4']); @@ -1186,16 +1193,16 @@ describe('lifecycles', () => { it('should call ngAfterViewChecked every update', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); } - } + }, 1, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(allEvents).toEqual(['comp init', 'comp check']); - renderToHtml(Template, {}, defs); + fixture.update(); expect(allEvents).toEqual(['comp init', 'comp check', 'comp check']); }); @@ -1210,20 +1217,21 @@ describe('lifecycles', () => { it('should call ngAfterViewChecked with bindings', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); } if (rf & RenderFlags.Update) { elementProperty(0, 'val', bind(ctx.myVal)); } - } + }, 1, defs); - renderToHtml(Template, {myVal: 5}, defs); - expect(allEvents).toEqual(['comp5 init', 'comp5 check']); + const fixture = new ComponentFixture(App); + expect(allEvents).toEqual(['comp init', 'comp check']); - renderToHtml(Template, {myVal: 6}, defs); - expect(allEvents).toEqual(['comp5 init', 'comp5 check', 'comp6 check']); + fixture.component.myVal = 2; + fixture.update(); + expect(allEvents).toEqual(['comp init', 'comp check', 'comp2 check']); }); it('should be called in correct order with for loops with children', () => { @@ -1234,7 +1242,7 @@ describe('lifecycles', () => { * % } * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); container(1); @@ -1246,7 +1254,7 @@ describe('lifecycles', () => { containerRefreshStart(1); { for (let i = 2; i < 4; i++) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'parent'); } @@ -1258,9 +1266,9 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 3, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(allEvents).toEqual([ 'comp2 init', 'comp2 check', 'parent2 init', 'parent2 check', 'comp3 init', 'comp3 check', 'parent3 init', 'parent3 check', 'comp1 init', 'comp1 check', 'comp4 init', 'comp4 check', @@ -1274,25 +1282,25 @@ describe('lifecycles', () => { describe('directives', () => { it('should be called on directives after component', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp', ['dir', '']); } - } + }, 1, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual(['comp', 'init', 'check']); }); it('should be called on directives on an element', () => { /**
                            */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['dir', '']); } - } + }, 1, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual(['init', 'check']); }); }); @@ -1308,11 +1316,12 @@ describe('lifecycles', () => { projectionDef(); projection(0); } - }); - let Parent = createOnDestroyComponent('parent', getParentTemplate('comp'), [Comp]); + }, 1); + let Parent = createOnDestroyComponent('parent', getParentTemplate('comp'), 1, [Comp]); function createOnDestroyComponent( - name: string, template: ComponentTemplate, directives: any[] = []) { + name: string, template: ComponentTemplate, consts: number = 0, + directives: any[] = []) { return class Component { val: string = ''; ngOnDestroy() { events.push(`${name}${this.val}`); } @@ -1321,6 +1330,7 @@ describe('lifecycles', () => { type: Component, selectors: [[name]], factory: () => new Component(), + consts: consts, inputs: {val: 'val'}, template: template, directives: directives @@ -1332,7 +1342,7 @@ describe('lifecycles', () => { if (rf & RenderFlags.Create) { element(0, 'parent'); } - }, [Parent]); + }, 1, [Parent]); const ProjectedComp = createOnDestroyComponent('projected', (rf: RenderFlags, ctx: any) => {}); @@ -1347,20 +1357,20 @@ describe('lifecycles', () => { it('should call destroy when view is removed', () => { /** - * % if (condition) { + * % if (!skip) { * * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } if (rf & RenderFlags.Update) { containerRefreshStart(0); { - if (ctx.condition) { - let rf1 = embeddedViewStart(0); + if (!ctx.skip) { + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -1369,30 +1379,32 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, defs); - renderToHtml(Template, {condition: true}, defs); - renderToHtml(Template, {condition: false}, defs); + const fixture = new ComponentFixture(App); + + fixture.component.skip = true; + fixture.update(); expect(events).toEqual(['comp']); }); it('should call destroy when multiple views are removed', () => { /** - * % if (condition) { + * % if (!skip) { * * * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } if (rf & RenderFlags.Update) { containerRefreshStart(0); { - if (ctx.condition) { - let rf1 = embeddedViewStart(0); + if (!ctx.skip) { + let rf1 = embeddedViewStart(0, 2); if (rf1 & RenderFlags.Create) { element(0, 'comp'); element(1, 'comp'); @@ -1406,31 +1418,33 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, defs); - renderToHtml(Template, {condition: true}, defs); - renderToHtml(Template, {condition: false}, defs); + const fixture = new ComponentFixture(App); + + fixture.component.skip = true; + fixture.update(); expect(events).toEqual(['comp1', 'comp2']); }); it('should be called in child components before parent components', () => { /** - * % if (condition) { + * % if (!skip) { * * % } * * parent template: */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } if (rf & RenderFlags.Update) { containerRefreshStart(0); { - if (ctx.condition) { - let rf1 = embeddedViewStart(0); + if (!ctx.skip) { + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'parent'); } @@ -1439,16 +1453,18 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, defs); - renderToHtml(Template, {condition: true}, defs); - renderToHtml(Template, {condition: false}, defs); + const fixture = new ComponentFixture(App); + + fixture.component.skip = true; + fixture.update(); expect(events).toEqual(['comp', 'parent']); }); it('should be called bottom up with children nested 2 levels deep', () => { /** - * % if (condition) { + * % if (!skip) { * * % } * @@ -1456,15 +1472,15 @@ describe('lifecycles', () => { * parent template: */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } if (rf & RenderFlags.Update) { containerRefreshStart(0); { - if (ctx.condition) { - let rf1 = embeddedViewStart(0); + if (!ctx.skip) { + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'grandparent'); } @@ -1473,16 +1489,18 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, defs); - renderToHtml(Template, {condition: true}, defs); - renderToHtml(Template, {condition: false}, defs); + const fixture = new ComponentFixture(App); + + fixture.component.skip = true; + fixture.update(); expect(events).toEqual(['comp', 'parent', 'grandparent']); }); it('should be called in projected components before their hosts', () => { /** - * % if (showing) { + * % if (!skip) { * * * @@ -1491,15 +1509,15 @@ describe('lifecycles', () => { * * } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } if (rf & RenderFlags.Update) { containerRefreshStart(0); { - if (ctx.showing) { - let rf1 = embeddedViewStart(0); + if (!ctx.skip) { + let rf1 = embeddedViewStart(0, 4); if (rf1 & RenderFlags.Create) { elementStart(0, 'comp'); { element(1, 'projected'); } @@ -1519,11 +1537,12 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, defs); - renderToHtml(Template, {showing: true}, defs); - renderToHtml(Template, {showing: false}, defs); + const fixture = new ComponentFixture(App); + fixture.component.skip = true; + fixture.update(); expect(events).toEqual(['projected1', 'comp1', 'projected2', 'comp2']); }); @@ -1539,7 +1558,7 @@ describe('lifecycles', () => { * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } @@ -1547,7 +1566,7 @@ describe('lifecycles', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 3); if (rf1 & RenderFlags.Create) { element(0, 'comp'); container(1); @@ -1559,7 +1578,7 @@ describe('lifecycles', () => { containerRefreshStart(1); { if (ctx.condition2) { - let rf2 = embeddedViewStart(0); + let rf2 = embeddedViewStart(0, 1); if (rf2 & RenderFlags.Create) { element(0, 'comp'); } @@ -1576,10 +1595,16 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, defs); - renderToHtml(Template, {condition: true, condition2: true}, defs); - renderToHtml(Template, {condition: false}, defs); + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.component.condition2 = true; + fixture.update(); + + // remove all views + fixture.component.condition = false; + fixture.update(); /** * Current angular will process in this same order (root is the top-level removed view): @@ -1594,13 +1619,25 @@ describe('lifecycles', () => { expect(events).toEqual(['comp2', 'comp1', 'comp3']); events = []; - renderToHtml(Template, {condition: true, condition2: false}, defs); - renderToHtml(Template, {condition: false}, defs); + // remove inner view + fixture.component.condition = true; + fixture.component.condition2 = false; + fixture.update(); + + // remove outer view + fixture.component.condition = false; + fixture.update(); expect(events).toEqual(['comp1', 'comp3']); events = []; - renderToHtml(Template, {condition: true, condition2: true}, defs); - renderToHtml(Template, {condition: false}, defs); + // restore both views + fixture.component.condition = true; + fixture.component.condition2 = true; + fixture.update(); + + // remove both views + fixture.component.condition = false; + fixture.update(); expect(events).toEqual(['comp2', 'comp1', 'comp3']); }); @@ -1614,7 +1651,7 @@ describe('lifecycles', () => { * * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } @@ -1622,7 +1659,7 @@ describe('lifecycles', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 3); if (rf1 & RenderFlags.Create) { element(0, 'comp'); container(1); @@ -1634,7 +1671,7 @@ describe('lifecycles', () => { containerRefreshStart(1); { for (let j = 2; j < ctx.len; j++) { - let rf2 = embeddedViewStart(0); + let rf2 = embeddedViewStart(0, 1); if (rf2 & RenderFlags.Create) { element(0, 'comp'); } @@ -1651,7 +1688,15 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, defs); + + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.component.len = 5; + fixture.update(); + + fixture.component.condition = false; + fixture.update(); /** * Current angular will process in this same order (root is the top-level removed view): @@ -1667,18 +1712,24 @@ describe('lifecycles', () => { * embeddedView.next.next -> container -> root * root onDestroy: [comp1, comp5] */ - renderToHtml(Template, {condition: true, len: 5}, defs); - renderToHtml(Template, {condition: false}, defs); expect(events).toEqual(['comp2', 'comp3', 'comp4', 'comp1', 'comp5']); events = []; - renderToHtml(Template, {condition: true, len: 4}, defs); - renderToHtml(Template, {condition: false}, defs); + fixture.component.condition = true; + fixture.component.len = 4; + fixture.update(); + + fixture.component.condition = false; + fixture.update(); expect(events).toEqual(['comp2', 'comp3', 'comp1', 'comp5']); events = []; - renderToHtml(Template, {condition: true, len: 5}, defs); - renderToHtml(Template, {condition: false}, defs); + fixture.component.condition = true; + fixture.component.len = 5; + fixture.update(); + + fixture.component.condition = false; + fixture.update(); expect(events).toEqual(['comp2', 'comp3', 'comp4', 'comp1', 'comp5']); }); @@ -1690,7 +1741,6 @@ describe('lifecycles', () => { * * % } */ - function Template(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); @@ -1699,7 +1749,7 @@ describe('lifecycles', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 5); if (rf1 & RenderFlags.Create) { elementStart(0, 'button'); { @@ -1729,7 +1779,7 @@ describe('lifecycles', () => { } const ctx: {counter: number} = new App(); - renderToHtml(Template, ctx, defs); + renderToHtml(Template, ctx, 1, defs); const buttons = containerEl.querySelectorAll('button') !; buttons[0].click(); @@ -1737,7 +1787,7 @@ describe('lifecycles', () => { buttons[1].click(); expect(ctx.counter).toEqual(2); - renderToHtml(Template, {condition: false}, defs); + renderToHtml(Template, {condition: false}, 1, defs); buttons[0].click(); buttons[1].click(); @@ -1752,7 +1802,7 @@ describe('lifecycles', () => { * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } @@ -1760,7 +1810,7 @@ describe('lifecycles', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp', ['dir', '']); } @@ -1769,12 +1819,15 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, defs); - renderToHtml(Template, {condition: true}, defs); + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.update(); expect(events).toEqual([]); - renderToHtml(Template, {condition: false}, defs); + fixture.component.condition = false; + fixture.update(); expect(events).toEqual(['comp', 'dir']); }); @@ -1786,7 +1839,7 @@ describe('lifecycles', () => { * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } @@ -1794,7 +1847,7 @@ describe('lifecycles', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'div', ['dir', '']); } @@ -1803,12 +1856,15 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, defs); - renderToHtml(Template, {condition: true}, defs); + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.update(); expect(events).toEqual([]); - renderToHtml(Template, {condition: false}, defs); + fixture.component.condition = false; + fixture.update(); expect(events).toEqual(['dir']); }); @@ -1826,7 +1882,7 @@ describe('lifecycles', () => { { projection(1); } elementEnd(); } - }); + }, 2); const Parent = createOnChangesComponent('parent', (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { element(0, 'comp'); @@ -1835,16 +1891,17 @@ describe('lifecycles', () => { elementProperty(0, 'val1', bind(ctx.a)); elementProperty(0, 'publicName', bind(ctx.b)); } - }, [Comp]); + }, 1, [Comp]); const ProjectedComp = createOnChangesComponent('projected', (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { text(0, 'content'); } - }); + }, 1); function createOnChangesComponent( - name: string, template: ComponentTemplate, directives: any[] = []) { + name: string, template: ComponentTemplate, consts: number = 0, + directives: any[] = []) { return class Component { // @Input() val1: string; // @Input('publicName') val2: string; @@ -1860,6 +1917,7 @@ describe('lifecycles', () => { selectors: [[name]], factory: () => new Component(), features: [NgOnChangesFeature], + consts: consts, inputs: {a: 'val1', b: ['publicName', 'val2']}, template, directives: directives }); @@ -1889,7 +1947,7 @@ describe('lifecycles', () => { it('should call onChanges method after inputs are set in creation and update mode', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); } @@ -1897,14 +1955,19 @@ describe('lifecycles', () => { elementProperty(0, 'val1', bind(ctx.val1)); elementProperty(0, 'publicName', bind(ctx.val2)); } - } + }, 1, defs); - renderToHtml(Template, {val1: '1', val2: 'a'}, defs); + const fixture = new ComponentFixture(App); + events = []; + fixture.component.val1 = '1'; + fixture.component.val2 = 'a'; + fixture.update(); expect(events).toEqual(['comp=comp val1=1 val2=a - changed=[val1,val2]']); - events.length = 0; - - renderToHtml(Template, {val1: '2', val2: 'b'}, defs); + events = []; + fixture.component.val1 = '2'; + fixture.component.val2 = 'b'; + fixture.update(); expect(events).toEqual(['comp=comp val1=2 val2=b - changed=[val1,val2]']); }); @@ -1913,8 +1976,7 @@ describe('lifecycles', () => { * * parent temp: */ - - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); } @@ -1922,9 +1984,14 @@ describe('lifecycles', () => { elementProperty(0, 'val1', bind(ctx.val1)); elementProperty(0, 'publicName', bind(ctx.val2)); } - } + }, 1, defs); + + const fixture = new ComponentFixture(App); + events = []; + fixture.component.val1 = '1'; + fixture.component.val2 = 'a'; + fixture.update(); - renderToHtml(Template, {val1: '1', val2: 'a'}, defs); expect(events).toEqual([ 'comp=parent val1=1 val2=a - changed=[val1,val2]', 'comp=comp val1=1 val2=a - changed=[val1,val2]' @@ -1939,7 +2006,7 @@ describe('lifecycles', () => { * parent temp: */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); element(1, 'parent'); @@ -1950,9 +2017,9 @@ describe('lifecycles', () => { elementProperty(1, 'val1', bind(2)); elementProperty(1, 'publicName', bind(2)); } - } + }, 2, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual([ 'comp=parent val1=1 val2=1 - changed=[val1,val2]', 'comp=parent val1=2 val2=2 - changed=[val1,val2]', @@ -1969,7 +2036,7 @@ describe('lifecycles', () => { * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } @@ -1977,7 +2044,7 @@ describe('lifecycles', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -1990,15 +2057,19 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 1, defs); - renderToHtml(Template, {condition: true}, defs); + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.update(); expect(events).toEqual(['comp=comp val1=1 val2=1 - changed=[val1,val2]']); - renderToHtml(Template, {condition: false}, defs); + fixture.component.condition = false; + fixture.update(); expect(events).toEqual(['comp=comp val1=1 val2=1 - changed=[val1,val2]']); - renderToHtml(Template, {condition: true}, defs); + fixture.component.condition = true; + fixture.update(); expect(events).toEqual([ 'comp=comp val1=1 val2=1 - changed=[val1,val2]', 'comp=comp val1=1 val2=1 - changed=[val1,val2]' @@ -2011,7 +2082,7 @@ describe('lifecycles', () => { * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'comp'); { elementStart(1, 'projected'); } @@ -2023,9 +2094,9 @@ describe('lifecycles', () => { elementProperty(1, 'val1', bind(2)); elementProperty(1, 'publicName', bind(2)); } - } + }, 2, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual([ 'comp=comp val1=1 val2=1 - changed=[val1,val2]', 'comp=projected val1=2 val2=2 - changed=[val1,val2]' @@ -2041,7 +2112,7 @@ describe('lifecycles', () => { * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'comp'); { elementStart(1, 'projected'); } @@ -2060,9 +2131,9 @@ describe('lifecycles', () => { elementProperty(3, 'val1', bind(4)); elementProperty(3, 'publicName', bind(4)); } - } + }, 4, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual([ 'comp=comp val1=1 val2=1 - changed=[val1,val2]', 'comp=projected val1=2 val2=2 - changed=[val1,val2]', @@ -2073,7 +2144,7 @@ describe('lifecycles', () => { it('should be called on directives after component', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp', ['dir', '']); } @@ -2081,14 +2152,14 @@ describe('lifecycles', () => { elementProperty(0, 'val1', bind(1)); elementProperty(0, 'publicName', bind(1)); } - } + }, 1, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual([ 'comp=comp val1=1 val2=1 - changed=[val1,val2]', 'dir - val1=1 val2=1 - changed=[val1,val2]' ]); - renderToHtml(Template, {}, defs); + fixture.update(); expect(events).toEqual([ 'comp=comp val1=1 val2=1 - changed=[val1,val2]', 'dir - val1=1 val2=1 - changed=[val1,val2]' ]); @@ -2097,7 +2168,7 @@ describe('lifecycles', () => { it('should be called on directives on an element', () => { /**
                            */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['dir', '']); } @@ -2105,12 +2176,12 @@ describe('lifecycles', () => { elementProperty(0, 'val1', bind(1)); elementProperty(0, 'publicName', bind(1)); } - } + }, 1, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual(['dir - val1=1 val2=1 - changed=[val1,val2]']); - renderToHtml(Template, {}, defs); + fixture.update(); expect(events).toEqual(['dir - val1=1 val2=1 - changed=[val1,val2]']); }); @@ -2123,7 +2194,7 @@ describe('lifecycles', () => { * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); container(1); @@ -2137,7 +2208,7 @@ describe('lifecycles', () => { containerRefreshStart(1); { for (let j = 2; j < 5; j++) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -2150,9 +2221,9 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 3, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); // onChanges is called top to bottom, so top level comps (1 and 5) are called // before the comps inside the for loop's embedded view (2, 3, and 4) @@ -2174,7 +2245,7 @@ describe('lifecycles', () => { * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); container(1); @@ -2188,7 +2259,7 @@ describe('lifecycles', () => { containerRefreshStart(1); { for (let j = 2; j < 5; j++) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'parent'); } @@ -2201,9 +2272,9 @@ describe('lifecycles', () => { } containerRefreshEnd(); } - } + }, 3, defs); - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); // onChanges is called top to bottom, so top level comps (1 and 5) are called // before the comps inside the for loop's embedded view (2, 3, and 4) @@ -2229,7 +2300,8 @@ describe('lifecycles', () => { beforeEach(() => { events = []; }); function createAllHooksComponent( - name: string, template: ComponentTemplate, directives: any[] = []) { + name: string, template: ComponentTemplate, consts: number = 0, + directives: any[] = []) { return class Component { val: string = ''; @@ -2248,6 +2320,7 @@ describe('lifecycles', () => { type: Component, selectors: [[name]], factory: () => new Component(), + consts: consts, inputs: {val: 'val'}, template, features: [NgOnChangesFeature], directives: directives @@ -2258,12 +2331,11 @@ describe('lifecycles', () => { it('should call all hooks in correct order', () => { const Comp = createAllHooksComponent('comp', (rf: RenderFlags, ctx: any) => {}); - /** * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); element(1, 'comp'); @@ -2272,10 +2344,9 @@ describe('lifecycles', () => { elementProperty(0, 'val', 1); elementProperty(1, 'val', 2); } - } + }, 2, [Comp]); - const defs = [Comp]; - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual([ 'changes comp1', 'init comp1', 'check comp1', 'changes comp2', 'init comp2', 'check comp2', 'contentInit comp1', 'contentCheck comp1', 'contentInit comp2', 'contentCheck comp2', @@ -2283,7 +2354,7 @@ describe('lifecycles', () => { ]); events = []; - renderToHtml(Template, {}, defs); + fixture.update(); expect(events).toEqual([ 'changes comp1', 'check comp1', 'changes comp2', 'check comp2', 'contentCheck comp1', 'contentCheck comp2', 'viewCheck comp1', 'viewCheck comp2' @@ -2301,13 +2372,13 @@ describe('lifecycles', () => { if (rf & RenderFlags.Update) { elementProperty(0, 'val', bind(ctx.val)); } - }, [Comp]); + }, 1, [Comp]); /** * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent'); element(1, 'parent'); @@ -2316,10 +2387,9 @@ describe('lifecycles', () => { elementProperty(0, 'val', 1); elementProperty(1, 'val', 2); } - } + }, 2, [Parent]); - const defs = [Parent]; - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual([ 'changes parent1', 'init parent1', 'check parent1', 'changes parent2', 'init parent2', 'check parent2', @@ -2334,7 +2404,7 @@ describe('lifecycles', () => { ]); events = []; - renderToHtml(Template, {}, defs); + fixture.update(); expect(events).toEqual([ 'changes parent1', 'check parent1', 'changes parent2', 'check parent2', 'contentCheck parent1', 'contentCheck parent2', 'check comp1', 'contentCheck comp1', @@ -2360,7 +2430,7 @@ describe('lifecycles', () => { if (rf & RenderFlags.Update) { elementProperty(1, 'val', bind(ctx.val)); } - }, [View]); + }, 2, [View]); /** * @@ -2370,7 +2440,7 @@ describe('lifecycles', () => { * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'parent'); { element(1, 'content'); } @@ -2385,10 +2455,9 @@ describe('lifecycles', () => { elementProperty(2, 'val', bind(2)); elementProperty(3, 'val', bind(2)); } - } + }, 4, [Parent, Content]); - const defs = [Parent, Content]; - renderToHtml(Template, {}, defs); + const fixture = new ComponentFixture(App); expect(events).toEqual([ 'changes parent1', 'init parent1', 'check parent1', 'changes content1', @@ -2414,7 +2483,7 @@ describe('lifecycles', () => { ]); events = []; - renderToHtml(Template, {}, defs); + fixture.update(); expect(events).toEqual([ 'check parent1', 'check content1', 'check parent2', 'check content2', 'contentCheck content1', 'contentCheck parent1', 'contentCheck content2', @@ -2445,7 +2514,7 @@ describe('lifecycles', () => { function conditionTpl(rf: RenderFlags, ctx: Cmpt) { if (rf & RenderFlags.Create) { - template(0, cmptTpl, null, [AttributeMarker.SelectOnly, 'onDestroyDirective']); + template(0, null, 0, null, [AttributeMarker.SelectOnly, 'onDestroyDirective']); } } @@ -2456,7 +2525,7 @@ describe('lifecycles', () => { */ function cmptTpl(rf: RenderFlags, cmpt: Cmpt) { if (rf & RenderFlags.Create) { - template(0, conditionTpl, null, [AttributeMarker.SelectOnly, 'ngIf']); + template(0, conditionTpl, 1, null, [AttributeMarker.SelectOnly, 'ngIf']); } if (rf & RenderFlags.Update) { elementProperty(0, 'ngIf', bind(cmpt.showing)); @@ -2469,6 +2538,7 @@ describe('lifecycles', () => { type: Cmpt, factory: () => new Cmpt(), selectors: [['cmpt']], + consts: 1, template: cmptTpl, directives: [NgIf, OnDestroyDirective] }); diff --git a/packages/core/test/render3/listeners_spec.ts b/packages/core/test/render3/listeners_spec.ts index 08c96c7de9..4d3ff3e55b 100644 --- a/packages/core/test/render3/listeners_spec.ts +++ b/packages/core/test/render3/listeners_spec.ts @@ -26,6 +26,7 @@ describe('event listeners', () => { static ngComponentDef = defineComponent({ type: MyComp, selectors: [['comp']], + consts: 2, /** */ template: function CompTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -65,6 +66,7 @@ describe('event listeners', () => { type: PreventDefaultComp, selectors: [['prevent-default-comp']], factory: () => new PreventDefaultComp(), + consts: 2, /** */ template: (rf: RenderFlags, ctx: PreventDefaultComp) => { if (rf & RenderFlags.Create) { @@ -146,7 +148,7 @@ describe('event listeners', () => { onClick: function() { this.counter++; }, onClick2: function() { this.counter2++; } }; - renderToHtml(Template, ctx); + renderToHtml(Template, ctx, 2); const button = containerEl.querySelector('button') !; button.click(); @@ -173,7 +175,7 @@ describe('event listeners', () => { } const ctx = {showing: false}; - renderToHtml(Template, ctx); + renderToHtml(Template, ctx, 2); const button = containerEl.querySelector('button') !; button.click(); @@ -198,7 +200,7 @@ describe('event listeners', () => { containerRefreshStart(0); { if (ctx.showing) { - if (embeddedViewStart(1)) { + if (embeddedViewStart(1, 2)) { elementStart(0, 'button'); { listener('click', function() { return ctx.onClick(); }); @@ -214,7 +216,7 @@ describe('event listeners', () => { } let comp = new MyComp(); - renderToHtml(Template, comp); + renderToHtml(Template, comp, 1); const button = containerEl.querySelector('button') !; button.click(); @@ -225,7 +227,7 @@ describe('event listeners', () => { // the listener should be removed when the view is removed comp.showing = false; - renderToHtml(Template, comp); + renderToHtml(Template, comp, 1); button.click(); expect(comp.counter).toEqual(2); }); @@ -247,6 +249,7 @@ describe('event listeners', () => { type: AppComp, selectors: [['app-comp']], factory: () => new AppComp(), + consts: 1, template: function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); @@ -255,7 +258,7 @@ describe('event listeners', () => { containerRefreshStart(0); { if (ctx.showing) { - if (embeddedViewStart(0)) { + if (embeddedViewStart(0, 2)) { elementStart(0, 'button'); { listener('click', function() { return ctx.onClick(); }); @@ -306,6 +309,7 @@ describe('event listeners', () => { type: AppComp, selectors: [['app-comp']], factory: () => new AppComp(), + consts: 1, template: function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); @@ -314,7 +318,7 @@ describe('event listeners', () => { containerRefreshStart(0); { for (let i = 0; i < ctx.buttons; i++) { - if (embeddedViewStart(0)) { + if (embeddedViewStart(0, 2)) { elementStart(0, 'button'); { listener('click', function() { return ctx.onClick(i); }); @@ -367,6 +371,7 @@ describe('event listeners', () => { type: AppComp, selectors: [['app-comp']], factory: () => new AppComp(), + consts: 1, template: function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); @@ -375,7 +380,7 @@ describe('event listeners', () => { containerRefreshStart(0); { for (let i = 0; i < ctx.buttons; i++) { - if (embeddedViewStart(1)) { + if (embeddedViewStart(1, 2)) { elementStart(0, 'button'); { listener('click', function() { return ctx.onClick(i); }); @@ -437,7 +442,7 @@ describe('event listeners', () => { } } - renderToHtml(Template, {}, [HostListenerDir]); + renderToHtml(Template, {}, 2, [HostListenerDir]); const button = containerEl.querySelector('button') !; button.click(); expect(events).toEqual(['click!']); @@ -464,7 +469,7 @@ describe('event listeners', () => { containerRefreshStart(0); { if (ctx.showing) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 2); if (rf1 & RenderFlags.Create) { text(0, 'Hello'); container(1); @@ -473,7 +478,7 @@ describe('event listeners', () => { containerRefreshStart(1); { if (ctx.button) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 2); if (rf1 & RenderFlags.Create) { elementStart(0, 'button'); { @@ -495,7 +500,7 @@ describe('event listeners', () => { } const comp = {showing: true, counter: 0, button: true, onClick: function() { this.counter++; }}; - renderToHtml(Template, comp); + renderToHtml(Template, comp, 1); const button = containerEl.querySelector('button') !; button.click(); @@ -503,7 +508,7 @@ describe('event listeners', () => { // the child view listener should be removed when the parent view is removed comp.showing = false; - renderToHtml(Template, comp); + renderToHtml(Template, comp, 1); button.click(); expect(comp.counter).toEqual(1); }); @@ -528,7 +533,7 @@ describe('event listeners', () => { containerRefreshStart(0); { if (ctx.showing) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 3); if (rf1 & RenderFlags.Create) { text(0, 'Hello'); element(1, 'comp'); @@ -542,7 +547,7 @@ describe('event listeners', () => { } const ctx = {showing: true}; - renderToHtml(Template, ctx, [MyComp]); + renderToHtml(Template, ctx, 1, [MyComp]); const buttons = containerEl.querySelectorAll('button') !; buttons[0].click(); @@ -553,7 +558,7 @@ describe('event listeners', () => { // the child view listener should be removed when the parent view is removed ctx.showing = false; - renderToHtml(Template, ctx, [MyComp]); + renderToHtml(Template, ctx, 1, [MyComp]); buttons[0].click(); buttons[1].click(); expect(comps[0] !.counter).toEqual(1); @@ -581,7 +586,7 @@ describe('event listeners', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 3); if (rf1 & RenderFlags.Create) { text(0, 'Hello'); container(1); @@ -591,7 +596,7 @@ describe('event listeners', () => { containerRefreshStart(1); { if (ctx.sub1) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 2); if (rf1 & RenderFlags.Create) { elementStart(0, 'button'); { @@ -607,7 +612,7 @@ describe('event listeners', () => { containerRefreshStart(2); { if (ctx.sub2) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 2); if (rf1 & RenderFlags.Create) { elementStart(0, 'button'); { @@ -629,7 +634,7 @@ describe('event listeners', () => { } const ctx = {condition: true, counter1: 0, counter2: 0, sub1: true, sub2: true}; - renderToHtml(Template, ctx); + renderToHtml(Template, ctx, 1); const buttons = containerEl.querySelectorAll('button') !; buttons[0].click(); @@ -640,7 +645,7 @@ describe('event listeners', () => { // the child view listeners should be removed when the parent view is removed ctx.condition = false; - renderToHtml(Template, ctx); + renderToHtml(Template, ctx, 1); buttons[0].click(); buttons[1].click(); expect(ctx.counter1).toEqual(1); diff --git a/packages/core/test/render3/outputs_spec.ts b/packages/core/test/render3/outputs_spec.ts index be55a67907..131a29aabc 100644 --- a/packages/core/test/render3/outputs_spec.ts +++ b/packages/core/test/render3/outputs_spec.ts @@ -27,6 +27,7 @@ describe('outputs', () => { type: ButtonToggle, selectors: [['button-toggle']], template: function(rf: RenderFlags, ctx: any) {}, + consts: 0, factory: () => buttonToggle = new ButtonToggle(), outputs: {change: 'change', resetStream: 'reset'} }); @@ -52,6 +53,7 @@ describe('outputs', () => { static ngComponentDef = defineComponent({ type: DestroyComp, selectors: [['destroy-comp']], + consts: 0, template: function(rf: RenderFlags, ctx: any) {}, factory: () => destroyComp = new DestroyComp() }); @@ -86,7 +88,7 @@ describe('outputs', () => { let counter = 0; const ctx = {onChange: () => counter++}; - renderToHtml(Template, ctx, deps); + renderToHtml(Template, ctx, 1, deps); buttonToggle !.change.next(); expect(counter).toEqual(1); @@ -111,7 +113,7 @@ describe('outputs', () => { let counter = 0; let resetCounter = 0; const ctx = {onChange: () => counter++, onReset: () => resetCounter++}; - renderToHtml(Template, ctx, deps); + renderToHtml(Template, ctx, 1, deps); buttonToggle !.change.next(); expect(counter).toEqual(1); @@ -133,7 +135,7 @@ describe('outputs', () => { } const ctx = {counter: 0}; - renderToHtml(Template, ctx, deps); + renderToHtml(Template, ctx, 1, deps); buttonToggle !.change.next(); expect(ctx.counter).toEqual(1); @@ -158,7 +160,7 @@ describe('outputs', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { elementStart(0, 'button-toggle'); { @@ -175,13 +177,13 @@ describe('outputs', () => { let counter = 0; const ctx = {onChange: () => counter++, condition: true}; - renderToHtml(Template, ctx, deps); + renderToHtml(Template, ctx, 1, deps); buttonToggle !.change.next(); expect(counter).toEqual(1); ctx.condition = false; - renderToHtml(Template, ctx, deps); + renderToHtml(Template, ctx, 1, deps); buttonToggle !.change.next(); expect(counter).toEqual(1); @@ -205,14 +207,14 @@ describe('outputs', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { container(0); } containerRefreshStart(0); { if (ctx.condition2) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { elementStart(0, 'button-toggle'); { @@ -233,13 +235,13 @@ describe('outputs', () => { let counter = 0; const ctx = {onChange: () => counter++, condition: true, condition2: true}; - renderToHtml(Template, ctx, deps); + renderToHtml(Template, ctx, 1, deps); buttonToggle !.change.next(); expect(counter).toEqual(1); ctx.condition = false; - renderToHtml(Template, ctx, deps); + renderToHtml(Template, ctx, 1, deps); buttonToggle !.change.next(); expect(counter).toEqual(1); @@ -261,7 +263,7 @@ describe('outputs', () => { containerRefreshStart(0); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 4); if (rf1 & RenderFlags.Create) { elementStart(0, 'button'); { @@ -286,7 +288,7 @@ describe('outputs', () => { let clickCounter = 0; let changeCounter = 0; const ctx = {condition: true, onChange: () => changeCounter++, onClick: () => clickCounter++}; - renderToHtml(Template, ctx, deps); + renderToHtml(Template, ctx, 1, deps); buttonToggle !.change.next(); expect(changeCounter).toEqual(1); @@ -298,7 +300,7 @@ describe('outputs', () => { expect(clickCounter).toEqual(1); ctx.condition = false; - renderToHtml(Template, ctx, deps); + renderToHtml(Template, ctx, 1, deps); expect(destroyComp !.events).toEqual(['destroy']); @@ -320,7 +322,7 @@ describe('outputs', () => { } let counter = 0; - renderToHtml(Template, {counter, onClick: () => counter++}, deps); + renderToHtml(Template, {counter, onClick: () => counter++}, 1, deps); // To match current Angular behavior, the click listener is still // set up in addition to any matching outputs. @@ -345,7 +347,7 @@ describe('outputs', () => { } let counter = 0; - renderToHtml(Template, {counter, onChange: () => counter++}, deps); + renderToHtml(Template, {counter, onChange: () => counter++}, 1, deps); buttonToggle !.change.next(); expect(counter).toEqual(1); @@ -385,10 +387,10 @@ describe('outputs', () => { let counter = 0; const deps = [ButtonToggle, OtherChangeDir]; - renderToHtml(Template, {counter, onChange: () => counter++, change: true}, deps); + renderToHtml(Template, {counter, onChange: () => counter++, change: true}, 1, deps); expect(otherDir !.change).toEqual(true); - renderToHtml(Template, {counter, onChange: () => counter++, change: false}, deps); + renderToHtml(Template, {counter, onChange: () => counter++, change: false}, 1, deps); expect(otherDir !.change).toEqual(false); buttonToggle !.change.next(); @@ -419,7 +421,7 @@ describe('outputs', () => { containerRefreshStart(2); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { elementStart(0, 'button-toggle'); { @@ -429,7 +431,7 @@ describe('outputs', () => { } embeddedViewEnd(); } else { - if (embeddedViewStart(1)) { + if (embeddedViewStart(1, 1)) { elementStart(0, 'div', ['otherDir', '']); { listener('change', function() { return ctx.onChange(); }); @@ -445,13 +447,13 @@ describe('outputs', () => { let counter = 0; const ctx = {condition: true, onChange: () => counter++, onClick: () => {}}; - renderToHtml(Template, ctx, deps); + renderToHtml(Template, ctx, 3, deps); buttonToggle !.change.next(); expect(counter).toEqual(1); ctx.condition = false; - renderToHtml(Template, ctx, deps); + renderToHtml(Template, ctx, 3, deps); expect(counter).toEqual(1); otherDir !.changeStream.next(); diff --git a/packages/core/test/render3/pipe_spec.ts b/packages/core/test/render3/pipe_spec.ts index b81731583e..fe60fe9612 100644 --- a/packages/core/test/render3/pipe_spec.ts +++ b/packages/core/test/render3/pipe_spec.ts @@ -45,7 +45,7 @@ describe('pipe', () => { } person.init('bob', null); - expect(renderToHtml(Template, person, null, pipes)).toEqual('bob state:0'); + expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bob state:0'); }); it('should throw if pipe is not found', () => { @@ -57,7 +57,7 @@ describe('pipe', () => { if (rf & RenderFlags.Update) { textBinding(0, interpolation1('', pipeBind1(1, 1, ctx.value), '')); } - }, [], pipes); + }, 2, [], pipes); expect(() => { const fixture = new ComponentFixture(App); @@ -103,7 +103,7 @@ describe('pipe', () => { directive = loadDirective(0); } } - renderToHtml(Template, 'a', [MyDir], [DoublePipe]); + renderToHtml(Template, 'a', 2, [MyDir], [DoublePipe]); expect(directive !.dirProp).toEqual('aa'); }); @@ -120,7 +120,7 @@ describe('pipe', () => { } person.init('value', new Address('two')); - expect(renderToHtml(Template, person, null, pipes)).toEqual('value one two default'); + expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('value one two default'); }); it('should support calling pipes with different number of arguments', () => { @@ -138,7 +138,7 @@ describe('pipe', () => { } person.init('value', null); - expect(renderToHtml(Template, person, null, pipes)).toEqual('value a b default 0 1 2'); + expect(renderToHtml(Template, person, 3, null, pipes)).toEqual('value a b default 0 1 2'); }); it('should do nothing when no change', () => { @@ -164,11 +164,11 @@ describe('pipe', () => { } } - renderToHtml(Template, person, null, [IdentityPipe], rendererFactory2); + renderToHtml(Template, person, 2, null, [IdentityPipe], rendererFactory2); expect(renderLog.log).toEqual(['someProp=Megatron']); renderLog.clear(); - renderToHtml(Template, person, null, pipes, rendererFactory2); + renderToHtml(Template, person, 2, null, pipes, rendererFactory2); expect(renderLog.log).toEqual([]); }); @@ -186,18 +186,18 @@ describe('pipe', () => { // change from undefined -> null person.name = null; - expect(renderToHtml(Template, person, null, pipes)).toEqual('null state:0'); - expect(renderToHtml(Template, person, null, pipes)).toEqual('null state:0'); + expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('null state:0'); + expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('null state:0'); // change from null -> some value person.name = 'bob'; - expect(renderToHtml(Template, person, null, pipes)).toEqual('bob state:1'); - expect(renderToHtml(Template, person, null, pipes)).toEqual('bob state:1'); + expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bob state:1'); + expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bob state:1'); // change from some value -> some other value person.name = 'bart'; - expect(renderToHtml(Template, person, null, pipes)).toEqual('bart state:2'); - expect(renderToHtml(Template, person, null, pipes)).toEqual('bart state:2'); + expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bart state:2'); + expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bart state:2'); }); }); @@ -214,8 +214,8 @@ describe('pipe', () => { } person.name = 'bob'; - expect(renderToHtml(Template, person, null, pipes)).toEqual('bob state:0'); - expect(renderToHtml(Template, person, null, pipes)).toEqual('bob state:1'); + expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bob state:0'); + expect(renderToHtml(Template, person, 2, null, pipes)).toEqual('bob state:1'); }); it('should not cache impure pipes', () => { @@ -236,7 +236,7 @@ describe('pipe', () => { containerRefreshStart(4); { for (let i of [1, 2]) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { elementStart(0, 'div'); @@ -256,7 +256,7 @@ describe('pipe', () => { } const pipeInstances: CountingImpurePipe[] = []; - renderToHtml(Template, {}, null, pipes, rendererFactory2); + renderToHtml(Template, {}, 5, null, pipes, rendererFactory2); expect(pipeInstances.length).toEqual(4); expect(pipeInstances[0]).toBeAnInstanceOf(CountingImpurePipe); expect(pipeInstances[1]).toBeAnInstanceOf(CountingImpurePipe); @@ -291,7 +291,7 @@ describe('pipe', () => { containerRefreshStart(0); { if (person.age > 20) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { text(0); @@ -310,20 +310,20 @@ describe('pipe', () => { const pipes = [PipeWithOnDestroy]; person.age = 25; - renderToHtml(Template, person, null, pipes); + renderToHtml(Template, person, 1, null, pipes); person.age = 15; - renderToHtml(Template, person, null, pipes); + renderToHtml(Template, person, 1, null, pipes); expect(log).toEqual(['pipeWithOnDestroy - ngOnDestroy']); log = []; person.age = 30; - renderToHtml(Template, person, null, pipes); + renderToHtml(Template, person, 1, null, pipes); expect(log).toEqual([]); log = []; person.age = 10; - renderToHtml(Template, person, null, pipes); + renderToHtml(Template, person, 1, null, pipes); expect(log).toEqual(['pipeWithOnDestroy - ngOnDestroy']); }); }); diff --git a/packages/core/test/render3/properties_spec.ts b/packages/core/test/render3/properties_spec.ts index 5f447a0f8d..3bbda34da2 100644 --- a/packages/core/test/render3/properties_spec.ts +++ b/packages/core/test/render3/properties_spec.ts @@ -8,26 +8,33 @@ import {EventEmitter} from '@angular/core'; -import {defineComponent, defineDirective, tick} from '../../src/render3/index'; +import {AttributeMarker, defineComponent, defineDirective, tick} from '../../src/render3/index'; import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, listener, loadDirective, reference, text, textBinding} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; +import {pureFunction1, pureFunction2} from '../../src/render3/pure_function'; -import {ComponentFixture, renderToHtml} from './render_util'; +import {ComponentFixture, TemplateFixture, createComponent, renderToHtml} from './render_util'; describe('elementProperty', () => { it('should support bindings to properties', () => { - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'span'); } if (rf & RenderFlags.Update) { - elementProperty(0, 'id', bind(ctx)); + elementProperty(0, 'id', bind(ctx.id)); } - } + }, 1); - expect(renderToHtml(Template, 'testId')).toEqual(''); - expect(renderToHtml(Template, 'otherId')).toEqual(''); + const fixture = new ComponentFixture(App); + fixture.component.id = 'testId'; + fixture.update(); + expect(fixture.html).toEqual(''); + + fixture.component.id = 'otherId'; + fixture.update(); + expect(fixture.html).toEqual(''); }); it('should support creation time bindings to properties', () => { @@ -48,22 +55,28 @@ describe('elementProperty', () => { } } - expect(renderToHtml(Template, 'cheapId')).toEqual(''); - expect(renderToHtml(Template, 'expensiveId')).toEqual(''); + expect(renderToHtml(Template, 'cheapId', 1)).toEqual(''); + expect(renderToHtml(Template, 'expensiveId', 1)).toEqual(''); }); it('should support interpolation for properties', () => { - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'span'); } if (rf & RenderFlags.Update) { - elementProperty(0, 'id', interpolation1('_', ctx, '_')); + elementProperty(0, 'id', interpolation1('_', ctx.id, '_')); } - } + }, 1); - expect(renderToHtml(Template, 'testId')).toEqual(''); - expect(renderToHtml(Template, 'otherId')).toEqual(''); + const fixture = new ComponentFixture(App); + fixture.component.id = 'testId'; + fixture.update(); + expect(fixture.html).toEqual(''); + + fixture.component.id = 'otherId'; + fixture.update(); + expect(fixture.html).toEqual(''); }); it('should support host bindings on root component', () => { @@ -74,6 +87,7 @@ describe('elementProperty', () => { type: HostBindingComp, selectors: [['host-binding-comp']], factory: () => new HostBindingComp(), + consts: 0, hostBindings: (dirIndex: number, elIndex: number) => { const instance = loadDirective(dirIndex) as HostBindingComp; elementProperty(elIndex, 'id', bind(instance.id)); @@ -152,7 +166,7 @@ describe('elementProperty', () => { it('should check input properties before setting (directives)', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'button', ['otherDir', '', 'myButton', '']); { text(1, 'Click me'); } @@ -162,18 +176,20 @@ describe('elementProperty', () => { elementProperty(0, 'disabled', bind(ctx.isDisabled)); elementProperty(0, 'id', bind(ctx.id)); } - } + }, 2, deps); - const ctx: any = {isDisabled: true, id: 0}; - expect(renderToHtml(Template, ctx, deps)) - .toEqual(``); + const fixture = new ComponentFixture(App); + fixture.component.isDisabled = true; + fixture.component.id = 0; + fixture.update(); + expect(fixture.html).toEqual(``); expect(button !.disabled).toEqual(true); expect(otherDir !.id).toEqual(0); - ctx.isDisabled = false; - ctx.id = 1; - expect(renderToHtml(Template, ctx, deps)) - .toEqual(``); + fixture.component.isDisabled = false; + fixture.component.id = 1; + fixture.update(); + expect(fixture.html).toEqual(``); expect(button !.disabled).toEqual(false); expect(otherDir !.id).toEqual(1); }); @@ -181,7 +197,7 @@ describe('elementProperty', () => { it('should support mixed element properties and input properties', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'button', ['myButton', '']); { text(1, 'Click me'); } @@ -191,18 +207,20 @@ describe('elementProperty', () => { elementProperty(0, 'disabled', bind(ctx.isDisabled)); elementProperty(0, 'id', bind(ctx.id)); } - } + }, 2, deps); - const ctx: any = {isDisabled: true, id: 0}; - expect(renderToHtml(Template, ctx, deps)) - .toEqual(``); + const fixture = new ComponentFixture(App); + fixture.component.isDisabled = true; + fixture.component.id = 0; + fixture.update(); + expect(fixture.html).toEqual(``); expect(button !.disabled).toEqual(true); - ctx.isDisabled = false; - ctx.id = 1; - expect(renderToHtml(Template, ctx, deps)) - .toEqual(``); + fixture.component.isDisabled = false; + fixture.component.id = 1; + fixture.update(); + expect(fixture.html).toEqual(``); expect(button !.disabled).toEqual(false); }); @@ -216,6 +234,7 @@ describe('elementProperty', () => { static ngComponentDef = defineComponent({ type: Comp, selectors: [['comp']], + consts: 0, template: function(rf: RenderFlags, ctx: any) {}, factory: () => comp = new Comp(), inputs: {id: 'id'} @@ -223,27 +242,31 @@ describe('elementProperty', () => { } /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); } if (rf & RenderFlags.Update) { elementProperty(0, 'id', bind(ctx.id)); } - } + }, 1, [Comp]); - const deps = [Comp]; - expect(renderToHtml(Template, {id: 1}, deps)).toEqual(``); + const fixture = new ComponentFixture(App); + fixture.component.id = 1; + fixture.update(); + expect(fixture.html).toEqual(``); expect(comp !.id).toEqual(1); - expect(renderToHtml(Template, {id: 2}, deps)).toEqual(``); + fixture.component.id = 2; + fixture.update(); + expect(fixture.html).toEqual(``); expect(comp !.id).toEqual(2); }); it('should support two input properties with the same name', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'button', ['myButton', '', 'otherDisabledDir', '']); { text(1, 'Click me'); } @@ -252,28 +275,29 @@ describe('elementProperty', () => { if (rf & RenderFlags.Update) { elementProperty(0, 'disabled', bind(ctx.isDisabled)); } - } + }, 2, deps); - const ctx: any = {isDisabled: true}; - expect(renderToHtml(Template, ctx, deps)) - .toEqual(``); + const fixture = new ComponentFixture(App); + fixture.component.isDisabled = true; + fixture.update(); + expect(fixture.html).toEqual(``); expect(button !.disabled).toEqual(true); expect(otherDisabledDir !.disabled).toEqual(true); - ctx.isDisabled = false; - expect(renderToHtml(Template, ctx, deps)) - .toEqual(``); + fixture.component.isDisabled = false; + fixture.update(); + expect(fixture.html).toEqual(``); expect(button !.disabled).toEqual(false); expect(otherDisabledDir !.disabled).toEqual(false); }); it('should set input property if there is an output first', () => { /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'button', ['otherDir', '']); { - listener('click', ctx.onClick.bind(ctx)); + listener('click', () => ctx.onClick()); text(1, 'Click me'); } elementEnd(); @@ -281,18 +305,22 @@ describe('elementProperty', () => { if (rf & RenderFlags.Update) { elementProperty(0, 'id', bind(ctx.id)); } - } + }, 2, deps); + const fixture = new ComponentFixture(App); let counter = 0; - const ctx: any = {id: 1, onClick: () => counter++}; - expect(renderToHtml(Template, ctx, deps)).toEqual(``); + fixture.component.id = 1; + fixture.component.onClick = () => counter++; + fixture.update(); + expect(fixture.html).toEqual(``); expect(otherDir !.id).toEqual(1); otherDir !.clickStream.next(); expect(counter).toEqual(1); - ctx.id = 2; - renderToHtml(Template, ctx, deps); + fixture.component.id = 2; + fixture.update(); + fixture.html; expect(otherDir !.id).toEqual(2); }); @@ -305,7 +333,7 @@ describe('elementProperty', () => { * // inputs: {'id': [0, 'id']} * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'button', ['idDir', '']); { text(1, 'Click me'); } @@ -317,7 +345,7 @@ describe('elementProperty', () => { containerRefreshStart(2); { if (ctx.condition) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 2); if (rf0 & RenderFlags.Create) { elementStart(0, 'button'); { text(1, 'Click me too'); } @@ -328,7 +356,7 @@ describe('elementProperty', () => { } embeddedViewEnd(); } else { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 2); if (rf1 & RenderFlags.Create) { elementStart(0, 'button', ['otherDir', '']); { text(1, 'Click me too'); } @@ -342,13 +370,22 @@ describe('elementProperty', () => { } containerRefreshEnd(); } - } + }, 3, deps); - expect(renderToHtml(Template, {condition: true, id1: 'one', id2: 'two', id3: 3}, deps)) + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.component.id1 = 'one'; + fixture.component.id2 = 'two'; + fixture.component.id3 = 3; + fixture.update(); + expect(fixture.html) .toEqual(``); expect(idDir !.idNumber).toEqual('one'); - expect(renderToHtml(Template, {condition: false, id1: 'four', id2: 'two', id3: 3}, deps)) + fixture.component.condition = false; + fixture.component.id1 = 'four'; + fixture.update(); + expect(fixture.html) .toEqual(``); expect(idDir !.idNumber).toEqual('four'); expect(otherDir !.id).toEqual(3); @@ -393,47 +430,51 @@ describe('elementProperty', () => { it('should set input property based on attribute if existing', () => { /**
                            */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['role', 'button', 'myDir', '']); } - } + }, 1, deps); - expect(renderToHtml(Template, {}, deps)).toEqual(`
                            `); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual(`
                            `); expect(myDir !.role).toEqual('button'); }); it('should set input property and attribute if both defined', () => { /**
                            */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['role', 'button', 'myDir', '']); } if (rf & RenderFlags.Update) { elementProperty(0, 'role', bind(ctx.role)); } - } + }, 1, deps); - expect(renderToHtml(Template, {role: 'listbox'}, deps)) - .toEqual(`
                            `); + const fixture = new ComponentFixture(App); + fixture.component.role = 'listbox'; + fixture.update(); + expect(fixture.html).toEqual(`
                            `); expect(myDir !.role).toEqual('listbox'); - renderToHtml(Template, {role: 'button'}, deps); + fixture.component.role = 'button'; + fixture.update(); expect(myDir !.role).toEqual('button'); }); it('should set two directive input properties based on same attribute', () => { /**
                            */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['role', 'button', 'myDir', '', 'myDirB', '']); } - } + }, 1, deps); - expect(renderToHtml(Template, {}, deps)) - .toEqual(`
                            `); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual(`
                            `); expect(myDir !.role).toEqual('button'); expect(dirB !.roleB).toEqual('button'); }); @@ -441,14 +482,14 @@ describe('elementProperty', () => { it('should process two attributes on same directive', () => { /**
                            */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['role', 'button', 'dir', 'rtl', 'myDir', '']); } - } + }, 1, deps); - expect(renderToHtml(Template, {}, deps)) - .toEqual(`
                            `); + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual(`
                            `); expect(myDir !.role).toEqual('button'); expect(myDir !.direction).toEqual('rtl'); }); @@ -456,17 +497,19 @@ describe('elementProperty', () => { it('should process attributes and outputs properly together', () => { /**
                            */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div', ['role', 'button', 'myDir', '']); - { listener('change', ctx.onChange.bind(ctx)); } + { listener('change', () => ctx.onChange()); } elementEnd(); } - } + }, 1, deps); + const fixture = new ComponentFixture(App); let counter = 0; - expect(renderToHtml(Template, {onChange: () => counter++}, deps)) - .toEqual(`
                            `); + fixture.component.onChange = () => counter++; + fixture.update(); + expect(fixture.html).toEqual(`
                            `); expect(myDir !.role).toEqual('button'); myDir !.changeStream.next(); @@ -479,14 +522,15 @@ describe('elementProperty', () => { *
                            *
                            */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['role', 'button', 'dir', 'rtl', 'myDir', '']); element(1, 'div', ['role', 'listbox', 'myDirB', '']); } - } + }, 2, deps); - expect(renderToHtml(Template, {}, deps)) + const fixture = new ComponentFixture(App); + expect(fixture.html) .toEqual( `
                            `); expect(myDir !.role).toEqual('button'); @@ -504,7 +548,7 @@ describe('elementProperty', () => { *
                            // initialInputs: [null] * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['role', 'listbox', 'myDir', '']); container(1); @@ -513,13 +557,13 @@ describe('elementProperty', () => { containerRefreshStart(1); { if (ctx.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'div', ['role', 'button', 'myDirB', '']); } embeddedViewEnd(); } else { - let rf2 = embeddedViewStart(1); + let rf2 = embeddedViewStart(1, 1); if (rf2 & RenderFlags.Create) { element(0, 'div', ['role', 'menu']); } @@ -528,16 +572,20 @@ describe('elementProperty', () => { } containerRefreshEnd(); } - } + }, 2, deps); - expect(renderToHtml(Template, {condition: true}, deps)) + const fixture = new ComponentFixture(App); + fixture.component.condition = true; + fixture.update(); + expect(fixture.html) .toEqual(`
                            `); expect(myDir !.role).toEqual('listbox'); expect(dirB !.roleB).toEqual('button'); expect((dirB !as any).role).toBeUndefined(); - expect(renderToHtml(Template, {condition: false}, deps)) - .toEqual(`
                            `); + fixture.component.condition = false; + fixture.update(); + expect(fixture.html).toEqual(`
                            `); expect(myDir !.role).toEqual('listbox'); }); @@ -547,6 +595,7 @@ describe('elementProperty', () => { static ngComponentDef = defineComponent({ type: Comp, selectors: [['comp']], + consts: 3, /**
                            {{ dir.role }} */ template: function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -568,7 +617,7 @@ describe('elementProperty', () => { * * % } */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { container(0); } @@ -576,7 +625,7 @@ describe('elementProperty', () => { containerRefreshStart(0); { for (let i = 0; i < 2; i++) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { element(0, 'comp'); } @@ -585,9 +634,10 @@ describe('elementProperty', () => { } containerRefreshEnd(); } - } + }, 1, [Comp]); - expect(renderToHtml(Template, {}, [Comp])) + const fixture = new ComponentFixture(App); + expect(fixture.html) .toEqual( `
                            button
                            button
                            `); }); diff --git a/packages/core/test/render3/pure_function_spec.ts b/packages/core/test/render3/pure_function_spec.ts index 6591cc6c6f..14246c8f02 100644 --- a/packages/core/test/render3/pure_function_spec.ts +++ b/packages/core/test/render3/pure_function_spec.ts @@ -23,6 +23,7 @@ describe('array literals', () => { type: MyComp, selectors: [['my-comp']], factory: function MyComp_Factory() { return myComp = new MyComp(); }, + consts: 0, template: function MyComp_Template(rf: RenderFlags, ctx: MyComp) {}, inputs: {names: 'names'} }); @@ -34,24 +35,27 @@ describe('array literals', () => { const e0_ff = (v: any) => ['Nancy', v, 'Bess']; /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'my-comp'); } if (rf & RenderFlags.Update) { elementProperty(0, 'names', bind(pureFunction1(1, e0_ff, ctx.customName))); } - } + }, 1, directives); - renderToHtml(Template, {customName: 'Carson'}, directives); + const fixture = new ComponentFixture(App); + fixture.component.customName = 'Carson'; + fixture.update(); const firstArray = myComp !.names; expect(firstArray).toEqual(['Nancy', 'Carson', 'Bess']); - renderToHtml(Template, {customName: 'Carson'}, directives); + fixture.update(); expect(myComp !.names).toEqual(['Nancy', 'Carson', 'Bess']); expect(firstArray).toBe(myComp !.names); - renderToHtml(Template, {customName: 'Hannah'}, directives); + fixture.component.customName = 'Hannah'; + fixture.update(); expect(myComp !.names).toEqual(['Nancy', 'Hannah', 'Bess']); // Identity must change if binding changes @@ -60,7 +64,7 @@ describe('array literals', () => { // The property should not be set if the exp value is the same, so artificially // setting the property to ensure it's not overwritten. myComp !.names = ['should not be overwritten']; - renderToHtml(Template, {customName: 'Hannah'}, directives); + fixture.update(); expect(myComp !.names).toEqual(['should not be overwritten']); }); @@ -82,12 +86,12 @@ describe('array literals', () => { */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(0, IfTemplate, null, [AttributeMarker.SelectOnly, 'ngIf']); + template(0, IfTemplate, 1, null, [AttributeMarker.SelectOnly, 'ngIf']); } if (rf & RenderFlags.Update) { elementProperty(0, 'ngIf', bind(ctx.showing)); } - }, [MyComp, NgIf]); + }, 1, [MyComp, NgIf]); const fixture = new ComponentFixture(App); fixture.component.showing = true; @@ -110,6 +114,7 @@ describe('array literals', () => { type: ManyPropComp, selectors: [['many-prop-comp']], factory: function ManyPropComp_Factory() { return manyPropComp = new ManyPropComp(); }, + consts: 0, template: function ManyPropComp_Template(rf: RenderFlags, ctx: ManyPropComp) {}, inputs: {names1: 'names1', names2: 'names2'} }); @@ -122,7 +127,7 @@ describe('array literals', () => { * * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'many-prop-comp'); } @@ -130,14 +135,18 @@ describe('array literals', () => { elementProperty(0, 'names1', bind(pureFunction1(2, e0_ff, ctx.customName))); elementProperty(0, 'names2', bind(pureFunction1(4, e0_ff_1, ctx.customName2))); } - } + }, 1, [ManyPropComp]); - const defs = [ManyPropComp]; - renderToHtml(Template, {customName: 'Carson', customName2: 'George'}, defs); + const fixture = new ComponentFixture(App); + fixture.component.customName = 'Carson'; + fixture.component.customName2 = 'George'; + fixture.update(); expect(manyPropComp !.names1).toEqual(['Nancy', 'Carson']); expect(manyPropComp !.names2).toEqual(['George']); - renderToHtml(Template, {customName: 'George', customName2: 'Carson'}, defs); + fixture.component.customName = 'George'; + fixture.component.customName2 = 'Carson'; + fixture.update(); expect(manyPropComp !.names1).toEqual(['Nancy', 'George']); expect(manyPropComp !.names2).toEqual(['Carson']); }); @@ -160,6 +169,7 @@ describe('array literals', () => { type: ParentComp, selectors: [['parent-comp']], factory: () => new ParentComp(), + consts: 1, template: function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'my-comp'); @@ -174,21 +184,21 @@ describe('array literals', () => { }); } - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'parent-comp'); element(1, 'parent-comp'); } - } + }, 2, [ParentComp]); - renderToHtml(Template, {}, [ParentComp]); + const fixture = new ComponentFixture(App); const firstArray = myComps[0].names; const secondArray = myComps[1].names; expect(firstArray).toEqual(['NANCY', 'Bess']); expect(secondArray).toEqual(['NANCY', 'Bess']); expect(firstArray).not.toBe(secondArray); - renderToHtml(Template, {}, [ParentComp]); + fixture.update(); expect(firstArray).toEqual(['NANCY', 'Bess']); expect(secondArray).toEqual(['NANCY', 'Bess']); expect(firstArray).toBe(myComps[0].names); @@ -199,34 +209,40 @@ describe('array literals', () => { const e0_ff = (v1: any, v2: any) => ['Nancy', v1, 'Bess', v2]; /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'my-comp'); } if (rf & RenderFlags.Update) { elementProperty(0, 'names', bind(pureFunction2(1, e0_ff, ctx.customName, ctx.customName2))); } - } + }, 1, directives); - renderToHtml(Template, {customName: 'Carson', customName2: 'Hannah'}, directives); + const fixture = new ComponentFixture(App); + fixture.component.customName = 'Carson'; + fixture.component.customName2 = 'Hannah'; + fixture.update(); const firstArray = myComp !.names; expect(firstArray).toEqual(['Nancy', 'Carson', 'Bess', 'Hannah']); - renderToHtml(Template, {customName: 'Carson', customName2: 'Hannah'}, directives); + fixture.update(); expect(myComp !.names).toEqual(['Nancy', 'Carson', 'Bess', 'Hannah']); expect(firstArray).toBe(myComp !.names); - renderToHtml(Template, {customName: 'George', customName2: 'Hannah'}, directives); + fixture.component.customName = 'George'; + fixture.update(); expect(myComp !.names).toEqual(['Nancy', 'George', 'Bess', 'Hannah']); expect(firstArray).not.toBe(myComp !.names); - renderToHtml(Template, {customName: 'Frank', customName2: 'Ned'}, directives); + fixture.component.customName = 'Frank'; + fixture.component.customName2 = 'Ned'; + fixture.update(); expect(myComp !.names).toEqual(['Nancy', 'Frank', 'Bess', 'Ned']); // The property should not be set if the exp value is the same, so artificially // setting the property to ensure it's not overwritten. myComp !.names = ['should not be overwritten']; - renderToHtml(Template, {customName: 'Frank', customName2: 'Ned'}, directives); + fixture.update(); expect(myComp !.names).toEqual(['should not be overwritten']); }); @@ -288,7 +304,7 @@ describe('array literals', () => { } } - renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], directives); + renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], 6, directives); expect(f3Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']); expect(f4Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']); expect(f5Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']); @@ -296,7 +312,7 @@ describe('array literals', () => { expect(f7Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']); expect(f8Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']); - renderToHtml(Template, ['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1', 'i1'], directives); + renderToHtml(Template, ['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1', 'i1'], 6, directives); expect(f3Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f1', 'g1', 'h1']); expect(f4Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e1', 'f1', 'g1', 'h1']); expect(f5Comp !.names).toEqual(['a', 'b', 'c', 'd1', 'e1', 'f1', 'g1', 'h1']); @@ -304,7 +320,7 @@ describe('array literals', () => { expect(f7Comp !.names).toEqual(['a', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1']); expect(f8Comp !.names).toEqual(['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1']); - renderToHtml(Template, ['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2', 'i1'], directives); + renderToHtml(Template, ['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2', 'i1'], 6, directives); expect(f3Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f1', 'g1', 'h2']); expect(f4Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e1', 'f1', 'g1', 'h2']); expect(f5Comp !.names).toEqual(['a', 'b', 'c', 'd1', 'e1', 'f1', 'g1', 'h2']); @@ -319,7 +335,7 @@ describe('array literals', () => { v8: any) => ['start', v0, v1, v2, v3, v4, v5, v6, v7, v8, 'end']; const e0_ff_1 = (v: any) => `modified_${v}`; - renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], directives); + renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], 1, directives); /** * * @@ -340,12 +356,12 @@ describe('array literals', () => { 'start', 'a', 'b', 'c', 'd', 'modified_e', 'f', 'g', 'h', 'i', 'end' ]); - renderToHtml(Template, ['a1', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], directives); + renderToHtml(Template, ['a1', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], 1, directives); expect(myComp !.names).toEqual([ 'start', 'a1', 'b', 'c', 'd', 'modified_e', 'f', 'g', 'h', 'i', 'end' ]); - renderToHtml(Template, ['a1', 'b', 'c', 'd', 'e5', 'f', 'g', 'h', 'i'], directives); + renderToHtml(Template, ['a1', 'b', 'c', 'd', 'e5', 'f', 'g', 'h', 'i'], 1, directives); expect(myComp !.names).toEqual([ 'start', 'a1', 'b', 'c', 'd', 'modified_e5', 'f', 'g', 'h', 'i', 'end' ]); @@ -363,6 +379,7 @@ describe('object literals', () => { type: ObjectComp, selectors: [['object-comp']], factory: function ObjectComp_Factory() { return objectComp = new ObjectComp(); }, + consts: 0, template: function ObjectComp_Template(rf: RenderFlags, ctx: ObjectComp) {}, inputs: {config: 'config'} }); @@ -374,24 +391,27 @@ describe('object literals', () => { const e0_ff = (v: any) => { return {duration: 500, animation: v}; }; /** */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'object-comp'); } if (rf & RenderFlags.Update) { elementProperty(0, 'config', bind(pureFunction1(1, e0_ff, ctx.name))); } - } + }, 1, defs); - renderToHtml(Template, {name: 'slide'}, defs); + const fixture = new ComponentFixture(App); + fixture.component.name = 'slide'; + fixture.update(); const firstObj = objectComp !.config; expect(objectComp !.config).toEqual({duration: 500, animation: 'slide'}); - renderToHtml(Template, {name: 'slide'}, defs); + fixture.update(); expect(objectComp !.config).toEqual({duration: 500, animation: 'slide'}); expect(firstObj).toBe(objectComp !.config); - renderToHtml(Template, {name: 'tap'}, defs); + fixture.component.name = 'tap'; + fixture.update(); expect(objectComp !.config).toEqual({duration: 500, animation: 'tap'}); // Identity must change if binding changes @@ -408,7 +428,7 @@ describe('object literals', () => { * duration: duration }]}"> * */ - function Template(rf: RenderFlags, ctx: any) { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'object-comp'); } @@ -418,36 +438,43 @@ describe('object literals', () => { 5, e0_ff, ctx.name, pureFunction1(3, e0_ff_1, pureFunction1(1, e0_ff_2, ctx.duration))))); } - } + }, 1, defs); - renderToHtml(Template, {name: 'slide', duration: 100}, defs); + const fixture = new ComponentFixture(App); + fixture.component.name = 'slide'; + fixture.component.duration = 100; + fixture.update(); expect(objectComp !.config).toEqual({ animation: 'slide', actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 100}] }); const firstConfig = objectComp !.config; - renderToHtml(Template, {name: 'slide', duration: 100}, defs); + fixture.update(); expect(objectComp !.config).toEqual({ animation: 'slide', actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 100}] }); expect(objectComp !.config).toBe(firstConfig); - renderToHtml(Template, {name: 'slide', duration: 50}, defs); + fixture.component.duration = 50; + fixture.update(); expect(objectComp !.config).toEqual({ animation: 'slide', actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 50}] }); expect(objectComp !.config).not.toBe(firstConfig); - renderToHtml(Template, {name: 'tap', duration: 50}, defs); + fixture.component.name = 'tap'; + fixture.update(); expect(objectComp !.config).toEqual({ animation: 'tap', actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 50}] }); - renderToHtml(Template, {name: 'drag', duration: 500}, defs); + fixture.component.name = 'drag'; + fixture.component.duration = 500; + fixture.update(); expect(objectComp !.config).toEqual({ animation: 'drag', actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 500}] @@ -456,7 +483,7 @@ describe('object literals', () => { // The property should not be set if the exp value is the same, so artificially // setting the property to ensure it's not overwritten. objectComp !.config = ['should not be overwritten']; - renderToHtml(Template, {name: 'drag', duration: 500}, defs); + fixture.update(); expect(objectComp !.config).toEqual(['should not be overwritten']); }); @@ -477,7 +504,7 @@ describe('object literals', () => { containerRefreshStart(0); { for (let i = 0; i < 2; i++) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); if (rf1 & RenderFlags.Create) { elementStart(0, 'object-comp'); objectComps.push(loadDirective(0)); @@ -498,12 +525,12 @@ describe('object literals', () => { const e0_ff = (v1: any, v2: any) => { return {opacity: v1, duration: v2}; }; const configs = [{opacity: 0, duration: 500}, {opacity: 1, duration: 600}]; - renderToHtml(Template, {configs}, defs); + renderToHtml(Template, {configs}, 1, defs); expect(objectComps[0].config).toEqual({opacity: 0, duration: 500}); expect(objectComps[1].config).toEqual({opacity: 1, duration: 600}); configs[0].duration = 1000; - renderToHtml(Template, {configs}, defs); + renderToHtml(Template, {configs}, 1, defs); expect(objectComps[0].config).toEqual({opacity: 0, duration: 1000}); expect(objectComps[1].config).toEqual({opacity: 1, duration: 600}); }); diff --git a/packages/core/test/render3/query_spec.ts b/packages/core/test/render3/query_spec.ts index aff63ad407..4c65098272 100644 --- a/packages/core/test/render3/query_spec.ts +++ b/packages/core/test/render3/query_spec.ts @@ -77,7 +77,7 @@ describe('query', () => { child2 = loadDirective(1); } }, - [Child], [], + 2, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, Child, false); @@ -115,7 +115,7 @@ describe('query', () => { elToQuery = loadElement(1).native; } }, - [Child], [], + 1, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, Child, false, QUERY_READ_ELEMENT_REF); @@ -152,7 +152,7 @@ describe('query', () => { elementEnd(); } }, - [Child, OtherChild], [], + 1, [Child, OtherChild], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, Child, false, OtherChild); @@ -185,7 +185,7 @@ describe('query', () => { element(1, 'div', ['child', '']); } }, - [Child, OtherChild], [], + 1, [Child, OtherChild], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, Child, false, OtherChild); @@ -223,7 +223,7 @@ describe('query', () => { element(3, 'div'); } }, - [], [], + 3, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], false, QUERY_READ_FROM_NODE); @@ -260,7 +260,7 @@ describe('query', () => { element(5, 'div'); } }, - [], [], + 4, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], false, QUERY_READ_FROM_NODE); @@ -309,7 +309,7 @@ describe('query', () => { el2ToQuery = loadElement(4).native; } }, - [], [], + 5, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE); @@ -346,7 +346,7 @@ describe('query', () => { element(3, 'div'); } }, - [], [], + 3, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], false, QUERY_READ_ELEMENT_REF); @@ -382,7 +382,7 @@ describe('query', () => { elementContainerEnd(); } }, - [], [], + 2, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], false, QUERY_READ_ELEMENT_REF); @@ -447,7 +447,7 @@ describe('query', () => { elementContainerEnd(); } }, - [], [], + 3, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_ELEMENT_REF); @@ -482,7 +482,7 @@ describe('query', () => { element(1, 'div', null, ['foo', '']); } }, - [], [], + 2, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], false, QUERY_READ_CONTAINER_REF); @@ -510,10 +510,10 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, null, null, null, ['foo', '']); + template(1, null, 0, null, null, ['foo', '']); } }, - [], [], + 2, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], false, QUERY_READ_CONTAINER_REF); @@ -542,10 +542,10 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, null, null, null, ['foo', '']); + template(1, null, 0, null, null, ['foo', '']); } }, - [], [], + 2, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -577,10 +577,10 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, null, null, null, ['foo', '']); + template(1, null, 0, null, null, ['foo', '']); } }, - [], [], + 2, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], undefined, QUERY_READ_FROM_NODE); @@ -609,10 +609,10 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, null, null, null, ['foo', '']); + template(1, null, 0, null, null, ['foo', '']); } }, - [], [], + 2, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], false, QUERY_READ_TEMPLATE_REF); @@ -649,7 +649,7 @@ describe('query', () => { childInstance = loadDirective(0); } }, - [Child], [], + 2, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -674,6 +674,7 @@ describe('query', () => { type: Child, selectors: [['child']], factory: () => childInstance = new Child(), + consts: 0, template: (rf: RenderFlags, ctx: Child) => {}, exportAs: 'child' }); @@ -692,7 +693,7 @@ describe('query', () => { element(1, 'child', null, ['foo', 'child']); } }, - [Child], [], + 2, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -730,7 +731,7 @@ describe('query', () => { childInstance = loadDirective(0); } }, - [Child], [], + 2, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -770,7 +771,7 @@ describe('query', () => { child2Instance = loadDirective(1); } }, - [Child1, Child2], [], + 3, [Child1, Child2], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo', 'bar'], true, QUERY_READ_FROM_NODE); @@ -809,7 +810,7 @@ describe('query', () => { childInstance = loadDirective(0); } }, - [Child], [], + 3, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -853,7 +854,7 @@ describe('query', () => { div = loadElement(1).native; } }, - [Child], [], + 2, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], undefined, QUERY_READ_ELEMENT_REF); @@ -891,7 +892,7 @@ describe('query', () => { childInstance = loadDirective(0); } }, - [Child], [], + 3, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE); @@ -925,7 +926,7 @@ describe('query', () => { element(1, 'div', ['foo', '']); } }, - [Child], [], + 2, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], false, Child); @@ -975,6 +976,12 @@ describe('query', () => { it('should report results in views inserted / removed by ngIf', () => { + function Cmpt_Template_1(rf: RenderFlags, ctx1: any) { + if (rf & RenderFlags.Create) { + element(0, 'div', null, ['foo', '']); + } + } + /** * *
                            @@ -987,17 +994,13 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, (rf1: RenderFlags, ctx1: any) => { - if (rf1 & RenderFlags.Create) { - element(0, 'div', null, ['foo', '']); - } - }, null, ['ngIf', '']); + template(1, Cmpt_Template_1, 2, null, ['ngIf', '']); } if (rf & RenderFlags.Update) { elementProperty(1, 'ngIf', bind(ctx.value)); } }, - [NgIf], [], + 2, [NgIf], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -1023,6 +1026,15 @@ describe('query', () => { it('should report results in views inserted / removed by ngFor', () => { + function Cmpt_Template_1(rf1: RenderFlags, row: NgForOfContext) { + if (rf1 & RenderFlags.Create) { + element(0, 'div', null, ['foo', '']); + } + if (rf1 & RenderFlags.Update) { + elementProperty(0, 'id', bind(row.$implicit)); + } + } + /** * *
                            @@ -1039,16 +1051,10 @@ describe('query', () => { type: Cmpt, factory: () => new Cmpt(), selectors: [['my-app']], + consts: 2, template: function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, (rf1: RenderFlags, row: NgForOfContext) => { - if (rf1 & RenderFlags.Create) { - element(0, 'div', null, ['foo', '']); - } - if (rf1 & RenderFlags.Update) { - elementProperty(0, 'id', bind(row.$implicit)); - } - }, null, ['ngForOf', '']); + template(1, Cmpt_Template_1, 2, null, ['ngForOf', '']); } if (rf & RenderFlags.Update) { elementProperty(1, 'ngForOf', bind(ctx.value)); @@ -1091,6 +1097,23 @@ describe('query', () => { let tpl1: TemplateRef<{}>; let tpl2: TemplateRef<{}>; + function Cmpt_Template_1(rf: RenderFlags, ctx: {idx: number}) { + if (rf & RenderFlags.Create) { + element(0, 'div', null, ['foo', '']); + } + if (rf & RenderFlags.Update) { + elementProperty(0, 'id', bind('foo1_' + ctx.idx)); + } + } + + function Cmpt_Template_5(rf: RenderFlags, ctx: {idx: number}) { + if (rf & RenderFlags.Create) { + element(0, 'div', null, ['foo', '']); + } + if (rf & RenderFlags.Update) { + elementProperty(0, 'id', bind('foo2_' + ctx.idx)); + } + } /** * @@ -1109,27 +1132,10 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, (rf: RenderFlags, ctx: {idx: number}) => { - if (rf & RenderFlags.Create) { - element(0, 'div', null, ['foo', '']); - } - if (rf & RenderFlags.Update) { - elementProperty(0, 'id', bind('foo1_' + ctx.idx)); - } - }, null, null, ['tpl1', ''], templateRefExtractor); - + template(1, Cmpt_Template_1, 2, null, null, ['tpl1', ''], templateRefExtractor); element(3, 'div', ['id', 'middle'], ['foo', '']); - - template(5, (rf: RenderFlags, ctx: {idx: number}) => { - if (rf & RenderFlags.Create) { - element(0, 'div', null, ['foo', '']); - } - if (rf & RenderFlags.Update) { - elementProperty(0, 'id', bind('foo2_' + ctx.idx)); - } - }, null, null, ['tpl2', ''], templateRefExtractor); - - template(7, null, null, [AttributeMarker.SelectOnly, 'vc']); + template(5, Cmpt_Template_5, 2, null, null, ['tpl2', ''], templateRefExtractor); + template(7, null, 0, null, [AttributeMarker.SelectOnly, 'vc']); } if (rf & RenderFlags.Update) { @@ -1138,7 +1144,7 @@ describe('query', () => { } }, - [ViewContainerManipulatorDirective], [], + 6, [ViewContainerManipulatorDirective], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -1195,6 +1201,15 @@ describe('query', () => { () => { let tpl: TemplateRef<{}>; + function Cmpt_Template_1(rf: RenderFlags, ctx: {idx: number, container_idx: number}) { + if (rf & RenderFlags.Create) { + element(0, 'div', null, ['foo', '']); + } + if (rf & RenderFlags.Update) { + elementProperty(0, 'id', bind('foo_' + ctx.container_idx + '_' + ctx.idx)); + } + } + /** * *
                            @@ -1209,20 +1224,13 @@ describe('query', () => { type: Cmpt, factory: () => new Cmpt(), selectors: [['my-app']], + consts: 4, template: function(rf: RenderFlags, ctx: any) { let tmp: any; if (rf & RenderFlags.Create) { - template(1, (rf: RenderFlags, ctx: {idx: number, container_idx: number}) => { - if (rf & RenderFlags.Create) { - element(0, 'div', null, ['foo', '']); - } - if (rf & RenderFlags.Update) { - elementProperty(0, 'id', bind('foo_' + ctx.container_idx + '_' + ctx.idx)); - } - }, null, [], ['tpl', ''], templateRefExtractor); - - template(3, null, null, [AttributeMarker.SelectOnly, 'vc']); - template(4, null, null, [AttributeMarker.SelectOnly, 'vc']); + template(1, Cmpt_Template_1, 2, null, [], ['tpl', ''], templateRefExtractor); + template(3, null, 0, null, [AttributeMarker.SelectOnly, 'vc']); + template(4, null, 0, null, [AttributeMarker.SelectOnly, 'vc']); } if (rf & RenderFlags.Update) { @@ -1270,6 +1278,12 @@ describe('query', () => { // https://stackblitz.com/edit/angular-wpd6gv?file=src%2Fapp%2Fapp.component.ts it('should report results from views inserted in a lifecycle hook', () => { + function MyApp_Template_1(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + element(0, 'span', ['id', 'from_tpl'], ['foo', '']); + } + } + class MyApp { show = false; query: any; @@ -1277,18 +1291,17 @@ describe('query', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], + consts: 4, /** - * from tpl + * * */ template: (rf: RenderFlags, myApp: MyApp) => { if (rf & RenderFlags.Create) { - template(1, (rf1: RenderFlags) => { - if (rf1 & RenderFlags.Create) { - element(0, 'span', ['id', 'from_tpl'], ['foo', '']); - } - }, undefined, undefined, ['tpl', ''], templateRefExtractor); - template(3, null, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']); + template( + 1, MyApp_Template_1, 2, undefined, undefined, ['tpl', ''], + templateRefExtractor); + template(3, null, 0, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']); } if (rf & RenderFlags.Update) { const tplRef = reference(2); @@ -1348,7 +1361,7 @@ describe('query', () => { containerRefreshStart(1); { if (ctx.exp) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { element(0, 'div', null, ['foo', '']); @@ -1361,7 +1374,7 @@ describe('query', () => { containerRefreshEnd(); } }, - [], [], + 1, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -1413,7 +1426,7 @@ describe('query', () => { containerRefreshStart(3); { if (ctx.exp) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { element(0, 'div', null, ['foo', '']); @@ -1426,7 +1439,7 @@ describe('query', () => { containerRefreshEnd(); } }, - [], [], + 5, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -1480,7 +1493,7 @@ describe('query', () => { containerRefreshStart(1); { if (ctx.exp1) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 2); { if (rf0 & RenderFlags.Create) { element(0, 'div', null, ['foo', '']); @@ -1490,7 +1503,7 @@ describe('query', () => { embeddedViewEnd(); } if (ctx.exp2) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 2); { if (rf1 & RenderFlags.Create) { element(0, 'span', null, ['foo', '']); @@ -1503,7 +1516,7 @@ describe('query', () => { containerRefreshEnd(); } }, - [], [], + 1, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -1553,7 +1566,7 @@ describe('query', () => { containerRefreshStart(1); { if (ctx.exp1) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 3); { if (rf0 & RenderFlags.Create) { element(0, 'div', null, ['foo', '']); @@ -1564,7 +1577,7 @@ describe('query', () => { containerRefreshStart(2); { if (ctx.exp2) { - let rf2 = embeddedViewStart(0); + let rf2 = embeddedViewStart(0, 2); { if (rf2) { element(0, 'span', null, ['foo', '']); @@ -1583,7 +1596,7 @@ describe('query', () => { containerRefreshEnd(); } }, - [], [], + 1, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -1638,7 +1651,7 @@ describe('query', () => { containerRefreshStart(2); { if (ctx.exp) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 4); { if (rf0 & RenderFlags.Create) { elementStart(0, 'div', null, ['foo', '']); @@ -1652,7 +1665,7 @@ describe('query', () => { containerRefreshEnd(); } }, - [], [], + 3, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -1733,7 +1746,7 @@ describe('query', () => { element(1, 'div', null, ['foo', '']); } }, - [], [], + 1, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], false, QUERY_READ_FROM_NODE); @@ -1751,7 +1764,7 @@ describe('query', () => { containerRefreshStart(0); { if (condition) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 1); { if (rf1 & RenderFlags.Create) { element(0, 'some-component-with-query'); @@ -1769,7 +1782,7 @@ describe('query', () => { * %} */ let condition = true; - const t = new TemplateFixture(createTemplate, updateTemplate, [SimpleComponentWithQuery]); + const t = new TemplateFixture(createTemplate, updateTemplate, 1, [SimpleComponentWithQuery]); expect(t.html).toEqual('
                            '); expect((queryInstance !.changes as EventEmitter).closed).toBeFalsy(); @@ -1807,11 +1820,11 @@ describe('query', () => { 'app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, AppComponent_Template_1, null, [AttributeMarker.SelectOnly, 'someDir']); + template(1, AppComponent_Template_1, 1, null, [AttributeMarker.SelectOnly, 'someDir']); element(2, 'div', null, ['foo', '']); } }, - [SomeDir], [], + 3, [SomeDir], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo'], true, QUERY_READ_FROM_NODE); @@ -1871,6 +1884,7 @@ describe('query', () => { selectors: [['shallow-comp']], factory: () => new ShallowComp(), template: function(rf: RenderFlags, ctx: any) {}, + consts: 0, contentQueries: () => { registerContentQuery(query(null, ['foo'], false, QUERY_READ_FROM_NODE)); }, contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => { @@ -1894,7 +1908,7 @@ describe('query', () => { { element(1, 'span', null, ['foo', '']); } elementEnd(); } - }, [WithContentDirective]); + }, 3, [WithContentDirective]); const fixture = new ComponentFixture(AppComponent); expect(withContentInstance !.foos.length) @@ -1920,7 +1934,7 @@ describe('query', () => { if (rf & RenderFlags.Create) { element(0, 'div', ['with-content', ''], ['foo', '']); } - }, [WithContentDirective]); + }, 2, [WithContentDirective]); const fixture = new ComponentFixture(AppComponent); expect(withContentInstance !.foos.length) @@ -1942,13 +1956,13 @@ describe('query', () => { const AppComponent = createComponent('app-component', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'shallow-comp'); - { template(1, IfTemplate, null, [AttributeMarker.SelectOnly, 'ngIf', '']); } + { template(1, IfTemplate, 2, null, [AttributeMarker.SelectOnly, 'ngIf', '']); } elementEnd(); } if (rf & RenderFlags.Update) { elementProperty(1, 'ngIf', bind(ctx.showing)); } - }, [ShallowComp, NgIf]); + }, 2, [ShallowComp, NgIf]); const fixture = new ComponentFixture(AppComponent); const qList = shallowCompInstance !.foos; @@ -1985,7 +1999,7 @@ describe('query', () => { element(4, 'div', ['id', 'after'], ['bar', '']); } }, - [WithContentDirective], [], + 5, [WithContentDirective], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['foo', 'bar'], true, QUERY_READ_FROM_NODE); @@ -2025,7 +2039,7 @@ describe('query', () => { element(4, 'div', null, ['foo', '']); } }, - [WithContentDirective], [], + 5, [WithContentDirective], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { query(0, ['bar'], true, QUERY_READ_FROM_NODE); @@ -2094,7 +2108,7 @@ describe('query', () => { inInstance = load(5); } }, - [QueryDirective]); + 10, [QueryDirective]); const fixture = new ComponentFixture(AppComponent); expect(outInstance !.fooBars.length).toBe(3); @@ -2151,7 +2165,7 @@ describe('query', () => { inInstance = load(3); } }, - [QueryDirective]); + 7, [QueryDirective]); const fixture = new ComponentFixture(AppComponent); expect(outInstance !.fooBars.length).toBe(1); @@ -2231,7 +2245,7 @@ describe('query', () => { deepInstance = load(2); } }, - [ShallowQueryDirective, DeepQueryDirective]); + 8, [ShallowQueryDirective, DeepQueryDirective]); const fixture = new ComponentFixture(AppComponent); expect(shallowInstance !.foos.length).toBe(1); diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index b299c3993c..168df0db64 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -59,7 +59,7 @@ export class TemplateFixture extends BaseFixture { * `if (rf & RenderFlags.Update) { __here__ }`. */ constructor( - private createBlock: () => void, private updateBlock: () => void = noop, + private createBlock: () => void, private updateBlock: () => void = noop, consts: number = 0, directives?: DirectiveTypesOrFactory|null, pipes?: PipeTypesOrFactory|null, sanitizer?: Sanitizer|null, rendererFactory?: RendererFactory3) { super(); @@ -74,7 +74,7 @@ export class TemplateFixture extends BaseFixture { if (rf & RenderFlags.Update) { this.updateBlock(); } - }, null !, this._rendererFactory, null, this._directiveDefs, this._pipeDefs, sanitizer); + }, consts, null !, this._rendererFactory, null, this._directiveDefs, this._pipeDefs, sanitizer); } /** @@ -84,7 +84,7 @@ export class TemplateFixture extends BaseFixture { */ update(updateBlock?: () => void): void { renderTemplate( - this.hostNode.native, updateBlock || this.updateBlock, null !, this._rendererFactory, + this.hostNode.native, updateBlock || this.updateBlock, 0, null !, this._rendererFactory, this.hostNode, this._directiveDefs, this._pipeDefs, this._sanitizer); } } @@ -170,10 +170,11 @@ export function resetDOM() { * @deprecated use `TemplateFixture` or `ComponentFixture` */ export function renderToHtml( - template: ComponentTemplate, ctx: any, directives?: DirectiveTypesOrFactory | null, - pipes?: PipeTypesOrFactory | null, providedRendererFactory?: RendererFactory3 | null) { + template: ComponentTemplate, ctx: any, consts: number = 0, + directives?: DirectiveTypesOrFactory | null, pipes?: PipeTypesOrFactory | null, + providedRendererFactory?: RendererFactory3 | null) { host = renderTemplate( - containerEl, template, ctx, providedRendererFactory || testRendererFactory, host, + containerEl, template, consts, ctx, providedRendererFactory || testRendererFactory, host, toDefs(directives, extractDirectiveDef), toDefs(pipes, extractPipeDef)); return toHtml(containerEl); } @@ -228,14 +229,15 @@ export function toHtml(componentOrElement: T | RElement): string { } export function createComponent( - name: string, template: ComponentTemplate, directives: DirectiveTypesOrFactory = [], - pipes: PipeTypesOrFactory = [], + name: string, template: ComponentTemplate, consts: number = 0, + directives: DirectiveTypesOrFactory = [], pipes: PipeTypesOrFactory = [], viewQuery: ComponentTemplate| null = null): ComponentType { return class Component { value: any; static ngComponentDef = defineComponent({ type: Component, selectors: [[name]], + consts: consts, factory: () => new Component, template: template, viewQuery: viewQuery, diff --git a/packages/core/test/render3/renderer_factory_spec.ts b/packages/core/test/render3/renderer_factory_spec.ts index 194a65671f..b241f7cb42 100644 --- a/packages/core/test/render3/renderer_factory_spec.ts +++ b/packages/core/test/render3/renderer_factory_spec.ts @@ -33,6 +33,7 @@ describe('renderer factory lifecycle', () => { static ngComponentDef = defineComponent({ type: SomeComponent, selectors: [['some-component']], + consts: 1, template: function(rf: RenderFlags, ctx: SomeComponent) { logs.push('component'); if (rf & RenderFlags.Create) { @@ -47,6 +48,7 @@ describe('renderer factory lifecycle', () => { static ngComponentDef = defineComponent({ type: SomeComponentWhichThrows, selectors: [['some-component-with-Error']], + consts: 0, template: function(rf: RenderFlags, ctx: SomeComponentWhichThrows) { throw(new Error('SomeComponentWhichThrows threw')); }, @@ -88,7 +90,7 @@ describe('renderer factory lifecycle', () => { }); it('should work with a template', () => { - renderToHtml(Template, {}, null, null, rendererFactory); + renderToHtml(Template, {}, 1, null, null, rendererFactory); expect(logs).toEqual(['create', 'begin', 'function', 'end']); logs = []; @@ -97,12 +99,12 @@ describe('renderer factory lifecycle', () => { }); it('should work with a template which contains a component', () => { - renderToHtml(TemplateWithComponent, {}, directives, null, rendererFactory); + renderToHtml(TemplateWithComponent, {}, 2, directives, null, rendererFactory); expect(logs).toEqual( ['create', 'begin', 'function_with_component', 'create', 'component', 'end']); logs = []; - renderToHtml(TemplateWithComponent, {}, directives); + renderToHtml(TemplateWithComponent, {}, 2, directives); expect(logs).toEqual(['begin', 'function_with_component', 'component', 'end']); }); @@ -125,6 +127,7 @@ describe('animation renderer factory', () => { static ngComponentDef = defineComponent({ type: SomeComponent, selectors: [['some-component']], + consts: 1, template: function(rf: RenderFlags, ctx: SomeComponent) { if (rf & RenderFlags.Create) { text(0, 'foo'); @@ -143,6 +146,7 @@ describe('animation renderer factory', () => { static ngComponentDef = defineComponent({ type: SomeComponentWithAnimation, selectors: [['some-component']], + consts: 2, template: function(rf: RenderFlags, ctx: SomeComponentWithAnimation) { if (rf & RenderFlags.Create) { elementStart(0, 'div'); @@ -221,7 +225,7 @@ describe('Renderer2 destruction hooks', () => { containerRefreshStart(1); { if (condition) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 3); { if (rf1 & RenderFlags.Create) { element(0, 'span'); @@ -236,7 +240,7 @@ describe('Renderer2 destruction hooks', () => { } const t = - new TemplateFixture(createTemplate, updateTemplate, null, null, null, rendererFactory); + new TemplateFixture(createTemplate, updateTemplate, 2, null, null, null, rendererFactory); expect(t.html).toEqual('
                            '); @@ -251,6 +255,7 @@ describe('Renderer2 destruction hooks', () => { static ngComponentDef = defineComponent({ type: SimpleComponent, selectors: [['simple']], + consts: 1, template: function(rf: RenderFlags, ctx: SimpleComponent) { if (rf & RenderFlags.Create) { element(0, 'span'); @@ -272,7 +277,7 @@ describe('Renderer2 destruction hooks', () => { containerRefreshStart(1); { if (condition) { - let rf1 = embeddedViewStart(1); + let rf1 = embeddedViewStart(1, 3); { if (rf1 & RenderFlags.Create) { element(0, 'simple'); @@ -287,7 +292,7 @@ describe('Renderer2 destruction hooks', () => { } const t = new TemplateFixture( - createTemplate, updateTemplate, [SimpleComponent], null, null, rendererFactory); + createTemplate, updateTemplate, 2, [SimpleComponent], null, null, rendererFactory); expect(t.html).toEqual( '
                            '); diff --git a/packages/core/test/render3/view_container_ref_spec.ts b/packages/core/test/render3/view_container_ref_spec.ts index 6570f8be3d..7144e87a3b 100644 --- a/packages/core/test/render3/view_container_ref_spec.ts +++ b/packages/core/test/render3/view_container_ref_spec.ts @@ -28,6 +28,7 @@ describe('ViewContainerRef', () => { type: DirectiveWithVCRef, selectors: [['', 'vcref', '']], factory: () => directiveInstance = new DirectiveWithVCRef( + injectViewContainerRef(), injectComponentFactoryResolver()), inputs: {tplRef: 'tplRef'} }); @@ -63,7 +64,7 @@ describe('ViewContainerRef', () => { *

                            */ function createTemplate() { - template(0, embeddedTemplate, null, null, ['tplRef', ''], templateRefExtractor); + template(0, embeddedTemplate, 1, null, null, ['tplRef', ''], templateRefExtractor); element(2, 'p', ['vcref', '']); } @@ -80,12 +81,13 @@ describe('ViewContainerRef', () => { *
                            */ function createTemplate() { - template(0, embeddedTemplate, null, null, ['tplRef', ''], templateRefExtractor); + template(0, embeddedTemplate, 1, null, null, ['tplRef', ''], templateRefExtractor); element(2, 'header', ['vcref', '']); element(3, 'footer'); } - const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]); + const fixture = + new TemplateFixture(createTemplate, updateTemplate, 4, [DirectiveWithVCRef]); expect(fixture.html).toEqual('
                            '); createView('A'); @@ -115,13 +117,13 @@ describe('ViewContainerRef', () => { *
                            */ function createTemplate() { - template(0, embeddedTemplate, null, [], ['tplRef', ''], templateRefExtractor); + template(0, embeddedTemplate, 1, null, [], ['tplRef', ''], templateRefExtractor); element(2, 'header-cmp', ['vcref', '']); element(3, 'footer'); } const fixture = new TemplateFixture( - createTemplate, updateTemplate, [HeaderComponent, DirectiveWithVCRef]); + createTemplate, updateTemplate, 3, [HeaderComponent, DirectiveWithVCRef]); expect(fixture.html).toEqual('
                            '); createView('A'); @@ -151,7 +153,7 @@ describe('ViewContainerRef', () => { *
                            */ function createTemplate() { - template(0, embeddedTemplate, null, null, ['tplRef', ''], templateRefExtractor); + template(0, embeddedTemplate, 1, null, null, ['tplRef', ''], templateRefExtractor); element(2, 'div', ['vcref', '']); element(3, 'div', ['vcref', '']); @@ -166,7 +168,7 @@ describe('ViewContainerRef', () => { elementProperty(3, 'tplRef', bind(tplRef)); } - const fixture = new TemplateFixture(createTemplate, update, [DirectiveWithVCRef]); + const fixture = new TemplateFixture(createTemplate, update, 4, [DirectiveWithVCRef]); expect(fixture.html).toEqual('
                            '); firstDir !.vcref.createEmbeddedView(firstDir !.tplRef, {name: 'A'}); @@ -181,7 +183,8 @@ describe('ViewContainerRef', () => { *
                            */ function createTemplate() { - template(0, embeddedTemplate, null, ['vcref', ''], ['tplRef', ''], templateRefExtractor); + template( + 0, embeddedTemplate, 1, null, ['vcref', ''], ['tplRef', ''], templateRefExtractor); element(2, 'footer'); } @@ -190,7 +193,8 @@ describe('ViewContainerRef', () => { elementProperty(0, 'tplRef', bind(tplRef)); } - const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]); + const fixture = + new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]); expect(fixture.html).toEqual('
                            '); createView('A'); @@ -259,11 +263,12 @@ describe('ViewContainerRef', () => { type: TestComponent, selectors: [['test-cmp']], factory: () => new TestComponent(), + consts: 4, template: (rf: RenderFlags, cmp: TestComponent) => { if (rf & RenderFlags.Create) { text(0, 'before|'); - template(1, EmbeddedTemplateA, null, ['testdir', '']); - template(2, EmbeddedTemplateB, null, ['testdir', '']); + template(1, EmbeddedTemplateA, 1, null, ['testdir', '']); + template(2, EmbeddedTemplateB, 1, null, ['testdir', '']); text(3, '|after'); } }, @@ -327,11 +332,12 @@ describe('ViewContainerRef', () => { static ngComponentDef = defineComponent({ type: TestComponent, selectors: [['test-cmp']], + consts: 4, factory: () => new TestComponent(), template: (rf: RenderFlags, cmp: TestComponent) => { if (rf & RenderFlags.Create) { text(0, 'before|'); - template(1, EmbeddedTemplateA, null, ['testdir', '']); + template(1, EmbeddedTemplateA, 1, null, ['testdir', '']); container(2); text(3, '|after'); } @@ -339,7 +345,7 @@ describe('ViewContainerRef', () => { containerRefreshStart(2); { if (cmp.condition) { - let rf1 = embeddedViewStart(0); + let rf1 = embeddedViewStart(0, 1); { if (rf1 & RenderFlags.Create) { text(0, 'B'); @@ -387,6 +393,7 @@ describe('ViewContainerRef', () => { type: Child, selectors: [['child']], factory: () => new Child(), + consts: 1, template: (rf: RenderFlags, cmp: Child) => { if (rf & RenderFlags.Create) { text(0); @@ -434,9 +441,11 @@ describe('ViewContainerRef', () => { type: SomeComponent, selectors: [['some-comp']], factory: () => new SomeComponent(), + consts: 6, template: (rf: RenderFlags, cmp: SomeComponent) => { if (rf & RenderFlags.Create) { - template(0, SomeComponent_Template_0, null, [], ['foo', ''], templateRefExtractor); + template( + 0, SomeComponent_Template_0, 2, null, [], ['foo', ''], templateRefExtractor); pipe(2, 'starPipe'); element(3, 'child', ['vcref', '']); pipe(4, 'starPipe'); @@ -498,6 +507,7 @@ describe('ViewContainerRef', () => { type: Child, selectors: [['child']], factory: () => child = new Child(), + consts: 2, template: function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { elementStart(0, 'div', [AttributeMarker.SelectOnly, 'tplDir']); @@ -524,7 +534,7 @@ describe('ViewContainerRef', () => { */ const Parent = createComponent('parent', function(rf: RenderFlags, parent: any) { if (rf & RenderFlags.Create) { - template(0, fooTemplate, null, null, ['foo', ''], templateRefExtractor); + template(0, fooTemplate, 2, null, null, ['foo', ''], templateRefExtractor); element(2, 'child'); } @@ -533,7 +543,7 @@ describe('ViewContainerRef', () => { elementProperty(2, 'tpl', bind(tplRef)); } - }, [Child]); + }, 3, [Child]); function fooTemplate(rf1: RenderFlags, ctx: any) { if (rf1 & RenderFlags.Create) { @@ -581,9 +591,10 @@ describe('ViewContainerRef', () => { type: LoopComp, selectors: [['loop-comp']], factory: () => new LoopComp(), + consts: 1, template: function(rf: RenderFlags, loop: any) { if (rf & RenderFlags.Create) { - template(0, () => {}, null, [AttributeMarker.SelectOnly, 'ngForOf']); + template(0, null, 0, null, [AttributeMarker.SelectOnly, 'ngForOf']); } if (rf & RenderFlags.Update) { @@ -613,7 +624,7 @@ describe('ViewContainerRef', () => { */ const Parent = createComponent('parent', function(rf: RenderFlags, parent: any) { if (rf & RenderFlags.Create) { - template(0, rowTemplate, null, null, ['rowTemplate', ''], templateRefExtractor); + template(0, rowTemplate, 3, null, null, ['rowTemplate', ''], templateRefExtractor); element(2, 'loop-comp'); } @@ -623,11 +634,11 @@ describe('ViewContainerRef', () => { elementProperty(2, 'rows', bind(parent.rows)); } - }, [LoopComp]); + }, 3, [LoopComp]); function rowTemplate(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(0, cellTemplate, null, null, ['cellTemplate', ''], templateRefExtractor); + template(0, cellTemplate, 2, null, null, ['cellTemplate', ''], templateRefExtractor); element(2, 'loop-comp'); } @@ -685,7 +696,7 @@ describe('ViewContainerRef', () => { describe('detach', () => { it('should detach the right embedded view when an index is specified', () => { const fixture = new TemplateFixture( - createTemplate, updateTemplate, [DirectiveWithVCRef], null, null, rendererFactory); + createTemplate, updateTemplate, 3, [DirectiveWithVCRef], null, null, rendererFactory); const viewA = createView('A'); createView('B'); createView('C'); @@ -712,7 +723,7 @@ describe('ViewContainerRef', () => { it('should detach the last embedded view when no index is specified', () => { const fixture = new TemplateFixture( - createTemplate, updateTemplate, [DirectiveWithVCRef], null, null, rendererFactory); + createTemplate, updateTemplate, 3, [DirectiveWithVCRef], null, null, rendererFactory); createView('A'); createView('B'); createView('C'); @@ -732,7 +743,7 @@ describe('ViewContainerRef', () => { describe('remove', () => { it('should remove the right embedded view when an index is specified', () => { const fixture = new TemplateFixture( - createTemplate, updateTemplate, [DirectiveWithVCRef], null, null, rendererFactory); + createTemplate, updateTemplate, 3, [DirectiveWithVCRef], null, null, rendererFactory); const viewA = createView('A'); createView('B'); createView('C'); @@ -758,7 +769,7 @@ describe('ViewContainerRef', () => { it('should remove the last embedded view when no index is specified', () => { const fixture = new TemplateFixture( - createTemplate, updateTemplate, [DirectiveWithVCRef], null, null, rendererFactory); + createTemplate, updateTemplate, 3, [DirectiveWithVCRef], null, null, rendererFactory); createView('A'); createView('B'); createView('C'); @@ -776,7 +787,7 @@ describe('ViewContainerRef', () => { it('should throw when trying to insert a removed or destroyed view', () => { const fixture = new TemplateFixture( - createTemplate, updateTemplate, [DirectiveWithVCRef], null, null, rendererFactory); + createTemplate, updateTemplate, 3, [DirectiveWithVCRef], null, null, rendererFactory); const viewA = createView('A'); const viewB = createView('B'); fixture.update(); @@ -793,7 +804,8 @@ describe('ViewContainerRef', () => { describe('length', () => { it('should return the number of embedded views', () => { - const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]); + const fixture = + new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]); expect(directiveInstance !.vcref.length).toEqual(0); createView('A'); @@ -814,7 +826,8 @@ describe('ViewContainerRef', () => { describe('get and indexOf', () => { it('should retrieve a ViewRef from its index, and vice versa', () => { - const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]); + const fixture = + new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]); createView('A'); createView('B'); createView('C'); @@ -831,7 +844,8 @@ describe('ViewContainerRef', () => { }); it('should handle out of bounds cases', () => { - const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]); + const fixture = + new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]); createView('A'); fixture.update(); @@ -846,7 +860,8 @@ describe('ViewContainerRef', () => { describe('move', () => { it('should move embedded views and associated DOM nodes without recreating them', () => { - const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]); + const fixture = + new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]); createView('A'); createView('B'); createView('C'); @@ -883,6 +898,7 @@ describe('ViewContainerRef', () => { type: EmbeddedComponent, selectors: [['embedded-cmp']], factory: () => new EmbeddedComponent(), + consts: 1, template: (rf: RenderFlags, cmp: EmbeddedComponent) => { templateExecutionCounter++; if (rf & RenderFlags.Create) { @@ -894,7 +910,8 @@ describe('ViewContainerRef', () => { it('should work without Injector and NgModuleRef', () => { templateExecutionCounter = 0; - const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]); + const fixture = + new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]); expect(fixture.html).toEqual('

                            '); expect(templateExecutionCounter).toEqual(0); @@ -939,7 +956,8 @@ describe('ViewContainerRef', () => { const injector = createInjector(SomeModule); templateExecutionCounter = 0; - const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]); + const fixture = + new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]); expect(fixture.html).toEqual('

                            '); expect(templateExecutionCounter).toEqual(0); @@ -964,6 +982,7 @@ describe('ViewContainerRef', () => { type: EmbeddedComponentWithNgContent, selectors: [['embedded-cmp-with-ngcontent']], factory: () => new EmbeddedComponentWithNgContent(), + consts: 3, template: (rf: RenderFlags, cmp: EmbeddedComponentWithNgContent) => { if (rf & RenderFlags.Create) { projectionDef(); @@ -976,7 +995,8 @@ describe('ViewContainerRef', () => { } it('should support projectable nodes', () => { - const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]); + const fixture = + new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]); expect(fixture.html).toEqual('

                            '); const myNode = document.createElement('div'); @@ -1000,6 +1020,7 @@ describe('ViewContainerRef', () => { type: Reprojector, selectors: [['reprojector']], factory: () => new Reprojector(), + consts: 2, template: (rf: RenderFlags, cmp: Reprojector) => { if (rf & RenderFlags.Create) { projectionDef(); @@ -1012,7 +1033,8 @@ describe('ViewContainerRef', () => { }); } - const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]); + const fixture = + new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]); expect(fixture.html).toEqual('

                            '); const myNode = document.createElement('div'); @@ -1030,7 +1052,8 @@ describe('ViewContainerRef', () => { }); it('should support many projectable nodes with many slots', () => { - const fixture = new TemplateFixture(createTemplate, updateTemplate, [DirectiveWithVCRef]); + const fixture = + new TemplateFixture(createTemplate, updateTemplate, 3, [DirectiveWithVCRef]); expect(fixture.html).toEqual('

                            '); directiveInstance !.vcref.createComponent( @@ -1053,7 +1076,7 @@ describe('ViewContainerRef', () => { element(1, 'footer'); } - new TemplateFixture(createTemplate, undefined, [DirectiveWithVCRef]); + new TemplateFixture(createTemplate, undefined, 2, [DirectiveWithVCRef]); expect(directiveInstance !.vcref.element.nativeElement.tagName.toLowerCase()) .toEqual('header'); @@ -1072,7 +1095,7 @@ describe('ViewContainerRef', () => { element(1, 'footer'); } - new TemplateFixture(createTemplate, undefined, [HeaderComponent, DirectiveWithVCRef]); + new TemplateFixture(createTemplate, undefined, 2, [HeaderComponent, DirectiveWithVCRef]); expect(directiveInstance !.vcref.element.nativeElement.tagName.toLowerCase()) .toEqual('header-cmp'); @@ -1084,11 +1107,11 @@ describe('ViewContainerRef', () => { it('should work on templates', () => { function createTemplate() { - template(0, embeddedTemplate, null, ['vcref', '']); + template(0, embeddedTemplate, 1, null, ['vcref', '']); element(1, 'footer'); } - new TemplateFixture(createTemplate, () => {}, [DirectiveWithVCRef]); + new TemplateFixture(createTemplate, () => {}, 2, [DirectiveWithVCRef]); expect(directiveInstance !.vcref.element.nativeElement.textContent).toEqual('container'); expect(directiveInstance !.vcref.injector.get(ElementRef).nativeElement.textContent) .toEqual('container'); @@ -1114,6 +1137,7 @@ describe('ViewContainerRef', () => { type: Child, selectors: [['child']], factory: () => new Child(), + consts: 2, template: (rf: RenderFlags, cmp: Child) => { if (rf & RenderFlags.Create) { projectionDef(); @@ -1139,9 +1163,10 @@ describe('ViewContainerRef', () => { type: Parent, selectors: [['parent']], factory: () => new Parent(), + consts: 5, template: (rf: RenderFlags, cmp: Parent) => { if (rf & RenderFlags.Create) { - template(0, embeddedTemplate, null, null, ['foo', ''], templateRefExtractor); + template(0, embeddedTemplate, 2, null, null, ['foo', ''], templateRefExtractor); elementStart(2, 'child'); { elementStart(3, 'header', ['vcref', '']); @@ -1187,6 +1212,7 @@ describe('ViewContainerRef', () => { type: ChildWithView, selectors: [['child-with-view']], factory: () => new ChildWithView(), + consts: 3, template: (rf: RenderFlags, cmp: ChildWithView) => { if (rf & RenderFlags.Create) { projectionDef(); @@ -1197,7 +1223,7 @@ describe('ViewContainerRef', () => { if (rf & RenderFlags.Update) { containerRefreshStart(1); if (cmp.show) { - let rf0 = embeddedViewStart(0); + let rf0 = embeddedViewStart(0, 1); if (rf0 & RenderFlags.Create) { projection(0); } @@ -1227,9 +1253,10 @@ describe('ViewContainerRef', () => { type: Parent, selectors: [['parent']], factory: () => new Parent(), + consts: 7, template: (rf: RenderFlags, cmp: Parent) => { if (rf & RenderFlags.Create) { - template(0, embeddedTemplate, null, undefined, ['foo', ''], templateRefExtractor); + template(0, embeddedTemplate, 2, null, undefined, ['foo', ''], templateRefExtractor); elementStart(2, 'child-with-view'); text(3, 'Before projected'); elementStart(4, 'header', ['vcref', '']); @@ -1272,6 +1299,7 @@ describe('ViewContainerRef', () => { type: ChildWithSelector, selectors: [['child-with-selector']], factory: () => new ChildWithSelector(), + consts: 4, template: (rf: RenderFlags, cmp: ChildWithSelector) => { if (rf & RenderFlags.Create) { projectionDef([[['header']]], ['header']); @@ -1303,10 +1331,11 @@ describe('ViewContainerRef', () => { type: Parent, selectors: [['parent']], factory: () => new Parent(), + consts: 5, template: (rf: RenderFlags, cmp: Parent) => { let tplRef: any; if (rf & RenderFlags.Create) { - template(0, embeddedTemplate, null, null, ['foo', ''], templateRefExtractor); + template(0, embeddedTemplate, 2, null, null, ['foo', ''], templateRefExtractor); elementStart(2, 'child-with-selector'); elementStart(3, 'header', ['vcref', '']); text(4, 'blah'); @@ -1352,10 +1381,11 @@ describe('ViewContainerRef', () => { type: Parent, selectors: [['parent']], factory: () => new Parent(), + consts: 5, template: (rf: RenderFlags, cmp: Parent) => { let tplRef: any; if (rf & RenderFlags.Create) { - template(0, embeddedTemplate, null, null, ['foo', ''], templateRefExtractor); + template(0, embeddedTemplate, 2, null, null, ['foo', ''], templateRefExtractor); elementStart(2, 'child-with-selector'); elementStart(3, 'footer', ['vcref', '']); text(4, 'blah'); @@ -1415,6 +1445,7 @@ describe('ViewContainerRef', () => { type: ComponentWithHooks, selectors: [['hooks']], factory: () => new ComponentWithHooks(), + consts: 1, template: (rf: RenderFlags, cmp: ComponentWithHooks) => { if (rf & RenderFlags.Create) { text(0); @@ -1429,6 +1460,15 @@ describe('ViewContainerRef', () => { } it('should call all hooks in correct order when creating with createEmbeddedView', () => { + function SomeComponent_Template_0(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + element(0, 'hooks'); + } + if (rf & RenderFlags.Update) { + elementProperty(0, 'name', bind('C')); + } + } + @Component({ template: ` @@ -1443,16 +1483,10 @@ describe('ViewContainerRef', () => { type: SomeComponent, selectors: [['some-comp']], factory: () => new SomeComponent(), + consts: 4, template: (rf: RenderFlags, cmp: SomeComponent) => { if (rf & RenderFlags.Create) { - template(0, (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Create) { - element(0, 'hooks'); - } - if (rf & RenderFlags.Update) { - elementProperty(0, 'name', bind('C')); - } - }, null, [], ['foo', ''], templateRefExtractor); + template(0, SomeComponent_Template_0, 1, null, [], ['foo', ''], templateRefExtractor); element(2, 'hooks', ['vcref', '']); element(3, 'hooks'); } @@ -1542,6 +1576,7 @@ describe('ViewContainerRef', () => { type: SomeComponent, selectors: [['some-comp']], factory: () => new SomeComponent(), + consts: 2, template: (rf: RenderFlags, cmp: SomeComponent) => { if (rf & RenderFlags.Create) { element(0, 'hooks', ['vcref', '']);