diff --git a/src/e2e-app/e2e-app-module.ts b/src/e2e-app/e2e-app-module.ts index 7c30a9e0f02d..dc60972c9b8f 100644 --- a/src/e2e-app/e2e-app-module.ts +++ b/src/e2e-app/e2e-app-module.ts @@ -1,4 +1,4 @@ -import {NgModule, ApplicationRef} from '@angular/core'; +import {NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {RouterModule} from '@angular/router'; import {E2EApp, Home} from './e2e-app/e2e-app'; @@ -24,14 +24,6 @@ import {E2E_APP_ROUTES} from './e2e-app/routes'; BasicTabs, Home, ], - entryComponents: [ - E2EApp, - ], + bootstrap: [E2EApp], }) -export class E2eAppModule { - constructor(private _appRef: ApplicationRef) { } - - ngDoBootstrap() { - this._appRef.bootstrap(E2EApp); - } -} +export class E2eAppModule { } diff --git a/tools/gulp/tasks/ci.ts b/tools/gulp/tasks/ci.ts index 9b6122dafc55..9bd14e3a99bd 100644 --- a/tools/gulp/tasks/ci.ts +++ b/tools/gulp/tasks/ci.ts @@ -11,4 +11,4 @@ task('ci:forbidden-identifiers', function() { // Travis sometimes does not exit the process and times out. This is to prevent that. task('ci:test', ['test:single-run'], () => process.exit(0)); // Travis sometimes does not exit the process and times out. This is to prevent that. -task('ci:e2e', ['e2e'], () => process.exit(0)); +task('ci:e2e', ['e2e:single-run'], () => process.exit(0)); diff --git a/tools/gulp/tasks/components.ts b/tools/gulp/tasks/components.ts index 30d39c6d7246..ce8da967d336 100644 --- a/tools/gulp/tasks/components.ts +++ b/tools/gulp/tasks/components.ts @@ -1,5 +1,4 @@ import {task, watch} from 'gulp'; -import {readdirSync, statSync, readFileSync} from 'fs'; import * as path from 'path'; import {SOURCE_ROOT, DIST_COMPONENTS_ROOT, PROJECT_ROOT} from '../constants'; @@ -10,15 +9,29 @@ import {writeFileSync} from 'fs'; const inlineResources = require('../../../scripts/release/inline-resources'); const rollup = require('rollup').rollup; + +// NOTE: there are two build "modes" in this file, based on which tsconfig is used. +// When `tsconfig.json` is used, we are outputting ES6 modules and a UMD bundle. This is used +// for serving and for release. +// +// When `tsconfig-spec.json` is used, we are outputting CommonJS modules. This is used +// for unit tests (karma). + +/** Path to the root of the Angular Material component library. */ const componentsDir = path.join(SOURCE_ROOT, 'lib'); +/** Path to the tsconfig used for ESM output. */ +const tsconfigPath = path.relative(PROJECT_ROOT, path.join(componentsDir, 'tsconfig.json')); + +/** [Watch task] Rebuilds (ESM output) whenever ts, scss, or html sources change. */ task(':watch:components', () => { watch(path.join(componentsDir, '**/*.ts'), [':build:components:ts']); watch(path.join(componentsDir, '**/*.scss'), [':build:components:scss']); watch(path.join(componentsDir, '**/*.html'), [':build:components:assets']); }); +/** [Watch task] Rebuilds for tests (CJS output) whenever ts, scss, or html sources change. */ task(':watch:components:spec', () => { watch(path.join(componentsDir, '**/*.ts'), [':build:components:spec']); watch(path.join(componentsDir, '**/*.scss'), [':build:components:scss']); @@ -26,15 +39,24 @@ task(':watch:components:spec', () => { }); +/** Builds component typescript only (ESM output). */ task(':build:components:ts', tsBuildTask(componentsDir)); + +/** Builds components typescript for tests (CJS output). */ task(':build:components:spec', tsBuildTask(path.join(componentsDir, 'tsconfig-spec.json'))); + +/** Copies assets (html, markdown) to build output. */ task(':build:components:assets', copyTask([ path.join(componentsDir, '**/*.!(ts|spec.ts)'), path.join(PROJECT_ROOT, 'README.md'), ], DIST_COMPONENTS_ROOT)); + +/** Builds scss into css. */ task(':build:components:scss', sassBuildTask( DIST_COMPONENTS_ROOT, componentsDir, [path.join(componentsDir, 'core/style')] )); + +/** Builds the UMD bundle for all of Angular Material. */ task(':build:components:rollup', [':build:components:inline'], () => { const globals: {[name: string]: string} = { // Angular dependencies @@ -85,18 +107,19 @@ task(':build:components:rollup', [':build:components:inline'], () => { }); }); -task(':build:components:inline', [ - ':build:components:ts', - ':build:components:scss', - ':build:components:assets' -], () => { - return inlineResources(DIST_COMPONENTS_ROOT); -}); - -task('build:components', sequenceTask( - ':build:components:rollup', +/** Builds components with resources (html, css) inlined into the built JS (ESM output). */ +task(':build:components:inline', sequenceTask( + [':build:components:ts', ':build:components:scss', ':build:components:assets'], + ':inline-resources', )); +/** Inlines resources (html, css) into the JS output (for either ESM or CJS output). */ +task(':inline-resources', () => inlineResources(DIST_COMPONENTS_ROOT)); + +/** Builds components to ESM output and UMD bundle. */ +task('build:components', [':build:components:rollup']); + +/** Generates metadata.json files for all of the components. */ task(':build:components:ngc', ['build:components'], execNodeTask( - '@angular/compiler-cli', 'ngc', ['-p', path.relative(PROJECT_ROOT, path.join(componentsDir, 'tsconfig.json'))] + '@angular/compiler-cli', 'ngc', ['-p', tsconfigPath] )); diff --git a/tools/gulp/tasks/e2e.ts b/tools/gulp/tasks/e2e.ts index 064dd4b59912..7880c84e9786 100644 --- a/tools/gulp/tasks/e2e.ts +++ b/tools/gulp/tasks/e2e.ts @@ -17,36 +17,75 @@ const PROTRACTOR_CONFIG_PATH = path.join(PROJECT_ROOT, 'test/protractor.conf.js' task(':watch:e2eapp', () => { watch(path.join(appDir, '**/*.ts'), [':build:e2eapp:ts']); - watch(path.join(appDir, '**/*.scss'), [':build:e2eapp:scss']); watch(path.join(appDir, '**/*.html'), [':build:e2eapp:assets']); }); - +/** Copies e2e app dependencies to build output. */ task(':build:e2eapp:vendor', vendorTask()); + +/** Builds e2e app ts to js. */ task(':build:e2eapp:ts', [':build:components:ts'], tsBuildTask(appDir)); + +/** No-op (needed by buildAppTask). */ task(':build:e2eapp:scss', [':build:components:scss'], sassBuildTask(outDir, appDir, [])); + +/** Copies e2e app assets (html, css) to build output. */ task(':build:e2eapp:assets', copyTask(appDir, outDir)); +/** Builds the entire e2e app. */ task('build:e2eapp', buildAppTask('e2eapp')); - +/** Ensures that protractor and webdriver are set up to run. */ task(':test:protractor:setup', execNodeTask('protractor', 'webdriver-manager', ['update'])); + +/** Runs protractor tests (assumes that server is already running. */ task(':test:protractor', execNodeTask('protractor', [PROTRACTOR_CONFIG_PATH])); -// This task is used because, in some cases, protractor will block and not exit the process, -// causing Travis to timeout. This task should always be used in a synchronous sequence as -// the last step. + +/** + * Forces process termination. + * + * This task is used because, in some cases, protractor will block and not exit the process, + * causing Travis to timeout. This task should always be used in a synchronous sequence as + * the last step. + */ task(':e2e:done', () => process.exit(0)); let stopE2eServer: () => void = null; + +/** Starts up the e2e app server. */ task(':serve:e2eapp', serverTask(false, (stream) => { stopE2eServer = () => stream.emit('kill') })); + +/** Terminates the e2e app server */ task(':serve:e2eapp:stop', () => stopE2eServer()); -task('serve:e2eapp', ['build:e2eapp'], sequenceTask([ - ':serve:e2eapp', - ':watch:components', -])); +/** Builds and serves the e2e app. */ +task('serve:e2eapp', sequenceTask('build:components', 'build:e2eapp', ':serve:e2eapp')); + +/** + * [Watch task] Builds and serves e2e app, rebuilding whenever the sources change. + * This should only be used when running e2e tests locally. + */ +task('serve:e2eapp:watch', ['serve:e2eapp', ':watch:components', ':watch:e2eapp']); +/** + * [Watch task] Serves the e2e app and runs the protractor tests. Rebuilds when sources change. + * + * This task should only be used when running the e2e tests locally. + */ task('e2e', sequenceTask( + ':test:protractor:setup', + 'serve:e2eapp:watch', + ':test:protractor', + ':serve:e2eapp:stop', + ':e2e:done', +)); + +/** + * Runs the e2e once. Does not watch for changes. + * + * This task should be used when running tests on the CI server. + */ +task('e2e:single-run', sequenceTask( ':test:protractor:setup', 'serve:e2eapp', ':test:protractor', diff --git a/tools/gulp/tasks/unit-test.ts b/tools/gulp/tasks/unit-test.ts index 32b5792dbec0..7cfee833eb64 100644 --- a/tools/gulp/tasks/unit-test.ts +++ b/tools/gulp/tasks/unit-test.ts @@ -6,8 +6,8 @@ import {PROJECT_ROOT, DIST_COMPONENTS_ROOT} from '../constants'; import {sequenceTask} from '../task_helpers'; const karma = require('karma'); -const runSequence = require('run-sequence'); +/** Copies deps for unit tests to the build output. */ gulp.task(':build:test:vendor', function() { const npmVendorFiles = [ '@angular', 'core-js/client', 'hammerjs', 'rxjs', 'systemjs/dist', 'zone.js/dist' @@ -21,24 +21,45 @@ gulp.task(':build:test:vendor', function() { })); }); +/** Builds dependencies for unit tests. */ gulp.task(':test:deps', sequenceTask( 'clean', [ ':build:test:vendor', ':build:components:assets', + ':build:components:scss', ':build:components:spec', - ':build:components:inline', - ':watch:components:spec', ] )); -gulp.task('test', [':test:deps'], (done: () => void) => { +/** + * [Watch task] Build unit test dependencies, and rebuild whenever sources are changed. + * This should only be used when running tests locally. + */ +gulp.task(':test:watch', sequenceTask(':test:deps', ':watch:components:spec')); + +/** Build unit test dependencies and then inlines resources (html, css) into the JS output. */ +gulp.task(':test:deps:inline', sequenceTask(':test:deps', ':inline-resources')); + + +/** + * [Watch task] Runs the unit tests, rebuilding and re-testing when sources change. + * Does not inline resources. + * + * This task should be used when running unit tests locally. + */ +gulp.task('test', [':test:watch'], (done: () => void) => { new karma.Server({ configFile: path.join(PROJECT_ROOT, 'test/karma.conf.js') }, done).start(); }); -gulp.task('test:single-run', [':test:deps'], (done: () => void) => { +/** + * Runs the unit tests once with inlined resources (html, css). Does not watch for changes. + * + * This task should be used when running tests on the CI server. + */ +gulp.task('test:single-run', [':test:deps:inline'], (done: () => void) => { new karma.Server({ configFile: path.join(PROJECT_ROOT, 'test/karma.conf.js'), singleRun: true