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() {
const moduleFilename = module.filename.replace(/\\/g, '/');
const distIndex = moduleFilename.indexOf('/dist/all');
return moduleFilename.substr(0, distIndex);
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) + '/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,15 +110,31 @@ describe('extract_i18n command line', () => {
beforeEach(() => {
errorSpy = jasmine.createSpy('consoleError').and.callFake(console.error);
basePath = makeTempDir();
write = (fileName: string, content: string) => {
const dir = path.dirname(fileName);
if (dir != '.') {
const newDir = path.join(basePath, dir);
if (!fs.existsSync(newDir)) fs.mkdirSync(newDir);
}
fs.writeFileSync(path.join(basePath, fileName), content, {encoding: 'utf-8'});
};
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);
if (dir != '.') {
const newDir = path.join(basePath, dir);
if (!fs.existsSync(newDir)) fs.mkdirSync(newDir);
}
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,16 +44,33 @@ describe('ngc transformer command-line', () => {
beforeEach(() => {
errorSpy = jasmine.createSpy('consoleError').and.callFake(console.error);
basePath = makeTempDir();
process.chdir(basePath);
write = (fileName: string, content: string) => {
const dir = path.dirname(fileName);
if (dir != '.') {
const newDir = path.join(basePath, dir);
if (!fs.existsSync(newDir)) fs.mkdirSync(newDir);
}
fs.writeFileSync(path.join(basePath, fileName), content, {encoding: 'utf-8'});
};
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) => {
const dir = path.dirname(fileName);
if (dir != '.') {
const newDir = path.join(basePath, dir);
if (!fs.existsSync(newDir)) fs.mkdirSync(newDir);
}
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);
expect(fs.existsSync(path.resolve(
outDir, 'node_modules', '@angular', 'core', 'src',
'application_module.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);
expect(fs.existsSync(path.resolve(
outDir, 'node_modules', '@angular', 'core', 'src',
'application_module.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', () => {
}
`);
expect(main(['-p', path.join(basePath, 'tsconfig-ng.json')], errorSpy)).toBe(0);
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,106 +1190,109 @@ describe('ngc transformer command-line', () => {
shouldExist('app/main.js');
});
it('should be able to compile libraries with summaries and flat modules', () => {
writeFiles();
compile();
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();
// libraries
// make `shouldExist` / `shouldNotExist` relative to `node_modules`
outDir = path.resolve(basePath, 'node_modules');
shouldExist('flat_module/index.ngfactory.js');
shouldExist('flat_module/index.ngsummary.json');
// libraries
// make `shouldExist` / `shouldNotExist` relative to `node_modules`
outDir = path.resolve(basePath, 'node_modules');
shouldExist('flat_module/index.ngfactory.js');
shouldExist('flat_module/index.ngsummary.json');
// app
// make `shouldExist` / `shouldNotExist` relative to `built`
outDir = path.resolve(basePath, 'built');
shouldExist('app/main.ngfactory.js');
// app
// make `shouldExist` / `shouldNotExist` relative to `built`
outDir = path.resolve(basePath, 'built');
shouldExist('app/main.ngfactory.js');
const factory = fs.readFileSync(path.resolve(outDir, 'app/main.ngfactory.js')).toString();
// reference to the module itself
expect(factory).toMatch(/from "flat_module"/);
// no reference to a deep file
expect(factory).not.toMatch(/from "flat_module\//);
const factory = fs.readFileSync(path.resolve(outDir, 'app/main.ngfactory.js')).toString();
// reference to the module itself
expect(factory).toMatch(/from "flat_module"/);
// no reference to a deep file
expect(factory).not.toMatch(/from "flat_module\//);
function writeFiles() {
createFlatModuleInNodeModules();
function writeFiles() {
createFlatModuleInNodeModules();
// Angular + flat module
write('tsconfig-lib.json', `{
"extends": "./tsconfig-base.json",
"angularCompilerOptions": {
"generateCodeForLibraries": true
},
"compilerOptions": {
"outDir": "."
},
"include": ["node_modules/@angular/core/**/*", "node_modules/flat_module/**/*"],
"exclude": [
"node_modules/@angular/core/test/**",
"node_modules/@angular/core/testing/**"
]
}`);
// Angular + flat module
write('tsconfig-lib.json', `{
"extends": "./tsconfig-base.json",
"angularCompilerOptions": {
"generateCodeForLibraries": true
},
"compilerOptions": {
"outDir": "."
},
"include": ["node_modules/@angular/core/**/*", "node_modules/flat_module/**/*"],
"exclude": [
"node_modules/@angular/core/test/**",
"node_modules/@angular/core/testing/**"
]
}`);
// Application
write('app/tsconfig-app.json', `{
"extends": "../tsconfig-base.json",
"angularCompilerOptions": {
"generateCodeForLibraries": false
},
"compilerOptions": {
"rootDir": ".",
"outDir": "../built/app"
}
}`);
write('app/main.ts', `
import {NgModule} from '@angular/core';
import {FlatModule} from 'flat_module';
@NgModule({
imports: [FlatModule]
})
export class AppModule {}
`);
}
function createFlatModuleInNodeModules() {
// compile the flat module
writeFlatModule('index.js');
expect(main(['-p', basePath], errorSpy)).toBe(0);
// move the flat module output into node_modules
const flatModuleNodeModulesPath = path.resolve(basePath, 'node_modules', 'flat_module');
fs.renameSync(outDir, flatModuleNodeModulesPath);
fs.renameSync(
path.resolve(basePath, 'src/flat.component.html'),
path.resolve(flatModuleNodeModulesPath, 'src/flat.component.html'));
// and remove the sources.
fs.renameSync(path.resolve(basePath, 'src'), path.resolve(basePath, 'flat_module_src'));
fs.unlinkSync(path.resolve(basePath, 'public-api.ts'));
// add a flatModuleIndexRedirect
write('node_modules/flat_module/redirect.metadata.json', `{
"__symbolic": "module",
"version": 3,
"metadata": {},
"exports": [
{
"from": "./index"
// Application
write('app/tsconfig-app.json', `{
"extends": "../tsconfig-base.json",
"angularCompilerOptions": {
"generateCodeForLibraries": false
},
"compilerOptions": {
"rootDir": ".",
"outDir": "../built/app"
}
],
"flatModuleIndexRedirect": true,
"importAs": "flat_module"
}`);
write('node_modules/flat_module/redirect.d.ts', `export * from './index';`);
// add a package.json to use the redirect
write('node_modules/flat_module/package.json', `{"typings": "./redirect.d.ts"}`);
}
}`);
write('app/main.ts', `
import {NgModule} from '@angular/core';
import {FlatModule} from 'flat_module';
function compile() {
expect(main(['-p', path.join(basePath, 'tsconfig-lib.json')], errorSpy)).toBe(0);
expect(main(['-p', path.join(basePath, 'app', 'tsconfig-app.json')], errorSpy)).toBe(0);
}
});
@NgModule({
imports: [FlatModule]
})
export class AppModule {}
`);
}
function createFlatModuleInNodeModules() {
// compile the flat module
writeFlatModule('index.js');
expect(main(['-p', basePath], errorSpy)).toBe(0);
// move the flat module output into node_modules
const flatModuleNodeModulesPath = path.resolve(basePath, 'node_modules', 'flat_module');
fs.renameSync(outDir, flatModuleNodeModulesPath);
fs.renameSync(
path.resolve(basePath, 'src/flat.component.html'),
path.resolve(flatModuleNodeModulesPath, 'src/flat.component.html'));
// and remove the sources.
fs.renameSync(path.resolve(basePath, 'src'), path.resolve(basePath, 'flat_module_src'));
fs.unlinkSync(path.resolve(basePath, 'public-api.ts'));
// add a flatModuleIndexRedirect
write('node_modules/flat_module/redirect.metadata.json', `{
"__symbolic": "module",
"version": 3,
"metadata": {},
"exports": [
{
"from": "./index"
}
],
"flatModuleIndexRedirect": true,
"importAs": "flat_module"
}`);
write('node_modules/flat_module/redirect.d.ts', `export * from './index';`);
// add a package.json to use the redirect
write('node_modules/flat_module/package.json', `{"typings": "./redirect.d.ts"}`);
}
function compile() {
expect(main(['-p', path.join(basePath, 'tsconfig-lib.json')], errorSpy)).toBe(0);
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,56 +267,59 @@ describe('ng program', () => {
.toBe(false);
});
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,
// and therefore changes the structure again
const p1 = compile().program;
const p2 = compile(p1).program;
compile(p2);
expect(tsStructureIsReused(p2.getTsProgram())).toBe(StructureIsReused.Completely);
});
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,
// and therefore changes the structure again
const p1 = compile().program;
const p2 = compile(p1).program;
compile(p2);
expect(tsStructureIsReused(p2.getTsProgram())).toBe(StructureIsReused.Completely);
});
it('should reuse the old ts program completely if a template or a ts file changed', () => {
testSupport.writeFiles({
'src/main.ts': createModuleAndCompSource('main', 'main.html'),
'src/main.html': `Some template`,
'src/util.ts': `export const x = 1`,
'src/index.ts': `
export * from './main';
export * from './util';
`
it('should reuse the old ts program completely if a template or a ts file changed', () => {
testSupport.writeFiles({
'src/main.ts': createModuleAndCompSource('main', 'main.html'),
'src/main.html': `Some template`,
'src/util.ts': `export const x = 1`,
'src/index.ts': `
export * from './main';
export * from './util';
`
});
// Note: the second compile drops factories for library files,
// and therefore changes the structure again
const p1 = compile().program;
const p2 = compile(p1).program;
testSupport.writeFiles({
'src/main.html': `Another template`,
'src/util.ts': `export const x = 2`,
});
compile(p2);
expect(tsStructureIsReused(p2.getTsProgram())).toBe(StructureIsReused.Completely);
});
// Note: the second compile drops factories for library files,
// and therefore changes the structure again
const p1 = compile().program;
const p2 = compile(p1).program;
testSupport.writeFiles({
'src/main.html': `Another template`,
'src/util.ts': `export const x = 2`,
});
compile(p2);
expect(tsStructureIsReused(p2.getTsProgram())).toBe(StructureIsReused.Completely);
});
it('should not reuse the old ts program if an import changed', () => {
testSupport.writeFiles({
'src/main.ts': createModuleAndCompSource('main'),
'src/util.ts': `export const x = 1`,
'src/index.ts': `
export * from './main';
export * from './util';
`
it('should not reuse the old ts program if an import changed', () => {
testSupport.writeFiles({
'src/main.ts': createModuleAndCompSource('main'),
'src/util.ts': `export const x = 1`,
'src/index.ts': `
export * from './main';
export * from './util';
`
});
// Note: the second compile drops factories for library files,
// and therefore changes the structure again
const p1 = compile().program;
const p2 = compile(p1).program;
testSupport.writeFiles(
{'src/util.ts': `import {Injectable} from '@angular/core'; export const x = 1;`});
compile(p2);
expect(tsStructureIsReused(p2.getTsProgram())).toBe(StructureIsReused.SafeModules);
});
// Note: the second compile drops factories for library files,
// and therefore changes the structure again
const p1 = compile().program;
const p2 = compile(p1).program;
testSupport.writeFiles(
{'src/util.ts': `import {Injectable} from '@angular/core'; export const x = 1;`});
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",