refactor(compiler): refactor ast spans test to be more human readable (#38902)

The current tests print out the span numbers, which are really difficult to verify
since it requires manually going to the template string and looking at what
characters appear within those indexes. The better humanization would be
to use the toString method of the spans, which prints the span text itself

PR Close #38902
This commit is contained in:
Andrew Scott 2020-09-18 12:11:00 -07:00 committed by Misko Hevery
parent d5ddb9f340
commit a91f0f6b82
1 changed files with 83 additions and 64 deletions

View File

@ -95,7 +95,7 @@ function humanizeSpan(span: ParseSourceSpan|null|undefined): string {
if (span === null || span === undefined) { if (span === null || span === undefined) {
return `<empty>`; return `<empty>`;
} }
return `${span.start.offset}:${span.end.offset}`; return span.toString();
} }
function expectFromHtml(html: string) { function expectFromHtml(html: string) {
@ -113,21 +113,21 @@ describe('R3 AST source spans', () => {
describe('nodes without binding', () => { describe('nodes without binding', () => {
it('is correct for text nodes', () => { it('is correct for text nodes', () => {
expectFromHtml('a').toEqual([ expectFromHtml('a').toEqual([
['Text', '0:1'], ['Text', 'a'],
]); ]);
}); });
it('is correct for elements with attributes', () => { it('is correct for elements with attributes', () => {
expectFromHtml('<div a="b"></div>').toEqual([ expectFromHtml('<div a="b"></div>').toEqual([
['Element', '0:17', '0:11', '11:17'], ['Element', '<div a="b"></div>', '<div a="b">', '</div>'],
['TextAttribute', '5:10', '8:9'], ['TextAttribute', 'a="b"', 'b'],
]); ]);
}); });
it('is correct for elements with attributes without value', () => { it('is correct for elements with attributes without value', () => {
expectFromHtml('<div a></div>').toEqual([ expectFromHtml('<div a></div>').toEqual([
['Element', '0:13', '0:7', '7:13'], ['Element', '<div a></div>', '<div a>', '</div>'],
['TextAttribute', '5:6', '<empty>'], ['TextAttribute', 'a', '<empty>'],
]); ]);
}); });
}); });
@ -135,7 +135,7 @@ describe('R3 AST source spans', () => {
describe('bound text nodes', () => { describe('bound text nodes', () => {
it('is correct for bound text nodes', () => { it('is correct for bound text nodes', () => {
expectFromHtml('{{a}}').toEqual([ expectFromHtml('{{a}}').toEqual([
['BoundText', '0:5'], ['BoundText', '{{a}}'],
]); ]);
}); });
}); });
@ -143,29 +143,29 @@ describe('R3 AST source spans', () => {
describe('bound attributes', () => { describe('bound attributes', () => {
it('is correct for bound properties', () => { it('is correct for bound properties', () => {
expectFromHtml('<div [someProp]="v"></div>').toEqual([ expectFromHtml('<div [someProp]="v"></div>').toEqual([
['Element', '0:26', '0:20', '20:26'], ['Element', '<div [someProp]="v"></div>', '<div [someProp]="v">', '</div>'],
['BoundAttribute', '5:19', '17:18'], ['BoundAttribute', '[someProp]="v"', 'v'],
]); ]);
}); });
it('is correct for bound properties without value', () => { it('is correct for bound properties without value', () => {
expectFromHtml('<div [someProp]></div>').toEqual([ expectFromHtml('<div [someProp]></div>').toEqual([
['Element', '0:22', '0:16', '16:22'], ['Element', '<div [someProp]></div>', '<div [someProp]>', '</div>'],
['BoundAttribute', '5:15', '<empty>'], ['BoundAttribute', '[someProp]', '<empty>'],
]); ]);
}); });
it('is correct for bound properties via bind- ', () => { it('is correct for bound properties via bind- ', () => {
expectFromHtml('<div bind-prop="v"></div>').toEqual([ expectFromHtml('<div bind-prop="v"></div>').toEqual([
['Element', '0:25', '0:19', '19:25'], ['Element', '<div bind-prop="v"></div>', '<div bind-prop="v">', '</div>'],
['BoundAttribute', '5:18', '16:17'], ['BoundAttribute', 'bind-prop="v"', 'v'],
]); ]);
}); });
it('is correct for bound properties via {{...}}', () => { it('is correct for bound properties via {{...}}', () => {
expectFromHtml('<div prop="{{v}}"></div>').toEqual([ expectFromHtml('<div prop="{{v}}"></div>').toEqual([
['Element', '0:24', '0:18', '18:24'], ['Element', '<div prop="{{v}}"></div>', '<div prop="{{v}}">', '</div>'],
['BoundAttribute', '5:17', '11:16'], ['BoundAttribute', 'prop="{{v}}"', '{{v}}'],
]); ]);
}); });
}); });
@ -173,57 +173,68 @@ describe('R3 AST source spans', () => {
describe('templates', () => { describe('templates', () => {
it('is correct for * directives', () => { it('is correct for * directives', () => {
expectFromHtml('<div *ngIf></div>').toEqual([ expectFromHtml('<div *ngIf></div>').toEqual([
['Template', '0:17', '0:11', '11:17'], ['Template', '<div *ngIf></div>', '<div *ngIf>', '</div>'],
['TextAttribute', '6:10', '<empty>'], // ngIf ['TextAttribute', 'ngIf', '<empty>'],
['Element', '0:17', '0:11', '11:17'], ['Element', '<div *ngIf></div>', '<div *ngIf>', '</div>'],
]); ]);
}); });
it('is correct for <ng-template>', () => { it('is correct for <ng-template>', () => {
expectFromHtml('<ng-template></ng-template>').toEqual([ expectFromHtml('<ng-template></ng-template>').toEqual([
['Template', '0:27', '0:13', '13:27'], ['Template', '<ng-template></ng-template>', '<ng-template>', '</ng-template>'],
]); ]);
}); });
it('is correct for reference via #...', () => { it('is correct for reference via #...', () => {
expectFromHtml('<ng-template #a></ng-template>').toEqual([ expectFromHtml('<ng-template #a></ng-template>').toEqual([
['Template', '0:30', '0:16', '16:30'], ['Template', '<ng-template #a></ng-template>', '<ng-template #a>', '</ng-template>'],
['Reference', '13:15', '<empty>'], ['Reference', '#a', '<empty>'],
]); ]);
}); });
it('is correct for reference with name', () => { it('is correct for reference with name', () => {
expectFromHtml('<ng-template #a="b"></ng-template>').toEqual([ expectFromHtml('<ng-template #a="b"></ng-template>').toEqual([
['Template', '0:34', '0:20', '20:34'], [
['Reference', '13:19', '17:18'], 'Template', '<ng-template #a="b"></ng-template>', '<ng-template #a="b">', '</ng-template>'
],
['Reference', '#a="b"', 'b'],
]); ]);
}); });
it('is correct for reference via ref-...', () => { it('is correct for reference via ref-...', () => {
expectFromHtml('<ng-template ref-a></ng-template>').toEqual([ expectFromHtml('<ng-template ref-a></ng-template>').toEqual([
['Template', '0:33', '0:19', '19:33'], ['Template', '<ng-template ref-a></ng-template>', '<ng-template ref-a>', '</ng-template>'],
['Reference', '13:18', '<empty>'], ['Reference', 'ref-a', '<empty>'],
]); ]);
}); });
it('is correct for variables via let-...', () => { it('is correct for variables via let-...', () => {
expectFromHtml('<ng-template let-a="b"></ng-template>').toEqual([ expectFromHtml('<ng-template let-a="b"></ng-template>').toEqual([
['Template', '0:37', '0:23', '23:37'], [
['Variable', '13:22', '20:21'], 'Template', '<ng-template let-a="b"></ng-template>', '<ng-template let-a="b">',
'</ng-template>'
],
['Variable', 'let-a="b"', 'b'],
]); ]);
}); });
it('is correct for attributes', () => { it('is correct for attributes', () => {
expectFromHtml('<ng-template k1="v1"></ng-template>').toEqual([ expectFromHtml('<ng-template k1="v1"></ng-template>').toEqual([
['Template', '0:35', '0:21', '21:35'], [
['TextAttribute', '13:20', '17:19'], 'Template', '<ng-template k1="v1"></ng-template>', '<ng-template k1="v1">',
'</ng-template>'
],
['TextAttribute', 'k1="v1"', 'v1'],
]); ]);
}); });
it('is correct for bound attributes', () => { it('is correct for bound attributes', () => {
expectFromHtml('<ng-template [k1]="v1"></ng-template>').toEqual([ expectFromHtml('<ng-template [k1]="v1"></ng-template>').toEqual([
['Template', '0:37', '0:23', '23:37'], [
['BoundAttribute', '13:22', '19:21'], 'Template', '<ng-template [k1]="v1"></ng-template>', '<ng-template [k1]="v1">',
'</ng-template>'
],
['BoundAttribute', '[k1]="v1"', 'v1'],
]); ]);
}); });
}); });
@ -236,11 +247,17 @@ describe('R3 AST source spans', () => {
// <div></div> // <div></div>
// </ng-template> // </ng-template>
expectFromHtml('<div *ngFor="let item of items"></div>').toEqual([ expectFromHtml('<div *ngFor="let item of items"></div>').toEqual([
['Template', '0:38', '0:32', '32:38'], [
['TextAttribute', '6:11', '<empty>'], // ngFor 'Template', '<div *ngFor="let item of items"></div>', '<div *ngFor="let item of items">',
['BoundAttribute', '5:31', '25:30'], // *ngFor="let item of items" -> items '</div>'
['Variable', '13:22', '<empty>'], // let item ],
['Element', '0:38', '0:32', '32:38'], ['TextAttribute', 'ngFor', '<empty>'],
['BoundAttribute', '*ngFor="let item of items"', 'items'],
['Variable', 'let item ', '<empty>'],
[
'Element', '<div *ngFor="let item of items"></div>', '<div *ngFor="let item of items">',
'</div>'
],
]); ]);
// Note that this test exercises an *incorrect* usage of the ngFor // Note that this test exercises an *incorrect* usage of the ngFor
@ -250,28 +267,30 @@ describe('R3 AST source spans', () => {
// <div></div> // <div></div>
// </ng-template> // </ng-template>
expectFromHtml('<div *ngFor="item of items"></div>').toEqual([ expectFromHtml('<div *ngFor="item of items"></div>').toEqual([
['Template', '0:34', '0:28', '28:34'], [
['BoundAttribute', '5:27', '13:17'], // ngFor="item of items" -> item 'Template', '<div *ngFor="item of items"></div>', '<div *ngFor="item of items">', '</div>'
['BoundAttribute', '5:27', '21:26'], // ngFor="item of items" -> items ],
['Element', '0:34', '0:28', '28:34'], ['BoundAttribute', '*ngFor="item of items"', 'item'],
['BoundAttribute', '*ngFor="item of items"', 'items'],
['Element', '<div *ngFor="item of items"></div>', '<div *ngFor="item of items">', '</div>'],
]); ]);
}); });
it('is correct for variables via let ...', () => { it('is correct for variables via let ...', () => {
expectFromHtml('<div *ngIf="let a=b"></div>').toEqual([ expectFromHtml('<div *ngIf="let a=b"></div>').toEqual([
['Template', '0:27', '0:21', '21:27'], ['Template', '<div *ngIf="let a=b"></div>', '<div *ngIf="let a=b">', '</div>'],
['TextAttribute', '6:10', '<empty>'], // ngIf ['TextAttribute', 'ngIf', '<empty>'],
['Variable', '12:19', '18:19'], // let a=b -> b ['Variable', 'let a=b', 'b'],
['Element', '0:27', '0:21', '21:27'], ['Element', '<div *ngIf="let a=b"></div>', '<div *ngIf="let a=b">', '</div>'],
]); ]);
}); });
it('is correct for variables via as ...', () => { it('is correct for variables via as ...', () => {
expectFromHtml('<div *ngIf="expr as local"></div>').toEqual([ expectFromHtml('<div *ngIf="expr as local"></div>').toEqual([
['Template', '0:33', '0:27', '27:33'], ['Template', '<div *ngIf="expr as local"></div>', '<div *ngIf="expr as local">', '</div>'],
['BoundAttribute', '5:26', '12:16'], // ngIf="expr as local" -> expr ['BoundAttribute', '*ngIf="expr as local"', 'expr'],
['Variable', '6:25', '6:10'], // ngIf="expr as local -> ngIf ['Variable', 'ngIf="expr as local', 'ngIf'],
['Element', '0:33', '0:27', '27:33'], ['Element', '<div *ngIf="expr as local"></div>', '<div *ngIf="expr as local">', '</div>'],
]); ]);
}); });
}); });
@ -279,31 +298,31 @@ describe('R3 AST source spans', () => {
describe('events', () => { describe('events', () => {
it('is correct for event names case sensitive', () => { it('is correct for event names case sensitive', () => {
expectFromHtml('<div (someEvent)="v"></div>').toEqual([ expectFromHtml('<div (someEvent)="v"></div>').toEqual([
['Element', '0:27', '0:21', '21:27'], ['Element', '<div (someEvent)="v"></div>', '<div (someEvent)="v">', '</div>'],
['BoundEvent', '5:20', '18:19'], ['BoundEvent', '(someEvent)="v"', 'v'],
]); ]);
}); });
it('is correct for bound events via on-', () => { it('is correct for bound events via on-', () => {
expectFromHtml('<div on-event="v"></div>').toEqual([ expectFromHtml('<div on-event="v"></div>').toEqual([
['Element', '0:24', '0:18', '18:24'], ['Element', '<div on-event="v"></div>', '<div on-event="v">', '</div>'],
['BoundEvent', '5:17', '15:16'], ['BoundEvent', 'on-event="v"', 'v'],
]); ]);
}); });
it('is correct for bound events and properties via [(...)]', () => { it('is correct for bound events and properties via [(...)]', () => {
expectFromHtml('<div [(prop)]="v"></div>').toEqual([ expectFromHtml('<div [(prop)]="v"></div>').toEqual([
['Element', '0:24', '0:18', '18:24'], ['Element', '<div [(prop)]="v"></div>', '<div [(prop)]="v">', '</div>'],
['BoundAttribute', '5:17', '15:16'], ['BoundAttribute', '[(prop)]="v"', 'v'],
['BoundEvent', '5:17', '15:16'], ['BoundEvent', '[(prop)]="v"', 'v'],
]); ]);
}); });
it('is correct for bound events and properties via bindon-', () => { it('is correct for bound events and properties via bindon-', () => {
expectFromHtml('<div bindon-prop="v"></div>').toEqual([ expectFromHtml('<div bindon-prop="v"></div>').toEqual([
['Element', '0:27', '0:21', '21:27'], ['Element', '<div bindon-prop="v"></div>', '<div bindon-prop="v">', '</div>'],
['BoundAttribute', '5:20', '18:19'], ['BoundAttribute', 'bindon-prop="v"', 'v'],
['BoundEvent', '5:20', '18:19'], ['BoundEvent', 'bindon-prop="v"', 'v'],
]); ]);
}); });
}); });
@ -311,22 +330,22 @@ describe('R3 AST source spans', () => {
describe('references', () => { describe('references', () => {
it('is correct for references via #...', () => { it('is correct for references via #...', () => {
expectFromHtml('<div #a></div>').toEqual([ expectFromHtml('<div #a></div>').toEqual([
['Element', '0:14', '0:8', '8:14'], ['Element', '<div #a></div>', '<div #a>', '</div>'],
['Reference', '5:7', '<empty>'], ['Reference', '#a', '<empty>'],
]); ]);
}); });
it('is correct for references with name', () => { it('is correct for references with name', () => {
expectFromHtml('<div #a="b"></div>').toEqual([ expectFromHtml('<div #a="b"></div>').toEqual([
['Element', '0:18', '0:12', '12:18'], ['Element', '<div #a="b"></div>', '<div #a="b">', '</div>'],
['Reference', '5:11', '9:10'], ['Reference', '#a="b"', 'b'],
]); ]);
}); });
it('is correct for references via ref-', () => { it('is correct for references via ref-', () => {
expectFromHtml('<div ref-a></div>').toEqual([ expectFromHtml('<div ref-a></div>').toEqual([
['Element', '0:17', '0:11', '11:17'], ['Element', '<div ref-a></div>', '<div ref-a>', '</div>'],
['Reference', '5:10', '<empty>'], ['Reference', 'ref-a', '<empty>'],
]); ]);
}); });
}); });