Skip to content

Commit 388afa4

Browse files
chuckjazmhevery
authored andcommitted
test(compiler): add integration like tests to compiler unit tests (angular#14157)
Closes PR angular#14157 PR Close angular#14157
1 parent 4370049 commit 388afa4

File tree

4 files changed

+595
-0
lines changed

4 files changed

+595
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Tests in this directory are excluded from running in the browser and only running
2+
in node.
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {AotCompiler, AotCompilerHost, createAotCompiler} from '@angular/compiler';
10+
import {async} from '@angular/core/testing';
11+
import * as path from 'path';
12+
import * as ts from 'typescript';
13+
14+
import {ReflectionCapabilities, reflector} from './private_import_core';
15+
import {EmittingCompilerHost, MockAotCompilerHost, MockCompilerHost, MockData, settings} from './test_util';
16+
17+
const DTS = /\.d\.ts$/;
18+
19+
// These are the files that contain the well known annotations.
20+
const CORE_FILES = [
21+
'@angular/core/src/metadata.ts', '@angular/core/src/di/metadata.ts',
22+
'@angular/core/src/di/injection_token.ts', '@angular/core/src/animation/metadata.ts',
23+
'@angular/core/src/di/provider.ts', '@angular/core/src/linker/view.ts'
24+
];
25+
26+
describe('compiler', () => {
27+
let angularFiles: Map<string, string>;
28+
29+
beforeAll(() => {
30+
const emittingHost = new EmittingCompilerHost(CORE_FILES);
31+
const emittingProgram = ts.createProgram(emittingHost.scripts, settings, emittingHost);
32+
emittingProgram.emit();
33+
angularFiles = emittingHost.written;
34+
});
35+
36+
describe('Quickstart', () => {
37+
let host: MockCompilerHost;
38+
let aotHost: MockAotCompilerHost;
39+
40+
beforeEach(() => {
41+
host = new MockCompilerHost(QUICKSTART, FILES, angularFiles);
42+
aotHost = new MockAotCompilerHost(host);
43+
});
44+
45+
// Restore reflector since AoT compiler will update it with a new static reflector
46+
afterEach(() => { reflector.updateCapabilities(new ReflectionCapabilities()); });
47+
48+
it('should compile',
49+
async(() => compile(host, aotHost, expectNoDiagnostics).then(generatedFiles => {
50+
expect(generatedFiles.find(f => /app\.component\.ngfactory\.ts/.test(f.genFileUrl)))
51+
.not.toBeUndefined();
52+
expect(generatedFiles.find(f => /app\.module\.ngfactory\.ts/.test(f.genFileUrl)))
53+
.not.toBeUndefined();
54+
})));
55+
56+
it('should compile using summaries',
57+
async(() => summaryCompile(host, aotHost).then(generatedFiles => {
58+
expect(generatedFiles.find(f => /app\.component\.ngfactory\.ts/.test(f.genFileUrl)))
59+
.not.toBeUndefined();
60+
expect(generatedFiles.find(f => /app\.module\.ngfactory\.ts/.test(f.genFileUrl)))
61+
.not.toBeUndefined();
62+
})));
63+
});
64+
});
65+
66+
function expectNoDiagnostics(program: ts.Program) {
67+
function fileInfo(diagnostic: ts.Diagnostic): string {
68+
if (diagnostic.file) {
69+
return `${diagnostic.file.fileName}(${diagnostic.start}): `;
70+
}
71+
return '';
72+
}
73+
74+
function chars(len: number, ch: string): string { return new Array(len).fill(ch).join(''); }
75+
76+
function lineNoOf(offset: number, text: string): number {
77+
let result = 1;
78+
for (let i = 0; i < offset; i++) {
79+
if (text[i] == '\n') result++;
80+
}
81+
return result;
82+
}
83+
84+
function lineInfo(diagnostic: ts.Diagnostic): string {
85+
if (diagnostic.file) {
86+
const start = diagnostic.start;
87+
let end = diagnostic.start + diagnostic.length;
88+
const source = diagnostic.file.text;
89+
let lineStart = start;
90+
let lineEnd = end;
91+
while (lineStart > 0 && source[lineStart] != '\n') lineStart--;
92+
if (lineStart < start) lineStart++;
93+
while (lineEnd < source.length && source[lineEnd] != '\n') lineEnd++;
94+
let line = source.substring(lineStart, lineEnd);
95+
const lineIndex = line.indexOf('/n');
96+
if (lineIndex > 0) {
97+
line = line.substr(0, lineIndex);
98+
end = start + lineIndex;
99+
}
100+
const lineNo = lineNoOf(start, source) + ': ';
101+
return '\n' + lineNo + line + '\n' + chars(start - lineStart + lineNo.length, ' ') +
102+
chars(end - start, '^');
103+
}
104+
return '';
105+
}
106+
107+
function expectNoDiagnostics(diagnostics: ts.Diagnostic[]) {
108+
if (diagnostics && diagnostics.length) {
109+
throw new Error(
110+
'Errors from TypeScript:\n' +
111+
diagnostics.map(d => `${fileInfo(d)}${d.messageText}${lineInfo(d)}`).join(' \n'));
112+
}
113+
}
114+
expectNoDiagnostics(program.getOptionsDiagnostics());
115+
expectNoDiagnostics(program.getSyntacticDiagnostics());
116+
expectNoDiagnostics(program.getSemanticDiagnostics());
117+
}
118+
119+
function isDTS(fileName: string): boolean {
120+
return /\.d\.ts$/.test(fileName);
121+
}
122+
123+
function isSource(fileName: string): boolean {
124+
return /\.ts$/.test(fileName);
125+
}
126+
127+
function isFactory(fileName: string): boolean {
128+
return /\.ngfactory\./.test(fileName);
129+
}
130+
131+
function summaryCompile(
132+
host: MockCompilerHost, aotHost: MockAotCompilerHost,
133+
preCompile?: (program: ts.Program) => void) {
134+
// First compile the program to generate the summary files.
135+
return compile(host, aotHost).then(generatedFiles => {
136+
// Remove generated files that were not generated from a DTS file
137+
host.remove(generatedFiles.filter(f => !isDTS(f.srcFileUrl)).map(f => f.genFileUrl));
138+
139+
// Next compile the program shrowding metadata and only treating .ts files as source.
140+
aotHost.hideMetadata();
141+
aotHost.tsFilesOnly();
142+
143+
return compile(host, aotHost);
144+
});
145+
}
146+
147+
function compile(
148+
host: MockCompilerHost, aotHost: AotCompilerHost, preCompile?: (program: ts.Program) => void,
149+
postCompile: (program: ts.Program) => void = expectNoDiagnostics) {
150+
const program = ts.createProgram(host.scriptNames, settings, host);
151+
if (preCompile) preCompile(program);
152+
const {compiler, reflector} = createAotCompiler(aotHost, {});
153+
return compiler.compileAll(program.getSourceFiles().map(sf => sf.fileName))
154+
.then(generatedFiles => {
155+
generatedFiles.forEach(
156+
file => isSource(file.genFileUrl) ? host.addScript(file.genFileUrl, file.source) :
157+
host.override(file.genFileUrl, file.source));
158+
const newProgram = ts.createProgram(host.scriptNames, settings, host, program);
159+
if (postCompile) postCompile(newProgram);
160+
return generatedFiles;
161+
});
162+
}
163+
164+
const QUICKSTART = ['/quickstart/app/app.module.ts'];
165+
const FILES: MockData = {
166+
quickstart: {
167+
app: {
168+
'app.component.ts': `
169+
import {Component} from '@angular/core/src/metadata';
170+
171+
@Component({
172+
template: '<h1>Hello {{name}}</h1>'
173+
})
174+
export class AppComponent {
175+
name = 'Angular';
176+
}
177+
`,
178+
'app.module.ts': `
179+
import { NgModule } from '@angular/core/src/metadata';
180+
181+
import { AppComponent } from './app.component';
182+
183+
@NgModule({
184+
declarations: [ AppComponent ],
185+
bootstrap: [ AppComponent ]
186+
})
187+
export class AppModule { }
188+
`
189+
}
190+
}
191+
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {__core_private__ as r} from '@angular/core';
10+
11+
export type ReflectionCapabilities = typeof r._ReflectionCapabilities;
12+
export const ReflectionCapabilities: typeof r.ReflectionCapabilities = r.ReflectionCapabilities;
13+
export const reflector: typeof r.reflector = r.reflector;

0 commit comments

Comments
 (0)