test(ivy): pure function acceptance tests (#30406)
- Moves tests related to the pureFunction instructions from render3 to acceptance tests - Leaves behind one test for in-template javascript that is not supported syntax yet PR Close #30406
This commit is contained in:
parent
7dad3284e3
commit
7569a2e0d9
|
@ -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: `
|
||||
<my-comp [names]="['Nancy', customName, 'Bess']"></my-comp>
|
||||
`,
|
||||
})
|
||||
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: `
|
||||
<my-comp *ngIf="showing" [names]="['Nancy', customName, 'Bess']"></my-comp>
|
||||
`,
|
||||
})
|
||||
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: `
|
||||
<many-prop-comp [names1]="['Nancy', customName]" [names2]="[customName2]">
|
||||
</many-prop-comp>
|
||||
`,
|
||||
})
|
||||
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: `
|
||||
<my-comp [names]="someFn(['Nancy', customName])"></my-comp>
|
||||
`
|
||||
})
|
||||
class ParentComp {
|
||||
customName = 'Bess';
|
||||
|
||||
someFn(arr: string[]): string[] {
|
||||
arr[0] = arr[0].toUpperCase();
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<parent-comp></parent-comp>
|
||||
<parent-comp></parent-comp>
|
||||
`
|
||||
})
|
||||
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: `
|
||||
<my-comp *ngIf="showing" [names]="['Nancy', customName, 'Bess', customName2]"></my-comp>
|
||||
`,
|
||||
})
|
||||
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: `
|
||||
<my-comp [names]="['a', 'b', 'c', 'd', 'e', 'f', 'g', v8]"></my-comp>
|
||||
<my-comp [names]="['a', 'b', 'c', 'd', 'e', 'f', v7, v8]"></my-comp>
|
||||
<my-comp [names]="['a', 'b', 'c', 'd', 'e', v6, v7, v8]"></my-comp>
|
||||
<my-comp [names]="['a', 'b', 'c', 'd', v5, v6, v7, v8]"></my-comp>
|
||||
<my-comp [names]="['a', 'b', 'c', v4, v5, v6, v7, v8]"></my-comp>
|
||||
<my-comp [names]="['a', 'b', v3, v4, v5, v6, v7, v8]"></my-comp>
|
||||
<my-comp [names]="['a', v2, v3, v4, v5, v6, v7, v8]"></my-comp>
|
||||
<my-comp [names]="[v1, v2, v3, v4, v5, v6, v7, v8]"></my-comp>
|
||||
`
|
||||
})
|
||||
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: `
|
||||
<my-comp [names]="['start', v0, v1, v2, v3, 'modified_' + v4, v5, v6, v7, v8, 'end']">
|
||||
</my-comp>
|
||||
`
|
||||
})
|
||||
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: '<object-comp [config]="{duration: 500, animation: name}"></object-comp>',
|
||||
})
|
||||
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: `
|
||||
<object-comp [config]="{animation: name, actions: [{ opacity: 0, duration: 0}, {opacity: 1,
|
||||
duration: duration }]}">
|
||||
</object-comp>
|
||||
`,
|
||||
})
|
||||
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: `
|
||||
<object-comp *ngFor="let config of configs" [config]="config">
|
||||
</object-comp>
|
||||
`,
|
||||
})
|
||||
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});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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'];
|
||||
|
||||
/** <my-comp [names]="['Nancy', customName, 'Bess']"></my-comp> */
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <my-comp *ngIf="showing" [names]="['Nancy', customName, 'Bess']"></my-comp>
|
||||
*/
|
||||
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];
|
||||
|
||||
/**
|
||||
* <many-prop-comp [names1]="['Nancy', customName]" [names2]="[customName2]">
|
||||
* </many-prop-comp>
|
||||
*/
|
||||
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];
|
||||
|
||||
/** <my-comp [names]="someFn(['Nancy', customName])"></my-comp> */
|
||||
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];
|
||||
|
||||
/** <my-comp [names]="['Nancy', customName, 'Bess', customName2]"></my-comp> */
|
||||
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}`;
|
||||
|
||||
/**
|
||||
* <my-comp [names]="['start', v0, v1, v2, v3, `modified_${v4}`, v5, v6, v7, v8, 'end']">
|
||||
* </my-comp>
|
||||
*/
|
||||
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}; };
|
||||
|
||||
/** <object-comp [config]="{duration: 500, animation: name}"></object-comp> */
|
||||
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}; };
|
||||
|
||||
/**
|
||||
* <object-comp [config]="{animation: name, actions: [{ opacity: 0, duration: 0}, {opacity: 1,
|
||||
* duration: duration }]}">
|
||||
* </object-comp>
|
||||
*/
|
||||
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[] = [];
|
||||
|
||||
|
|
Loading…
Reference in New Issue