test(core): make tests more resilient to header offset changes (#41883)

Updates some tests where values related to the `HEADER_OFFSET` are hardcoded, causing them to break when the offset is updated. This comes up once in a while during refactorings and these changes should save us some time in the future.

PR Close #41883
This commit is contained in:
Kristiyan Kostadinov 2021-04-29 18:22:59 +02:00 committed by Misko Hevery
parent 77d920e461
commit 36c7bebe40
5 changed files with 313 additions and 260 deletions

View File

@ -652,12 +652,15 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
const lViewDebug = lView.debug!;
fixture.detectChanges();
expect((fixture.nativeElement as Element).textContent).toEqual('just now');
expect(lViewDebug.nodes.map(toTypeContent)).toEqual(['IcuContainer(<!--ICU 21:0-->)']);
expect(lViewDebug.nodes.map(toTypeContent)).toEqual([
`IcuContainer(<!--ICU ${HEADER_OFFSET + 0}:0-->)`
]);
// We want to ensure that the ICU container does not have any content!
// This is because the content is instance dependent and therefore can't be shared
// across `TNode`s.
expect(lViewDebug.nodes[0].children.map(toTypeContent)).toEqual([]);
expect(fixture.nativeElement.innerHTML).toEqual('just now<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML)
.toEqual(`just now<!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
it('should support multiple ICUs', () => {
@ -674,15 +677,16 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
`);
const lView = getComponentLView(fixture.componentInstance);
expect(lView.debug!.nodes.map(toTypeContent)).toEqual([
'IcuContainer(<!--ICU 21:0-->)',
'IcuContainer(<!--ICU 22:0-->)',
`IcuContainer(<!--ICU ${HEADER_OFFSET + 0}:0-->)`,
`IcuContainer(<!--ICU ${HEADER_OFFSET + 1}:0-->)`,
]);
// We want to ensure that the ICU container does not have any content!
// This is because the content is instance dependent and therefore can't be shared
// across `TNode`s.
expect(lView.debug!.nodes[0].children.map(toTypeContent)).toEqual([]);
expect(fixture.nativeElement.innerHTML)
.toEqual('just now<!--ICU 21:0-->Mr. Angular<!--ICU 22:0-->');
.toEqual(`just now<!--ICU ${HEADER_OFFSET + 0}:0-->Mr. Angular<!--ICU ${
HEADER_OFFSET + 1}:0-->`);
});
});
});
@ -778,19 +782,21 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
other {({{name}})}
}</div>`);
expect(fixture.nativeElement.innerHTML)
.toEqual(`<div>aucun <b>email</b>!<!--ICU 22:0--> - (Angular)<!--ICU 22:3--></div>`);
.toEqual(`<div>aucun <b>email</b>!<!--ICU ${HEADER_OFFSET + 1}:0--> - (Angular)<!--ICU ${
HEADER_OFFSET + 1}:3--></div>`);
fixture.componentRef.instance.count = 4;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(
`<div>4 <span title="Angular">emails</span><!--ICU 22:0--> - (Angular)<!--ICU 22:3--></div>`);
.toEqual(`<div>4 <span title="Angular">emails</span><!--ICU ${
HEADER_OFFSET + 1}:0--> - (Angular)<!--ICU ${HEADER_OFFSET + 1}:3--></div>`);
fixture.componentRef.instance.count = 0;
fixture.componentRef.instance.name = 'John';
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(`<div>aucun <b>email</b>!<!--ICU 22:0--> - (John)<!--ICU 22:3--></div>`);
.toEqual(`<div>aucun <b>email</b>!<!--ICU ${HEADER_OFFSET + 1}:0--> - (John)<!--ICU ${
HEADER_OFFSET + 1}:3--></div>`);
});
it('with custom interpolation config', () => {
@ -829,9 +835,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
expect(fixture.nativeElement.innerHTML)
.toEqual(
`<div>` +
`<span>aucun <b>email</b>!<!--ICU 22:0--></span>` +
`<span>aucun <b>email</b>!<!--ICU ${HEADER_OFFSET + 1}:0--></span>` +
` - ` +
`<span>(Angular)<!--ICU 22:3--></span>` +
`<span>(Angular)<!--ICU ${HEADER_OFFSET + 1}:3--></span>` +
`</div>`);
fixture.componentRef.instance.count = 4;
@ -839,9 +845,10 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
expect(fixture.nativeElement.innerHTML)
.toEqual(
`<div>` +
`<span>4 <span title="Angular">emails</span><!--ICU 22:0--></span>` +
`<span>4 <span title="Angular">emails</span><!--ICU ${
HEADER_OFFSET + 1}:0--></span>` +
` - ` +
`<span>(Angular)<!--ICU 22:3--></span>` +
`<span>(Angular)<!--ICU ${HEADER_OFFSET + 1}:3--></span>` +
`</div>`);
fixture.componentRef.instance.count = 0;
@ -850,9 +857,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
expect(fixture.nativeElement.innerHTML)
.toEqual(
`<div>` +
`<span>aucun <b>email</b>!<!--ICU 22:0--></span>` +
`<span>aucun <b>email</b>!<!--ICU ${HEADER_OFFSET + 1}:0--></span>` +
` - ` +
`<span>(John)<!--ICU 22:3--></span>` +
`<span>(John)<!--ICU ${HEADER_OFFSET + 1}:3--></span>` +
`</div>`);
});
@ -867,7 +874,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
other {({{name}})}
}</span></div>`);
expect(fixture.nativeElement.innerHTML)
.toEqual(`<div><span>(Angular)<!--ICU 21:0--></span><!--bindings={
.toEqual(`<div><span>(Angular)<!--ICU ${HEADER_OFFSET + 0}:0--></span><!--bindings={
"ng-reflect-ng-if": "true"
}--></div>`);
@ -887,7 +894,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
other {({{name}})}
}</ng-container>`);
expect(fixture.nativeElement.innerHTML)
.toEqual(`(Angular)<!--ICU 22:0--><!--ng-container-->`);
.toEqual(`(Angular)<!--ICU ${HEADER_OFFSET + 1}:0--><!--ng-container-->`);
});
it('inside <ng-template>', () => {
@ -922,12 +929,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
other {animals}
}!}
}</div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div>zero<!--ICU 22:1--></div>`);
expect(fixture.nativeElement.innerHTML)
.toEqual(`<div>zero<!--ICU ${HEADER_OFFSET + 1}:1--></div>`);
fixture.componentRef.instance.count = 4;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(`<div>4 animaux<!--nested ICU 0-->!<!--ICU 22:1--></div>`);
.toEqual(`<div>4 animaux<!--nested ICU 0-->!<!--ICU ${HEADER_OFFSET + 1}:1--></div>`);
});
it('nested with interpolations in "other" blocks', () => {
@ -947,16 +955,18 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
}!}
other {other - {{count}}}
}</div>`);
expect(fixture.nativeElement.innerHTML).toEqual(`<div>zero<!--ICU 22:1--></div>`);
expect(fixture.nativeElement.innerHTML)
.toEqual(`<div>zero<!--ICU ${HEADER_OFFSET + 1}:1--></div>`);
fixture.componentRef.instance.count = 2;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(`<div>2 animaux<!--nested ICU 0-->!<!--ICU 22:1--></div>`);
.toEqual(`<div>2 animaux<!--nested ICU 0-->!<!--ICU ${HEADER_OFFSET + 1}:1--></div>`);
fixture.componentRef.instance.count = 4;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual(`<div>autre - 4<!--ICU 22:1--></div>`);
expect(fixture.nativeElement.innerHTML)
.toEqual(`<div>autre - 4<!--ICU ${HEADER_OFFSET + 1}:1--></div>`);
});
it('should return the correct plural form for ICU expressions when using "ro" locale', () => {
@ -989,31 +999,34 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
=other {lots of emails}
}`);
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML).toEqual(`no email<!--ICU ${HEADER_OFFSET + 0}:0-->`);
// Change detection cycle, no model changes
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML).toEqual(`no email<!--ICU ${HEADER_OFFSET + 0}:0-->`);
fixture.componentInstance.count = 3;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML)
.toEqual(`a few emails<!--ICU ${HEADER_OFFSET + 0}:0-->`);
fixture.componentInstance.count = 1;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML).toEqual(`one email<!--ICU ${HEADER_OFFSET + 0}:0-->`);
fixture.componentInstance.count = 10;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML)
.toEqual(`a few emails<!--ICU ${HEADER_OFFSET + 0}:0-->`);
fixture.componentInstance.count = 20;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML)
.toEqual(`lots of emails<!--ICU ${HEADER_OFFSET + 0}:0-->`);
fixture.componentInstance.count = 0;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML).toEqual(`no email<!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
it(`should return the correct plural form for ICU expressions when using "es" locale`, () => {
@ -1040,31 +1053,34 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
=other {lots of emails}
}`);
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML).toEqual(`no email<!--ICU ${HEADER_OFFSET + 0}:0-->`);
// Change detection cycle, no model changes
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML).toEqual(`no email<!--ICU ${HEADER_OFFSET + 0}:0-->`);
fixture.componentInstance.count = 3;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML)
.toEqual(`lots of emails<!--ICU ${HEADER_OFFSET + 0}:0-->`);
fixture.componentInstance.count = 1;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML).toEqual(`one email<!--ICU ${HEADER_OFFSET + 0}:0-->`);
fixture.componentInstance.count = 10;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML)
.toEqual(`lots of emails<!--ICU ${HEADER_OFFSET + 0}:0-->`);
fixture.componentInstance.count = 20;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML)
.toEqual(`lots of emails<!--ICU ${HEADER_OFFSET + 0}:0-->`);
fixture.componentInstance.count = 0;
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 21:0-->');
expect(fixture.nativeElement.innerHTML).toEqual(`no email<!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
it('projection', () => {
@ -1159,12 +1175,14 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.innerHTML)
.toContain('<my-cmp><div>ONE<!--ICU 22:0--></div><!--container--></my-cmp>');
.toContain(
`<my-cmp><div>ONE<!--ICU ${HEADER_OFFSET + 1}:0--></div><!--container--></my-cmp>`);
fixture.componentRef.instance.count = 2;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.innerHTML)
.toContain('<my-cmp><div>OTHER<!--ICU 22:0--></div><!--container--></my-cmp>');
.toContain(
`<my-cmp><div>OTHER<!--ICU ${HEADER_OFFSET + 1}:0--></div><!--container--></my-cmp>`);
// destroy component
fixture.componentInstance.condition = false;
@ -1176,7 +1194,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
fixture.componentInstance.count = 1;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.innerHTML)
.toContain('<my-cmp><div>ONE<!--ICU 22:0--></div><!--container--></my-cmp>');
.toContain(
`<my-cmp><div>ONE<!--ICU ${HEADER_OFFSET + 1}:0--></div><!--container--></my-cmp>`);
});
it('with nested ICU expression and inside a container when creating a view via vcr.createEmbeddedView',
@ -1247,13 +1266,14 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
dir!.attachEmbeddedView();
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.innerHTML)
.toBe(
'<my-cmp><div>2 animals<!--nested ICU 0-->!<!--ICU 22:1--></div><!--container--></my-cmp>');
.toBe(`<my-cmp><div>2 animals<!--nested ICU 0-->!<!--ICU ${
HEADER_OFFSET + 1}:1--></div><!--container--></my-cmp>`);
fixture.componentRef.instance.count = 1;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.innerHTML)
.toBe('<my-cmp><div>ONE<!--ICU 22:1--></div><!--container--></my-cmp>');
.toBe(`<my-cmp><div>ONE<!--ICU ${
HEADER_OFFSET + 1}:1--></div><!--container--></my-cmp>`);
});
it('with nested containers', () => {
@ -2356,14 +2376,14 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
const fixture = TestBed.createComponent(Parent);
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(
`<child><div>Contenu enfant et projection depuis Parent<!--ICU 22:0--></div></child>`);
.toEqual(`<child><div>Contenu enfant et projection depuis Parent<!--ICU ${
HEADER_OFFSET + 1}:0--></div></child>`);
fixture.componentRef.instance.name = 'angular';
fixture.detectChanges();
expect(fixture.nativeElement.innerHTML)
.toEqual(
`<child><div>Contenu enfant et projection depuis Angular<!--ICU 22:0--></div></child>`);
.toEqual(`<child><div>Contenu enfant et projection depuis Angular<!--ICU ${
HEADER_OFFSET + 1}:0--></div></child>`);
});
it(`shouldn't project deleted projections in i18n blocks`, () => {

View File

@ -9,6 +9,7 @@
import {addTNodeAndUpdateInsertBeforeIndex} from '@angular/core/src/render3/i18n/i18n_insert_before_index';
import {createTNode} from '@angular/core/src/render3/instructions/shared';
import {TNode, TNodeType} from '@angular/core/src/render3/interfaces/node';
import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view';
import {matchTNode} from '../matchers';
@ -29,9 +30,9 @@ describe('addTNodeAndUpdateInsertBeforeIndex', () => {
it('should add first node', () => {
const previousTNodes: TNode[] = [];
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(21));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(HEADER_OFFSET + 0));
expect(previousTNodes).toEqual([
matchTNode({index: 21, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 0, insertBeforeIndex: null}),
]);
});
@ -39,14 +40,15 @@ describe('addTNodeAndUpdateInsertBeforeIndex', () => {
describe('whose index is greater than those already there', () => {
it('should not update the `insertBeforeIndex` values', () => {
const previousTNodes: TNode[] = [
tPlaceholderElementNode(21),
tPlaceholderElementNode(22),
tPlaceholderElementNode(HEADER_OFFSET + 0),
tPlaceholderElementNode(HEADER_OFFSET + 1),
];
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(23));
addTNodeAndUpdateInsertBeforeIndex(
previousTNodes, tPlaceholderElementNode(HEADER_OFFSET + 2));
expect(previousTNodes).toEqual([
matchTNode({index: 21, insertBeforeIndex: null}),
matchTNode({index: 22, insertBeforeIndex: null}),
matchTNode({index: 23, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 0, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 1, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 2, insertBeforeIndex: null}),
]);
});
});
@ -54,44 +56,47 @@ describe('addTNodeAndUpdateInsertBeforeIndex', () => {
describe('whose index is smaller than current nodes', () => {
it('should update the previous insertBeforeIndex', () => {
const previousTNodes: TNode[] = [
tPlaceholderElementNode(22),
tPlaceholderElementNode(23),
tPlaceholderElementNode(HEADER_OFFSET + 1),
tPlaceholderElementNode(HEADER_OFFSET + 2),
];
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(21));
addTNodeAndUpdateInsertBeforeIndex(
previousTNodes, tPlaceholderElementNode(HEADER_OFFSET + 0));
expect(previousTNodes).toEqual([
matchTNode({index: 22, insertBeforeIndex: 21}),
matchTNode({index: 23, insertBeforeIndex: 21}),
matchTNode({index: 21, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 1, insertBeforeIndex: HEADER_OFFSET + 0}),
matchTNode({index: HEADER_OFFSET + 2, insertBeforeIndex: HEADER_OFFSET + 0}),
matchTNode({index: HEADER_OFFSET + 0, insertBeforeIndex: null}),
]);
});
it('should not update the previous insertBeforeIndex if it is already set', () => {
const previousTNodes: TNode[] = [
tPlaceholderElementNode(23, 22),
tPlaceholderElementNode(24, 22),
tPlaceholderElementNode(22),
tPlaceholderElementNode(HEADER_OFFSET + 2, HEADER_OFFSET + 1),
tPlaceholderElementNode(HEADER_OFFSET + 3, HEADER_OFFSET + 1),
tPlaceholderElementNode(HEADER_OFFSET + 1),
];
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(21));
addTNodeAndUpdateInsertBeforeIndex(
previousTNodes, tPlaceholderElementNode(HEADER_OFFSET + 0));
expect(previousTNodes).toEqual([
matchTNode({index: 23, insertBeforeIndex: 22}),
matchTNode({index: 24, insertBeforeIndex: 22}),
matchTNode({index: 22, insertBeforeIndex: 21}),
matchTNode({index: 21, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 2, insertBeforeIndex: HEADER_OFFSET + 1}),
matchTNode({index: HEADER_OFFSET + 3, insertBeforeIndex: HEADER_OFFSET + 1}),
matchTNode({index: HEADER_OFFSET + 1, insertBeforeIndex: HEADER_OFFSET + 0}),
matchTNode({index: HEADER_OFFSET + 0, insertBeforeIndex: null}),
]);
});
it('should not update the previous insertBeforeIndex if it is created after', () => {
const previousTNodes: TNode[] = [
tPlaceholderElementNode(26, 21),
tPlaceholderElementNode(27, 21),
tPlaceholderElementNode(21),
tPlaceholderElementNode(HEADER_OFFSET + 5, HEADER_OFFSET + 0),
tPlaceholderElementNode(HEADER_OFFSET + 6, HEADER_OFFSET + 0),
tPlaceholderElementNode(HEADER_OFFSET + 0),
];
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(24));
addTNodeAndUpdateInsertBeforeIndex(
previousTNodes, tPlaceholderElementNode(HEADER_OFFSET + 3));
expect(previousTNodes).toEqual([
matchTNode({index: 26, insertBeforeIndex: 21}),
matchTNode({index: 27, insertBeforeIndex: 21}),
matchTNode({index: 21, insertBeforeIndex: null}),
matchTNode({index: 24, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 5, insertBeforeIndex: HEADER_OFFSET + 0}),
matchTNode({index: HEADER_OFFSET + 6, insertBeforeIndex: HEADER_OFFSET + 0}),
matchTNode({index: HEADER_OFFSET + 0, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 3, insertBeforeIndex: null}),
]);
});
});
@ -101,14 +106,14 @@ describe('addTNodeAndUpdateInsertBeforeIndex', () => {
describe('whose index is greater than those already there', () => {
it('should not update the `insertBeforeIndex` values', () => {
const previousTNodes: TNode[] = [
tPlaceholderElementNode(21),
tPlaceholderElementNode(22),
tPlaceholderElementNode(HEADER_OFFSET + 0),
tPlaceholderElementNode(HEADER_OFFSET + 1),
];
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(23));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(HEADER_OFFSET + 2));
expect(previousTNodes).toEqual([
matchTNode({index: 21, insertBeforeIndex: 23}),
matchTNode({index: 22, insertBeforeIndex: 23}),
matchTNode({index: 23, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 0, insertBeforeIndex: HEADER_OFFSET + 2}),
matchTNode({index: HEADER_OFFSET + 1, insertBeforeIndex: HEADER_OFFSET + 2}),
matchTNode({index: HEADER_OFFSET + 2, insertBeforeIndex: null}),
]);
});
});
@ -116,44 +121,44 @@ describe('addTNodeAndUpdateInsertBeforeIndex', () => {
describe('whose index is smaller than current nodes', () => {
it('should update the previous insertBeforeIndex', () => {
const previousTNodes: TNode[] = [
tPlaceholderElementNode(22),
tPlaceholderElementNode(23),
tPlaceholderElementNode(HEADER_OFFSET + 1),
tPlaceholderElementNode(HEADER_OFFSET + 2),
];
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(21));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(HEADER_OFFSET + 0));
expect(previousTNodes).toEqual([
matchTNode({index: 22, insertBeforeIndex: 21}),
matchTNode({index: 23, insertBeforeIndex: 21}),
matchTNode({index: 21, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 1, insertBeforeIndex: HEADER_OFFSET + 0}),
matchTNode({index: HEADER_OFFSET + 2, insertBeforeIndex: HEADER_OFFSET + 0}),
matchTNode({index: HEADER_OFFSET + 0, insertBeforeIndex: null}),
]);
});
it('should not update the previous insertBeforeIndex if it is already set', () => {
const previousTNodes: TNode[] = [
tPlaceholderElementNode(23, 22),
tPlaceholderElementNode(24, 22),
tPlaceholderElementNode(22),
tPlaceholderElementNode(HEADER_OFFSET + 2, HEADER_OFFSET + 1),
tPlaceholderElementNode(HEADER_OFFSET + 3, HEADER_OFFSET + 1),
tPlaceholderElementNode(HEADER_OFFSET + 1),
];
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(21));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(HEADER_OFFSET + 0));
expect(previousTNodes).toEqual([
matchTNode({index: 23, insertBeforeIndex: 22}),
matchTNode({index: 24, insertBeforeIndex: 22}),
matchTNode({index: 22, insertBeforeIndex: 21}),
matchTNode({index: 21, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 2, insertBeforeIndex: HEADER_OFFSET + 1}),
matchTNode({index: HEADER_OFFSET + 3, insertBeforeIndex: HEADER_OFFSET + 1}),
matchTNode({index: HEADER_OFFSET + 1, insertBeforeIndex: HEADER_OFFSET + 0}),
matchTNode({index: HEADER_OFFSET + 0, insertBeforeIndex: null}),
]);
});
it('should not update the previous insertBeforeIndex if it is created after', () => {
const previousTNodes: TNode[] = [
tPlaceholderElementNode(26, 21),
tPlaceholderElementNode(27, 21),
tPlaceholderElementNode(21),
tPlaceholderElementNode(HEADER_OFFSET + 5, HEADER_OFFSET + 0),
tPlaceholderElementNode(HEADER_OFFSET + 6, HEADER_OFFSET + 0),
tPlaceholderElementNode(HEADER_OFFSET + 0),
];
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(24));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(HEADER_OFFSET + 3));
expect(previousTNodes).toEqual([
matchTNode({index: 26, insertBeforeIndex: 21}),
matchTNode({index: 27, insertBeforeIndex: 21}),
matchTNode({index: 21, insertBeforeIndex: 24}),
matchTNode({index: 24, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 5, insertBeforeIndex: HEADER_OFFSET + 0}),
matchTNode({index: HEADER_OFFSET + 6, insertBeforeIndex: HEADER_OFFSET + 0}),
matchTNode({index: HEADER_OFFSET + 0, insertBeforeIndex: HEADER_OFFSET + 3}),
matchTNode({index: HEADER_OFFSET + 3, insertBeforeIndex: null}),
]);
});
});
@ -162,21 +167,27 @@ describe('addTNodeAndUpdateInsertBeforeIndex', () => {
describe('scenario', () => {
it('should rearrange the nodes', () => {
const previousTNodes: TNode[] = [];
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(23));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(29));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(25));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(26));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(30));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(24));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(28));
addTNodeAndUpdateInsertBeforeIndex(
previousTNodes, tPlaceholderElementNode(HEADER_OFFSET + 2));
addTNodeAndUpdateInsertBeforeIndex(
previousTNodes, tPlaceholderElementNode(HEADER_OFFSET + 8));
addTNodeAndUpdateInsertBeforeIndex(
previousTNodes, tPlaceholderElementNode(HEADER_OFFSET + 4));
addTNodeAndUpdateInsertBeforeIndex(
previousTNodes, tPlaceholderElementNode(HEADER_OFFSET + 5));
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(HEADER_OFFSET + 9));
addTNodeAndUpdateInsertBeforeIndex(
previousTNodes, tPlaceholderElementNode(HEADER_OFFSET + 3));
addTNodeAndUpdateInsertBeforeIndex(
previousTNodes, tPlaceholderElementNode(HEADER_OFFSET + 7));
expect(previousTNodes).toEqual([
matchTNode({index: 23, insertBeforeIndex: 30}),
matchTNode({index: 29, insertBeforeIndex: 25}),
matchTNode({index: 25, insertBeforeIndex: 30}),
matchTNode({index: 26, insertBeforeIndex: 30}),
matchTNode({index: 30, insertBeforeIndex: null}),
matchTNode({index: 24, insertBeforeIndex: null}),
matchTNode({index: 28, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 2, insertBeforeIndex: HEADER_OFFSET + 9}),
matchTNode({index: HEADER_OFFSET + 8, insertBeforeIndex: HEADER_OFFSET + 4}),
matchTNode({index: HEADER_OFFSET + 4, insertBeforeIndex: HEADER_OFFSET + 9}),
matchTNode({index: HEADER_OFFSET + 5, insertBeforeIndex: HEADER_OFFSET + 9}),
matchTNode({index: HEADER_OFFSET + 9, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 3, insertBeforeIndex: null}),
matchTNode({index: HEADER_OFFSET + 7, insertBeforeIndex: null}),
]);
});
});

