refactor(ivy): run the compiler compliance tests against ngtsc (#24862)
This commit moves the compiler compliance tests into compiler-cli, and uses ngtsc to run them instead of the custom compilation pipeline used before. Testing against ngtsc allows for validation of the real compiler output. This commit also fixes a few small issues that prevented the tests from passing. PR Close #24862
This commit is contained in:

committed by
Victor Berchet

parent
b7bbc82e3e
commit
9fd70c9715
217
packages/compiler-cli/test/compliance/mock_compiler_spec.ts
Normal file
217
packages/compiler-cli/test/compliance/mock_compiler_spec.ts
Normal file
@ -0,0 +1,217 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
|
||||
import {MockDirectory, setup} from '@angular/compiler/test/aot/test_util';
|
||||
import {compile, expectEmit} from './mock_compile';
|
||||
|
||||
describe('mock_compiler', () => {
|
||||
// This produces a MockDirectory of the file needed to compile an Angular application.
|
||||
// This setup is performed in a beforeAll which populates the map returned.
|
||||
const angularFiles = setup({
|
||||
compileAngular: true,
|
||||
compileAnimations: false,
|
||||
compileCommon: true,
|
||||
});
|
||||
|
||||
describe('compiling', () => {
|
||||
// To use compile you need to supply the files in a MockDirectory that can be merged
|
||||
// with a set of "environment" files such as the angular files.
|
||||
it('should be able to compile a simple application', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'hello.component.ts': `
|
||||
import {Component, Input} from '@angular/core';
|
||||
|
||||
@Component({template: 'Hello {{name}}!'})
|
||||
export class HelloComponent {
|
||||
@Input() name: string = 'world';
|
||||
}
|
||||
`,
|
||||
'hello.module.ts': `
|
||||
import {NgModule} from '@angular/core';
|
||||
import {HelloComponent} from './hello.component';
|
||||
|
||||
@NgModule({declarations: [HelloComponent]})
|
||||
export class HelloModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
const result = compile(files, angularFiles);
|
||||
|
||||
// result.source contains just the emitted factory declarations regardless of the original
|
||||
// module.
|
||||
expect(result.source).toContain('Hello');
|
||||
});
|
||||
});
|
||||
|
||||
describe('expecting emitted output', () => {
|
||||
it('should be able to find a simple expression in the output', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'hello.component.ts': `
|
||||
import {Component, Input} from '@angular/core';
|
||||
|
||||
@Component({template: 'Hello {{name}}! Your name as {{name.length}} characters'})
|
||||
export class HelloComponent {
|
||||
@Input() name: string = 'world';
|
||||
}
|
||||
`,
|
||||
'hello.module.ts': `
|
||||
import {NgModule} from '@angular/core';
|
||||
import {HelloComponent} from './hello.component';
|
||||
|
||||
@NgModule({declarations: [HelloComponent]})
|
||||
export class HelloModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
|
||||
// The expression can expected directly.
|
||||
expectEmit(result.source, 'name.length', 'name length expression not found');
|
||||
|
||||
// Whitespace is not significant
|
||||
expectEmit(
|
||||
result.source, 'name \n\n . \n length',
|
||||
'name length expression not found (whitespace)');
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to skip untested regions (… and // ...)', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'hello.component.ts': `
|
||||
import {Component, Input} from '@angular/core';
|
||||
|
||||
@Component({template: 'Hello {{name}}! Your name as {{name.length}} characters'})
|
||||
export class HelloComponent {
|
||||
@Input() name: string = 'world';
|
||||
}
|
||||
`,
|
||||
'hello.module.ts': `
|
||||
import {NgModule} from '@angular/core';
|
||||
import {HelloComponent} from './hello.component';
|
||||
|
||||
@NgModule({declarations: [HelloComponent]})
|
||||
export class HelloModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
|
||||
// The special character … means anything can be generated between the two sections allowing
|
||||
// skipping sections of the output that are not under test. The ellipsis unicode char (…) is
|
||||
// used instead of '...' because '...' is legal JavaScript (the spread operator) and might
|
||||
// need to be tested. `// ...` could also be used in place of `…`.
|
||||
expectEmit(result.source, 'ctx.name … ctx.name.length', 'could not find correct length access');
|
||||
expectEmit(
|
||||
result.source, 'ctx.name // ... ctx.name.length', 'could not find correct length access');
|
||||
});
|
||||
|
||||
it('should be able to skip TODO comments (// TODO)', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'hello.component.ts': `
|
||||
import {Component, Input} from '@angular/core';
|
||||
|
||||
@Component({template: 'Hello!'})
|
||||
export class HelloComponent { }
|
||||
`,
|
||||
'hello.module.ts': `
|
||||
import {NgModule} from '@angular/core';
|
||||
import {HelloComponent} from './hello.component';
|
||||
|
||||
@NgModule({declarations: [HelloComponent]})
|
||||
export class HelloModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
|
||||
expectEmit(
|
||||
result.source, `
|
||||
// TODO: this comment should not be taken into account
|
||||
$r3$.ɵT(0, "Hello!");
|
||||
// TODO: this comment should not be taken into account
|
||||
`,
|
||||
'todo comments should be ignored');
|
||||
});
|
||||
|
||||
|
||||
it('should be able to enforce consistent identifiers', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'hello.component.ts': `
|
||||
import {Component, Input} from '@angular/core';
|
||||
|
||||
@Component({template: 'Hello {{name}}! Your name as {{name.length}} characters'})
|
||||
export class HelloComponent {
|
||||
@Input() name: string = 'world';
|
||||
}
|
||||
`,
|
||||
'hello.module.ts': `
|
||||
import {NgModule} from '@angular/core';
|
||||
import {HelloComponent} from './hello.component';
|
||||
|
||||
@NgModule({declarations: [HelloComponent]})
|
||||
export class HelloModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
|
||||
// IDENT can be used a wild card for any identifier
|
||||
expectEmit(result.source, 'IDENT.name', 'could not find context access');
|
||||
|
||||
// $<ident>$ can be used as a wild-card but all the content matched by the identifiers must
|
||||
// match each other.
|
||||
// This is useful if the code generator is free to invent a name but should use the name
|
||||
// consistently.
|
||||
expectEmit(
|
||||
result.source, '$ctx$.$name$ … $ctx$.$name$.length',
|
||||
'could not find correct length access');
|
||||
});
|
||||
|
||||
it('should be able to enforce that identifiers match a regexp', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'hello.component.ts': `
|
||||
import {Component, Input} from '@angular/core';
|
||||
|
||||
@Component({template: 'Hello {{name}}! Your name as {{name.length}} characters'})
|
||||
export class HelloComponent {
|
||||
@Input() name: string = 'world';
|
||||
}
|
||||
`,
|
||||
'hello.module.ts': `
|
||||
import {NgModule} from '@angular/core';
|
||||
import {HelloComponent} from './hello.component';
|
||||
|
||||
@NgModule({declarations: [HelloComponent]})
|
||||
export class HelloModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
|
||||
// Pass: `$n$` ends with `ME` in the generated code
|
||||
expectEmit(result.source, '$ctx$.$n$ … $ctx$.$n$.length', 'Match names', {'$n$': /ME$/i});
|
||||
|
||||
// Fail: `$n$` does not match `/(not)_(\1)/` in the generated code
|
||||
expect(() => {
|
||||
expectEmit(
|
||||
result.source, '$ctx$.$n$ … $ctx$.$n$.length', 'Match names', {'$n$': /(not)_(\1)/});
|
||||
}).toThrowError(/"\$n\$" is "name" which doesn't match \/\(not\)_\(\\1\)\//);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user