From a0dbd970e99a147577ff6f3c62eedea26815f8bd Mon Sep 17 00:00:00 2001 From: Chuck Jazdzewski Date: Wed, 21 Mar 2018 14:22:06 -0700 Subject: [PATCH 1/2] ci(compiler-cli): run compiler-cli tests in bazel --- packages/compiler-cli/src/transformers/api.ts | 5 - packages/compiler-cli/test/BUILD.bazel | 130 +++++++++ .../compiler-cli/test/diagnostics/BUILD.bazel | 99 +++++++ .../expression_diagnostics_spec.ts | 1 + .../compiler-cli/test/diagnostics/mocks.ts | 16 +- .../compiler-cli/test/extract_i18n_spec.ts | 96 +++--- .../compiler-cli/test/metadata/BUILD.bazel | 26 ++ .../test/metadata/collector_spec.ts | 2 +- packages/compiler-cli/test/ngc_spec.ts | 275 ++++++++++-------- .../compiler-cli/test/ngtools_api_spec.ts | 3 +- packages/compiler-cli/test/test_support.ts | 79 ++++- .../test/transformers/BUILD.bazel | 32 ++ .../test/transformers/program_spec.ts | 97 +++--- .../test/transformers/r3_transform_spec.ts | 4 +- packages/compiler/test/BUILD.bazel | 23 +- 15 files changed, 652 insertions(+), 236 deletions(-) create mode 100644 packages/compiler-cli/test/BUILD.bazel create mode 100644 packages/compiler-cli/test/diagnostics/BUILD.bazel create mode 100644 packages/compiler-cli/test/metadata/BUILD.bazel create mode 100644 packages/compiler-cli/test/transformers/BUILD.bazel diff --git a/packages/compiler-cli/src/transformers/api.ts b/packages/compiler-cli/src/transformers/api.ts index bb06876f0d34e..b0cd8ea1bca65 100644 --- a/packages/compiler-cli/src/transformers/api.ts +++ b/packages/compiler-cli/src/transformers/api.ts @@ -262,9 +262,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; @@ -367,8 +364,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; diff --git a/packages/compiler-cli/test/BUILD.bazel b/packages/compiler-cli/test/BUILD.bazel new file mode 100644 index 0000000000000..122700816a164 --- /dev/null +++ b/packages/compiler-cli/test/BUILD.bazel @@ -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", + ], +) diff --git a/packages/compiler-cli/test/diagnostics/BUILD.bazel b/packages/compiler-cli/test/diagnostics/BUILD.bazel new file mode 100644 index 0000000000000..5844c874206ce --- /dev/null +++ b/packages/compiler-cli/test/diagnostics/BUILD.bazel @@ -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", + ], +) diff --git a/packages/compiler-cli/test/diagnostics/expression_diagnostics_spec.ts b/packages/compiler-cli/test/diagnostics/expression_diagnostics_spec.ts index bffd7f3db8e4a..09d86347d2d01 100644 --- a/packages/compiler-cli/test/diagnostics/expression_diagnostics_spec.ts +++ b/packages/compiler-cli/test/diagnostics/expression_diagnostics_spec.ts @@ -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; diff --git a/packages/compiler-cli/test/diagnostics/mocks.ts b/packages/compiler-cli/test/diagnostics/mocks.ts index 76226efad2a11..98fd240daddaa 100644 --- a/packages/compiler-cli/test/diagnostics/mocks.ts +++ b/packages/compiler-cli/test/diagnostics/mocks.ts @@ -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(); @@ -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); } diff --git a/packages/compiler-cli/test/extract_i18n_spec.ts b/packages/compiler-cli/test/extract_i18n_spec.ts index ffba4b9d5ed88..04cfaa3d32fab 100644 --- a/packages/compiler-cli/test/extract_i18n_spec.ts +++ b/packages/compiler-cli/test/extract_i18n_spec.ts @@ -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,41 +110,65 @@ 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'}); - }; - write('tsconfig-base.json', `{ - "compilerOptions": { - "experimentalDecorators": true, - "skipLibCheck": true, - "noImplicitAny": true, - "types": [], - "outDir": "built", - "rootDir": ".", - "baseUrl": ".", - "declaration": true, - "target": "es5", - "module": "es2015", - "moduleResolution": "node", - "lib": ["es6", "dom"], - "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')); + if (isInBazel()) { + const support = setup(); + write = (fileName: string, content: string) => { support.write(fileName, content); }; + write('tsconfig-base.json', `{ + "compilerOptions": { + "experimentalDecorators": true, + "skipLibCheck": true, + "noImplicitAny": true, + "types": [], + "outDir": "built", + "rootDir": ".", + "baseUrl": ".", + "declaration": true, + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "lib": ["es6", "dom"], + "typeRoots": ["node_modules/@types"] + } + }`); + 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'}); + }; + write('tsconfig-base.json', `{ + "compilerOptions": { + "experimentalDecorators": true, + "skipLibCheck": true, + "noImplicitAny": true, + "types": [], + "outDir": "built", + "rootDir": ".", + "baseUrl": ".", + "declaration": true, + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "lib": ["es6", "dom"], + "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() { diff --git a/packages/compiler-cli/test/metadata/BUILD.bazel b/packages/compiler-cli/test/metadata/BUILD.bazel new file mode 100644 index 0000000000000..1b075bb62b897 --- /dev/null +++ b/packages/compiler-cli/test/metadata/BUILD.bazel @@ -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", + ], +) diff --git a/packages/compiler-cli/test/metadata/collector_spec.ts b/packages/compiler-cli/test/metadata/collector_spec.ts index 4b0128f7723a0..8be8f40b1220d 100644 --- a/packages/compiler-cli/test/metadata/collector_spec.ts +++ b/packages/compiler-cli/test/metadata/collector_spec.ts @@ -877,7 +877,7 @@ describe('Collector', () => { export const InjectionToken: {new(desc: string): InjectionToken;} = 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) !; diff --git a/packages/compiler-cli/test/ngc_spec.ts b/packages/compiler-cli/test/ngc_spec.ts index fe8be7d934a32..a1d0aa2d4fb0b 100644 --- a/packages/compiler-cli/test/ngc_spec.ts +++ b/packages/compiler-cli/test/ngc_spec.ts @@ -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`, () => { @@ -1107,7 +1133,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); @@ -1144,106 +1173,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'); - - 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\//); + // app + // make `shouldExist` / `shouldNotExist` relative to `built` + outDir = path.resolve(basePath, 'built'); + shouldExist('app/main.ngfactory.js'); - function writeFiles() { - createFlatModuleInNodeModules(); + 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\//); - // 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/**" - ] - }`); + function writeFiles() { + createFlatModuleInNodeModules(); - // 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); + // 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/**" + ] + }`); - // 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'; + + @NgModule({ + imports: [FlatModule] + }) + export class AppModule {} + `); + } - 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); - } - }); + 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', () => { @@ -1291,6 +1323,7 @@ describe('ngc transformer command-line', () => { }); }); + describe('expression lowering', () => { const shouldExist = (fileName: string) => { if (!fs.existsSync(path.resolve(basePath, fileName))) { diff --git a/packages/compiler-cli/test/ngtools_api_spec.ts b/packages/compiler-cli/test/ngtools_api_spec.ts index b20d9e705464f..bab62130151f2 100644 --- a/packages/compiler-cli/test/ngtools_api_spec.ts +++ b/packages/compiler-cli/test/ngtools_api_spec.ts @@ -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)', () => { diff --git a/packages/compiler-cli/test/test_support.ts b/packages/compiler-cli/test/test_support.ts index 19785a893e069..c957a735e459a 100644 --- a/packages/compiler-cli/test/test_support.ts +++ b/packages/compiler-cli/test/test_support.ts @@ -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) { diff --git a/packages/compiler-cli/test/transformers/BUILD.bazel b/packages/compiler-cli/test/transformers/BUILD.bazel new file mode 100644 index 0000000000000..2e4649fe9c800 --- /dev/null +++ b/packages/compiler-cli/test/transformers/BUILD.bazel @@ -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", + ], +) diff --git a/packages/compiler-cli/test/transformers/program_spec.ts b/packages/compiler-cli/test/transformers/program_spec.ts index dcfbad2035cfe..bbf7c526aee7b 100644 --- a/packages/compiler-cli/test/transformers/program_spec.ts +++ b/packages/compiler-cli/test/transformers/program_spec.ts @@ -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); - }); - - 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'; - ` + 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); }); - // 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`, + + 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); }); - 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', diff --git a/packages/compiler-cli/test/transformers/r3_transform_spec.ts b/packages/compiler-cli/test/transformers/r3_transform_spec.ts index 7659f9171ac0a..778db8104899d 100644 --- a/packages/compiler-cli/test/transformers/r3_transform_spec.ts +++ b/packages/compiler-cli/test/transformers/r3_transform_spec.ts @@ -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'; diff --git a/packages/compiler/test/BUILD.bazel b/packages/compiler/test/BUILD.bazel index 8a3d929988293..3cf1eb3dbfba2 100644 --- a/packages/compiler/test/BUILD.bazel +++ b/packages/compiler/test/BUILD.bazel @@ -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", From 693478227c5099c56e1bdccc31ca2cbf52fcccbe Mon Sep 17 00:00:00 2001 From: Chuck Jazdzewski Date: Mon, 26 Mar 2018 14:40:24 -0700 Subject: [PATCH 2/2] fixup! ci(compiler-cli): run compiler-cli tests in bazel --- .../compiler-cli/test/extract_i18n_spec.ts | 51 +++++++------------ 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/packages/compiler-cli/test/extract_i18n_spec.ts b/packages/compiler-cli/test/extract_i18n_spec.ts index 04cfaa3d32fab..4373fef3380a6 100644 --- a/packages/compiler-cli/test/extract_i18n_spec.ts +++ b/packages/compiler-cli/test/extract_i18n_spec.ts @@ -113,23 +113,6 @@ describe('extract_i18n command line', () => { if (isInBazel()) { const support = setup(); write = (fileName: string, content: string) => { support.write(fileName, content); }; - write('tsconfig-base.json', `{ - "compilerOptions": { - "experimentalDecorators": true, - "skipLibCheck": true, - "noImplicitAny": true, - "types": [], - "outDir": "built", - "rootDir": ".", - "baseUrl": ".", - "declaration": true, - "target": "es5", - "module": "es2015", - "moduleResolution": "node", - "lib": ["es6", "dom"], - "typeRoots": ["node_modules/@types"] - } - }`); basePath = support.basePath; outDir = path.join(basePath, 'built'); } else { @@ -142,23 +125,6 @@ describe('extract_i18n command line', () => { } fs.writeFileSync(path.join(basePath, fileName), content, {encoding: 'utf-8'}); }; - write('tsconfig-base.json', `{ - "compilerOptions": { - "experimentalDecorators": true, - "skipLibCheck": true, - "noImplicitAny": true, - "types": [], - "outDir": "built", - "rootDir": ".", - "baseUrl": ".", - "declaration": true, - "target": "es5", - "module": "es2015", - "moduleResolution": "node", - "lib": ["es6", "dom"], - "typeRoots": ["node_modules/@types"] - } - }`); outDir = path.resolve(basePath, 'built'); const ngRootDir = getNgRootDir(); const nodeModulesPath = path.resolve(basePath, 'node_modules'); @@ -169,6 +135,23 @@ describe('extract_i18n command line', () => { fs.symlinkSync( path.resolve(ngRootDir, 'node_modules', 'rxjs'), path.resolve(nodeModulesPath, 'rxjs')); } + write('tsconfig-base.json', `{ + "compilerOptions": { + "experimentalDecorators": true, + "skipLibCheck": true, + "noImplicitAny": true, + "types": [], + "outDir": "built", + "rootDir": ".", + "baseUrl": ".", + "declaration": true, + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "lib": ["es6", "dom"], + "typeRoots": ["node_modules/@types"] + } + }`); }); function writeSources() {