View File

@ -11,7 +11,7 @@ import {applyCreateOpCodes} from '@angular/core/src/render3/i18n/i18n_apply';
import {i18nStartFirstCreatePass} from '@angular/core/src/render3/i18n/i18n_parse';
import {getTIcu} from '@angular/core/src/render3/i18n/i18n_util';
import {I18nUpdateOpCodes, IcuType, TI18n} from '@angular/core/src/render3/interfaces/i18n';
import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view';
import {HEADER_OFFSET, HOST} from '@angular/core/src/render3/interfaces/view';
import {expect} from '@angular/core/testing/src/testing_internal';
import {matchTI18n, matchTIcu} from '../matchers';
import {matchDebug} from '../utils';
@ -26,8 +26,8 @@ describe('i18n_parse', () => {
const tI18n = toT18n('some text');
expect(tI18n).toEqual(matchTI18n({
create: matchDebug([
'lView[23] = document.createText("some text");',
'parent.appendChild(lView[23]);',
`lView[${HEADER_OFFSET + 2}] = document.createText("some text");`,
`parent.appendChild(lView[${HEADER_OFFSET + 2}]);`,
]),
update: [] as unknown as I18nUpdateOpCodes,
}));
@ -57,30 +57,30 @@ describe('i18n_parse', () => {
}|after`);
expect(tI18n).toEqual(matchTI18n({
create: matchDebug([
'lView[23] = document.createText("before|");',
'parent.appendChild(lView[23]);',
'lView[24] = document.createComment("ICU 21:0");',
'parent.appendChild(lView[24]);',
'lView[28] = document.createText("|after");',
'parent.appendChild(lView[28]);',
`lView[${HEADER_OFFSET + 2}] = document.createText("before|");`,
`parent.appendChild(lView[${HEADER_OFFSET + 2}]);`,
`lView[${HEADER_OFFSET + 3}] = document.createComment("ICU ${HEADER_OFFSET + 0}:0");`,
`parent.appendChild(lView[${HEADER_OFFSET + 3}]);`,
`lView[${HEADER_OFFSET + 7}] = document.createText("|after");`,
`parent.appendChild(lView[${HEADER_OFFSET + 7}]);`,
]),
update: matchDebug([
'if (mask & 0b1) { icuSwitchCase(24, `${lView[i-1]}`); }',
`if (mask & 0b1) { icuSwitchCase(${HEADER_OFFSET + 3}, \`\${lView[i-1]}\`); }`,
])
}));
expect(getTIcu(fixture.tView, 24)).toEqual(matchTIcu({
expect(getTIcu(fixture.tView, HEADER_OFFSET + 3)).toEqual(matchTIcu({
type: IcuType.select,
anchorIdx: 24,
currentCaseLViewIndex: 25,
anchorIdx: HEADER_OFFSET + 3,
currentCaseLViewIndex: HEADER_OFFSET + 4,
cases: ['A', 'other'],
create: [
matchDebug([
'lView[26] = document.createTextNode("caseA")',
'(lView[0] as Element).appendChild(lView[26])'
`lView[${HEADER_OFFSET + 5}] = document.createTextNode("caseA")`,
`(lView[${HOST}] as Element).appendChild(lView[${HEADER_OFFSET + 5}])`
]),
matchDebug([
'lView[27] = document.createTextNode("otherCase")',
'(lView[0] as Element).appendChild(lView[27])',
`lView[${HEADER_OFFSET + 6}] = document.createTextNode("otherCase")`,
`(lView[${HOST}] as Element).appendChild(lView[${HEADER_OFFSET + 6}])`,
])
],
update: [
@ -88,29 +88,32 @@ describe('i18n_parse', () => {
matchDebug([]),
],
remove: [
matchDebug(['remove(lView[26])']),
matchDebug(['remove(lView[27])']),
matchDebug([`remove(lView[${HEADER_OFFSET + 5}])`]),
matchDebug([`remove(lView[${HEADER_OFFSET + 6}])`]),
],
}));
fixture.apply(() => {
applyCreateOpCodes(fixture.lView, tI18n.create, fixture.host, null);
expect(fixture.host.innerHTML).toEqual('before|<!--ICU 21:0-->|after');
expect(fixture.host.innerHTML).toEqual(`before|<!--ICU ${HEADER_OFFSET + 0}:0-->|after`);
});
fixture.apply(() => {
ɵɵi18nExp('A');
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
expect(fixture.host.innerHTML).toEqual('before|caseA<!--ICU 21:0-->|after');
ɵɵi18nApply(0);
expect(fixture.host.innerHTML)
.toEqual(`before|caseA<!--ICU ${HEADER_OFFSET + 0}:0-->|after`);
});
fixture.apply(() => {
ɵɵi18nExp('x');
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
expect(fixture.host.innerHTML).toEqual('before|otherCase<!--ICU 21:0-->|after');
ɵɵi18nApply(0);
expect(fixture.host.innerHTML)
.toEqual(`before|otherCase<!--ICU ${HEADER_OFFSET + 0}:0-->|after`);
});
fixture.apply(() => {
ɵɵi18nExp('A');
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
expect(fixture.host.innerHTML).toEqual('before|caseA<!--ICU 21:0-->|after');
ɵɵi18nApply(0);
expect(fixture.host.innerHTML)
.toEqual(`before|caseA<!--ICU ${HEADER_OFFSET + 0}:0-->|after`);
});
});
@ -122,23 +125,25 @@ describe('i18n_parse', () => {
}`);
fixture.apply(() => {
applyCreateOpCodes(fixture.lView, tI18n.create, fixture.host, null);
expect(fixture.host.innerHTML).toEqual('<!--ICU 21:0-->');
expect(fixture.host.innerHTML).toEqual(`<!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
fixture.apply(() => {
ɵɵi18nExp('A');
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
expect(fixture.host.innerHTML).toEqual('Hello <b>world<i>!</i></b><!--ICU 21:0-->');
ɵɵi18nApply(0);
expect(fixture.host.innerHTML)
.toEqual(`Hello <b>world<i>!</i></b><!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
fixture.apply(() => {
ɵɵi18nExp('x');
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
ɵɵi18nApply(0);
expect(fixture.host.innerHTML)
.toEqual('<div>nestedOther<!--nested ICU 0--></div><!--ICU 21:0-->');
.toEqual(`<div>nestedOther<!--nested ICU 0--></div><!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
fixture.apply(() => {
ɵɵi18nExp('A');
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
expect(fixture.host.innerHTML).toEqual('Hello <b>world<i>!</i></b><!--ICU 21:0-->');
ɵɵi18nApply(0);
expect(fixture.host.innerHTML)
.toEqual(`Hello <b>world<i>!</i></b><!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
});
@ -170,32 +175,32 @@ describe('i18n_parse', () => {
}`);
expect(tI18n).toEqual(matchTI18n({
create: matchDebug([
'lView[25] = document.createComment("ICU 21:0");',
'parent.appendChild(lView[25]);',
`lView[${HEADER_OFFSET + 4}] = document.createComment("ICU ${HEADER_OFFSET + 0}:0");`,
`parent.appendChild(lView[${HEADER_OFFSET + 4}]);`,
]),
update: matchDebug([
'if (mask & 0b1) { icuSwitchCase(25, `${lView[i-1]}`); }',
'if (mask & 0b10) { icuSwitchCase(28, `${lView[i-2]}`); }',
'if (mask & 0b100) { icuUpdateCase(28); }',
`if (mask & 0b1) { icuSwitchCase(${HEADER_OFFSET + 4}, \`\${lView[i-1]}\`); }`,
`if (mask & 0b10) { icuSwitchCase(${HEADER_OFFSET + 7}, \`\${lView[i-2]}\`); }`,
`if (mask & 0b100) { icuUpdateCase(${HEADER_OFFSET + 7}); }`,
]),
}));
expect(getTIcu(fixture.tView, 25)).toEqual(matchTIcu({
expect(getTIcu(fixture.tView, HEADER_OFFSET + 4)).toEqual(matchTIcu({
type: IcuType.select,
anchorIdx: 25,
currentCaseLViewIndex: 26,
anchorIdx: HEADER_OFFSET + 4,
currentCaseLViewIndex: HEADER_OFFSET + 5,
cases: ['A', 'other'],
create: [
matchDebug([
'lView[27] = document.createTextNode("parentA ")',
'(lView[0] as Element).appendChild(lView[27])',
'lView[28] = document.createComment("nested ICU 0")',
'(lView[0] as Element).appendChild(lView[28])',
'lView[32] = document.createTextNode("!")',
'(lView[0] as Element).appendChild(lView[32])',
`lView[${HEADER_OFFSET + 6}] = document.createTextNode("parentA ")`,
`(lView[${HOST}] as Element).appendChild(lView[${HEADER_OFFSET + 6}])`,
`lView[${HEADER_OFFSET + 7}] = document.createComment("nested ICU 0")`,
`(lView[${HOST}] as Element).appendChild(lView[${HEADER_OFFSET + 7}])`,
`lView[${HEADER_OFFSET + 11}] = document.createTextNode("!")`,
`(lView[${HOST}] as Element).appendChild(lView[${HEADER_OFFSET + 11}])`,
]),
matchDebug([
'lView[33] = document.createTextNode("parentOther")',
'(lView[0] as Element).appendChild(lView[33])',
`lView[${HEADER_OFFSET + 12}] = document.createTextNode("parentOther")`,
`(lView[${HOST}] as Element).appendChild(lView[${HEADER_OFFSET + 12}])`,
])
],
update: [
@ -204,76 +209,79 @@ describe('i18n_parse', () => {
],
remove: [
matchDebug([
'remove(lView[27])',
'removeNestedICU(28)',
'remove(lView[28])',
'remove(lView[32])',
`remove(lView[${HEADER_OFFSET + 6}])`,
`removeNestedICU(${HEADER_OFFSET + 7})`,
`remove(lView[${HEADER_OFFSET + 7}])`,
`remove(lView[${HEADER_OFFSET + 11}])`,
]),
matchDebug([
'remove(lView[33])',
`remove(lView[${HEADER_OFFSET + 12}])`,
])
],
}));
expect(getTIcu(fixture.tView, 28)).toEqual(matchTIcu({
expect(getTIcu(fixture.tView, HEADER_OFFSET + 7)).toEqual(matchTIcu({
type: IcuType.select,
anchorIdx: 28,
currentCaseLViewIndex: 29,
anchorIdx: HEADER_OFFSET + 7,
currentCaseLViewIndex: HEADER_OFFSET + 8,
cases: ['0', 'other'],
create: [
matchDebug([
'lView[30] = document.createTextNode("nested0")',
'(lView[0] as Element).appendChild(lView[30])'
`lView[${HEADER_OFFSET + 9}] = document.createTextNode("nested0")`,
`(lView[${HOST}] as Element).appendChild(lView[${HEADER_OFFSET + 9}])`
]),
matchDebug([
'lView[31] = document.createTextNode("")',
'(lView[0] as Element).appendChild(lView[31])',
`lView[${HEADER_OFFSET + 10}] = document.createTextNode("")`,
`(lView[${HOST}] as Element).appendChild(lView[${HEADER_OFFSET + 10}])`,
])
],
update: [
matchDebug([]),
matchDebug([
'if (mask & 0b100) { (lView[31] as Text).textContent = `${lView[i-3]}`; }',
`if (mask & 0b100) { (lView[${
HEADER_OFFSET + 10}] as Text).textContent = \`\${lView[i-3]}\`; }`,
]),
],
remove: [
matchDebug(['remove(lView[30])']),
matchDebug(['remove(lView[31])']),
matchDebug([`remove(lView[${HEADER_OFFSET + 9}])`]),
matchDebug([`remove(lView[${HEADER_OFFSET + 10}])`]),
],
}));
fixture.apply(() => {
applyCreateOpCodes(fixture.lView, tI18n.create, fixture.host, null);
expect(fixture.host.innerHTML).toEqual('<!--ICU 21:0-->');
expect(fixture.host.innerHTML).toEqual(`<!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
fixture.apply(() => {
ɵɵi18nExp('A');
ɵɵi18nExp('0');
ɵɵi18nExp('value1');
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
ɵɵi18nApply(0);
expect(fixture.host.innerHTML)
.toEqual('parentA nested0<!--nested ICU 0-->!<!--ICU 21:0-->');
.toEqual(`parentA nested0<!--nested ICU 0-->!<!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
fixture.apply(() => {
ɵɵi18nExp('A');
ɵɵi18nExp('x');
ɵɵi18nExp('value1');
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
expect(fixture.host.innerHTML).toEqual('parentA value1<!--nested ICU 0-->!<!--ICU 21:0-->');
ɵɵi18nApply(0);
expect(fixture.host.innerHTML)
.toEqual(`parentA value1<!--nested ICU 0-->!<!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
fixture.apply(() => {
ɵɵi18nExp('x');
ɵɵi18nExp('x');
ɵɵi18nExp('value2');
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
expect(fixture.host.innerHTML).toEqual('parentOther<!--ICU 21:0-->');
ɵɵi18nApply(0);
expect(fixture.host.innerHTML).toEqual(`parentOther<!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
fixture.apply(() => {
ɵɵi18nExp('A');
ɵɵi18nExp('A');
ɵɵi18nExp('value2');
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
expect(fixture.host.innerHTML).toEqual('parentA value2<!--nested ICU 0-->!<!--ICU 21:0-->');
ɵɵi18nApply(0);
expect(fixture.host.innerHTML)
.toEqual(`parentA value2<!--nested ICU 0-->!<!--ICU ${HEADER_OFFSET + 0}:0-->`);
});
});
});

View File

@ -127,9 +127,8 @@ describe('Runtime i18n', () => {
ɵɵelementEnd();
}, undefined, nbConsts, HEADER_OFFSET + index);
expect((opCodes as any).update.debug).toEqual([
'if (mask & 0b1) { (lView[23] as Text).textContent = `Hello ${lView[i-1]}!`; }'
]);
expect((opCodes as any).update.debug).toEqual([`if (mask & 0b1) { (lView[${
HEADER_OFFSET + 2}] as Text).textContent = \`Hello \${lView[i-1]}!\`; }`]);
expect(opCodes).toEqual({
create: matchDebug([
@ -137,7 +136,8 @@ describe('Runtime i18n', () => {
`parent.appendChild(lView[${HEADER_OFFSET + 2}]);`,
]),
update: matchDebug([
'if (mask & 0b1) { (lView[23] as Text).textContent = `Hello ${lView[i-1]}!`; }',
`if (mask & 0b1) { (lView[${
HEADER_OFFSET + 2}] as Text).textContent = \`Hello \${lView[i-1]}!\`; }`,
]),
});
});
@ -158,7 +158,9 @@ describe('Runtime i18n', () => {
`parent.appendChild(lView[${HEADER_OFFSET + 2}]);`,
]),
update: matchDebug([
'if (mask & 0b11) { (lView[23] as Text).textContent = `Hello ${lView[i-1]} and ${lView[i-2]}, again ${lView[i-1]}!`; }',
`if (mask & 0b11) { (lView[${
HEADER_OFFSET +
2}] as Text).textContent = \`Hello \${lView[i-1]} and \${lView[i-2]}, again \${lView[i-1]}!\`; }`,
]),
});
});
@ -193,7 +195,8 @@ describe('Runtime i18n', () => {
`parent.appendChild(lView[${HEADER_OFFSET + 4}]);`,
]),
update: matchDebug([
'if (mask & 0b1) { (lView[24] as Text).textContent = `${lView[i-1]} is rendered as: `; }',
`if (mask & 0b1) { (lView[${
HEADER_OFFSET + 3}] as Text).textContent = \`\${lView[i-1]} is rendered as: \`; }`,
]),
});
@ -249,26 +252,26 @@ describe('Runtime i18n', () => {
expect(opCodes).toEqual({
create: matchDebug([
`lView[${HEADER_OFFSET + 2}] = document.createComment("ICU 22:0");`,
`lView[${HEADER_OFFSET + 2}] = document.createComment("ICU ${HEADER_OFFSET + 1}:0");`,
`parent.appendChild(lView[${HEADER_OFFSET + 2}]);`,
]),
update: matchDebug([
'if (mask & 0b1) { icuSwitchCase(23, `${lView[i-1]}`); }',
'if (mask & 0b1) { icuUpdateCase(23); }',
`if (mask & 0b1) { icuSwitchCase(${HEADER_OFFSET + 2}, \`\${lView[i-1]}\`); }`,
`if (mask & 0b1) { icuUpdateCase(${HEADER_OFFSET + 2}); }`,
]),
});
expect(getTIcu(tView, 23)).toEqual(<TIcu>{
expect(getTIcu(tView, HEADER_OFFSET + 2)).toEqual(<TIcu>{
type: 1,
currentCaseLViewIndex: 24,
anchorIdx: 23,
currentCaseLViewIndex: HEADER_OFFSET + 3,
anchorIdx: HEADER_OFFSET + 2,
cases: ['0', '1', 'other'],
create: [
matchDebug([
`lView[${HEADER_OFFSET + 4}] = document.createTextNode("no ")`,
`(lView[${HEADER_OFFSET + 0}] as Element).appendChild(lView[${HEADER_OFFSET + 4}])`,
'lView[26] = document.createElement("b")',
`lView[${HEADER_OFFSET + 5}] = document.createElement("b")`,
`(lView[${HEADER_OFFSET + 0}] as Element).appendChild(lView[${HEADER_OFFSET + 5}])`,
'(lView[26] as Element).setAttribute("title", "none")',
`(lView[${HEADER_OFFSET + 5}] as Element).setAttribute("title", "none")`,
`lView[${HEADER_OFFSET + 6}] = document.createTextNode("emails")`,
`(lView[${HEADER_OFFSET + 5}] as Element).appendChild(lView[${HEADER_OFFSET + 6}])`,
`lView[${HEADER_OFFSET + 7}] = document.createTextNode("!")`,
@ -277,41 +280,43 @@ describe('Runtime i18n', () => {
matchDebug([
`lView[${HEADER_OFFSET + 8}] = document.createTextNode("one ")`,
`(lView[${HEADER_OFFSET + 0}] as Element).appendChild(lView[${HEADER_OFFSET + 8}])`,
'lView[30] = document.createElement("i")',
`lView[${HEADER_OFFSET + 9}] = document.createElement("i")`,
`(lView[${HEADER_OFFSET + 0}] as Element).appendChild(lView[${HEADER_OFFSET + 9}])`,
'lView[31] = document.createTextNode("email")',
'(lView[30] as Element).appendChild(lView[31])',
`lView[${HEADER_OFFSET + 10}] = document.createTextNode("email")`,
`(lView[${HEADER_OFFSET + 9}] as Element).appendChild(lView[${HEADER_OFFSET + 10}])`,
]),
matchDebug([
'lView[32] = document.createTextNode("")',
'(lView[21] as Element).appendChild(lView[32])',
'lView[33] = document.createElement("span")',
'(lView[21] as Element).appendChild(lView[33])',
'lView[34] = document.createTextNode("emails")',
'(lView[33] as Element).appendChild(lView[34])',
`lView[${HEADER_OFFSET + 11}] = document.createTextNode("")`,
`(lView[${HEADER_OFFSET + 0}] as Element).appendChild(lView[${HEADER_OFFSET + 11}])`,
`lView[${HEADER_OFFSET + 12}] = document.createElement("span")`,
`(lView[${HEADER_OFFSET + 0}] as Element).appendChild(lView[${HEADER_OFFSET + 12}])`,
`lView[${HEADER_OFFSET + 13}] = document.createTextNode("emails")`,
`(lView[${HEADER_OFFSET + 12}] as Element).appendChild(lView[${HEADER_OFFSET + 13}])`,
]),
],
remove: [
matchDebug([
'remove(lView[25])',
'remove(lView[26])',
'remove(lView[28])',
`remove(lView[${HEADER_OFFSET + 4}])`,
`remove(lView[${HEADER_OFFSET + 5}])`,
`remove(lView[${HEADER_OFFSET + 7}])`,
]),
matchDebug([
'remove(lView[29])',
'remove(lView[30])',
`remove(lView[${HEADER_OFFSET + 8}])`,
`remove(lView[${HEADER_OFFSET + 9}])`,
]),
matchDebug([
'remove(lView[32])',
'remove(lView[33])',
`remove(lView[${HEADER_OFFSET + 11}])`,
`remove(lView[${HEADER_OFFSET + 12}])`,
]),
],
update: [
matchDebug([]),
matchDebug([]),
matchDebug([
'if (mask & 0b1) { (lView[32] as Text).textContent = `${lView[i-1]} `; }',
'if (mask & 0b10) { (lView[33] as Element).setAttribute(\'title\', `${lView[i-2]}`); }',
`if (mask & 0b1) { (lView[${
HEADER_OFFSET + 11}] as Text).textContent = \`\${lView[i-1]} \`; }`,
`if (mask & 0b10) { (lView[${
HEADER_OFFSET + 12}] as Element).setAttribute('title', \`\${lView[i-2]}\`); }`,
]),
]
});
@ -336,19 +341,19 @@ describe('Runtime i18n', () => {
expect(opCodes).toEqual({
create: matchDebug([
`lView[${HEADER_OFFSET + 2}] = document.createComment("ICU 22:0");`,
`lView[${HEADER_OFFSET + 2}] = document.createComment("ICU ${HEADER_OFFSET + 1}:0");`,
`parent.appendChild(lView[${HEADER_OFFSET + 2}]);`,
]),
update: matchDebug([
'if (mask & 0b1) { icuSwitchCase(23, `${lView[i-1]}`); }',
'if (mask & 0b10) { icuSwitchCase(27, `${lView[i-2]}`); }',
'if (mask & 0b1) { icuUpdateCase(23); }',
`if (mask & 0b1) { icuSwitchCase(${HEADER_OFFSET + 2}, \`\${lView[i-1]}\`); }`,
`if (mask & 0b10) { icuSwitchCase(${HEADER_OFFSET + 6}, \`\${lView[i-2]}\`); }`,
`if (mask & 0b1) { icuUpdateCase(${HEADER_OFFSET + 2}); }`,
]),
});
expect(getTIcu(tView, 23)).toEqual({
expect(getTIcu(tView, HEADER_OFFSET + 2)).toEqual({
type: 1,
anchorIdx: 23,
currentCaseLViewIndex: 24,
anchorIdx: HEADER_OFFSET + 2,
currentCaseLViewIndex: HEADER_OFFSET + 3,
cases: ['0', 'other'],
create: [
matchDebug([
@ -358,34 +363,35 @@ describe('Runtime i18n', () => {
matchDebug([
`lView[${HEADER_OFFSET + 5}] = document.createTextNode("")`,
`(lView[${HEADER_OFFSET + 0}] as Element).appendChild(lView[${HEADER_OFFSET + 5}])`,
'lView[27] = document.createComment("nested ICU 0")',
`lView[${HEADER_OFFSET + 6}] = document.createComment("nested ICU 0")`,
`(lView[${HEADER_OFFSET + 0}] as Element).appendChild(lView[${HEADER_OFFSET + 6}])`,
'lView[32] = document.createTextNode("!")',
'(lView[21] as Element).appendChild(lView[32])',
`lView[${HEADER_OFFSET + 11}] = document.createTextNode("!")`,
`(lView[${HEADER_OFFSET + 0}] as Element).appendChild(lView[${HEADER_OFFSET + 11}])`,
]),
],
update: [
matchDebug([]),
matchDebug([
'if (mask & 0b1) { (lView[26] as Text).textContent = `${lView[i-1]} `; }',
`if (mask & 0b1) { (lView[${
HEADER_OFFSET + 5}] as Text).textContent = \`\${lView[i-1]} \`; }`,
]),
],
remove: [
matchDebug([
'remove(lView[25])',
`remove(lView[${HEADER_OFFSET + 4}])`,
]),
matchDebug([
'remove(lView[26])',
'removeNestedICU(27)',
'remove(lView[27])',
'remove(lView[32])',
`remove(lView[${HEADER_OFFSET + 5}])`,
`removeNestedICU(${HEADER_OFFSET + 6})`,
`remove(lView[${HEADER_OFFSET + 6}])`,
`remove(lView[${HEADER_OFFSET + 11}])`,
]),
],
});
expect(tView.data[27]).toEqual({
expect(tView.data[HEADER_OFFSET + 6]).toEqual({
type: 0,
anchorIdx: 27,
currentCaseLViewIndex: 28,
anchorIdx: HEADER_OFFSET + 6,
currentCaseLViewIndex: HEADER_OFFSET + 7,
cases: ['cat', 'dog', 'other'],
create: [
matchDebug([
@ -397,8 +403,8 @@ describe('Runtime i18n', () => {
`(lView[${HEADER_OFFSET + 0}] as Element).appendChild(lView[${HEADER_OFFSET + 9}])`,
]),
matchDebug([
'lView[31] = document.createTextNode("animals")',
'(lView[21] as Element).appendChild(lView[31])',
`lView[${HEADER_OFFSET + 10}] = document.createTextNode("animals")`,
`(lView[${HEADER_OFFSET + 0}] as Element).appendChild(lView[${HEADER_OFFSET + 10}])`,
]),
],
update: [
@ -407,9 +413,9 @@ describe('Runtime i18n', () => {
matchDebug([]),
],
remove: [
matchDebug(['remove(lView[29])']),
matchDebug(['remove(lView[30])']),
matchDebug(['remove(lView[31])']),
matchDebug([`remove(lView[${HEADER_OFFSET + 8}])`]),
matchDebug([`remove(lView[${HEADER_OFFSET + 9}])`]),
matchDebug([`remove(lView[${HEADER_OFFSET + 10}])`]),
],
});
});
@ -428,7 +434,8 @@ describe('Runtime i18n', () => {
}, undefined, nbConsts, HEADER_OFFSET + index);
expect(opCodes).toEqual(matchDebug([
'if (mask & 0b1) { (lView[21] as Element).setAttribute(\'title\', `Hello ${lView[i-1]}!`); }',
`if (mask & 0b1) { (lView[${
HEADER_OFFSET + 0}] as Element).setAttribute('title', \`Hello \$\{lView[i-1]}!\`); }`,
]));
});
@ -444,7 +451,9 @@ describe('Runtime i18n', () => {
}, undefined, nbConsts, HEADER_OFFSET + index);
expect(opCodes).toEqual(matchDebug([
'if (mask & 0b11) { (lView[21] as Element).setAttribute(\'title\', `Hello ${lView[i-1]} and ${lView[i-2]}, again ${lView[i-1]}!`); }',
`if (mask & 0b11) { (lView[${
HEADER_OFFSET +
0}] as Element).setAttribute('title', \`Hello \$\{lView[i-1]} and \$\{lView[i-2]}, again \$\{lView[i-1]}!\`); }`,
]));
});
@ -460,8 +469,11 @@ describe('Runtime i18n', () => {
}, undefined, nbConsts, HEADER_OFFSET + index);
expect(opCodes).toEqual(matchDebug([
'if (mask & 0b1) { (lView[21] as Element).setAttribute(\'title\', `Hello ${lView[i-1]}!`); }',
'if (mask & 0b1) { (lView[21] as Element).setAttribute(\'aria-label\', `Hello ${lView[i-1]}!`); }',
`if (mask & 0b1) { (lView[${
HEADER_OFFSET + 0}] as Element).setAttribute('title', \`Hello \$\{lView[i-1]}!\`); }`,
`if (mask & 0b1) { (lView[${
HEADER_OFFSET +
0}] as Element).setAttribute('aria-label', \`Hello \$\{lView[i-1]}!\`); }`,
]));
});
});
@ -702,8 +714,10 @@ describe('Runtime i18n', () => {
],
}));
expect(ti18n.update).toEqual(matchDebug([
'if (mask & 0b1) { (lView[51] as Text).textContent = `${lView[i-1]} `; }',
'if (mask & 0b10) { (lView[52] as Text).textContent = `${lView[i-2]}`; }'
`if (mask & 0b1) { (lView[${
HEADER_OFFSET + 30}] as Text).textContent = \`\${lView[i-1]} \`; }`,
`if (mask & 0b10) { (lView[${
HEADER_OFFSET + 31}] as Text).textContent = \`\${lView[i-2]}\`; }`
]));
const lViewDebug = fixture.lView.debug!;
expect(lViewDebug.template).toEqual('<div>{{?}}<Placeholder>{{?}}</Placeholder>!</div>');
@ -714,16 +728,16 @@ describe('Runtime i18n', () => {
fixture.tView, 0, fixture.lView, HEADER_OFFSET + 1, 'Hello <20>*2:1<>World<6C>/*2:1<>!', -1);
const ti18n = fixture.tView.data[HEADER_OFFSET + 1] as TI18n;
expect(ti18n.create.debug).toEqual([
'lView[51] = document.createText("Hello ");',
'parent.appendChild(lView[51]);',
'lView[52] = document.createText("!");',
'parent.appendChild(lView[52]);',
`lView[${HEADER_OFFSET + 30}] = document.createText("Hello ");`,
`parent.appendChild(lView[${HEADER_OFFSET + 30}]);`,
`lView[${HEADER_OFFSET + 31}] = document.createText("!");`,
`parent.appendChild(lView[${HEADER_OFFSET + 31}]);`,
]);
// Leave behind `Placeholder` to be picked up by `TNode` creation.
// It should insert itself in front of "!"
expect(fixture.tView.data[HEADER_OFFSET + 2]).toEqual(matchTNode({
type: TNodeType.Placeholder,
insertBeforeIndex: 52,
insertBeforeIndex: HEADER_OFFSET + 31,
}));
});
});

View File

@ -13,7 +13,7 @@ import {ɵɵelement, ɵɵelementEnd, ɵɵelementStart} from '@angular/core/src/r
import {TNodeDebug} from '@angular/core/src/render3/instructions/lview_debug';
import {createTNode, createTView} from '@angular/core/src/render3/instructions/shared';
import {TNodeType} from '@angular/core/src/render3/interfaces/node';
import {LView, LViewDebug, TView, TViewType} from '@angular/core/src/render3/interfaces/view';
import {HEADER_OFFSET, LView, LViewDebug, TView, TViewType} from '@angular/core/src/render3/interfaces/view';
import {enterView, leaveView} from '@angular/core/src/render3/state';
import {insertTStylingBinding} from '@angular/core/src/render3/styling/style_binding_list';
import {getComponentLView} from '@angular/core/src/render3/util/discovery_utils';
@ -242,7 +242,7 @@ describe('lView_debug', () => {
cumulativeBloom: jasmine.anything(),
providers: [MyChild.ɵdir],
viewProviders: [],
parentInjectorIndex: 23,
parentInjectorIndex: HEADER_OFFSET + 2,
});
});
});