ci(compiler-cli): run compiler-cli tests in bazel (#22997)

PR Close #22997
This commit is contained in:
Chuck Jazdzewski 2018-03-21 14:22:06 -07:00 committed by Alex Rickabaugh
parent d9dc46e651
commit 4e004f3783
15 changed files with 618 additions and 219 deletions

View File

@ -266,9 +266,6 @@ export interface TsEmitArguments {
export interface TsEmitCallback { (args: TsEmitArguments): ts.EmitResult; }
export interface TsMergeEmitResultsCallback { (results: ts.EmitResult[]): ts.EmitResult; }
/**
* @internal
*/
export interface LibrarySummary {
fileName: string;
text: string;
@ -371,8 +368,6 @@ export interface Program {
* Returns the .d.ts / .ngsummary.json / .ngfactory.d.ts files of libraries that have been emitted
* in this program or previous programs with paths that emulate the fact that these libraries
* have been compiled before with no outDir.
*
* @internal
*/
getLibrarySummaries(): Map<string, LibrarySummary>;

View File

@ -0,0 +1,130 @@
load("//tools:defaults.bzl", "ts_library", "ts_web_test")
load("@build_bazel_rules_nodejs//:defs.bzl", "jasmine_node_test")
# Uses separate test rules to allow the tests to run in parallel
ts_library(
name = "test_utils",
testonly = 1,
srcs = [
"mocks.ts",
"test_support.ts",
],
visibility = [":__subpackages__"],
deps = [
"//packages:types",
"//packages/compiler",
"//packages/compiler-cli",
],
)
# extract_18n_spec
ts_library(
name = "extract_i18n_lib",
testonly = 1,
srcs = [
"extract_i18n_spec.ts",
],
deps = [
":test_utils",
"//packages/compiler",
"//packages/compiler-cli",
],
)
jasmine_node_test(
name = "extract_i18n",
bootstrap = ["angular/tools/testing/init_node_spec.js"],
data = [
"//packages/core:npm_package",
],
deps = [
":extract_i18n_lib",
"//packages/core",
"//tools/testing:node",
],
)
# ngc_spec
ts_library(
name = "ngc_lib",
testonly = 1,
srcs = [
"ngc_spec.ts",
],
deps = [
":test_utils",
"//packages/compiler",
"//packages/compiler-cli",
],
)
jasmine_node_test(
name = "ngc",
bootstrap = ["angular/tools/testing/init_node_spec.js"],
data = [
"//packages/common:npm_package",
"//packages/core:npm_package",
"//packages/platform-browser:npm_package",
],
deps = [
":ngc_lib",
"//packages/core",
"//tools/testing:node",
],
)
# ngctools_api_spec
ts_library(
name = "ngtools_api_lib",
testonly = 1,
srcs = [
"ngtools_api_spec.ts",
],
deps = [
":test_utils",
"//packages/compiler",
"//packages/compiler-cli",
],
)
jasmine_node_test(
name = "ngtools_api",
bootstrap = ["angular/tools/testing/init_node_spec.js"],
data = [
"//packages/core:npm_package",
"//packages/router:npm_package",
],
deps = [
":ngtools_api_lib",
"//packages/core",
"//tools/testing:node",
],
)
# perform_watch_spec
ts_library(
name = "perform_watch_lib",
testonly = 1,
srcs = [
"perform_watch_spec.ts",
],
deps = [
":test_utils",
"//packages/compiler",
"//packages/compiler-cli",
],
)
jasmine_node_test(
name = "perform_watch",
bootstrap = ["angular/tools/testing/init_node_spec.js"],
data = [
"//packages/core:npm_package",
],
deps = [
":perform_watch_lib",
"//packages/core",
"//tools/testing:node",
],
)

View File

@ -0,0 +1,99 @@
load("//tools:defaults.bzl", "ts_library", "ts_web_test")
load("@build_bazel_rules_nodejs//:defs.bzl", "jasmine_node_test")
ts_library(
name = "mocks",
testonly = 1,
srcs = [
"mocks.ts",
],
deps = [
"//packages:types",
"//packages/compiler",
"//packages/compiler-cli",
"//packages/compiler-cli/test:test_utils",
"//packages/core",
],
)
# check_types_spec
ts_library(
name = "check_types_lib",
testonly = 1,
srcs = ["check_types_spec.ts"],
deps = [
":mocks",
"//packages/compiler-cli",
"//packages/compiler-cli/test:test_utils",
],
)
jasmine_node_test(
name = "check_types",
bootstrap = ["angular/tools/testing/init_node_spec.js"],
data = [
"//packages/common:npm_package",
"//packages/core:npm_package",
],
deps = [
":check_types_lib",
"//packages/core",
"//tools/testing:node",
],
)
# expression_diagnostics_spec
ts_library(
name = "expression_diagnostics_lib",
testonly = 1,
srcs = ["expression_diagnostics_spec.ts"],
deps = [
":mocks",
"//packages/compiler",
"//packages/compiler-cli",
"//packages/compiler-cli/test:test_utils",
"//packages/language-service",
],
)
jasmine_node_test(
name = "expression_diagnostics",
bootstrap = ["angular/tools/testing/init_node_spec.js"],
data = [
"//packages/common:npm_package",
"//packages/core:npm_package",
"//packages/forms:npm_package",
],
deps = [
":expression_diagnostics_lib",
"//packages/core",
"//tools/testing:node",
],
)
# symbol_query_spec
ts_library(
name = "symbol_query_lib",
testonly = 1,
srcs = ["symbol_query_spec.ts"],
deps = [
":mocks",
"//packages/compiler",
"//packages/compiler-cli",
"//packages/compiler-cli/test:test_utils",
"//packages/compiler/test:test_utils",
"//packages/language-service",
],
)
jasmine_node_test(
name = "symbol_query",
bootstrap = ["angular/tools/testing/init_node_spec.js"],
data = [
],
deps = [
":symbol_query_lib",
"//packages/core",
"//tools/testing:node",
],
)

View File

@ -19,6 +19,7 @@ import {DiagnosticContext, MockLanguageServiceHost, getDiagnosticTemplateInfo} f
describe('expression diagnostics', () => {
let registry: ts.DocumentRegistry;
let host: MockLanguageServiceHost;
let service: ts.LanguageService;
let context: DiagnosticContext;

View File

@ -15,11 +15,17 @@ import * as ts from 'typescript';
import {DiagnosticTemplateInfo} from '../../src/diagnostics/expression_diagnostics';
import {getClassFromStaticSymbol, getClassMembers, getPipesTable, getSymbolQuery} from '../../src/diagnostics/typescript_symbols';
import {Directory, MockAotContext} from '../mocks';
import {isInBazel, setup} from '../test_support';
function calcRootPath() {
function calculateAngularPath() {
if (isInBazel()) {
const support = setup();
return path.join(support.basePath, 'node_modules/@angular/*');
} else {
const moduleFilename = module.filename.replace(/\\/g, '/');
const distIndex = moduleFilename.indexOf('/dist/all');
return moduleFilename.substr(0, distIndex);
return moduleFilename.substr(0, distIndex) + '/packages/*';
}
}
const realFiles = new Map<string, string>();
@ -43,7 +49,7 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost {
strictNullChecks: true,
baseUrl: currentDirectory,
lib: ['lib.es2015.d.ts', 'lib.dom.d.ts'],
paths: {'@angular/*': [calcRootPath() + '/packages/*']}
paths: {'@angular/*': [calculateAngularPath()]}
};
this.context = new MockAotContext(currentDirectory, files);
}

View File

@ -12,7 +12,7 @@ import * as ts from 'typescript';
import {mainXi18n} from '../src/extract_i18n';
import {makeTempDir} from './test_support';
import {isInBazel, makeTempDir, setup} from './test_support';
function getNgRootDir() {
const moduleFilename = module.filename.replace(/\\/g, '/');
@ -110,6 +110,12 @@ describe('extract_i18n command line', () => {
beforeEach(() => {
errorSpy = jasmine.createSpy('consoleError').and.callFake(console.error);
if (isInBazel()) {
const support = setup();
write = (fileName: string, content: string) => { support.write(fileName, content); };
basePath = support.basePath;
outDir = path.join(basePath, 'built');
} else {
basePath = makeTempDir();
write = (fileName: string, content: string) => {
const dir = path.dirname(fileName);
@ -119,6 +125,16 @@ describe('extract_i18n command line', () => {
}
fs.writeFileSync(path.join(basePath, fileName), content, {encoding: 'utf-8'});
};
outDir = path.resolve(basePath, 'built');
const ngRootDir = getNgRootDir();
const nodeModulesPath = path.resolve(basePath, 'node_modules');
fs.mkdirSync(nodeModulesPath);
fs.symlinkSync(
path.resolve(ngRootDir, 'dist', 'all', '@angular'),
path.resolve(nodeModulesPath, '@angular'));
fs.symlinkSync(
path.resolve(ngRootDir, 'node_modules', 'rxjs'), path.resolve(nodeModulesPath, 'rxjs'));
}
write('tsconfig-base.json', `{
"compilerOptions": {
"experimentalDecorators": true,
@ -136,15 +152,6 @@ describe('extract_i18n command line', () => {
"typeRoots": ["node_modules/@types"]
}
}`);
outDir = path.resolve(basePath, 'built');
const ngRootDir = getNgRootDir();
const nodeModulesPath = path.resolve(basePath, 'node_modules');
fs.mkdirSync(nodeModulesPath);
fs.symlinkSync(
path.resolve(ngRootDir, 'dist', 'all', '@angular'),
path.resolve(nodeModulesPath, '@angular'));
fs.symlinkSync(
path.resolve(ngRootDir, 'node_modules', 'rxjs'), path.resolve(nodeModulesPath, 'rxjs'));
});
function writeSources() {

View File

@ -0,0 +1,26 @@
load("//tools:defaults.bzl", "ts_library", "ts_web_test")
load("@build_bazel_rules_nodejs//:defs.bzl", "jasmine_node_test")
ts_library(
name = "test_lib",
testonly = 1,
srcs = glob(["**/*.ts"]),
deps = [
"//packages:types",
"//packages/compiler",
"//packages/compiler-cli",
"//packages/core",
],
)
jasmine_node_test(
name = "test",
bootstrap = ["angular/tools/testing/init_node_spec.js"],
data = [
],
deps = [
":test_lib",
"//packages/core",
"//tools/testing:node",
],
)

View File

@ -877,7 +877,7 @@ describe('Collector', () => {
export const InjectionToken: {new<T>(desc: string): InjectionToken<T>;} = class {
constructor(protected _desc: string) {}
toString(): string { return \`InjectionToken ${this._desc}\`; }
toString(): string { return \`InjectionToken \${this._desc}\`; }
} as any;`,
ts.ScriptTarget.Latest, true);
const metadata = collector.getMetadata(source) !;

View File

@ -11,7 +11,8 @@ import * as path from 'path';
import * as ts from 'typescript';
import {main, readCommandLineAndConfiguration, watchMode} from '../src/main';
import {makeTempDir} from './test_support';
import {isInBazel, makeTempDir, setup} from './test_support';
function getNgRootDir() {
const moduleFilename = module.filename.replace(/\\/g, '/');
@ -43,6 +44,13 @@ describe('ngc transformer command-line', () => {
beforeEach(() => {
errorSpy = jasmine.createSpy('consoleError').and.callFake(console.error);
if (isInBazel) {
const support = setup();
basePath = support.basePath;
outDir = path.join(basePath, 'built');
process.chdir(basePath);
write = (fileName: string, content: string) => { support.write(fileName, content); };
} else {
basePath = makeTempDir();
process.chdir(basePath);
write = (fileName: string, content: string) => {
@ -53,6 +61,16 @@ describe('ngc transformer command-line', () => {
}
fs.writeFileSync(path.join(basePath, fileName), content, {encoding: 'utf-8'});
};
outDir = path.resolve(basePath, 'built');
const ngRootDir = getNgRootDir();
const nodeModulesPath = path.resolve(basePath, 'node_modules');
fs.mkdirSync(nodeModulesPath);
fs.symlinkSync(
path.resolve(ngRootDir, 'dist', 'all', '@angular'),
path.resolve(nodeModulesPath, '@angular'));
fs.symlinkSync(
path.resolve(ngRootDir, 'node_modules', 'rxjs'), path.resolve(nodeModulesPath, 'rxjs'));
}
write('tsconfig-base.json', `{
"compilerOptions": {
"experimentalDecorators": true,
@ -70,15 +88,6 @@ describe('ngc transformer command-line', () => {
"typeRoots": ["node_modules/@types"]
}
}`);
outDir = path.resolve(basePath, 'built');
const ngRootDir = getNgRootDir();
const nodeModulesPath = path.resolve(basePath, 'node_modules');
fs.mkdirSync(nodeModulesPath);
fs.symlinkSync(
path.resolve(ngRootDir, 'dist', 'all', '@angular'),
path.resolve(nodeModulesPath, '@angular'));
fs.symlinkSync(
path.resolve(ngRootDir, 'node_modules', 'rxjs'), path.resolve(nodeModulesPath, 'rxjs'));
});
it('should compile without errors', () => {
@ -243,10 +252,19 @@ describe('ngc transformer command-line', () => {
expect(exitCode).toEqual(0);
expect(fs.existsSync(path.resolve(outDir, 'mymodule.ngfactory.js'))).toBe(true);
if (isInBazel()) {
// In bazel we use the packaged version so the factory is at the root and we
// get the flattened factory.
expect(fs.existsSync(
path.resolve(outDir, 'node_modules', '@angular', 'core', 'core.ngfactory.js')))
.toBe(true);
} else {
expect(fs.existsSync(path.resolve(
outDir, 'node_modules', '@angular', 'core', 'src',
'application_module.ngfactory.js')))
.toBe(true);
}
});
describe('comments', () => {
@ -351,10 +369,18 @@ describe('ngc transformer command-line', () => {
const exitCode = main(['-p', path.join(basePath, 'tsconfig.json')], errorSpy);
expect(exitCode).toEqual(0);
expect(fs.existsSync(path.resolve(outDir, 'mymodule.ngfactory.js'))).toBe(true);
if (isInBazel()) {
// In bazel we use the packaged version so the factory is at the root and we
// get the flattened factory.
expect(fs.existsSync(
path.resolve(outDir, 'node_modules', '@angular', 'core', 'core.ngfactory.js')))
.toBe(true);
} else {
expect(fs.existsSync(path.resolve(
outDir, 'node_modules', '@angular', 'core', 'src',
'application_module.ngfactory.js')))
.toBe(true);
}
});
describe(`emit generated files depending on the source file`, () => {
@ -1124,7 +1150,10 @@ describe('ngc transformer command-line', () => {
}
`);
if (!isInBazel()) {
// This is not necessary in bazel as it uses the npm_package
expect(main(['-p', path.join(basePath, 'tsconfig-ng.json')], errorSpy)).toBe(0);
}
expect(main(['-p', path.join(basePath, 'lib1', 'tsconfig-lib1.json')], errorSpy)).toBe(0);
expect(main(['-p', path.join(basePath, 'lib2', 'tsconfig-lib2.json')], errorSpy)).toBe(0);
expect(main(['-p', path.join(basePath, 'app', 'tsconfig-app.json')], errorSpy)).toBe(0);
@ -1161,6 +1190,8 @@ describe('ngc transformer command-line', () => {
shouldExist('app/main.js');
});
if (!isInBazel()) {
// This is an unnecessary test bazel as it always uses flat modules
it('should be able to compile libraries with summaries and flat modules', () => {
writeFiles();
compile();
@ -1261,6 +1292,7 @@ describe('ngc transformer command-line', () => {
expect(main(['-p', path.join(basePath, 'app', 'tsconfig-app.json')], errorSpy)).toBe(0);
}
});
}
describe('enableResourceInlining', () => {
it('should inline templateUrl and styleUrl in JS and metadata', () => {
@ -1308,6 +1340,7 @@ describe('ngc transformer command-line', () => {
});
});
describe('expression lowering', () => {
const shouldExist = (fileName: string) => {
if (!fs.existsSync(path.resolve(basePath, fileName))) {

View File

@ -6,11 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {__NGTOOLS_PRIVATE_API_2 as NgTools_InternalApi_NG_2} from '@angular/compiler-cli';
import * as path from 'path';
import * as ts from 'typescript';
import {NgTools_InternalApi_NG_2} from '../src/ngtools_api';
import {TestSupport, setup} from './test_support';
describe('ngtools_api (deprecated)', () => {

View File

@ -48,21 +48,7 @@ export interface TestSupport {
shouldNotExist(fileName: string): void;
}
export function setup(): TestSupport {
const basePath = makeTempDir();
const ngRootDir = getNgRootDir();
const nodeModulesPath = path.resolve(basePath, 'node_modules');
fs.mkdirSync(nodeModulesPath);
fs.symlinkSync(
path.resolve(ngRootDir, 'dist', 'all', '@angular'),
path.resolve(nodeModulesPath, '@angular'));
fs.symlinkSync(
path.resolve(ngRootDir, 'node_modules', 'rxjs'), path.resolve(nodeModulesPath, 'rxjs'));
fs.symlinkSync(
path.resolve(ngRootDir, 'node_modules', 'typescript'),
path.resolve(nodeModulesPath, 'typescript'));
function createTestSupportFor(basePath: string) {
return {basePath, write, writeFiles, createCompilerOptions, shouldExist, shouldNotExist};
function write(fileName: string, content: string) {
@ -114,6 +100,69 @@ export function setup(): TestSupport {
}
}
export function setupBazelTo(basePath: string) {
const sources = process.env.TEST_SRCDIR;
const packages = path.join(sources, 'angular/packages');
const nodeModulesPath = path.join(basePath, 'node_modules');
const angularDirectory = path.join(nodeModulesPath, '@angular');
fs.mkdirSync(nodeModulesPath);
// Link the built angular packages
fs.mkdirSync(angularDirectory);
const packageNames = fs.readdirSync(packages).filter(
name => fs.statSync(path.join(packages, name)).isDirectory() &&
fs.existsSync(path.join(packages, name, 'npm_package')));
for (const pkg of packageNames) {
fs.symlinkSync(path.join(packages, `${pkg}/npm_package`), path.join(angularDirectory, pkg));
}
// Link rxjs
const rxjsSource = path.join(sources, 'rxjs');
const rxjsDest = path.join(nodeModulesPath, 'rxjs');
if (fs.existsSync(rxjsSource)) {
fs.symlinkSync(rxjsSource, rxjsDest);
}
// Link typescript
const typescriptSource = path.join(sources, 'angular/node_modules/typescript');
const typescriptDest = path.join(nodeModulesPath, 'typescript');
if (fs.existsSync(typescriptSource)) {
fs.symlinkSync(typescriptSource, typescriptDest);
}
}
function setupBazel(): TestSupport {
const basePath = makeTempDir();
setupBazelTo(basePath);
return createTestSupportFor(basePath);
}
function setupTestSh(): TestSupport {
const basePath = makeTempDir();
const ngRootDir = getNgRootDir();
const nodeModulesPath = path.resolve(basePath, 'node_modules');
fs.mkdirSync(nodeModulesPath);
fs.symlinkSync(
path.resolve(ngRootDir, 'dist', 'all', '@angular'),
path.resolve(nodeModulesPath, '@angular'));
fs.symlinkSync(
path.resolve(ngRootDir, 'node_modules', 'rxjs'), path.resolve(nodeModulesPath, 'rxjs'));
fs.symlinkSync(
path.resolve(ngRootDir, 'node_modules', 'typescript'),
path.resolve(nodeModulesPath, 'typescript'));
return createTestSupportFor(basePath);
}
export function isInBazel() {
return process.env.TEST_SRCDIR != null;
}
export function setup(): TestSupport {
return isInBazel() ? setupBazel() : setupTestSh();
}
export function expectNoDiagnostics(options: ng.CompilerOptions, diags: ng.Diagnostics) {
const errorDiags = diags.filter(d => d.category !== ts.DiagnosticCategory.Message);
if (errorDiags.length) {

View File

@ -0,0 +1,32 @@
load("//tools:defaults.bzl", "ts_library", "ts_web_test")
load("@build_bazel_rules_nodejs//:defs.bzl", "jasmine_node_test")
ts_library(
name = "test_lib",
testonly = 1,
srcs = glob(["**/*.ts"]),
deps = [
"//packages:types",
"//packages/compiler",
"//packages/compiler-cli",
"//packages/compiler-cli/test:test_utils",
"//packages/compiler/test:test_utils",
"//packages/core",
"//packages/platform-browser",
],
)
jasmine_node_test(
name = "test",
bootstrap = ["angular/tools/testing/init_node_spec.js"],
data = [
"//packages/common:npm_package",
"//packages/core:npm_package",
"//packages/router:npm_package",
],
deps = [
":test_lib",
"//packages/core",
"//tools/testing:node",
],
)

View File

@ -15,7 +15,7 @@ import {formatDiagnostics} from '../../src/perform_compile';
import {CompilerHost, EmitFlags, LazyRoute} from '../../src/transformers/api';
import {createSrcToOutPathMapper} from '../../src/transformers/program';
import {GENERATED_FILES, StructureIsReused, tsStructureIsReused} from '../../src/transformers/util';
import {TestSupport, expectNoDiagnosticsInProgram, setup} from '../test_support';
import {TestSupport, expectNoDiagnosticsInProgram, isInBazel, setup} from '../test_support';
describe('ng program', () => {
let testSupport: TestSupport;
@ -267,6 +267,7 @@ describe('ng program', () => {
.toBe(false);
});
if (!isInBazel()) {
it('should reuse the old ts program completely if nothing changed', () => {
testSupport.writeFiles({'src/index.ts': createModuleAndCompSource('main')});
// Note: the second compile drops factories for library files,
@ -317,6 +318,8 @@ describe('ng program', () => {
compile(p2);
expect(tsStructureIsReused(p2.getTsProgram())).toBe(StructureIsReused.SafeModules);
});
}
});
it('should not typecheck templates if skipTemplateCodegen is set but fullTemplateTypeCheck is not',

View File

@ -8,8 +8,8 @@
import {PartialModule} from '@angular/compiler';
import * as o from '@angular/compiler/src/output/output_ast';
import {MockAotCompilerHost} from 'compiler/test/aot/test_util';
import {initDomAdapter} from 'platform-browser/src/browser';
import {MockAotCompilerHost} from '@angular/compiler/test/aot/test_util';
import {initDomAdapter} from '@angular/platform-browser/src/browser';
import * as ts from 'typescript';
import {getAngularClassTransformerFactory} from '../../src/transformers/r3_transform';

View File

@ -8,12 +8,27 @@ NODE_ONLY = [
"render3/**/*.ts",
]
UTILS = [
"aot/test_util.ts",
]
ts_library(
name = "test_utils",
srcs = UTILS,
visibility = ["//packages/compiler-cli/test:__subpackages__"],
deps = [
"//packages:types",
"//packages/compiler",
"//packages/compiler-cli",
],
)
ts_library(
name = "test_lib",
testonly = 1,
srcs = glob(
["**/*.ts"],
exclude = NODE_ONLY,
exclude = NODE_ONLY + UTILS,
),
deps = [
"//packages:types",
@ -31,9 +46,13 @@ ts_library(
ts_library(
name = "test_node_only_lib",
testonly = 1,
srcs = glob(NODE_ONLY),
srcs = glob(
NODE_ONLY,
exclude = UTILS,
),
deps = [
":test_lib",
":test_utils",
"//packages/compiler",
"//packages/compiler-cli",
"//packages/compiler/testing",