mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-16 10:33:43 +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.
|
||||
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as glob from 'glob';
|
||||
import * as webpack from 'webpack';
|
||||
const webpackDevMiddleware = require('webpack-dev-middleware');
|
||||
|
||||
import { AssetPattern } from '../../browser/schema';
|
||||
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
|
||||
@ -62,7 +64,7 @@ const init: any = (config: any, emitter: any, customFileHandlers: any) => {
|
||||
)
|
||||
}
|
||||
const options = config.buildWebpack.options;
|
||||
const projectRoot = config.buildWebpack.projectRoot as string;
|
||||
const logger: logging.Logger = config.buildWebpack.logger || createConsoleLogger();
|
||||
successCb = config.buildWebpack.successCb;
|
||||
failureCb = config.buildWebpack.failureCb;
|
||||
|
||||
@ -93,7 +95,9 @@ const init: any = (config: any, emitter: any, customFileHandlers: any) => {
|
||||
// Add webpack config.
|
||||
const webpackConfig = config.buildWebpack.webpackConfig;
|
||||
const webpackMiddlewareConfig = {
|
||||
logLevel: 'error', // Hide webpack output because its noisy.
|
||||
// Hide webpack output because its noisy.
|
||||
logLevel: 'error',
|
||||
stats: false,
|
||||
watchOptions: { poll: options.poll },
|
||||
publicPath: '/_karma_webpack_/',
|
||||
};
|
||||
@ -147,9 +151,9 @@ const init: any = (config: any, emitter: any, customFileHandlers: any) => {
|
||||
try {
|
||||
compiler = webpack(webpackConfig);
|
||||
} catch (e) {
|
||||
console.error(e.stack || e);
|
||||
logger.error(e.stack || e)
|
||||
if (e.details) {
|
||||
console.error(e.details);
|
||||
logger.error(e.details)
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
@ -175,9 +179,17 @@ const init: any = (config: any, emitter: any, customFileHandlers: any) => {
|
||||
}
|
||||
|
||||
let lastCompilationHash: string | undefined;
|
||||
const statsConfig = getWebpackStatsConfig();
|
||||
compiler.hooks.done.tap('karma', (stats: any) => {
|
||||
// Refresh karma only when there are no webpack errors, and if the compilation changed.
|
||||
if (stats.compilation.errors.length === 0 && stats.hash != lastCompilationHash) {
|
||||
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.
|
||||
lastCompilationHash = stats.hash;
|
||||
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
|
||||
// version that has a fix for this issue.
|
||||
toJSON: () => { },
|
||||
logger: this.context.logger,
|
||||
};
|
||||
|
||||
// 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
|
||||
*/
|
||||
|
||||
import { runTargetSpec } from '@angular-devkit/architect/testing';
|
||||
import { debounceTime, take, tap } from 'rxjs/operators';
|
||||
import { DefaultTimeout, runTargetSpec } from '@angular-devkit/architect/testing';
|
||||
import { Subject } from 'rxjs';
|
||||
import { debounceTime, delay, take, takeUntil, takeWhile, tap } from 'rxjs/operators';
|
||||
import { host, karmaTargetSpec } from '../utils';
|
||||
|
||||
|
||||
describe('Karma Builder watch mode', () => {
|
||||
beforeEach(done => host.initialize().toPromise().then(done, done.fail));
|
||||
afterEach(done => host.restore().toPromise().then(done, done.fail));
|
||||
@ -23,5 +25,83 @@ describe('Karma Builder watch mode', () => {
|
||||
).toPromise();
|
||||
|
||||
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