test(compiler-cli): add source-mapping test helper (#39717)

This helper improves the message given when an expectation
fails in a source-mapping test.

PR Close #39717
This commit is contained in:
Pete Bacon Darwin 2020-11-19 12:21:01 +00:00 committed by Andrew Kushnir
parent 1cba56e11f
commit 6b38c44a22
1 changed files with 179 additions and 112 deletions

View File

@ -31,20 +31,22 @@ runInEachFileSystem((os) => {
describe('(element creation)', () => { describe('(element creation)', () => {
it('should map simple element with content', () => { it('should map simple element with content', () => {
const mappings = compileAndMap('<h1>Heading 1</h1>'); const mappings = compileAndMap('<h1>Heading 1</h1>');
expect(mappings).toContain( expectMapping(
mappings,
{source: '<h1>', generated: 'i0.ɵɵelementStart(0, "h1")', sourceUrl: '../test.ts'}); {source: '<h1>', generated: 'i0.ɵɵelementStart(0, "h1")', sourceUrl: '../test.ts'});
expect(mappings).toContain({ expectMapping(mappings, {
source: 'Heading 1', source: 'Heading 1',
generated: 'i0.ɵɵtext(1, "Heading 1")', generated: 'i0.ɵɵtext(1, "Heading 1")',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
{source: '</h1>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); mappings, {source: '</h1>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
}); });
it('should map void element', () => { it('should map void element', () => {
const mappings = compileAndMap('<hr>'); const mappings = compileAndMap('<hr>');
expect(mappings).toContain( expectMapping(
mappings,
{source: '<hr>', generated: 'i0.ɵɵelement(0, "hr")', sourceUrl: '../test.ts'}); {source: '<hr>', generated: 'i0.ɵɵelement(0, "hr")', sourceUrl: '../test.ts'});
}); });
}); });
@ -52,38 +54,40 @@ runInEachFileSystem((os) => {
describe('(interpolations)', () => { describe('(interpolations)', () => {
it('should map a mix of interpolated and static content', () => { it('should map a mix of interpolated and static content', () => {
const mappings = compileAndMap('<h3>Hello {{ name }}</h3>'); const mappings = compileAndMap('<h3>Hello {{ name }}</h3>');
expect(mappings).toContain( expectMapping(
mappings,
{source: '<h3>', generated: 'i0.ɵɵelementStart(0, "h3")', sourceUrl: '../test.ts'}); {source: '<h3>', generated: 'i0.ɵɵelementStart(0, "h3")', sourceUrl: '../test.ts'});
expect(mappings).toContain({ expectMapping(mappings, {
source: 'Hello {{ name }}', source: 'Hello {{ name }}',
generated: 'i0.ɵɵtextInterpolate1("Hello ", ctx.name, "")', generated: 'i0.ɵɵtextInterpolate1("Hello ", ctx.name, "")',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
{source: '</h3>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); mappings, {source: '</h3>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
}); });
it('should map a complex interpolated expression', () => { it('should map a complex interpolated expression', () => {
const mappings = compileAndMap('<h2>{{ greeting + " " + name }}</h2>'); const mappings = compileAndMap('<h2>{{ greeting + " " + name }}</h2>');
expect(mappings).toContain( expectMapping(
mappings,
{source: '<h2>', generated: 'i0.ɵɵelementStart(0, "h2")', sourceUrl: '../test.ts'}); {source: '<h2>', generated: 'i0.ɵɵelementStart(0, "h2")', sourceUrl: '../test.ts'});
expect(mappings).toContain({ expectMapping(mappings, {
source: '{{ greeting + " " + name }}', source: '{{ greeting + " " + name }}',
generated: 'i0.ɵɵtextInterpolate(ctx.greeting + " " + ctx.name)', generated: 'i0.ɵɵtextInterpolate(ctx.greeting + " " + ctx.name)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
{source: '</h2>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); mappings, {source: '</h2>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
}); });
it('should map interpolated properties', () => { it('should map interpolated properties', () => {
const mappings = compileAndMap('<div id="{{name}}"></div>'); const mappings = compileAndMap('<div id="{{name}}"></div>');
expect(mappings).toContain({ expectMapping(mappings, {
source: '<div id="{{name}}"></div>', source: '<div id="{{name}}"></div>',
generated: 'i0.ɵɵelement(0, "div", 0)', generated: 'i0.ɵɵelement(0, "div", 0)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: 'id="{{name}}"', source: 'id="{{name}}"',
generated: 'i0.ɵɵpropertyInterpolate("id", ctx.name)', generated: 'i0.ɵɵpropertyInterpolate("id", ctx.name)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -92,14 +96,16 @@ runInEachFileSystem((os) => {
it('should map interpolation with pipe', () => { it('should map interpolation with pipe', () => {
const mappings = compileAndMap('<div>{{200.3 | percent : 2 }}</div>'); const mappings = compileAndMap('<div>{{200.3 | percent : 2 }}</div>');
expect(mappings).toContain( expectMapping(
mappings,
{source: '<div>', generated: 'i0.ɵɵelementStart(0, "div")', sourceUrl: '../test.ts'}); {source: '<div>', generated: 'i0.ɵɵelementStart(0, "div")', sourceUrl: '../test.ts'});
expect(mappings).toContain({ expectMapping(mappings, {
source: '{{200.3 | percent : 2 }}', source: '{{200.3 | percent : 2 }}',
generated: 'i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(2, 1, 200.3, 2))', generated: 'i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(2, 1, 200.3, 2))',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
mappings,
{source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); {source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
}); });
}); });
@ -107,12 +113,12 @@ runInEachFileSystem((os) => {
describe('(property bindings)', () => { describe('(property bindings)', () => {
it('should map a simple input binding expression', () => { it('should map a simple input binding expression', () => {
const mappings = compileAndMap('<div [attr]="name"></div>'); const mappings = compileAndMap('<div [attr]="name"></div>');
expect(mappings).toContain({ expectMapping(mappings, {
source: '<div [attr]="name"></div>', source: '<div [attr]="name"></div>',
generated: 'i0.ɵɵelement(0, "div", 0)', generated: 'i0.ɵɵelement(0, "div", 0)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: '[attr]="name"', source: '[attr]="name"',
generated: 'i0.ɵɵproperty("attr", ctx.name)', generated: 'i0.ɵɵproperty("attr", ctx.name)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -122,12 +128,12 @@ runInEachFileSystem((os) => {
it('should map a complex input binding expression', () => { it('should map a complex input binding expression', () => {
const mappings = compileAndMap('<div [attr]="greeting + name"></div>'); const mappings = compileAndMap('<div [attr]="greeting + name"></div>');
expect(mappings).toContain({ expectMapping(mappings, {
source: '<div [attr]="greeting + name"></div>', source: '<div [attr]="greeting + name"></div>',
generated: 'i0.ɵɵelement(0, "div", 0)', generated: 'i0.ɵɵelement(0, "div", 0)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: '[attr]="greeting + name"', source: '[attr]="greeting + name"',
generated: 'i0.ɵɵproperty("attr", ctx.greeting + ctx.name)', generated: 'i0.ɵɵproperty("attr", ctx.greeting + ctx.name)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -136,12 +142,12 @@ runInEachFileSystem((os) => {
it('should map a longhand input binding expression', () => { it('should map a longhand input binding expression', () => {
const mappings = compileAndMap('<div bind-attr="name"></div>'); const mappings = compileAndMap('<div bind-attr="name"></div>');
expect(mappings).toContain({ expectMapping(mappings, {
source: '<div bind-attr="name"></div>', source: '<div bind-attr="name"></div>',
generated: 'i0.ɵɵelement(0, "div", 0)', generated: 'i0.ɵɵelement(0, "div", 0)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: 'bind-attr="name"', source: 'bind-attr="name"',
generated: 'i0.ɵɵproperty("attr", ctx.name)', generated: 'i0.ɵɵproperty("attr", ctx.name)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -150,72 +156,80 @@ runInEachFileSystem((os) => {
it('should map a simple output binding expression', () => { it('should map a simple output binding expression', () => {
const mappings = compileAndMap('<button (click)="doSomething()">Do it</button>'); const mappings = compileAndMap('<button (click)="doSomething()">Do it</button>');
expect(mappings).toContain({ expectMapping(mappings, {
source: '<button (click)="doSomething()">', source: '<button (click)="doSomething()">',
generated: 'i0.ɵɵelementStart(0, "button", 0)', generated: 'i0.ɵɵelementStart(0, "button", 0)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
mappings,
{source: 'Do it', generated: 'i0.ɵɵtext(1, "Do it")', sourceUrl: '../test.ts'}); {source: 'Do it', generated: 'i0.ɵɵtext(1, "Do it")', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
mappings,
{source: 'doSomething()', generated: 'ctx.doSomething()', sourceUrl: '../test.ts'}); {source: 'doSomething()', generated: 'ctx.doSomething()', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
mappings,
{source: '</button>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); {source: '</button>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
}); });
it('should map a complex output binding expression', () => { it('should map a complex output binding expression', () => {
const mappings = compileAndMap( const mappings = compileAndMap(
`<button (click)="items.push('item' + items.length)">Add Item</button>`); `<button (click)="items.push('item' + items.length)">Add Item</button>`);
expect(mappings).toContain({ expectMapping(mappings, {
source: `<button (click)="items.push('item' + items.length)">`, source: `<button (click)="items.push('item' + items.length)">`,
generated: 'i0.ɵɵelementStart(0, "button", 0)', generated: 'i0.ɵɵelementStart(0, "button", 0)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
mappings,
{source: 'Add Item', generated: 'i0.ɵɵtext(1, "Add Item")', sourceUrl: '../test.ts'}); {source: 'Add Item', generated: 'i0.ɵɵtext(1, "Add Item")', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
mappings,
{source: 'items.push(', generated: 'ctx.items.push(', sourceUrl: '../test.ts'}); {source: 'items.push(', generated: 'ctx.items.push(', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(mappings, {source: `'item'`, generated: `"item"`, sourceUrl: '../test.ts'});
{source: `'item'`, generated: `"item"`, sourceUrl: '../test.ts'}); expectMapping(mappings, {
expect(mappings).toContain({
source: ' + items.length)', source: ' + items.length)',
generated: ' + ctx.items.length)', generated: ' + ctx.items.length)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
mappings,
{source: '</button>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); {source: '</button>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
}); });
it('should map a longhand output binding expression', () => { it('should map a longhand output binding expression', () => {
const mappings = compileAndMap('<button on-click="doSomething()">Do it</button>'); const mappings = compileAndMap('<button on-click="doSomething()">Do it</button>');
expect(mappings).toContain({ expectMapping(mappings, {
source: '<button on-click="doSomething()">', source: '<button on-click="doSomething()">',
generated: 'i0.ɵɵelementStart(0, "button", 0)', generated: 'i0.ɵɵelementStart(0, "button", 0)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
mappings,
{source: 'Do it', generated: 'i0.ɵɵtext(1, "Do it")', sourceUrl: '../test.ts'}); {source: 'Do it', generated: 'i0.ɵɵtext(1, "Do it")', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
mappings,
{source: 'doSomething()', generated: 'ctx.doSomething()', sourceUrl: '../test.ts'}); {source: 'doSomething()', generated: 'ctx.doSomething()', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
mappings,
{source: '</button>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); {source: '</button>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
}); });
it('should map a two-way binding expression', () => { it('should map a two-way binding expression', () => {
const mappings = compileAndMap('Name: <input [(ngModel)]="name">'); const mappings = compileAndMap('Name: <input [(ngModel)]="name">');
expect(mappings).toContain({ expectMapping(mappings, {
source: '<input [(ngModel)]="name">', source: '<input [(ngModel)]="name">',
generated: 'i0.ɵɵelementStart(1, "input", 0)', generated: 'i0.ɵɵelementStart(1, "input", 0)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
// TODO: improve mappings here // TODO: improve mappings here
expect(mappings).toContain({ expectMapping(mappings, {
source: '[(ngModel)]="name"', source: '[(ngModel)]="name"',
generated: generated:
'i0.ɵɵlistener("ngModelChange", function TestCmp_Template_input_ngModelChange_1_listener($event) { return ctx.name = $event; })', 'i0.ɵɵlistener("ngModelChange", function TestCmp_Template_input_ngModelChange_1_listener($event) { return ctx.name = $event; })',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: '<input [(ngModel)]="name">', source: '<input [(ngModel)]="name">',
generated: 'i0.ɵɵelementEnd()', generated: 'i0.ɵɵelementEnd()',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -224,19 +238,19 @@ runInEachFileSystem((os) => {
it('should map a longhand two-way binding expression', () => { it('should map a longhand two-way binding expression', () => {
const mappings = compileAndMap('Name: <input bindon-ngModel="name">'); const mappings = compileAndMap('Name: <input bindon-ngModel="name">');
expect(mappings).toContain({ expectMapping(mappings, {
source: '<input bindon-ngModel="name">', source: '<input bindon-ngModel="name">',
generated: 'i0.ɵɵelementStart(1, "input", 0)', generated: 'i0.ɵɵelementStart(1, "input", 0)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
// TODO: improve mappings here // TODO: improve mappings here
expect(mappings).toContain({ expectMapping(mappings, {
source: 'bindon-ngModel="name"', source: 'bindon-ngModel="name"',
generated: generated:
'i0.ɵɵlistener("ngModelChange", function TestCmp_Template_input_ngModelChange_1_listener($event) { return ctx.name = $event; })', 'i0.ɵɵlistener("ngModelChange", function TestCmp_Template_input_ngModelChange_1_listener($event) { return ctx.name = $event; })',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: '<input bindon-ngModel="name">', source: '<input bindon-ngModel="name">',
generated: 'i0.ɵɵelementEnd()', generated: 'i0.ɵɵelementEnd()',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -245,7 +259,7 @@ runInEachFileSystem((os) => {
it('should map a class input binding', () => { it('should map a class input binding', () => {
const mappings = compileAndMap('<div [class.initial]="isInitial">Message</div>'); const mappings = compileAndMap('<div [class.initial]="isInitial">Message</div>');
expect(mappings).toContain({ expectMapping(mappings, {
source: '<div [class.initial]="isInitial">', source: '<div [class.initial]="isInitial">',
generated: 'i0.ɵɵelementStart(0, "div")', generated: 'i0.ɵɵelementStart(0, "div")',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -253,10 +267,12 @@ runInEachFileSystem((os) => {
// TODO: Add better mappings for binding // TODO: Add better mappings for binding
expect(mappings).toContain( expectMapping(
mappings,
{source: 'Message', generated: 'i0.ɵɵtext(1, "Message")', sourceUrl: '../test.ts'}); {source: 'Message', generated: 'i0.ɵɵtext(1, "Message")', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
mappings,
{source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); {source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
}); });
}); });
@ -265,7 +281,7 @@ runInEachFileSystem((os) => {
it('should map *ngIf scenario', () => { it('should map *ngIf scenario', () => {
const mappings = compileAndMap('<div *ngIf="showMessage()">{{ name }}</div>'); const mappings = compileAndMap('<div *ngIf="showMessage()">{{ name }}</div>');
expect(mappings).toContain({ expectMapping(mappings, {
source: '<div *ngIf="showMessage()">', source: '<div *ngIf="showMessage()">',
generated: 'i0.ɵɵelementStart(0, "div")', generated: 'i0.ɵɵelementStart(0, "div")',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -273,12 +289,13 @@ runInEachFileSystem((os) => {
// TODO - map the bindings better // TODO - map the bindings better
expect(mappings).toContain( expectMapping(
mappings,
{source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); {source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
// TODO: the `ctx_r...` appears to be dependent upon previous tests!!! // TODO: the `ctx_r...` appears to be dependent upon previous tests!!!
// expect(mappings).toContain({ // expectMapping(mappings, {
// source: '{{ name }}', // source: '{{ name }}',
// generated: 'i0.ɵɵtextInterpolate(ctx_r0.name)', // generated: 'i0.ɵɵtextInterpolate(ctx_r0.name)',
// sourceUrl: '../test.ts' // sourceUrl: '../test.ts'
@ -292,17 +309,19 @@ runInEachFileSystem((os) => {
` <hr>\n` + ` <hr>\n` +
`</ng-template>`); `</ng-template>`);
expect(mappings).toContain( expectMapping(
mappings,
{source: '<div>', generated: 'i0.ɵɵelementStart(0, "div")', sourceUrl: '../test.ts'}); {source: '<div>', generated: 'i0.ɵɵelementStart(0, "div")', sourceUrl: '../test.ts'});
// TODO - map the bindings better // TODO - map the bindings better
expect(mappings).toContain( expectMapping(
mappings,
{source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); {source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
// TODO: the `ctx_r...` appears to be dependent upon previous tests!!! // TODO: the `ctx_r...` appears to be dependent upon previous tests!!!
// expect(mappings).toContain({ // expectMapping(mappings, {
// source: '{{ name }}', // source: '{{ name }}',
// generated: 'i0.ɵɵtextInterpolate(ctx_r0.name)', // generated: 'i0.ɵɵtextInterpolate(ctx_r0.name)',
// sourceUrl: '../test.ts' // sourceUrl: '../test.ts'
@ -313,7 +332,7 @@ runInEachFileSystem((os) => {
const mappings = compileAndMap( const mappings = compileAndMap(
'<div *ngFor="let item of items; index as i; trackBy: trackByFn">{{ item }}</div>'); '<div *ngFor="let item of items; index as i; trackBy: trackByFn">{{ item }}</div>');
expect(mappings).toContain({ expectMapping(mappings, {
source: '<div *ngFor="let item of items; index as i; trackBy: trackByFn">', source: '<div *ngFor="let item of items; index as i; trackBy: trackByFn">',
generated: 'i0.ɵɵelementStart(0, "div")', generated: 'i0.ɵɵelementStart(0, "div")',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -321,7 +340,8 @@ runInEachFileSystem((os) => {
// TODO - map the bindings better // TODO - map the bindings better
expect(mappings).toContain( expectMapping(
mappings,
{source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); {source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
}); });
@ -339,23 +359,26 @@ runInEachFileSystem((os) => {
`<h3><ng-content select="title"></ng-content></h3>\n` + `<h3><ng-content select="title"></ng-content></h3>\n` +
`<div><ng-content></ng-content></div>`); `<div><ng-content></ng-content></div>`);
expect(mappings).toContain( expectMapping(
mappings,
{source: '<h3>', generated: 'i0.ɵɵelementStart(0, "h3")', sourceUrl: '../test.ts'}); {source: '<h3>', generated: 'i0.ɵɵelementStart(0, "h3")', sourceUrl: '../test.ts'});
expect(mappings).toContain({ expectMapping(mappings, {
source: '<ng-content select="title"></ng-content>', source: '<ng-content select="title"></ng-content>',
generated: 'i0.ɵɵprojection(1)', generated: 'i0.ɵɵprojection(1)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
{source: '</h3>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); mappings, {source: '</h3>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
mappings,
{source: '<div>', generated: 'i0.ɵɵelementStart(2, "div")', sourceUrl: '../test.ts'}); {source: '<div>', generated: 'i0.ɵɵelementStart(2, "div")', sourceUrl: '../test.ts'});
expect(mappings).toContain({ expectMapping(mappings, {
source: '<ng-content></ng-content>', source: '<ng-content></ng-content>',
generated: 'i0.ɵɵprojection(3, 1)', generated: 'i0.ɵɵprojection(3, 1)',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
mappings,
{source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); {source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'});
}); });
}); });
@ -363,12 +386,12 @@ runInEachFileSystem((os) => {
describe('$localize', () => { describe('$localize', () => {
it('should create simple i18n message source-mapping', () => { it('should create simple i18n message source-mapping', () => {
const mappings = compileAndMap(`<div i18n>Hello, World!</div>`); const mappings = compileAndMap(`<div i18n>Hello, World!</div>`);
expect(mappings).toContain({ expectMapping(mappings, {
source: '<div i18n>', source: '<div i18n>',
generated: 'i0.ɵɵelementStart(0, "div")', generated: 'i0.ɵɵelementStart(0, "div")',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: 'Hello, World!', source: 'Hello, World!',
generated: '`Hello, World!`', generated: '`Hello, World!`',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
@ -377,27 +400,27 @@ runInEachFileSystem((os) => {
it('should create placeholder source-mappings', () => { it('should create placeholder source-mappings', () => {
const mappings = compileAndMap(`<div i18n>Hello, {{name}}!</div>`); const mappings = compileAndMap(`<div i18n>Hello, {{name}}!</div>`);
expect(mappings).toContain({ expectMapping(mappings, {
source: '<div i18n>', source: '<div i18n>',
generated: 'i0.ɵɵelementStart(0, "div")', generated: 'i0.ɵɵelementStart(0, "div")',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: '</div>', source: '</div>',
generated: 'i0.ɵɵelementEnd()', generated: 'i0.ɵɵelementEnd()',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: 'Hello, ', source: 'Hello, ',
generated: '`Hello, ${', generated: '`Hello, ${',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: '{{name}}', source: '{{name}}',
generated: '"\\uFFFD0\\uFFFD"', generated: '"\\uFFFD0\\uFFFD"',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: '!', source: '!',
generated: '}:INTERPOLATION:!`', generated: '}:INTERPOLATION:!`',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
@ -406,37 +429,37 @@ runInEachFileSystem((os) => {
it('should create tag (container) placeholder source-mappings', () => { it('should create tag (container) placeholder source-mappings', () => {
const mappings = compileAndMap(`<div i18n>Hello, <b>World</b>!</div>`); const mappings = compileAndMap(`<div i18n>Hello, <b>World</b>!</div>`);
expect(mappings).toContain({ expectMapping(mappings, {
source: '<div i18n>', source: '<div i18n>',
generated: 'i0.ɵɵelementStart(0, "div")', generated: 'i0.ɵɵelementStart(0, "div")',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: '</div>', source: '</div>',
generated: 'i0.ɵɵelementEnd()', generated: 'i0.ɵɵelementEnd()',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: 'Hello, ', source: 'Hello, ',
generated: '`Hello, ${', generated: '`Hello, ${',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: '<b>', source: '<b>',
generated: '"\\uFFFD#2\\uFFFD"', generated: '"\\uFFFD#2\\uFFFD"',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: 'World', source: 'World',
generated: '}:START_BOLD_TEXT:World${', generated: '}:START_BOLD_TEXT:World${',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: '</b>', source: '</b>',
generated: '"\\uFFFD/#2\\uFFFD"', generated: '"\\uFFFD/#2\\uFFFD"',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
}); });
expect(mappings).toContain({ expectMapping(mappings, {
source: '!', source: '!',
generated: '}:CLOSE_BOLD_TEXT:!`', generated: '}:CLOSE_BOLD_TEXT:!`',
sourceUrl: '../test.ts', sourceUrl: '../test.ts',
@ -448,24 +471,26 @@ runInEachFileSystem((os) => {
const mappings = compileAndMap('<div>this is a test</div><div>{{ 1 + 2 }}</div>'); const mappings = compileAndMap('<div>this is a test</div><div>{{ 1 + 2 }}</div>');
// Creation mode // Creation mode
expect(mappings).toContain( expectMapping(
mappings,
{generated: 'i0.ɵɵelementStart(0, "div")', source: '<div>', sourceUrl: '../test.ts'}); {generated: 'i0.ɵɵelementStart(0, "div")', source: '<div>', sourceUrl: '../test.ts'});
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵtext(1, "this is a test")', generated: 'i0.ɵɵtext(1, "this is a test")',
source: 'this is a test', source: 'this is a test',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
{generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../test.ts'}); mappings, {generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
mappings,
{generated: 'i0.ɵɵelementStart(2, "div")', source: '<div>', sourceUrl: '../test.ts'}); {generated: 'i0.ɵɵelementStart(2, "div")', source: '<div>', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
{generated: 'i0.ɵɵtext(3)', source: '{{ 1 + 2 }}', sourceUrl: '../test.ts'}); mappings, {generated: 'i0.ɵɵtext(3)', source: '{{ 1 + 2 }}', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
{generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../test.ts'}); mappings, {generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../test.ts'});
// Update mode // Update mode
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵtextInterpolate(1 + 2)', generated: 'i0.ɵɵtextInterpolate(1 + 2)',
source: '{{ 1 + 2 }}', source: '{{ 1 + 2 }}',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -476,25 +501,27 @@ runInEachFileSystem((os) => {
const mappings = compileAndMap('<div>this is a test</div><div>{{ 1 + 2 }}</div>'); const mappings = compileAndMap('<div>this is a test</div><div>{{ 1 + 2 }}</div>');
// Creation mode // Creation mode
expect(mappings).toContain( expectMapping(
mappings,
{generated: 'i0.ɵɵelementStart(0, "div")', source: '<div>', sourceUrl: '../test.ts'}); {generated: 'i0.ɵɵelementStart(0, "div")', source: '<div>', sourceUrl: '../test.ts'});
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵtext(1, "this is a test")', generated: 'i0.ɵɵtext(1, "this is a test")',
source: 'this is a test', source: 'this is a test',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
}); });
expect(mappings).toContain( expectMapping(
{generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../test.ts'}); mappings, {generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
mappings,
{generated: 'i0.ɵɵelementStart(2, "div")', source: '<div>', sourceUrl: '../test.ts'}); {generated: 'i0.ɵɵelementStart(2, "div")', source: '<div>', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
{generated: 'i0.ɵɵtext(3)', source: '{{ 1 + 2 }}', sourceUrl: '../test.ts'}); mappings, {generated: 'i0.ɵɵtext(3)', source: '{{ 1 + 2 }}', sourceUrl: '../test.ts'});
expect(mappings).toContain( expectMapping(
{generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../test.ts'}); mappings, {generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../test.ts'});
// TODO(benlesh): We need to circle back and prevent the extra parens from being generated. // TODO(benlesh): We need to circle back and prevent the extra parens from being generated.
// Update mode // Update mode
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵtextInterpolate(1 + 2)', generated: 'i0.ɵɵtextInterpolate(1 + 2)',
source: '{{ 1 + 2 }}', source: '{{ 1 + 2 }}',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -506,7 +533,7 @@ runInEachFileSystem((os) => {
// Note that the escaped double quotes, which need un-escaping to be parsed correctly. // Note that the escaped double quotes, which need un-escaping to be parsed correctly.
const mappings = compileAndMap('<div class=\\"some-class\\">this is a test</div>'); const mappings = compileAndMap('<div class=\\"some-class\\">this is a test</div>');
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵelementStart(0, "div", 0)', generated: 'i0.ɵɵelementStart(0, "div", 0)',
source: '<div class=\\"some-class\\">', source: '<div class=\\"some-class\\">',
sourceUrl: '../test.ts' sourceUrl: '../test.ts'
@ -525,30 +552,33 @@ runInEachFileSystem((os) => {
compileAndMap('<div>this is a test</div><div>{{ 1 + 2 }}</div>', './dir/test.html'); compileAndMap('<div>this is a test</div><div>{{ 1 + 2 }}</div>', './dir/test.html');
// Creation mode // Creation mode
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵelementStart(0, "div")', generated: 'i0.ɵɵelementStart(0, "div")',
source: '<div>', source: '<div>',
sourceUrl: '../dir/test.html' sourceUrl: '../dir/test.html'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵtext(1, "this is a test")', generated: 'i0.ɵɵtext(1, "this is a test")',
source: 'this is a test', source: 'this is a test',
sourceUrl: '../dir/test.html' sourceUrl: '../dir/test.html'
}); });
expect(mappings).toContain( expectMapping(
mappings,
{generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../dir/test.html'}); {generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../dir/test.html'});
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵelementStart(2, "div")', generated: 'i0.ɵɵelementStart(2, "div")',
source: '<div>', source: '<div>',
sourceUrl: '../dir/test.html' sourceUrl: '../dir/test.html'
}); });
expect(mappings).toContain( expectMapping(
mappings,
{generated: 'i0.ɵɵtext(3)', source: '{{ 1 + 2 }}', sourceUrl: '../dir/test.html'}); {generated: 'i0.ɵɵtext(3)', source: '{{ 1 + 2 }}', sourceUrl: '../dir/test.html'});
expect(mappings).toContain( expectMapping(
mappings,
{generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../dir/test.html'}); {generated: 'i0.ɵɵelementEnd()', source: '</div>', sourceUrl: '../dir/test.html'});
// Update mode // Update mode
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵtextInterpolate(1 + 2)', generated: 'i0.ɵɵtextInterpolate(1 + 2)',
source: '{{ 1 + 2 }}', source: '{{ 1 + 2 }}',
sourceUrl: '../dir/test.html' sourceUrl: '../dir/test.html'
@ -560,39 +590,39 @@ runInEachFileSystem((os) => {
'<div>this is a test</div><div>{{ 1 + 2 }}</div>', 'extraRootDir/test.html'); '<div>this is a test</div><div>{{ 1 + 2 }}</div>', 'extraRootDir/test.html');
// Creation mode // Creation mode
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵelementStart(0, "div")', generated: 'i0.ɵɵelementStart(0, "div")',
source: '<div>', source: '<div>',
sourceUrl: '../extraRootDir/test.html' sourceUrl: '../extraRootDir/test.html'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵtext(1, "this is a test")', generated: 'i0.ɵɵtext(1, "this is a test")',
source: 'this is a test', source: 'this is a test',
sourceUrl: '../extraRootDir/test.html' sourceUrl: '../extraRootDir/test.html'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵelementEnd()', generated: 'i0.ɵɵelementEnd()',
source: '</div>', source: '</div>',
sourceUrl: '../extraRootDir/test.html' sourceUrl: '../extraRootDir/test.html'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵelementStart(2, "div")', generated: 'i0.ɵɵelementStart(2, "div")',
source: '<div>', source: '<div>',
sourceUrl: '../extraRootDir/test.html' sourceUrl: '../extraRootDir/test.html'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵtext(3)', generated: 'i0.ɵɵtext(3)',
source: '{{ 1 + 2 }}', source: '{{ 1 + 2 }}',
sourceUrl: '../extraRootDir/test.html' sourceUrl: '../extraRootDir/test.html'
}); });
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵelementEnd()', generated: 'i0.ɵɵelementEnd()',
source: '</div>', source: '</div>',
sourceUrl: '../extraRootDir/test.html' sourceUrl: '../extraRootDir/test.html'
}); });
// Update mode // Update mode
expect(mappings).toContain({ expectMapping(mappings, {
generated: 'i0.ɵɵtextInterpolate(1 + 2)', generated: 'i0.ɵɵtextInterpolate(1 + 2)',
source: '{{ 1 + 2 }}', source: '{{ 1 + 2 }}',
sourceUrl: '../extraRootDir/test.html' sourceUrl: '../extraRootDir/test.html'
@ -638,5 +668,42 @@ runInEachFileSystem((os) => {
return value + padding; return value + padding;
} }
} }
function expectMapping(mappings: SegmentMapping[], expected: SegmentMapping): void {
if (mappings.some(
m => m.generated === expected.generated && m.source === expected.source &&
m.sourceUrl === expected.sourceUrl)) {
return;
}
const matchingGenerated = mappings.filter(m => m.generated === expected.generated);
const matchingSource = mappings.filter(m => m.source === expected.source);
const message = [
'Expected mappings to contain the following mapping',
prettyPrintMapping(expected),
];
if (matchingGenerated.length > 0) {
message.push('');
message.push('There are the following mappings that match the generated text:');
matchingGenerated.forEach(m => message.push(prettyPrintMapping(m)));
}
if (matchingSource.length > 0) {
message.push('');
message.push('There are the following mappings that match the source text:');
matchingSource.forEach(m => message.push(prettyPrintMapping(m)));
}
fail(message.join('\n'));
}
function prettyPrintMapping(mapping: SegmentMapping): string {
return [
'{',
` generated: ${JSON.stringify(mapping.generated)}`,
` source: ${JSON.stringify(mapping.source)}`,
` sourceUrl: ${JSON.stringify(mapping.sourceUrl)}`,
'}',
].join('\n');
}
}); });
}); });