Skip to content

Commit 3045a05

Browse files
authored
chore: fix CI flakiness caused by race condition (#1371)
* chore: fix CI flakiness by using correct build targets * wip flaky fix * fix inline build * fix typo
1 parent 276d07d commit 3045a05

File tree

5 files changed

+114
-39
lines changed

5 files changed

+114
-39
lines changed

src/e2e-app/e2e-app-module.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {NgModule, ApplicationRef} from '@angular/core';
1+
import {NgModule} from '@angular/core';
22
import {BrowserModule} from '@angular/platform-browser';
33
import {RouterModule} from '@angular/router';
44
import {E2EApp, Home} from './e2e-app/e2e-app';
@@ -24,14 +24,6 @@ import {E2E_APP_ROUTES} from './e2e-app/routes';
2424
BasicTabs,
2525
Home,
2626
],
27-
entryComponents: [
28-
E2EApp,
29-
],
27+
bootstrap: [E2EApp],
3028
})
31-
export class E2eAppModule {
32-
constructor(private _appRef: ApplicationRef) { }
33-
34-
ngDoBootstrap() {
35-
this._appRef.bootstrap(E2EApp);
36-
}
37-
}
29+
export class E2eAppModule { }

tools/gulp/tasks/ci.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ task('ci:forbidden-identifiers', function() {
1111
// Travis sometimes does not exit the process and times out. This is to prevent that.
1212
task('ci:test', ['test:single-run'], () => process.exit(0));
1313
// Travis sometimes does not exit the process and times out. This is to prevent that.
14-
task('ci:e2e', ['e2e'], () => process.exit(0));
14+
task('ci:e2e', ['e2e:single-run'], () => process.exit(0));

tools/gulp/tasks/components.ts

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {task, watch} from 'gulp';
2-
import {readdirSync, statSync, readFileSync} from 'fs';
32
import * as path from 'path';
43

54
import {SOURCE_ROOT, DIST_COMPONENTS_ROOT, PROJECT_ROOT} from '../constants';
@@ -10,31 +9,54 @@ import {writeFileSync} from 'fs';
109
const inlineResources = require('../../../scripts/release/inline-resources');
1110
const rollup = require('rollup').rollup;
1211

12+
13+
// NOTE: there are two build "modes" in this file, based on which tsconfig is used.
14+
// When `tsconfig.json` is used, we are outputting ES6 modules and a UMD bundle. This is used
15+
// for serving and for release.
16+
//
17+
// When `tsconfig-spec.json` is used, we are outputting CommonJS modules. This is used
18+
// for unit tests (karma).
19+
20+
/** Path to the root of the Angular Material component library. */
1321
const componentsDir = path.join(SOURCE_ROOT, 'lib');
1422

23+
/** Path to the tsconfig used for ESM output. */
24+
const tsconfigPath = path.relative(PROJECT_ROOT, path.join(componentsDir, 'tsconfig.json'));
25+
1526

27+
/** [Watch task] Rebuilds (ESM output) whenever ts, scss, or html sources change. */
1628
task(':watch:components', () => {
1729
watch(path.join(componentsDir, '**/*.ts'), [':build:components:ts']);
1830
watch(path.join(componentsDir, '**/*.scss'), [':build:components:scss']);
1931
watch(path.join(componentsDir, '**/*.html'), [':build:components:assets']);
2032
});
2133

34+
/** [Watch task] Rebuilds for tests (CJS output) whenever ts, scss, or html sources change. */
2235
task(':watch:components:spec', () => {
2336
watch(path.join(componentsDir, '**/*.ts'), [':build:components:spec']);
2437
watch(path.join(componentsDir, '**/*.scss'), [':build:components:scss']);
2538
watch(path.join(componentsDir, '**/*.html'), [':build:components:assets']);
2639
});
2740

2841

42+
/** Builds component typescript only (ESM output). */
2943
task(':build:components:ts', tsBuildTask(componentsDir));
44+
45+
/** Builds components typescript for tests (CJS output). */
3046
task(':build:components:spec', tsBuildTask(path.join(componentsDir, 'tsconfig-spec.json')));
47+
48+
/** Copies assets (html, markdown) to build output. */
3149
task(':build:components:assets', copyTask([
3250
path.join(componentsDir, '**/*.!(ts|spec.ts)'),
3351
path.join(PROJECT_ROOT, 'README.md'),
3452
], DIST_COMPONENTS_ROOT));
53+
54+
/** Builds scss into css. */
3555
task(':build:components:scss', sassBuildTask(
3656
DIST_COMPONENTS_ROOT, componentsDir, [path.join(componentsDir, 'core/style')]
3757
));
58+
59+
/** Builds the UMD bundle for all of Angular Material. */
3860
task(':build:components:rollup', [':build:components:inline'], () => {
3961
const globals: {[name: string]: string} = {
4062
// Angular dependencies
@@ -85,18 +107,19 @@ task(':build:components:rollup', [':build:components:inline'], () => {
85107
});
86108
});
87109

88-
task(':build:components:inline', [
89-
':build:components:ts',
90-
':build:components:scss',
91-
':build:components:assets'
92-
], () => {
93-
return inlineResources(DIST_COMPONENTS_ROOT);
94-
});
95-
96-
task('build:components', sequenceTask(
97-
':build:components:rollup',
110+
/** Builds components with resources (html, css) inlined into the built JS (ESM output). */
111+
task(':build:components:inline', sequenceTask(
112+
[':build:components:ts', ':build:components:scss', ':build:components:assets'],
113+
':inline-resources',
98114
));
99115

116+
/** Inlines resources (html, css) into the JS output (for either ESM or CJS output). */
117+
task(':inline-resources', () => inlineResources(DIST_COMPONENTS_ROOT));
118+
119+
/** Builds components to ESM output and UMD bundle. */
120+
task('build:components', [':build:components:rollup']);
121+
122+
/** Generates metadata.json files for all of the components. */
100123
task(':build:components:ngc', ['build:components'], execNodeTask(
101-
'@angular/compiler-cli', 'ngc', ['-p', path.relative(PROJECT_ROOT, path.join(componentsDir, 'tsconfig.json'))]
124+
'@angular/compiler-cli', 'ngc', ['-p', tsconfigPath]
102125
));

tools/gulp/tasks/e2e.ts

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,36 +17,75 @@ const PROTRACTOR_CONFIG_PATH = path.join(PROJECT_ROOT, 'test/protractor.conf.js'
1717

1818
task(':watch:e2eapp', () => {
1919
watch(path.join(appDir, '**/*.ts'), [':build:e2eapp:ts']);
20-
watch(path.join(appDir, '**/*.scss'), [':build:e2eapp:scss']);
2120
watch(path.join(appDir, '**/*.html'), [':build:e2eapp:assets']);
2221
});
2322

24-
23+
/** Copies e2e app dependencies to build output. */
2524
task(':build:e2eapp:vendor', vendorTask());
25+
26+
/** Builds e2e app ts to js. */
2627
task(':build:e2eapp:ts', [':build:components:ts'], tsBuildTask(appDir));
28+
29+
/** No-op (needed by buildAppTask). */
2730
task(':build:e2eapp:scss', [':build:components:scss'], sassBuildTask(outDir, appDir, []));
31+
32+
/** Copies e2e app assets (html, css) to build output. */
2833
task(':build:e2eapp:assets', copyTask(appDir, outDir));
2934

35+
/** Builds the entire e2e app. */
3036
task('build:e2eapp', buildAppTask('e2eapp'));
3137

32-
38+
/** Ensures that protractor and webdriver are set up to run. */
3339
task(':test:protractor:setup', execNodeTask('protractor', 'webdriver-manager', ['update']));
40+
41+
/** Runs protractor tests (assumes that server is already running. */
3442
task(':test:protractor', execNodeTask('protractor', [PROTRACTOR_CONFIG_PATH]));
35-
// This task is used because, in some cases, protractor will block and not exit the process,
36-
// causing Travis to timeout. This task should always be used in a synchronous sequence as
37-
// the last step.
43+
44+
/**
45+
* Forces process termination.
46+
*
47+
* This task is used because, in some cases, protractor will block and not exit the process,
48+
* causing Travis to timeout. This task should always be used in a synchronous sequence as
49+
* the last step.
50+
*/
3851
task(':e2e:done', () => process.exit(0));
3952

4053
let stopE2eServer: () => void = null;
54+
55+
/** Starts up the e2e app server. */
4156
task(':serve:e2eapp', serverTask(false, (stream) => { stopE2eServer = () => stream.emit('kill') }));
57+
58+
/** Terminates the e2e app server */
4259
task(':serve:e2eapp:stop', () => stopE2eServer());
43-
task('serve:e2eapp', ['build:e2eapp'], sequenceTask([
44-
':serve:e2eapp',
45-
':watch:components',
46-
]));
4760

61+
/** Builds and serves the e2e app. */
62+
task('serve:e2eapp', sequenceTask('build:components', 'build:e2eapp', ':serve:e2eapp'));
63+
64+
/**
65+
* [Watch task] Builds and serves e2e app, rebuilding whenever the sources change.
66+
* This should only be used when running e2e tests locally.
67+
*/
68+
task('serve:e2eapp:watch', ['serve:e2eapp', ':watch:components', ':watch:e2eapp']);
4869

70+
/**
71+
* [Watch task] Serves the e2e app and runs the protractor tests. Rebuilds when sources change.
72+
*
73+
* This task should only be used when running the e2e tests locally.
74+
*/
4975
task('e2e', sequenceTask(
76+
':test:protractor:setup',
77+
'serve:e2eapp:watch',
78+
':test:protractor',
79+
':serve:e2eapp:stop',
80+
':e2e:done',
81+
));
82+
83+
/**
84+
* Runs the e2e once. Does not watch for changes.
85+
*
86+
* This task should be used when running tests on the CI server.
87+
*/
88+
task('e2e:single-run', sequenceTask(
5089
':test:protractor:setup',
5190
'serve:e2eapp',
5291
':test:protractor',

tools/gulp/tasks/unit-test.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import {PROJECT_ROOT, DIST_COMPONENTS_ROOT} from '../constants';
66
import {sequenceTask} from '../task_helpers';
77

88
const karma = require('karma');
9-
const runSequence = require('run-sequence');
109

10+
/** Copies deps for unit tests to the build output. */
1111
gulp.task(':build:test:vendor', function() {
1212
const npmVendorFiles = [
1313
'@angular', 'core-js/client', 'hammerjs', 'rxjs', 'systemjs/dist', 'zone.js/dist'
@@ -21,24 +21,45 @@ gulp.task(':build:test:vendor', function() {
2121
}));
2222
});
2323

24+
/** Builds dependencies for unit tests. */
2425
gulp.task(':test:deps', sequenceTask(
2526
'clean',
2627
[
2728
':build:test:vendor',
2829
':build:components:assets',
30+
':build:components:scss',
2931
':build:components:spec',
30-
':build:components:inline',
31-
':watch:components:spec',
3232
]
3333
));
3434

35-
gulp.task('test', [':test:deps'], (done: () => void) => {
35+
/**
36+
* [Watch task] Build unit test dependencies, and rebuild whenever sources are changed.
37+
* This should only be used when running tests locally.
38+
*/
39+
gulp.task(':test:watch', sequenceTask(':test:deps', ':watch:components:spec'));
40+
41+
/** Build unit test dependencies and then inlines resources (html, css) into the JS output. */
42+
gulp.task(':test:deps:inline', sequenceTask(':test:deps', ':inline-resources'));
43+
44+
45+
/**
46+
* [Watch task] Runs the unit tests, rebuilding and re-testing when sources change.
47+
* Does not inline resources.
48+
*
49+
* This task should be used when running unit tests locally.
50+
*/
51+
gulp.task('test', [':test:watch'], (done: () => void) => {
3652
new karma.Server({
3753
configFile: path.join(PROJECT_ROOT, 'test/karma.conf.js')
3854
}, done).start();
3955
});
4056

41-
gulp.task('test:single-run', [':test:deps'], (done: () => void) => {
57+
/**
58+
* Runs the unit tests once with inlined resources (html, css). Does not watch for changes.
59+
*
60+
* This task should be used when running tests on the CI server.
61+
*/
62+
gulp.task('test:single-run', [':test:deps:inline'], (done: () => void) => {
4263
new karma.Server({
4364
configFile: path.join(PROJECT_ROOT, 'test/karma.conf.js'),
4465
singleRun: true

0 commit comments

Comments
 (0)