Skip to content

Commit 66c25be

Browse files
crisbetojelbourn
authored andcommitted
build: avoid multiple refreshes when running unit tests locally (#2162)
Avoids Karma running tests multiple times when developing locally, due to it triggering a test run whenever a new file is written to disk. This change switches to manually spawning a Karma server and then running the tests by depending on Gulp's API instead.
1 parent ac2f784 commit 66c25be

File tree

4 files changed

+49
-38
lines changed

4 files changed

+49
-38
lines changed

test/karma.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export function config(config) {
5858
port: 9876,
5959
colors: true,
6060
logLevel: config.LOG_INFO,
61-
autoWatch: true,
61+
autoWatch: false,
6262

6363
sauceLabs: {
6464
testName: 'material2',

tools/gulp/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ export const SASS_AUTOPREFIXER_OPTIONS = {
1818
export const NPM_VENDOR_FILES = [
1919
'@angular', 'core-js/client', 'hammerjs', 'rxjs', 'systemjs/dist', 'zone.js/dist'
2020
];
21+
22+
export const COMPONENTS_DIR = join(SOURCE_ROOT, 'lib');

tools/gulp/tasks/components.ts

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {task, watch} from 'gulp';
22
import * as path from 'path';
33

4-
import {SOURCE_ROOT, DIST_COMPONENTS_ROOT, PROJECT_ROOT} from '../constants';
4+
import {DIST_COMPONENTS_ROOT, PROJECT_ROOT, COMPONENTS_DIR} from '../constants';
55
import {sassBuildTask, tsBuildTask, execNodeTask, copyTask, sequenceTask} from '../task_helpers';
66
import {writeFileSync} from 'fs';
77

@@ -17,42 +17,32 @@ const rollup = require('rollup').rollup;
1717
// When `tsconfig-spec.json` is used, we are outputting CommonJS modules. This is used
1818
// for unit tests (karma).
1919

20-
/** Path to the root of the Angular Material component library. */
21-
const componentsDir = path.join(SOURCE_ROOT, 'lib');
22-
2320
/** Path to the tsconfig used for ESM output. */
24-
const tsconfigPath = path.relative(PROJECT_ROOT, path.join(componentsDir, 'tsconfig.json'));
21+
const tsconfigPath = path.relative(PROJECT_ROOT, path.join(COMPONENTS_DIR, 'tsconfig.json'));
2522

2623

2724
/** [Watch task] Rebuilds (ESM output) whenever ts, scss, or html sources change. */
2825
task(':watch:components', () => {
29-
watch(path.join(componentsDir, '**/*.ts'), [':build:components:rollup']);
30-
watch(path.join(componentsDir, '**/*.scss'), [':build:components:rollup']);
31-
watch(path.join(componentsDir, '**/*.html'), [':build:components:rollup']);
32-
});
33-
34-
/** [Watch task] Rebuilds for tests (CJS output) whenever ts, scss, or html sources change. */
35-
task(':watch:components:spec', () => {
36-
watch(path.join(componentsDir, '**/*.ts'), [':build:components:spec']);
37-
watch(path.join(componentsDir, '**/*.scss'), [':build:components:scss']);
38-
watch(path.join(componentsDir, '**/*.html'), [':build:components:assets']);
26+
watch(path.join(COMPONENTS_DIR, '**/*.ts'), [':build:components:rollup']);
27+
watch(path.join(COMPONENTS_DIR, '**/*.scss'), [':build:components:rollup']);
28+
watch(path.join(COMPONENTS_DIR, '**/*.html'), [':build:components:rollup']);
3929
});
4030

4131

4232
/** Builds component typescript only (ESM output). */
43-
task(':build:components:ts', tsBuildTask(componentsDir, 'tsconfig-srcs.json'));
33+
task(':build:components:ts', tsBuildTask(COMPONENTS_DIR, 'tsconfig-srcs.json'));
4434

4535
/** Builds components typescript for tests (CJS output). */
46-
task(':build:components:spec', tsBuildTask(componentsDir));
36+
task(':build:components:spec', tsBuildTask(COMPONENTS_DIR));
4737

4838
/** Copies assets (html, markdown) to build output. */
4939
task(':build:components:assets', copyTask([
50-
path.join(componentsDir, '**/*.!(ts|spec.ts)'),
40+
path.join(COMPONENTS_DIR, '**/*.!(ts|spec.ts)'),
5141
path.join(PROJECT_ROOT, 'README.md'),
5242
], DIST_COMPONENTS_ROOT));
5343

5444
/** Builds scss into css. */
55-
task(':build:components:scss', sassBuildTask(DIST_COMPONENTS_ROOT, componentsDir));
45+
task(':build:components:scss', sassBuildTask(DIST_COMPONENTS_ROOT, COMPONENTS_DIR));
5646

5747
/** Builds the UMD bundle for all of Angular Material. */
5848
task(':build:components:rollup', [':build:components:inline'], () => {

tools/gulp/tasks/unit-test.ts

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import gulp = require('gulp');
22
import path = require('path');
33
import gulpMerge = require('merge2');
44

5-
import {PROJECT_ROOT} from '../constants';
5+
import {PROJECT_ROOT, COMPONENTS_DIR} from '../constants';
66
import {sequenceTask} from '../task_helpers';
77

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

1011
/** Copies deps for unit tests to the build output. */
1112
gulp.task(':build:test:vendor', function() {
@@ -32,36 +33,54 @@ gulp.task(':test:deps', sequenceTask(
3233
]
3334
));
3435

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'));
4036

4137
/** Build unit test dependencies and then inlines resources (html, css) into the JS output. */
4238
gulp.task(':test:deps:inline', sequenceTask(':test:deps', ':inline-resources'));
4339

44-
4540
/**
46-
* [Watch task] Runs the unit tests, rebuilding and re-testing when sources change.
47-
* Does not inline resources.
41+
* Runs the unit tests once with inlined resources (html, css). Does not watch for changes.
4842
*
49-
* This task should be used when running unit tests locally.
43+
* This task should be used when running tests on the CI server.
5044
*/
51-
gulp.task('test', [':test:watch'], (done: () => void) => {
45+
gulp.task('test:single-run', [':test:deps:inline'], (done: () => void) => {
5246
new karma.Server({
53-
configFile: path.join(PROJECT_ROOT, 'test/karma.conf.js')
47+
configFile: path.join(PROJECT_ROOT, 'test/karma.conf.js'),
48+
singleRun: true
5449
}, done).start();
5550
});
5651

5752
/**
58-
* Runs the unit tests once with inlined resources (html, css). Does not watch for changes.
53+
* [Watch task] Runs the unit tests, rebuilding and re-testing when sources change.
54+
* Does not inline resources. Note that this doesn't use Karma's built-in file
55+
* watching. Due to the way our build process is set up, Karma ends up firing
56+
* it's change detection for every file that is written to disk, which causes
57+
* it to run tests multiple time and makes it hard to follow the console output.
58+
* This approach runs the Karma server and then depends on the Gulp API to tell
59+
* Karma when to run the tests.
5960
*
60-
* This task should be used when running tests on the CI server.
61+
* This task should be used when running unit tests locally.
6162
*/
62-
gulp.task('test:single-run', [':test:deps:inline'], (done: () => void) => {
63-
new karma.Server({
63+
gulp.task('test', [':test:deps'], () => {
64+
let patternRoot = path.join(COMPONENTS_DIR, '**/*');
65+
66+
// Configure the Karma server and override the autoWatch and singleRun just in case.
67+
let server = new karma.Server({
6468
configFile: path.join(PROJECT_ROOT, 'test/karma.conf.js'),
65-
singleRun: true
66-
}, done).start();
69+
autoWatch: false,
70+
singleRun: false
71+
});
72+
73+
// Refreshes Karma's file list and schedules a test run.
74+
let runTests = () => {
75+
server.refreshFiles().then(() => server._injector.get('executor').schedule());
76+
};
77+
78+
// Boot up the test server and run the tests whenever a new browser connects.
79+
server.start();
80+
server.on('browser_register', runTests);
81+
82+
// Watch for file changes, rebuild and run the tests.
83+
gulp.watch(patternRoot + '.ts', () => runSequence(':build:components:spec', runTests));
84+
gulp.watch(patternRoot + '.scss', () => runSequence(':build:components:scss', runTests));
85+
gulp.watch(patternRoot + '.html', () => runSequence(':build:components:assets', runTests));
6786
});

0 commit comments

Comments
 (0)