Skip to content

Commit f2fdc6e

Browse files
committed
feat(test): exclude files from coverage
Allow users to configure code-coverage excludes by setting the coverageExcludes property on their app config section in the angular-cli.json. The coverageExcludes property will accept a list of globs and/or file paths relative to the app root. The items are all processed with glob and appended to the excludes sent to sourcemap-istanbul-instrumenter-loader.
1 parent 75e83a4 commit f2fdc6e

File tree

4 files changed

+67
-9
lines changed

4 files changed

+67
-9
lines changed

packages/angular-cli/lib/config/schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@
6161
"test": {
6262
"type": "string"
6363
},
64+
"coverageExcludes": {
65+
"type": "array",
66+
"items": {
67+
"type": "string"
68+
}
69+
},
6470
"tsconfig": {
6571
"type": "string",
6672
"default": "tsconfig.json"

packages/angular-cli/models/webpack-build-test.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const path = require('path');
44
const webpack = require('webpack');
55
const ngtools = require('@ngtools/webpack');
6+
const glob = require('glob');
67

78

89
const g = global;
@@ -33,13 +34,28 @@ const getWebpackTestConfig = function (projectRoot, environment, appConfig, test
3334
const extraPlugins = [];
3435

3536
if (testConfig.codeCoverage) {
37+
var excludes = [
38+
/\.(e2e|spec)\.ts$/,
39+
/node_modules/
40+
];
41+
42+
// parse list of glob exclusions
43+
if (appConfig.hasOwnProperty('coverageExcludes')) {
44+
if (Object.prototype.toString.call(appConfig.coverageExcludes) === '[object Array]') {
45+
appConfig.coverageExcludes.forEach(function (exclude) {
46+
// get all files that will be ignored relative to appRoot
47+
glob.sync(appRoot + '/' + exclude).forEach(function (file) {
48+
// be sure to switch out to backslashes if on windows using path.resolve
49+
excludes.push(path.resolve(file));
50+
});
51+
});
52+
}
53+
}
54+
3655
extraRules.push({
3756
test: /\.(js|ts)$/, loader: 'sourcemap-istanbul-instrumenter-loader',
3857
enforce: 'post',
39-
exclude: [
40-
/\.(e2e|spec)\.ts$/,
41-
/node_modules/
42-
],
58+
exclude: excludes,
4359
query: { 'force-sourcemap': true }
4460
});
4561
}

tests/e2e/tests/misc/coverage.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
1-
import {expectFileToExist} from '../../utils/fs';
1+
import {expectFileToExist, expectFileNotToMatch, writeFile} from '../../utils/fs';
22
import {ng} from '../../utils/process';
3+
import {updateJsonFile} from '../../utils/project';
34

4-
5-
export default function() {
6-
return ng('test', '--single-run', '--code-coverage')
5+
export default function () {
6+
let ignoredGlobFileName = 'src/app/ignore.glob.ts';
7+
let ignoredExplicitFileName = 'src/app/ignore.explicit.ts';
8+
let coverageFileName = 'coverage/coverage.lcov';
9+
return updateJsonFile('angular-cli.json', configJson => {
10+
const app = configJson['apps'][0];
11+
app['configExcludes'] = ['**/*.glob.ts', ignoredExplicitFileName];
12+
})
13+
.then(() => writeFile(ignoredGlobFileName, ''))
14+
.then(() => expectFileToExist(ignoredGlobFileName))
15+
.then(() => writeFile(ignoredExplicitFileName, ''))
16+
.then(() => expectFileToExist(ignoredExplicitFileName))
17+
.then(() => ng('test', '--single-run', '--code-coverage'))
718
.then(() => expectFileToExist('coverage/src/app'))
8-
.then(() => expectFileToExist('coverage/coverage.lcov'));
19+
.then(() => expectFileToExist(coverageFileName))
20+
.then(() => expectFileNotToMatch(coverageFileName, ignoredGlobFileName))
21+
.then(() => expectFileNotToMatch(coverageFileName, ignoredExplicitFileName));
922
}

tests/e2e/utils/fs.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,29 @@ export function expectFileToMatch(fileName: string, regEx: RegExp | string) {
138138
});
139139
}
140140

141+
export function expectFileNotToMatch(fileName: string, regEx: RegExp | string) {
142+
return readFile(fileName)
143+
.then(content => {
144+
if (typeof regEx == 'string') {
145+
if (content.indexOf(regEx) != -1) {
146+
throw new Error(stripIndents`File "${fileName}" contained "${regEx}"...
147+
Content:
148+
${content}
149+
------
150+
`);
151+
}
152+
} else {
153+
if (content.match(regEx)) {
154+
throw new Error(stripIndents`File "${fileName}" contained "${regEx}"...
155+
Content:
156+
${content}
157+
------
158+
`);
159+
}
160+
}
161+
});
162+
}
163+
141164
export function expectFileSizeToBeUnder(fileName: string, sizeInBytes: number) {
142165
return readFile(fileName)
143166
.then(content => {

0 commit comments

Comments
 (0)