Skip to content

Commit 09ccaf4

Browse files
kyliauKeen Yee Liau
authored and
Keen Yee Liau
committed
feat(@angular-devkit/build-angular): Switch to karma-coverage
This commit switches coverage tooling from karma-coverage-istanbul-reporter to karma-coverage since it's better supported.
1 parent ceeb6fb commit 09ccaf4

File tree

12 files changed

+130
-73
lines changed

12 files changed

+130
-73
lines changed

integration/angular_cli/karma.conf.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,19 @@ module.exports = function (config) {
1212
require('karma-jasmine'),
1313
require('karma-chrome-launcher'),
1414
require('karma-jasmine-html-reporter'),
15-
require('karma-coverage-istanbul-reporter'),
15+
require('karma-coverage'),
1616
require('@angular-devkit/build-angular/plugins/karma'),
1717
],
1818
client: {
1919
clearContext: false, // leave Jasmine Spec Runner output visible in browser
2020
},
21-
coverageIstanbulReporter: {
21+
coverageReporter: {
2222
dir: path.join(__dirname, 'coverage'),
23-
reports: ['html', 'lcovonly'],
24-
fixWebpackSourcePaths: true,
23+
subdir: '.',
24+
reporters: [
25+
{type: 'html'},
26+
{type: 'lcov'},
27+
],
2528
},
2629
reporters: ['progress', 'kjhtml'],
2730
port: 9876,

integration/angular_cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"jasmine-spec-reporter": "~5.0.0",
3737
"karma": "~4.4.1",
3838
"karma-chrome-launcher": "~3.1.0",
39-
"karma-coverage-istanbul-reporter": "~2.1.0",
39+
"karma-coverage": "~2.0.3",
4040
"karma-jasmine": "~3.3.0",
4141
"karma-jasmine-html-reporter": "^1.5.0",
4242
"protractor": "~5.4.3",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@
161161
"jsonc-parser": "2.3.0",
162162
"karma": "~5.2.0",
163163
"karma-chrome-launcher": "~3.1.0",
164-
"karma-coverage-istanbul-reporter": "~3.0.0",
164+
"karma-coverage": "~2.0.3",
165165
"karma-jasmine": "~4.0.0",
166166
"karma-jasmine-html-reporter": "^1.5.0",
167167
"karma-source-map-support": "1.4.0",

packages/angular_devkit/build_angular/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ LARGE_SPECS = {
282282
"extra_deps": [
283283
"@npm//karma",
284284
"@npm//karma-chrome-launcher",
285-
"@npm//karma-coverage-istanbul-reporter",
285+
"@npm//karma-coverage",
286286
"@npm//karma-jasmine",
287287
"@npm//karma-jasmine-html-reporter",
288288
"@npm//puppeteer",

packages/angular_devkit/build_angular/src/angular-cli-files/plugins/karma.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,30 @@ const init: any = (config: any, emitter: any, customFileHandlers: any) => {
8888

8989
config.reporters.unshift('@angular-devkit/build-angular--event-reporter');
9090

91-
// When using code-coverage, auto-add coverage-istanbul.
92-
config.reporters = config.reporters || [];
93-
if (options.codeCoverage && config.reporters.indexOf('coverage-istanbul') === -1) {
94-
config.reporters.unshift('coverage-istanbul');
91+
// When using code-coverage, auto-add karma-coverage.
92+
if (options.codeCoverage) {
93+
config.plugins = config.plugins || [];
94+
config.reporters = config.reporters || [];
95+
const {plugins, reporters} = config;
96+
const hasCoveragePlugin = plugins.some((p: {}) => 'reporter:coverage' in p);
97+
const hasIstanbulPlugin = plugins.some((p: {}) => 'reporter:coverage-istanbul' in p);
98+
const hasCoverageReporter = reporters.includes('coverage');
99+
const hasIstanbulReporter = reporters.includes('coverage-istanbul');
100+
if (hasCoveragePlugin && !hasCoverageReporter) {
101+
reporters.push('coverage');
102+
}
103+
else if (hasIstanbulPlugin && !hasIstanbulReporter) {
104+
// coverage-istanbul is deprecated in favor of karma-coverage
105+
reporters.push('coverage-istanbul');
106+
}
107+
else {
108+
throw new Error('karma-coverage must be installed in order to run code coverage');
109+
}
110+
if (hasIstanbulPlugin) {
111+
logger.warn(`'karma-coverage-istanbul-reporter' has been deprecated since version 11. Please install 'karma-coverage' instead.`);
112+
}
95113
}
96-
114+
97115
// Add webpack config.
98116
const webpackConfig = config.buildWebpack.webpackConfig;
99117
const webpackMiddlewareConfig = {
@@ -188,7 +206,7 @@ const init: any = (config: any, emitter: any, customFileHandlers: any) => {
188206
logger.error(statsErrorsToString(json, statsConfig));
189207
lastCompilationHash = undefined;
190208
// Emit a failure build event if there are compilation errors.
191-
failureCb && failureCb();
209+
failureCb();
192210
} else if (stats.hash != lastCompilationHash) {
193211
// Refresh karma only when there are no webpack errors, and if the compilation changed.
194212
lastCompilationHash = stats.hash;
@@ -269,9 +287,9 @@ const eventReporter: any = function (this: any, baseReporterDecorator: any, conf
269287

270288
this.onRunComplete = function (_browsers: any, results: any) {
271289
if (results.exitCode === 0) {
272-
successCb && successCb();
290+
successCb();
273291
} else {
274-
failureCb && failureCb();
292+
failureCb();
275293
}
276294
}
277295

packages/angular_devkit/build_angular/src/karma/code-coverage_spec.ts

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,23 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8+
9+
// tslint:disable:no-implicit-dependencies
10+
811
import { Architect } from '@angular-devkit/architect';
912
import { normalize, virtualFs } from '@angular-devkit/core';
13+
import { promisify } from 'util';
1014
import { createArchitect, host, karmaTargetSpec } from '../test-utils';
1115

16+
// In each of the test below we'll have to call setTimeout to wait for the coverage
17+
// analysis to be done. This is because karma-coverage performs the analysis
18+
// asynchronously but the promise that it returns is not awaited by Karma.
19+
// Coverage analysis begins when onRunComplete() is invoked, and output files
20+
// are subsequently written to disk. For more information, see
21+
// https://github.com/karma-runner/karma-coverage/blob/32acafa90ed621abd1df730edb44ae55a4009c2c/lib/reporter.js#L221
22+
23+
const setTimeoutPromise = promisify(setTimeout);
24+
1225
describe('Karma Builder code coverage', () => {
1326
const coverageFilePath = normalize('coverage/lcov.info');
1427
let architect: Architect;
@@ -23,16 +36,19 @@ describe('Karma Builder code coverage', () => {
2336
it('supports code coverage option', async () => {
2437
const run = await architect.scheduleTarget(karmaTargetSpec, { codeCoverage: true });
2538

26-
await expectAsync(run.result).toBeResolvedTo(jasmine.objectContaining({ success: true }));
39+
const {success} = await run.result;
40+
expect(success).toBe(true);
2741

2842
await run.stop();
2943

44+
await setTimeoutPromise(1000);
45+
3046
const exists = host.scopedSync().exists(coverageFilePath);
31-
expect(exists).toBe(true);
47+
expect(exists).toBe(true, `${coverageFilePath} does not exist`);
3248

3349
if (exists) {
3450
const content = virtualFs.fileBufferToString(host.scopedSync().read(coverageFilePath));
35-
expect(content).toContain('polyfills.ts');
51+
expect(content).toContain('app.component.ts');
3652
expect(content).toContain('test.ts');
3753
}
3854
}, 120000);
@@ -41,23 +57,24 @@ describe('Karma Builder code coverage', () => {
4157
const overrides = {
4258
codeCoverage: true,
4359
codeCoverageExclude: [
44-
'src/polyfills.ts',
4560
'**/test.ts',
4661
],
4762
};
4863

4964
const run = await architect.scheduleTarget(karmaTargetSpec, overrides);
5065

51-
await expectAsync(run.result).toBeResolvedTo(jasmine.objectContaining({ success: true }));
66+
const {success} = await run.result;
67+
expect(success).toBe(true);
5268

5369
await run.stop();
5470

71+
await setTimeoutPromise(1000);
72+
5573
const exists = host.scopedSync().exists(coverageFilePath);
5674
expect(exists).toBe(true);
5775

5876
if (exists) {
5977
const content = virtualFs.fileBufferToString(host.scopedSync().read(coverageFilePath));
60-
expect(content).not.toContain('polyfills.ts');
6178
expect(content).not.toContain('test.ts');
6279
}
6380
}, 120000);
@@ -98,10 +115,13 @@ describe('Karma Builder code coverage', () => {
98115

99116
const run = await architect.scheduleTarget(karmaTargetSpec, { codeCoverage: true });
100117

101-
await expectAsync(run.result).toBeResolvedTo(jasmine.objectContaining({ success: true }));
118+
const {success} = await run.result;
119+
expect(success).toBe(true);
102120

103121
await run.stop();
104122

123+
await setTimeoutPromise(1000);
124+
105125
const exists = host.scopedSync().exists(coverageFilePath);
106126
expect(exists).toBe(true);
107127

@@ -111,20 +131,18 @@ describe('Karma Builder code coverage', () => {
111131
}
112132
}, 120000);
113133

114-
it(`should fail when coverage is below threhold and 'emitWarning' is false`, async () => {
115-
host.replaceInFile('karma.conf.js', 'fixWebpackSourcePaths: true',
116-
`
117-
fixWebpackSourcePaths: true,
118-
thresholds: {
119-
emitWarning: false,
120-
global: {
121-
statements: 100,
122-
lines: 100,
123-
branches: 100,
124-
functions: 100
134+
it(`should exit with non-zero code when coverage is below threshold`, async () => {
135+
host.replaceInFile('karma.conf.js', 'coverageReporter: {', `
136+
coverageReporter: {
137+
check: {
138+
global: {
139+
statements: 100,
140+
lines: 100,
141+
branches: 100,
142+
functions: 100
143+
}
125144
},
126-
}`,
127-
);
145+
`);
128146

129147
host.appendToFile('src/app/app.component.ts', `
130148
export function nonCovered(): boolean {
@@ -133,7 +151,16 @@ describe('Karma Builder code coverage', () => {
133151
`);
134152

135153
const run = await architect.scheduleTarget(karmaTargetSpec, { codeCoverage: true });
136-
await expectAsync(run.result).toBeResolvedTo(jasmine.objectContaining({ success: false }));
154+
155+
// In incremental mode, karma-coverage does not have the ability to mark a
156+
// run as failed if code coverage does not pass. This is because it does
157+
// the coverage asynchoronously and Karma does not await the promise
158+
// returned by the plugin.
159+
expect((await run.result).success).toBeTrue();
160+
161+
// However after we stop, the program must exit with non-zero exit code.
162+
// This is a more common use case of coverage testing and must be supported.
137163
await run.stop();
164+
// TODO: assert the exit code
138165
}, 120000);
139166
});

packages/angular_devkit/build_angular/test/hello-world-app/karma.conf.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,19 @@ module.exports = function(config) {
1919
require('karma-jasmine'),
2020
require('karma-chrome-launcher'),
2121
require('karma-jasmine-html-reporter'),
22-
require('karma-coverage-istanbul-reporter'),
22+
require('karma-coverage'),
2323
require('@angular-devkit/build-angular/plugins/karma'),
2424
],
2525
client: {
2626
clearContext: false, // leave Jasmine Spec Runner output visible in browser
2727
},
28-
coverageIstanbulReporter: {
29-
dir: path.join(__dirname, 'coverage'),
30-
reports: ['html', 'lcovonly'],
31-
fixWebpackSourcePaths: true,
28+
coverageReporter: {
29+
dir: path.join(__dirname, './coverage'),
30+
subdir: '.',
31+
reporters: [
32+
{type: 'html'},
33+
{type: 'lcov'},
34+
],
3235
},
3336
reporters: ['progress', 'kjhtml'],
3437
port: 9876,

packages/angular_devkit/build_ng_packagr/test/ng-packaged/projects/lib/karma.conf.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,20 @@ module.exports = function (config) {
1616
require('karma-jasmine'),
1717
require('karma-chrome-launcher'),
1818
require('karma-jasmine-html-reporter'),
19-
require('karma-coverage-istanbul-reporter'),
19+
require('karma-coverage'),
2020
require('@angular-devkit/build-angular/plugins/karma')
2121
],
2222
client: {
2323
clearContext: false // leave Jasmine Spec Runner output visible in browser
2424
},
25-
coverageIstanbulReporter: {
25+
coverageReporter: {
2626
dir: require('path').join(__dirname, 'coverage'),
27-
reports: ['html', 'lcovonly'],
28-
fixWebpackSourcePaths: true
27+
subdir: '.',
28+
reporters: [
29+
{type: 'html'},
30+
{type: 'lcov'},
31+
{type: 'text-summary'},
32+
],
2933
},
3034
reporters: ['progress', 'kjhtml'],
3135
port: 9876,

packages/schematics/angular/application/files/karma.conf.js.template

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,20 @@ module.exports = function (config) {
99
require('karma-jasmine'),
1010
require('karma-chrome-launcher'),
1111
require('karma-jasmine-html-reporter'),
12-
require('karma-coverage-istanbul-reporter'),
12+
require('karma-coverage'),
1313
require('@angular-devkit/build-angular/plugins/karma')
1414
],
1515
client: {
1616
clearContext: false // leave Jasmine Spec Runner output visible in browser
1717
},
18-
coverageIstanbulReporter: {
18+
coverageReporter: {
1919
dir: require('path').join(__dirname, '<%= relativePathToWorkspaceRoot %>/coverage/<%= appName%>'),
20-
reports: ['html', 'lcovonly', 'text-summary'],
21-
fixWebpackSourcePaths: true
20+
subdir: '.',
21+
reporters: [
22+
{type: 'html'},
23+
{type: 'lcov'},
24+
{type: 'text-summary'},
25+
],
2226
},
2327
reporters: ['progress', 'kjhtml'],
2428
port: 9876,

packages/schematics/angular/library/files/karma.conf.js.template

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,20 @@ module.exports = function (config) {
99
require('karma-jasmine'),
1010
require('karma-chrome-launcher'),
1111
require('karma-jasmine-html-reporter'),
12-
require('karma-coverage-istanbul-reporter'),
12+
require('karma-coverage'),
1313
require('@angular-devkit/build-angular/plugins/karma')
1414
],
1515
client: {
1616
clearContext: false // leave Jasmine Spec Runner output visible in browser
1717
},
18-
coverageIstanbulReporter: {
18+
coverageReporter: {
1919
dir: require('path').join(__dirname, '<%= relativePathToWorkspaceRoot %>/coverage/<%= folderName %>'),
20-
reports: ['html', 'lcovonly', 'text-summary'],
21-
fixWebpackSourcePaths: true
20+
subdir: '.',
21+
reporters: [
22+
{type: 'html'},
23+
{type: 'lcov'},
24+
{type: 'text-summary'},
25+
],
2226
},
2327
reporters: ['progress', 'kjhtml'],
2428
port: 9876,

packages/schematics/angular/workspace/files/package.json.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"jasmine-spec-reporter": "~5.0.0",
3434
"karma": "~5.2.0",
3535
"karma-chrome-launcher": "~3.1.0",
36-
"karma-coverage-istanbul-reporter": "~3.0.2",
36+
"karma-coverage": "~2.0.3",
3737
"karma-jasmine": "~4.0.0",
3838
"karma-jasmine-html-reporter": "^1.5.0",
3939
"protractor": "~7.0.0",<% } %>

0 commit comments

Comments
 (0)