Skip to content

fix(@angular/cli): fix test typings #5504

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [
"es2016"
"es2016",
"dom"
],<% } %>
"outDir": "<%= relativeRootPath %>/out-tsc/spec",
"module": "commonjs",
Expand All @@ -23,6 +24,7 @@
"test.ts"
],
"include": [
"**/*.spec.ts"
"**/*.spec.ts",
"**/*.d.ts"
]
}
4 changes: 3 additions & 1 deletion packages/@angular/cli/models/webpack-configs/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as webpack from 'webpack';

import { CliConfig } from '../config';
import { WebpackTestOptions } from '../webpack-test-config';
import { KarmaWebpackEmitlessError } from '../../plugins/karma-webpack-emitless-error';

/**
* Enumerate loaders and their dependencies from this file to let the dependency validator
Expand Down Expand Up @@ -57,7 +58,8 @@ export function getTestConfig(testConfig: WebpackTestOptions) {
new webpack.SourceMapDevToolPlugin({
filename: null, // if no value is provided the sourcemap is inlined
test: /\.(ts|js)($|\?)/i // process .js and .ts files only
})
}),
new KarmaWebpackEmitlessError()
]
};
}
1 change: 1 addition & 0 deletions packages/@angular/cli/models/webpack-test-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class WebpackTestConfig extends NgCliWebpackConfig {
];

this.config = webpackMerge(webpackConfigs);
delete this.config.entry;

// Remove any instance of CommonsChunkPlugin, not needed with karma-webpack.
this.config.plugins = this.config.plugins.filter((plugin: any) =>
Expand Down
20 changes: 20 additions & 0 deletions packages/@angular/cli/plugins/karma-webpack-emitless-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Don't emit anything when there are compilation errors. This is useful for preventing Karma
// from re-running tests when there is a compilation error.
// Workaround for https://github.com/webpack-contrib/karma-webpack/issues/49

export class KarmaWebpackEmitlessError {
constructor() { }

apply(compiler: any): void {
compiler.plugin('done', (stats: any) => {
if (stats.compilation.errors.length > 0) {
stats.stats = [{
toJson: function () {
return this;
},
assets: []
}];
}
});
}
}
14 changes: 14 additions & 0 deletions packages/@angular/cli/plugins/karma-webpack-throw-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Force Webpack to throw compilation errors. Useful with karma-webpack when in single-run mode.
// Workaround for https://github.com/webpack-contrib/karma-webpack/issues/66

export class KarmaWebpackThrowError {
constructor() { }

apply(compiler: any): void {
compiler.plugin('done', (stats: any) => {
if (stats.compilation.errors.length > 0) {
throw new Error(stats.compilation.errors.map((err: any) => err.message || err));
}
});
}
}
6 changes: 6 additions & 0 deletions packages/@angular/cli/plugins/karma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as glob from 'glob';
import { Pattern } from './glob-copy-webpack-plugin';
import { extraEntryParser } from '../models/webpack-configs/utils';
import { WebpackTestConfig, WebpackTestOptions } from '../models/webpack-test-config';
import { KarmaWebpackThrowError } from './karma-webpack-throw-error';

const getAppFromConfig = require('../utilities/app-utils').getAppFromConfig;

Expand Down Expand Up @@ -102,6 +103,11 @@ const init: any = (config: any) => {
}
};

// If Karma is being ran in single run mode, throw errors.
if (config.singleRun) {
webpackConfig.plugins.push(new KarmaWebpackThrowError());
}

config.webpack = Object.assign(webpackConfig, config.webpack);
config.webpackMiddleware = Object.assign(webpackMiddlewareConfig, config.webpackMiddleware);

Expand Down
3 changes: 2 additions & 1 deletion packages/@ngtools/webpack/src/extract_i18n_plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export class ExtractI18nPlugin implements Tapable {
if (!options.hasOwnProperty('tsConfigPath')) {
throw new Error('Must specify "tsConfigPath" in the configuration of @ngtools/webpack.');
}
this._tsConfigPath = options.tsConfigPath;
// TS represents paths internally with '/' and expects the tsconfig path to be in this format
this._tsConfigPath = options.tsConfigPath.replace(/\\/g, '/');

// Check the base path.
const maybeBasePath = path.resolve(process.cwd(), this._tsConfigPath);
Expand Down
3 changes: 2 additions & 1 deletion packages/@ngtools/webpack/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ export class AotPlugin implements Tapable {
if (!options.hasOwnProperty('tsConfigPath')) {
throw new Error('Must specify "tsConfigPath" in the configuration of @ngtools/webpack.');
}
this._tsConfigPath = options.tsConfigPath;
// TS represents paths internally with '/' and expects the tsconfig path to be in this format
this._tsConfigPath = options.tsConfigPath.replace(/\\/g, '/');

// Check the base path.
const maybeBasePath = path.resolve(process.cwd(), this._tsConfigPath);
Expand Down
1 change: 1 addition & 0 deletions tests/e2e/tests/build/aot/exclude.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default function () {
}))
.then(() => updateJsonFile('src/tsconfig.json', tsconfigJson => {
delete tsconfigJson['exclude'];
delete tsconfigJson['compilerOptions']['types'];
}))
.then(() => ng('build', '--aot'))
.then(() => !ejected && ng('test', '--single-run'));
Expand Down
10 changes: 10 additions & 0 deletions tests/e2e/tests/test/test-fail-single-run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ng } from '../../utils/process';
import { writeFile } from '../../utils/fs';
import { expectToFail } from '../../utils/utils';


export default function () {
// Fails on single run with broken compilation.
return writeFile('src/app.component.spec.ts', '<p> definitely not typescript </p>')
.then(() => expectToFail(() => ng('test', '--single-run')));
}
28 changes: 28 additions & 0 deletions tests/e2e/tests/test/test-fail-watch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
killAllProcesses,
waitForAnyProcessOutputToMatch,
silentExecAndWaitForOutputToMatch
} from '../../utils/process';
import { expectToFail } from '../../utils/utils';
import { readFile, writeFile } from '../../utils/fs';


// Karma is only really finished with a run when it shows a non-zero total time in the first slot.
const karmaGoodRegEx = /Executed 3 of 3 SUCCESS \(\d+\.\d+ secs/;

export default function () {
let originalSpec: string;
return silentExecAndWaitForOutputToMatch('ng', ['test', '--no-progress'], karmaGoodRegEx)
.then(() => readFile('src/app/app.component.spec.ts'))
.then((data) => originalSpec = data)
// Trigger a failed rebuild, which shouldn't run tests again.
.then(() => writeFile('src/app/app.component.spec.ts', '<p> definitely not typescript </p>'))
.then(() => expectToFail(() => waitForAnyProcessOutputToMatch(karmaGoodRegEx, 10000)))
// Restore working spec.
.then(() => writeFile('src/app/app.component.spec.ts', originalSpec))
.then(() => waitForAnyProcessOutputToMatch(karmaGoodRegEx, 10000))
.then(() => killAllProcesses(), (err: any) => {
killAllProcesses();
throw err;
});
}