mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-17 11:03:53 +08:00
test(@angular-devkit/build-angular): test karma on watch mode
This commit is contained in:
parent
e4c0151241
commit
0909943259
@ -9,13 +9,15 @@
|
|||||||
// TODO: cleanup this file, it's copied as is from Angular CLI.
|
// TODO: cleanup this file, it's copied as is from Angular CLI.
|
||||||
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as glob from 'glob';
|
import * as glob from 'glob';
|
||||||
import * as webpack from 'webpack';
|
import * as webpack from 'webpack';
|
||||||
const webpackDevMiddleware = require('webpack-dev-middleware');
|
const webpackDevMiddleware = require('webpack-dev-middleware');
|
||||||
|
|
||||||
import { AssetPattern } from '../../browser/schema';
|
|
||||||
import { KarmaWebpackFailureCb } from './karma-webpack-failure-cb';
|
import { KarmaWebpackFailureCb } from './karma-webpack-failure-cb';
|
||||||
|
import { statsErrorsToString } from '../utilities/stats';
|
||||||
|
import { getWebpackStatsConfig } from '../models/webpack-configs/stats';
|
||||||
|
import { createConsoleLogger } from '@angular-devkit/core/node';
|
||||||
|
import { logging } from '@angular-devkit/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumerate needed (but not require/imported) dependencies from this file
|
* Enumerate needed (but not require/imported) dependencies from this file
|
||||||
@ -62,7 +64,7 @@ const init: any = (config: any, emitter: any, customFileHandlers: any) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
const options = config.buildWebpack.options;
|
const options = config.buildWebpack.options;
|
||||||
const projectRoot = config.buildWebpack.projectRoot as string;
|
const logger: logging.Logger = config.buildWebpack.logger || createConsoleLogger();
|
||||||
successCb = config.buildWebpack.successCb;
|
successCb = config.buildWebpack.successCb;
|
||||||
failureCb = config.buildWebpack.failureCb;
|
failureCb = config.buildWebpack.failureCb;
|
||||||
|
|
||||||
@ -93,7 +95,9 @@ const init: any = (config: any, emitter: any, customFileHandlers: any) => {
|
|||||||
// Add webpack config.
|
// Add webpack config.
|
||||||
const webpackConfig = config.buildWebpack.webpackConfig;
|
const webpackConfig = config.buildWebpack.webpackConfig;
|
||||||
const webpackMiddlewareConfig = {
|
const webpackMiddlewareConfig = {
|
||||||
logLevel: 'error', // Hide webpack output because its noisy.
|
// Hide webpack output because its noisy.
|
||||||
|
logLevel: 'error',
|
||||||
|
stats: false,
|
||||||
watchOptions: { poll: options.poll },
|
watchOptions: { poll: options.poll },
|
||||||
publicPath: '/_karma_webpack_/',
|
publicPath: '/_karma_webpack_/',
|
||||||
};
|
};
|
||||||
@ -147,9 +151,9 @@ const init: any = (config: any, emitter: any, customFileHandlers: any) => {
|
|||||||
try {
|
try {
|
||||||
compiler = webpack(webpackConfig);
|
compiler = webpack(webpackConfig);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e.stack || e);
|
logger.error(e.stack || e)
|
||||||
if (e.details) {
|
if (e.details) {
|
||||||
console.error(e.details);
|
logger.error(e.details)
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -175,9 +179,17 @@ const init: any = (config: any, emitter: any, customFileHandlers: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let lastCompilationHash: string | undefined;
|
let lastCompilationHash: string | undefined;
|
||||||
|
const statsConfig = getWebpackStatsConfig();
|
||||||
compiler.hooks.done.tap('karma', (stats: any) => {
|
compiler.hooks.done.tap('karma', (stats: any) => {
|
||||||
|
if (stats.compilation.errors.length > 0) {
|
||||||
|
const json = stats.toJson(config.stats);
|
||||||
|
// Print compilation errors.
|
||||||
|
logger.error(statsErrorsToString(json, statsConfig));
|
||||||
|
lastCompilationHash = undefined;
|
||||||
|
// Emit a failure build event if there are compilation errors.
|
||||||
|
failureCb && failureCb();
|
||||||
|
} else if (stats.hash != lastCompilationHash) {
|
||||||
// Refresh karma only when there are no webpack errors, and if the compilation changed.
|
// Refresh karma only when there are no webpack errors, and if the compilation changed.
|
||||||
if (stats.compilation.errors.length === 0 && stats.hash != lastCompilationHash) {
|
|
||||||
lastCompilationHash = stats.hash;
|
lastCompilationHash = stats.hash;
|
||||||
emitter.refreshFiles();
|
emitter.refreshFiles();
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,7 @@ export class KarmaBuilder implements Builder<KarmaBuilderSchema> {
|
|||||||
// When this workaround is removed, user projects need to be updated to use a Karma
|
// When this workaround is removed, user projects need to be updated to use a Karma
|
||||||
// version that has a fix for this issue.
|
// version that has a fix for this issue.
|
||||||
toJSON: () => { },
|
toJSON: () => { },
|
||||||
|
logger: this.context.logger,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: inside the configs, always use the project root and not the workspace root.
|
// TODO: inside the configs, always use the project root and not the workspace root.
|
||||||
|
@ -6,10 +6,12 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { runTargetSpec } from '@angular-devkit/architect/testing';
|
import { DefaultTimeout, runTargetSpec } from '@angular-devkit/architect/testing';
|
||||||
import { debounceTime, take, tap } from 'rxjs/operators';
|
import { Subject } from 'rxjs';
|
||||||
|
import { debounceTime, delay, take, takeUntil, takeWhile, tap } from 'rxjs/operators';
|
||||||
import { host, karmaTargetSpec } from '../utils';
|
import { host, karmaTargetSpec } from '../utils';
|
||||||
|
|
||||||
|
|
||||||
describe('Karma Builder watch mode', () => {
|
describe('Karma Builder watch mode', () => {
|
||||||
beforeEach(done => host.initialize().toPromise().then(done, done.fail));
|
beforeEach(done => host.initialize().toPromise().then(done, done.fail));
|
||||||
afterEach(done => host.restore().toPromise().then(done, done.fail));
|
afterEach(done => host.restore().toPromise().then(done, done.fail));
|
||||||
@ -23,5 +25,83 @@ describe('Karma Builder watch mode', () => {
|
|||||||
).toPromise();
|
).toPromise();
|
||||||
|
|
||||||
expect(res).toEqual({ success: true });
|
expect(res).toEqual({ success: true });
|
||||||
}, 30000);
|
});
|
||||||
|
|
||||||
|
it('recovers from compilation failures in watch mode', (done) => {
|
||||||
|
const overrides = { watch: true };
|
||||||
|
let buildCount = 0;
|
||||||
|
let phase = 1;
|
||||||
|
|
||||||
|
runTargetSpec(host, karmaTargetSpec, overrides, DefaultTimeout * 3).pipe(
|
||||||
|
debounceTime(500),
|
||||||
|
tap((buildEvent) => {
|
||||||
|
buildCount += 1;
|
||||||
|
switch (phase) {
|
||||||
|
case 1:
|
||||||
|
// Karma run should succeed.
|
||||||
|
// Add a compilation error.
|
||||||
|
expect(buildEvent.success).toBe(true);
|
||||||
|
// Add an syntax error to a non-main file.
|
||||||
|
host.appendToFile('src/app/app.component.spec.ts', `]]]`);
|
||||||
|
phase = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Karma run should fail due to compilation error. Fix it.
|
||||||
|
expect(buildEvent.success).toBe(false);
|
||||||
|
host.replaceInFile('src/app/app.component.spec.ts', `]]]`, '');
|
||||||
|
phase = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
// Karma run should succeed again.
|
||||||
|
expect(buildEvent.success).toBe(true);
|
||||||
|
phase = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
takeWhile(() => phase < 4),
|
||||||
|
).toPromise().then(
|
||||||
|
() => done(),
|
||||||
|
() => done.fail(`stuck at phase ${phase} [builds: ${buildCount}]`),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not rebuild when nothing changed', (done) => {
|
||||||
|
const overrides = { watch: true };
|
||||||
|
let buildCount = 0;
|
||||||
|
let phase = 1;
|
||||||
|
|
||||||
|
const stopSubject = new Subject();
|
||||||
|
const stop$ = stopSubject.asObservable().pipe(delay(5000));
|
||||||
|
|
||||||
|
runTargetSpec(host, karmaTargetSpec, overrides, DefaultTimeout * 3).pipe(
|
||||||
|
debounceTime(500),
|
||||||
|
tap((buildEvent) => {
|
||||||
|
buildCount += 1;
|
||||||
|
switch (phase) {
|
||||||
|
case 1:
|
||||||
|
// Karma run should succeed.
|
||||||
|
// Add a compilation error.
|
||||||
|
expect(buildEvent.success).toBe(true);
|
||||||
|
// Touch the file.
|
||||||
|
host.appendToFile('src/app/app.component.spec.ts', ``);
|
||||||
|
// Signal the stopper, which delays emission by 5s.
|
||||||
|
// If there's no rebuild within that time then the test is successful.
|
||||||
|
stopSubject.next();
|
||||||
|
phase = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Should never trigger this second build.
|
||||||
|
expect(true).toBeFalsy('Should not trigger second build.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
takeUntil(stop$),
|
||||||
|
).toPromise().then(
|
||||||
|
() => done(),
|
||||||
|
() => done.fail(`stuck at phase ${phase} [builds: ${buildCount}]`),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user