diff --git a/packages/core/test/acceptance/pure_function_spec.ts b/packages/core/test/acceptance/pure_function_spec.ts
new file mode 100644
index 0000000000..01abb54b2e
--- /dev/null
+++ b/packages/core/test/acceptance/pure_function_spec.ts
@@ -0,0 +1,482 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+import {CommonModule} from '@angular/common';
+import {Component, Input} from '@angular/core';
+import {TestBed} from '@angular/core/testing';
+import {By} from '@angular/platform-browser';
+
+describe('components using pure function instructions internally', () => {
+ describe('with array literals', () => {
+ @Component({
+ selector: 'my-comp',
+ template: ``,
+ })
+ class MyComp {
+ @Input()
+ names: string[] = [];
+ }
+
+
+ it('should support an array literal with a binding', () => {
+ @Component({
+ template: `
+
+ `,
+ })
+ class App {
+ showing = true;
+ customName = 'Carson';
+ }
+
+ TestBed.configureTestingModule({
+ declarations: [App, MyComp],
+ });
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+ const myComp = fixture.debugElement.query(By.directive(MyComp)).componentInstance;
+
+ const firstArray = myComp.names;
+ expect(firstArray).toEqual(['Nancy', 'Carson', 'Bess']);
+
+ fixture.detectChanges();
+ expect(myComp.names).toEqual(['Nancy', 'Carson', 'Bess']);
+ expect(firstArray).toBe(myComp.names);
+
+ fixture.componentInstance.customName = 'Hannah';
+ fixture.detectChanges();
+ expect(myComp.names).toEqual(['Nancy', 'Hannah', 'Bess']);
+
+ // Identity must change if binding changes
+ expect(firstArray).not.toBe(myComp.names);
+
+ // 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'];
+ fixture.detectChanges();
+
+ expect(myComp !.names).toEqual(['should not be overwritten']);
+ });
+
+
+ it('should support array literals in dynamic views', () => {
+ @Component({
+ template: `
+
+ `,
+ })
+ class App {
+ showing = true;
+ customName = 'Carson';
+ }
+
+ TestBed.configureTestingModule({
+ declarations: [App, MyComp],
+ imports: [CommonModule],
+ });
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+ const myComp = fixture.debugElement.query(By.directive(MyComp)).componentInstance;
+ expect(myComp.names).toEqual(['Nancy', 'Carson', 'Bess']);
+ });
+
+ it('should support multiple array literals passed through to one node', () => {
+ @Component({
+ selector: 'many-prop-comp',
+ template: ``,
+ })
+ class ManyPropComp {
+ @Input()
+ names1: string[] = [];
+
+ @Input()
+ names2: string[] = [];
+ }
+
+ @Component({
+ template: `
+
+
+ `,
+ })
+ class App {
+ showing = true;
+ customName = 'Carson';
+ customName2 = 'George';
+ }
+
+ TestBed.configureTestingModule({
+ declarations: [App, ManyPropComp],
+ });
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+ const manyPropComp = fixture.debugElement.query(By.directive(ManyPropComp)).componentInstance;
+
+ expect(manyPropComp !.names1).toEqual(['Nancy', 'Carson']);
+ expect(manyPropComp !.names2).toEqual(['George']);
+
+ fixture.componentInstance.customName = 'George';
+ fixture.componentInstance.customName2 = 'Carson';
+ fixture.detectChanges();
+ expect(manyPropComp !.names1).toEqual(['Nancy', 'George']);
+ expect(manyPropComp !.names2).toEqual(['Carson']);
+ });
+
+
+ it('should support an array literals inside fn calls', () => {
+ @Component({
+ selector: 'parent-comp',
+ template: `
+
+ `
+ })
+ class ParentComp {
+ customName = 'Bess';
+
+ someFn(arr: string[]): string[] {
+ arr[0] = arr[0].toUpperCase();
+ return arr;
+ }
+ }
+
+ @Component({
+ template: `
+
+
+ `
+ })
+ class App {
+ }
+
+ TestBed.configureTestingModule({
+ declarations: [App, MyComp, ParentComp],
+ });
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+ const myComps =
+ fixture.debugElement.queryAll(By.directive(MyComp)).map(f => f.componentInstance);
+
+
+ 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);
+
+ fixture.detectChanges();
+ expect(firstArray).toEqual(['NANCY', 'Bess']);
+ expect(secondArray).toEqual(['NANCY', 'Bess']);
+ expect(firstArray).toBe(myComps[0].names);
+ expect(secondArray).toBe(myComps[1].names);
+ });
+
+
+ it('should support an array literal with more than 1 binding', () => {
+ @Component({
+ template: `
+
+ `,
+ })
+ class App {
+ showing = true;
+ customName = 'Carson';
+ customName2 = 'Hannah';
+ }
+
+ TestBed.configureTestingModule({
+ declarations: [App, MyComp],
+ imports: [CommonModule],
+ });
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+ const myComp = fixture.debugElement.query(By.directive(MyComp)).componentInstance;
+
+ const firstArray = myComp.names;
+ expect(firstArray).toEqual(['Nancy', 'Carson', 'Bess', 'Hannah']);
+
+ fixture.detectChanges();
+ expect(myComp.names).toEqual(['Nancy', 'Carson', 'Bess', 'Hannah']);
+ expect(firstArray).toBe(myComp.names);
+
+ fixture.componentInstance.customName = 'George';
+ fixture.detectChanges();
+ expect(myComp.names).toEqual(['Nancy', 'George', 'Bess', 'Hannah']);
+ expect(firstArray).not.toBe(myComp.names);
+
+ fixture.componentInstance.customName = 'Frank';
+ fixture.componentInstance.customName2 = 'Ned';
+ fixture.detectChanges();
+ 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'];
+ fixture.detectChanges();
+ expect(myComp.names).toEqual(['should not be overwritten']);
+ });
+
+
+ it('should work up to 8 bindings', () => {
+
+ @Component({
+ template: `
+
+
+
+
+
+
+
+
+ `
+ })
+ class App {
+ v1 = 'a';
+ v2 = 'b';
+ v3 = 'c';
+ v4 = 'd';
+ v5 = 'e';
+ v6 = 'f';
+ v7 = 'g';
+ v8 = 'h';
+ }
+
+ TestBed.configureTestingModule({
+ declarations: [App, MyComp],
+ });
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+
+ const myComps =
+ fixture.debugElement.queryAll(By.directive(MyComp)).map(f => f.componentInstance);
+
+ myComps.forEach(myComp => {
+ expect(myComp.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
+ });
+
+ const app = fixture.componentInstance;
+
+ app.v1 = 'a1';
+ app.v2 = 'b1';
+ app.v3 = 'c1';
+ app.v4 = 'd1';
+ app.v5 = 'e1';
+ app.v6 = 'f1';
+ app.v7 = 'g1';
+ app.v8 = 'h1';
+
+ fixture.detectChanges();
+
+ expect(myComps[0].names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h1']);
+ expect(myComps[1].names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g1', 'h1']);
+ expect(myComps[2].names).toEqual(['a', 'b', 'c', 'd', 'e', 'f1', 'g1', 'h1']);
+ expect(myComps[3].names).toEqual(['a', 'b', 'c', 'd', 'e1', 'f1', 'g1', 'h1']);
+ expect(myComps[4].names).toEqual(['a', 'b', 'c', 'd1', 'e1', 'f1', 'g1', 'h1']);
+ expect(myComps[5].names).toEqual(['a', 'b', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1']);
+ expect(myComps[6].names).toEqual(['a', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1']);
+ expect(myComps[7].names).toEqual(['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1']);
+
+ app.v8 = 'h2';
+ fixture.detectChanges();
+
+ expect(myComps[0].names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h2']);
+ expect(myComps[1].names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g1', 'h2']);
+ expect(myComps[2].names).toEqual(['a', 'b', 'c', 'd', 'e', 'f1', 'g1', 'h2']);
+ expect(myComps[3].names).toEqual(['a', 'b', 'c', 'd', 'e1', 'f1', 'g1', 'h2']);
+ expect(myComps[4].names).toEqual(['a', 'b', 'c', 'd1', 'e1', 'f1', 'g1', 'h2']);
+ expect(myComps[5].names).toEqual(['a', 'b', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2']);
+ expect(myComps[6].names).toEqual(['a', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2']);
+ expect(myComps[7].names).toEqual(['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2']);
+ });
+
+ it('should work with pureFunctionV for 9+ bindings', () => {
+ @Component({
+ template: `
+
+
+ `
+ })
+ class App {
+ v0 = 'a';
+ v1 = 'b';
+ v2 = 'c';
+ v3 = 'd';
+ v4 = 'e';
+ v5 = 'f';
+ v6 = 'g';
+ v7 = 'h';
+ v8 = 'i';
+ }
+ TestBed.configureTestingModule({
+ declarations: [App, MyComp],
+ });
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+ const myComp = fixture.debugElement.query(By.directive(MyComp)).componentInstance;
+ const app = fixture.componentInstance;
+
+ expect(myComp.names).toEqual([
+ 'start', 'a', 'b', 'c', 'd', 'modified_e', 'f', 'g', 'h', 'i', 'end'
+ ]);
+
+ app.v0 = 'a1';
+ fixture.detectChanges();
+
+ expect(myComp.names).toEqual([
+ 'start', 'a1', 'b', 'c', 'd', 'modified_e', 'f', 'g', 'h', 'i', 'end'
+ ]);
+
+ app.v4 = 'e5';
+ fixture.detectChanges();
+
+ expect(myComp.names).toEqual([
+ 'start', 'a1', 'b', 'c', 'd', 'modified_e5', 'f', 'g', 'h', 'i', 'end'
+ ]);
+ });
+ });
+
+ describe('with object literals', () => {
+ @Component({
+ selector: 'object-comp',
+ template: ``,
+ })
+ class ObjectComp {
+ @Input()
+ config: any = [];
+ }
+
+ it('should support an object literal', () => {
+ @Component({
+ template: '',
+ })
+ class App {
+ name = 'slide';
+ }
+
+ TestBed.configureTestingModule({
+ declarations: [App, ObjectComp],
+ });
+
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+ const objectComp = fixture.debugElement.query(By.directive(ObjectComp)).componentInstance;
+
+ const firstObj = objectComp.config;
+ expect(objectComp.config).toEqual({duration: 500, animation: 'slide'});
+
+ fixture.detectChanges();
+ expect(objectComp.config).toEqual({duration: 500, animation: 'slide'});
+ expect(firstObj).toBe(objectComp.config);
+
+ fixture.componentInstance.name = 'tap';
+ fixture.detectChanges();
+ expect(objectComp.config).toEqual({duration: 500, animation: 'tap'});
+
+ // Identity must change if binding changes
+ expect(firstObj).not.toBe(objectComp.config);
+ });
+
+
+ it('should support expressions nested deeply in object/array literals', () => {
+ @Component({
+ template: `
+
+
+ `,
+ })
+ class App {
+ name = 'slide';
+ duration = 100;
+ }
+
+ TestBed.configureTestingModule({
+ declarations: [App, ObjectComp],
+ });
+
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+ const objectComp = fixture.debugElement.query(By.directive(ObjectComp)).componentInstance;
+
+ expect(objectComp.config).toEqual({
+ animation: 'slide',
+ actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 100}]
+ });
+ const firstConfig = objectComp.config;
+
+ fixture.detectChanges();
+ expect(objectComp.config).toEqual({
+ animation: 'slide',
+ actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 100}]
+ });
+ expect(objectComp.config).toBe(firstConfig);
+
+ fixture.componentInstance.duration = 50;
+ fixture.detectChanges();
+ expect(objectComp.config).toEqual({
+ animation: 'slide',
+ actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 50}]
+ });
+ expect(objectComp.config).not.toBe(firstConfig);
+
+ fixture.componentInstance.name = 'tap';
+ fixture.detectChanges();
+ expect(objectComp.config).toEqual({
+ animation: 'tap',
+ actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 50}]
+ });
+
+ fixture.componentInstance.name = 'drag';
+ fixture.componentInstance.duration = 500;
+ fixture.detectChanges();
+ expect(objectComp.config).toEqual({
+ animation: 'drag',
+ actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 500}]
+ });
+
+ // 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'];
+ fixture.detectChanges();
+ expect(objectComp.config).toEqual(['should not be overwritten']);
+ });
+
+ it('should support multiple view instances with multiple bindings', () => {
+ @Component({
+ template: `
+
+
+ `,
+ })
+ class App {
+ configs = [
+ {opacity: 0, duration: 500},
+ {opacity: 1, duration: 600},
+ ];
+ }
+
+ TestBed.configureTestingModule({
+ declarations: [App, ObjectComp],
+ imports: [CommonModule],
+ });
+
+ const fixture = TestBed.createComponent(App);
+ fixture.detectChanges();
+ const app = fixture.componentInstance;
+ const objectComps =
+ fixture.debugElement.queryAll(By.directive(ObjectComp)).map(f => f.componentInstance);
+
+ expect(objectComps[0].config).toEqual({opacity: 0, duration: 500});
+ expect(objectComps[1].config).toEqual({opacity: 1, duration: 600});
+
+ app.configs[0].duration = 1000;
+ fixture.detectChanges();
+ 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/pure_function_spec.ts b/packages/core/test/render3/pure_function_spec.ts
index 2824d8ee2a..42f7a17476 100644
--- a/packages/core/test/render3/pure_function_spec.ts
+++ b/packages/core/test/render3/pure_function_spec.ts
@@ -5,381 +5,13 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
-import {AttributeMarker, ɵɵdefineComponent, ɵɵtemplate} from '../../src/render3/index';
-import {ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵnextContext} from '../../src/render3/instructions/all';
+import {ɵɵdefineComponent} from '../../src/render3/index';
+import {ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart} from '../../src/render3/instructions/all';
import {RenderFlags} from '../../src/render3/interfaces/definition';
-import {ɵɵpureFunction1, ɵɵpureFunction2, ɵɵpureFunction3, ɵɵpureFunction4, ɵɵpureFunction5, ɵɵpureFunction6, ɵɵpureFunction7, ɵɵpureFunction8, ɵɵpureFunctionV} from '../../src/render3/pure_function';
-import {ComponentFixture, createComponent, getDirectiveOnNode, renderToHtml} from '../../test/render3/render_util';
-
-import {NgIf} from './common_with_def';
-
-describe('array literals', () => {
- let myComp: MyComp;
-
- class MyComp {
- // TODO(issue/24571): remove '!'.
- names !: string[];
-
- static ngComponentDef = ɵɵdefineComponent({
- type: MyComp,
- selectors: [['my-comp']],
- factory: function MyComp_Factory() { return myComp = new MyComp(); },
- consts: 0,
- vars: 0,
- template: function MyComp_Template(rf: RenderFlags, ctx: MyComp) {},
- inputs: {names: 'names'}
- });
- }
-
- const directives = [MyComp];
-
- it('should support an array literal with a binding', () => {
- const e0_ff = (v: any) => ['Nancy', v, 'Bess'];
-
- /** */
- 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, 3, directives);
-
- const fixture = new ComponentFixture(App);
- fixture.component.customName = 'Carson';
- fixture.update();
- const firstArray = myComp !.names;
- expect(firstArray).toEqual(['Nancy', 'Carson', 'Bess']);
-
- fixture.update();
- expect(myComp !.names).toEqual(['Nancy', 'Carson', 'Bess']);
- expect(firstArray).toBe(myComp !.names);
-
- fixture.component.customName = 'Hannah';
- fixture.update();
- expect(myComp !.names).toEqual(['Nancy', 'Hannah', 'Bess']);
-
- // Identity must change if binding changes
- expect(firstArray).not.toBe(myComp !.names);
-
- // 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'];
- fixture.update();
- expect(myComp !.names).toEqual(['should not be overwritten']);
- });
-
- it('should support array literals in dynamic views', () => {
- const e0_ff = (v: any) => ['Nancy', v, 'Bess'];
-
- function IfTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelement(0, 'my-comp');
- }
- if (rf & RenderFlags.Update) {
- const comp = ɵɵnextContext();
- ɵɵelementProperty(0, 'names', ɵɵbind(ɵɵpureFunction1(1, e0_ff, comp.customName)));
- }
- }
-
- /**
- *
- */
- const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵtemplate(
- 0, IfTemplate, 1, 3, 'my-comp',
- [AttributeMarker.Bindings, 'names', AttributeMarker.Template, 'ngIf']);
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(0, 'ngIf', ɵɵbind(ctx.showing));
- }
- }, 1, 1, [MyComp, NgIf]);
-
- const fixture = new ComponentFixture(App);
- fixture.component.showing = true;
- fixture.component.customName = 'Carson';
- fixture.update();
-
- expect(myComp !.names).toEqual(['Nancy', 'Carson', 'Bess']);
- });
-
- it('should support multiple array literals passed through to one node', () => {
- let manyPropComp: ManyPropComp;
-
- class ManyPropComp {
- // TODO(issue/24571): remove '!'.
- names1 !: string[];
- // TODO(issue/24571): remove '!'.
- names2 !: string[];
-
- static ngComponentDef = ɵɵdefineComponent({
- type: ManyPropComp,
- selectors: [['many-prop-comp']],
- factory: function ManyPropComp_Factory() { return manyPropComp = new ManyPropComp(); },
- consts: 0,
- vars: 0,
- template: function ManyPropComp_Template(rf: RenderFlags, ctx: ManyPropComp) {},
- inputs: {names1: 'names1', names2: 'names2'}
- });
- }
-
- const e0_ff = (v: any) => ['Nancy', v];
- const e0_ff_1 = (v: any) => [v];
-
- /**
- *
- *
- */
- const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelement(0, 'many-prop-comp');
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(0, 'names1', ɵɵbind(ɵɵpureFunction1(2, e0_ff, ctx.customName)));
- ɵɵelementProperty(0, 'names2', ɵɵbind(ɵɵpureFunction1(4, e0_ff_1, ctx.customName2)));
- }
- }, 1, 6, [ManyPropComp]);
-
- 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']);
-
- fixture.component.customName = 'George';
- fixture.component.customName2 = 'Carson';
- fixture.update();
- expect(manyPropComp !.names1).toEqual(['Nancy', 'George']);
- expect(manyPropComp !.names2).toEqual(['Carson']);
- });
-
- it('should support an array literals inside fn calls', () => {
- let myComps: MyComp[] = [];
-
- const e0_ff = (v: any) => ['Nancy', v];
-
- /** */
- class ParentComp {
- customName = 'Bess';
-
- someFn(arr: string[]): string[] {
- arr[0] = arr[0].toUpperCase();
- return arr;
- }
-
- static ngComponentDef = ɵɵdefineComponent({
- type: ParentComp,
- selectors: [['parent-comp']],
- factory: () => new ParentComp(),
- consts: 1,
- vars: 3,
- template: function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'my-comp');
- myComps.push(getDirectiveOnNode(0));
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(
- 0, 'names', ɵɵbind(ctx.someFn(ɵɵpureFunction1(1, e0_ff, ctx.customName))));
- }
- },
- directives: directives
- });
- }
-
- const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelement(0, 'parent-comp');
- ɵɵelement(1, 'parent-comp');
- }
- }, 2, 0, [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);
-
- fixture.update();
- expect(firstArray).toEqual(['NANCY', 'Bess']);
- expect(secondArray).toEqual(['NANCY', 'Bess']);
- expect(firstArray).toBe(myComps[0].names);
- expect(secondArray).toBe(myComps[1].names);
- });
-
- it('should support an array literal with more than 1 binding', () => {
- const e0_ff = (v1: any, v2: any) => ['Nancy', v1, 'Bess', v2];
-
- /** */
- 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, 4, 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']);
-
- fixture.update();
- expect(myComp !.names).toEqual(['Nancy', 'Carson', 'Bess', 'Hannah']);
- expect(firstArray).toBe(myComp !.names);
-
- fixture.component.customName = 'George';
- fixture.update();
- expect(myComp !.names).toEqual(['Nancy', 'George', 'Bess', 'Hannah']);
- expect(firstArray).not.toBe(myComp !.names);
-
- 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'];
- fixture.update();
- expect(myComp !.names).toEqual(['should not be overwritten']);
- });
-
- it('should work up to 8 bindings', () => {
- let f3Comp: MyComp;
- let f4Comp: MyComp;
- let f5Comp: MyComp;
- let f6Comp: MyComp;
- let f7Comp: MyComp;
- let f8Comp: MyComp;
+import {ɵɵpureFunction2} from '../../src/render3/pure_function';
+import {getDirectiveOnNode, renderToHtml} from '../../test/render3/render_util';
- const e0_ff = (v1: any, v2: any, v3: any) => ['a', 'b', 'c', 'd', 'e', v1, v2, v3];
- const e2_ff = (v1: any, v2: any, v3: any, v4: any) => ['a', 'b', 'c', 'd', v1, v2, v3, v4];
- const e4_ff =
- (v1: any, v2: any, v3: any, v4: any, v5: any) => ['a', 'b', 'c', v1, v2, v3, v4, v5];
- const e6_ff =
- (v1: any, v2: any, v3: any, v4: any, v5: any,
- v6: any) => ['a', 'b', v1, v2, v3, v4, v5, v6];
- const e8_ff =
- (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any,
- v7: any) => ['a', v1, v2, v3, v4, v5, v6, v7];
- const e10_ff =
- (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any,
- v8: any) => [v1, v2, v3, v4, v5, v6, v7, v8];
-
- function Template(rf: RenderFlags, c: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'my-comp');
- f3Comp = getDirectiveOnNode(0);
- ɵɵelementEnd();
- ɵɵelementStart(1, 'my-comp');
- f4Comp = getDirectiveOnNode(1);
- ɵɵelementEnd();
- ɵɵelementStart(2, 'my-comp');
- f5Comp = getDirectiveOnNode(2);
- ɵɵelementEnd();
- ɵɵelementStart(3, 'my-comp');
- f6Comp = getDirectiveOnNode(3);
- ɵɵelementEnd();
- ɵɵelementStart(4, 'my-comp');
- f7Comp = getDirectiveOnNode(4);
- ɵɵelementEnd();
- ɵɵelementStart(5, 'my-comp');
- f8Comp = getDirectiveOnNode(5);
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(0, 'names', ɵɵbind(ɵɵpureFunction3(6, e0_ff, c[5], c[6], c[7])));
- ɵɵelementProperty(1, 'names', ɵɵbind(ɵɵpureFunction4(10, e2_ff, c[4], c[5], c[6], c[7])));
- ɵɵelementProperty(
- 2, 'names', ɵɵbind(ɵɵpureFunction5(15, e4_ff, c[3], c[4], c[5], c[6], c[7])));
- ɵɵelementProperty(
- 3, 'names', ɵɵbind(ɵɵpureFunction6(21, e6_ff, c[2], c[3], c[4], c[5], c[6], c[7])));
- ɵɵelementProperty(
- 4, 'names',
- ɵɵbind(ɵɵpureFunction7(28, e8_ff, c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
- ɵɵelementProperty(
- 5, 'names',
- ɵɵbind(ɵɵpureFunction8(36, e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
- }
- }
-
- renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], 6, 45, 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']);
- expect(f6Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
- 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'], 6, 45, 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']);
- expect(f6Comp !.names).toEqual(['a', 'b', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1']);
- 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'], 6, 45, 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']);
- expect(f6Comp !.names).toEqual(['a', 'b', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2']);
- expect(f7Comp !.names).toEqual(['a', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2']);
- expect(f8Comp !.names).toEqual(['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h2']);
- });
-
- it('should work with pureFunctionV for 9+ bindings', () => {
- const e0_ff =
- (v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any,
- v8: any) => ['start', v0, v1, v2, v3, v4, v5, v6, v7, v8, 'end'];
- const e0_ff_1 = (v: any) => `modified_${v}`;
-
- /**
- *
- *
- */
- function Template(rf: RenderFlags, c: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelement(0, 'my-comp');
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(
- 0, 'names', ɵɵbind(ɵɵpureFunctionV(3, e0_ff, [
- c[0], c[1], c[2], c[3], ɵɵpureFunction1(1, e0_ff_1, c[4]), c[5], c[6], c[7], c[8]
- ])));
- }
- }
-
- renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], 1, 13, directives);
- expect(myComp !.names).toEqual([
- 'start', 'a', 'b', 'c', 'd', 'modified_e', 'f', 'g', 'h', 'i', 'end'
- ]);
-
- renderToHtml(Template, ['a1', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], 1, 13, 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'], 1, 13, directives);
- expect(myComp !.names).toEqual([
- 'start', 'a1', 'b', 'c', 'd', 'modified_e5', 'f', 'g', 'h', 'i', 'end'
- ]);
- });
-
-});
describe('object literals', () => {
let objectComp: ObjectComp;
@@ -393,114 +25,15 @@ describe('object literals', () => {
factory: function ObjectComp_Factory() { return objectComp = new ObjectComp(); },
consts: 0,
vars: 1,
- template: function ObjectComp_Template(rf: RenderFlags, ctx: ObjectComp) {},
+ template: function ObjectComp_Template() {},
inputs: {config: 'config'}
});
}
const defs = [ObjectComp];
- it('should support an object literal', () => {
- const e0_ff = (v: any) => { return {duration: 500, animation: v}; };
-
- /** */
- 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, 3, defs);
-
- const fixture = new ComponentFixture(App);
- fixture.component.name = 'slide';
- fixture.update();
- const firstObj = objectComp !.config;
- expect(objectComp !.config).toEqual({duration: 500, animation: 'slide'});
-
- fixture.update();
- expect(objectComp !.config).toEqual({duration: 500, animation: 'slide'});
- expect(firstObj).toBe(objectComp !.config);
-
- fixture.component.name = 'tap';
- fixture.update();
- expect(objectComp !.config).toEqual({duration: 500, animation: 'tap'});
-
- // Identity must change if binding changes
- expect(firstObj).not.toBe(objectComp !.config);
- });
-
- it('should support expressions nested deeply in object/array literals', () => {
- const e0_ff = (v1: any, v2: any) => { return {animation: v1, actions: v2}; };
- const e0_ff_1 = (v: any) => [{opacity: 0, duration: 0}, v];
- const e0_ff_2 = (v: any) => { return {opacity: 1, duration: v}; };
-
- /**
- *
- *
- */
- 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(ɵɵpureFunction2(
- 5, e0_ff, ctx.name,
- ɵɵpureFunction1(3, e0_ff_1, ɵɵpureFunction1(1, e0_ff_2, ctx.duration)))));
- }
- }, 1, 8, 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;
-
- fixture.update();
- expect(objectComp !.config).toEqual({
- animation: 'slide',
- actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 100}]
- });
- expect(objectComp !.config).toBe(firstConfig);
-
- 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);
-
- fixture.component.name = 'tap';
- fixture.update();
- expect(objectComp !.config).toEqual({
- animation: 'tap',
- actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 50}]
- });
-
- 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}]
- });
-
- // 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'];
- fixture.update();
- expect(objectComp !.config).toEqual(['should not be overwritten']);
- });
-
+ // NOTE: This test cannot be ported to acceptance tests with TestBed because
+ // the syntax is still unsupported.
it('should support multiple view instances with multiple bindings', () => {
let objectComps: ObjectComp[] = [];