monocart-coverage-reports 2.6.2 → 2.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -15
- package/lib/cli.js +72 -121
- package/lib/converter/ast.js +3 -1
- package/lib/converter/converter.js +6 -1
- package/lib/default/options.js +28 -24
- package/lib/generate.js +9 -10
- package/lib/index.d.ts +103 -41
- package/lib/index.js +103 -15
- package/lib/packages/monocart-coverage-v8.js +1 -1
- package/lib/utils/source-path.js +7 -0
- package/lib/v8/v8.js +38 -27
- package/package.json +81 -81
package/README.md
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
- [Using `v8-to-istanbul`](#using-v8-to-istanbul)
|
|
34
34
|
- [How Monocart Works](#how-monocart-works)
|
|
35
35
|
* [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap)
|
|
36
|
+
* [Common issues](#common-issues)
|
|
36
37
|
* [Integration](#integration)
|
|
37
38
|
- [Playwright](#playwright)
|
|
38
39
|
- [Jest](#jest)
|
|
@@ -258,16 +259,19 @@ const coverageOptions = {
|
|
|
258
259
|
|
|
259
260
|
## `mcr` CLI
|
|
260
261
|
> The CLI will run the program as a [child process](https://nodejs.org/docs/latest/api/child_process.html) with `NODE_V8_COVERAGE=dir` until it exits gracefully, and generate the coverage report with the coverage data from the `dir`.
|
|
262
|
+
|
|
261
263
|
- Installing globally
|
|
262
264
|
```sh
|
|
263
265
|
npm i monocart-coverage-reports -g
|
|
264
|
-
mcr node ./test/
|
|
266
|
+
mcr node ./test/specs/node.test.js -r v8,console-summary --lcov
|
|
265
267
|
```
|
|
268
|
+
|
|
266
269
|
- Locally in your project
|
|
267
270
|
```sh
|
|
268
271
|
npm i monocart-coverage-reports
|
|
269
|
-
npx mcr node ./test/
|
|
272
|
+
npx mcr node ./test/specs/node.test.js -r v8,console-summary --lcov
|
|
270
273
|
```
|
|
274
|
+
|
|
271
275
|
- CLI Options
|
|
272
276
|
```sh
|
|
273
277
|
Usage: mcr [options] <command>
|
|
@@ -279,10 +283,11 @@ Arguments:
|
|
|
279
283
|
|
|
280
284
|
Options:
|
|
281
285
|
-V, --version output the version number
|
|
282
|
-
-c, --config <path> custom config path
|
|
283
|
-
|
|
284
|
-
-r, --reports <name[,name]> coverage reports to use
|
|
286
|
+
-c, --config <path> custom config file path
|
|
287
|
+
--logging <logging> off, error, info, debug
|
|
285
288
|
-n, --name <name> report name for title
|
|
289
|
+
-r, --reports <name[,name]> coverage reports to use
|
|
290
|
+
-o, --outputDir <dir> output dir for reports
|
|
286
291
|
-i, --inputDir <dir> input dir for merging raw files
|
|
287
292
|
--entryFilter <pattern> entry url filter
|
|
288
293
|
--sourceFilter <pattern> source path filter
|
|
@@ -290,19 +295,20 @@ Options:
|
|
|
290
295
|
--inline inline html for v8 report
|
|
291
296
|
--assetsPath <path> assets path if not inline
|
|
292
297
|
--lcov generate lcov.info file
|
|
293
|
-
--logging <logging> off, error, info, debug
|
|
294
298
|
-h, --help display help for command
|
|
295
299
|
```
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
- `
|
|
299
|
-
- `mcr.config.mjs`
|
|
300
|
-
- `mcr.config.cjs`
|
|
300
|
+
|
|
301
|
+
- Loading config file by priority:
|
|
302
|
+
- custom config file with `-c` or `--config`
|
|
301
303
|
- `mcr.config.js`
|
|
302
|
-
-
|
|
303
|
-
|
|
304
|
-
mcr
|
|
305
|
-
|
|
304
|
+
- `mcr.config.cjs`
|
|
305
|
+
- `mcr.config.mjs`
|
|
306
|
+
- `mcr.config.json` - json format
|
|
307
|
+
- `.mcrrc.js`
|
|
308
|
+
- `.mcrrc` - json format
|
|
309
|
+
- `mcr.config.ts` - it requires `NODE_OPTIONS="--loader ts-node/esm"`
|
|
310
|
+
|
|
311
|
+
- Working with `ts-node`, see [mcr-ts-node](https://github.com/cenfun/mcr-ts-node)
|
|
306
312
|
|
|
307
313
|
## Compare Reports
|
|
308
314
|
| | Istanbul | V8 | V8 to Istanbul |
|
|
@@ -699,6 +705,28 @@ When `logging` is `debug`, the raw report data will be preserved in `[outputDir]
|
|
|
699
705
|
|
|
700
706
|

|
|
701
707
|
|
|
708
|
+
## Common issues
|
|
709
|
+
- `Unparsable source`
|
|
710
|
+
|
|
711
|
+
It happens during the parsing of the source code into AST, if the source code is not in the standard ECMAScript. For example `ts`, `jsx` and so on. There is a option to fix it, which is to manually compile the source code for these files.
|
|
712
|
+
```js
|
|
713
|
+
import * as fs from "fs";
|
|
714
|
+
import * as path from "path";
|
|
715
|
+
import { fileURLToPath } from "url";
|
|
716
|
+
import * as TsNode from 'ts-node';
|
|
717
|
+
const coverageOptions = {
|
|
718
|
+
onEntry: async (entry) => {
|
|
719
|
+
const filePath = fileURLToPath(entry.url)
|
|
720
|
+
const originalSource = fs.readFileSync(filePath).toString("utf-8");
|
|
721
|
+
const fileName = path.basename(filePath);
|
|
722
|
+
const tn = TsNode.create({});
|
|
723
|
+
const source = tn.compile(originalSource, fileName);
|
|
724
|
+
entry.fake = false;
|
|
725
|
+
entry.source = source;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
```
|
|
729
|
+
|
|
702
730
|
## Integration
|
|
703
731
|
|
|
704
732
|
### [Playwright](https://github.com/microsoft/playwright)
|
package/lib/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const EC = require('eight-colors');
|
|
6
|
-
const { fileURLToPath
|
|
6
|
+
const { fileURLToPath } = require('url');
|
|
7
7
|
|
|
8
8
|
const {
|
|
9
9
|
foregroundChild,
|
|
@@ -12,93 +12,10 @@ const {
|
|
|
12
12
|
|
|
13
13
|
const MCR = require('./index.js');
|
|
14
14
|
const Util = require('./utils/util.js');
|
|
15
|
-
const defaultOptions = require('./default/options.js');
|
|
16
15
|
const { resolveSourceMap } = require('./converter/collect-source-maps.js');
|
|
17
16
|
|
|
18
17
|
const version = require('../package.json').version;
|
|
19
18
|
|
|
20
|
-
const cleanDir = (dir) => {
|
|
21
|
-
Util.rmSync(dir);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const resolveConfigPath = (customConfigPath) => {
|
|
25
|
-
|
|
26
|
-
const configList = [
|
|
27
|
-
'.mcrrc',
|
|
28
|
-
'mcr.config.json',
|
|
29
|
-
'mcr.config.mjs',
|
|
30
|
-
'mcr.config.cjs',
|
|
31
|
-
'mcr.config.js'
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
if (customConfigPath) {
|
|
35
|
-
configList.push(customConfigPath);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const existsList = configList.filter((p) => fs.existsSync(p));
|
|
39
|
-
if (!existsList.length) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// last one
|
|
44
|
-
const configPath = existsList.pop();
|
|
45
|
-
Util.logInfo(`Config: ${EC.cyan(configPath)}`);
|
|
46
|
-
|
|
47
|
-
return configPath;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const resolveConfigOptions = async (configPath) => {
|
|
51
|
-
|
|
52
|
-
// json format
|
|
53
|
-
const ext = path.extname(configPath);
|
|
54
|
-
if (ext === '.json' || configPath.slice(-2) === 'rc') {
|
|
55
|
-
return JSON.parse(Util.readFileSync(configPath));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
let configOptions;
|
|
59
|
-
let err;
|
|
60
|
-
try {
|
|
61
|
-
configOptions = await import(pathToFileURL(configPath));
|
|
62
|
-
} catch (ee) {
|
|
63
|
-
err = ee;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (!configOptions) {
|
|
67
|
-
Util.logError(`ERROR: failed to import "${configPath}" ${err.message} `);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
configOptions = configOptions.default || configOptions;
|
|
72
|
-
|
|
73
|
-
return configOptions;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const initOptions = async (cliOptions) => {
|
|
77
|
-
|
|
78
|
-
const configPath = resolveConfigPath(cliOptions.config);
|
|
79
|
-
if (configPath) {
|
|
80
|
-
const configOptions = await resolveConfigOptions(configPath);
|
|
81
|
-
if (configOptions) {
|
|
82
|
-
cliOptions = {
|
|
83
|
-
... configOptions,
|
|
84
|
-
... cliOptions
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// report options
|
|
90
|
-
const options = {
|
|
91
|
-
... defaultOptions
|
|
92
|
-
};
|
|
93
|
-
Object.keys(cliOptions).forEach((k) => {
|
|
94
|
-
if (Util.hasOwn(options, k)) {
|
|
95
|
-
options[k] = cliOptions[k];
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
return options;
|
|
100
|
-
};
|
|
101
|
-
|
|
102
19
|
const resolveEntrySource = (entry, sourceMapCache = {}) => {
|
|
103
20
|
let source;
|
|
104
21
|
const filePath = fileURLToPath(entry.url);
|
|
@@ -107,7 +24,7 @@ const resolveEntrySource = (entry, sourceMapCache = {}) => {
|
|
|
107
24
|
source = fs.readFileSync(filePath).toString('utf8');
|
|
108
25
|
}
|
|
109
26
|
|
|
110
|
-
// not for typescript
|
|
27
|
+
// not for typescript, but it could be jsx even it is `.js`
|
|
111
28
|
if (source && !['.ts', '.tsx'].includes(extname)) {
|
|
112
29
|
entry.source = source;
|
|
113
30
|
return;
|
|
@@ -118,7 +35,6 @@ const resolveEntrySource = (entry, sourceMapCache = {}) => {
|
|
|
118
35
|
|
|
119
36
|
// for fake source file (can not parse to AST)
|
|
120
37
|
if (lineLengths) {
|
|
121
|
-
// get runtime code with ts-node
|
|
122
38
|
let fakeSource = '';
|
|
123
39
|
sourcemapData.lineLengths.forEach((length) => {
|
|
124
40
|
fakeSource += `${''.padEnd(length, '*')}\n`;
|
|
@@ -142,7 +58,7 @@ const resolveEntrySourceMap = (entry, sourceMapCache = {}) => {
|
|
|
142
58
|
}
|
|
143
59
|
};
|
|
144
60
|
|
|
145
|
-
const collectCoverageData = (coverageList,
|
|
61
|
+
const collectCoverageData = (coverageList, entryFilter, sourceMapCache = {}) => {
|
|
146
62
|
|
|
147
63
|
if (!Util.isList(coverageList)) {
|
|
148
64
|
return;
|
|
@@ -150,7 +66,7 @@ const collectCoverageData = (coverageList, entryFilterHandler, sourceMapCache =
|
|
|
150
66
|
|
|
151
67
|
// filter node internal files
|
|
152
68
|
coverageList = coverageList.filter((entry) => entry.url && entry.url.startsWith('file:'));
|
|
153
|
-
coverageList = coverageList.filter(
|
|
69
|
+
coverageList = coverageList.filter(entryFilter);
|
|
154
70
|
|
|
155
71
|
if (!Util.isList(coverageList)) {
|
|
156
72
|
return;
|
|
@@ -164,57 +80,87 @@ const collectCoverageData = (coverageList, entryFilterHandler, sourceMapCache =
|
|
|
164
80
|
return coverageList;
|
|
165
81
|
};
|
|
166
82
|
|
|
167
|
-
const
|
|
83
|
+
const addCoverageData = async (coverageReport, nodeV8CoverageDir) => {
|
|
168
84
|
|
|
169
|
-
|
|
85
|
+
let added = false;
|
|
170
86
|
|
|
171
|
-
|
|
172
|
-
|
|
87
|
+
const files = fs.readdirSync(nodeV8CoverageDir);
|
|
88
|
+
if (!files.length) {
|
|
89
|
+
return added;
|
|
90
|
+
}
|
|
173
91
|
|
|
174
|
-
|
|
175
|
-
|
|
92
|
+
// filter before adding
|
|
93
|
+
const entryFilter = coverageReport.getEntryFilter();
|
|
94
|
+
for (const filename of files) {
|
|
95
|
+
const filePath = path.resolve(nodeV8CoverageDir, filename);
|
|
96
|
+
const content = fs.readFileSync(filePath).toString('utf-8');
|
|
97
|
+
if (content) {
|
|
98
|
+
const json = JSON.parse(content);
|
|
99
|
+
const coverageList = json.result;
|
|
100
|
+
const sourceMapCache = json['source-map-cache'];
|
|
101
|
+
const coverageData = collectCoverageData(coverageList, entryFilter, sourceMapCache);
|
|
102
|
+
if (coverageData) {
|
|
103
|
+
await coverageReport.add(coverageData);
|
|
104
|
+
added = true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
176
108
|
|
|
177
|
-
|
|
109
|
+
return added;
|
|
110
|
+
};
|
|
178
111
|
|
|
179
|
-
|
|
112
|
+
const executeCommand = async (command, cliOptions) => {
|
|
180
113
|
|
|
181
|
-
|
|
114
|
+
Util.logInfo(`Execute: ${EC.cyan(command)}`);
|
|
115
|
+
|
|
116
|
+
// console.log(options);
|
|
117
|
+
const coverageReport = MCR(cliOptions);
|
|
118
|
+
await coverageReport.loadConfig(cliOptions.config);
|
|
182
119
|
coverageReport.cleanCache();
|
|
183
120
|
|
|
184
|
-
|
|
185
|
-
|
|
121
|
+
const coverageOptions = coverageReport.options;
|
|
122
|
+
|
|
123
|
+
// dir for node v8 coverage
|
|
124
|
+
const nodeV8CoverageDir = Util.relativePath(path.resolve(coverageOptions.outputDir, '.v8-coverage'));
|
|
125
|
+
process.env.NODE_V8_COVERAGE = nodeV8CoverageDir;
|
|
126
|
+
// clean v8 cache before running
|
|
127
|
+
Util.rmSync(nodeV8CoverageDir);
|
|
128
|
+
// Util.logInfo(`V8 coverage dir: ${EC.cyan(nodeV8CoverageDir)}`);
|
|
129
|
+
|
|
130
|
+
// =========================================
|
|
131
|
+
// onStart hook
|
|
132
|
+
const onStart = coverageOptions.onStart;
|
|
186
133
|
if (typeof onStart === 'function') {
|
|
187
134
|
await onStart(coverageReport);
|
|
188
135
|
}
|
|
136
|
+
// =========================================
|
|
189
137
|
|
|
190
|
-
foregroundChild(command, {
|
|
138
|
+
const subprocess = foregroundChild(command, {
|
|
191
139
|
shell: true
|
|
192
|
-
}, async () => {
|
|
140
|
+
}, async (code, signal) => {
|
|
141
|
+
|
|
142
|
+
// generate coverage even it is failed. code != 0
|
|
193
143
|
|
|
194
144
|
if (!fs.existsSync(nodeV8CoverageDir)) {
|
|
195
|
-
EC.logRed(`Not found coverage
|
|
145
|
+
EC.logRed(`Not found V8 coverage dir: ${Util.relativePath(nodeV8CoverageDir)}`);
|
|
196
146
|
return 1;
|
|
197
147
|
}
|
|
198
148
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const coverageList = json.result;
|
|
206
|
-
const sourceMapCache = json['source-map-cache'];
|
|
207
|
-
const coverageData = await collectCoverageData(coverageList, entryFilterHandler, sourceMapCache);
|
|
208
|
-
if (coverageData) {
|
|
209
|
-
await coverageReport.add(coverageData);
|
|
210
|
-
}
|
|
149
|
+
// =========================================
|
|
150
|
+
// onReady hook before adding coverage data.
|
|
151
|
+
// Sometimes, the child process has not yet finished writing the coverage data, and it needs to wait here.
|
|
152
|
+
const onReady = coverageOptions.onReady;
|
|
153
|
+
if (typeof onReady === 'function') {
|
|
154
|
+
await onReady(coverageReport, nodeV8CoverageDir, subprocess);
|
|
211
155
|
}
|
|
156
|
+
// =========================================
|
|
212
157
|
|
|
158
|
+
await addCoverageData(coverageReport, nodeV8CoverageDir);
|
|
213
159
|
await coverageReport.generate();
|
|
214
160
|
|
|
215
161
|
// remove nodeV8CoverageDir
|
|
216
|
-
if (
|
|
217
|
-
|
|
162
|
+
if (!Util.isDebug()) {
|
|
163
|
+
Util.rmSync(nodeV8CoverageDir);
|
|
218
164
|
}
|
|
219
165
|
|
|
220
166
|
return process.exitCode;
|
|
@@ -222,16 +168,23 @@ const executeCommand = async (command, cliOptions) => {
|
|
|
222
168
|
|
|
223
169
|
};
|
|
224
170
|
|
|
171
|
+
process.on('uncaughtException', function(err) {
|
|
172
|
+
Util.logError(`ERROR: ${err.message || err}`);
|
|
173
|
+
});
|
|
174
|
+
|
|
225
175
|
program
|
|
226
176
|
.name('mcr')
|
|
227
177
|
.description('CLI to generate coverage reports')
|
|
228
178
|
.version(version)
|
|
229
179
|
.argument('<command>', 'command to execute')
|
|
230
180
|
.allowUnknownOption()
|
|
231
|
-
.option('-c, --config <path>', 'custom config path')
|
|
232
|
-
.option('
|
|
233
|
-
|
|
181
|
+
.option('-c, --config <path>', 'custom config file path')
|
|
182
|
+
.option('--logging <logging>', 'off, error, info, debug')
|
|
183
|
+
|
|
234
184
|
.option('-n, --name <name>', 'report name for title')
|
|
185
|
+
.option('-r, --reports <name[,name]>', 'coverage reports to use')
|
|
186
|
+
|
|
187
|
+
.option('-o, --outputDir <dir>', 'output dir for reports')
|
|
235
188
|
.option('-i, --inputDir <dir>', 'input dir for merging raw files')
|
|
236
189
|
|
|
237
190
|
.option('--entryFilter <pattern>', 'entry url filter')
|
|
@@ -243,8 +196,6 @@ program
|
|
|
243
196
|
|
|
244
197
|
.option('--lcov', 'generate lcov.info file')
|
|
245
198
|
|
|
246
|
-
.option('--logging <logging>', 'off, error, info, debug')
|
|
247
|
-
|
|
248
199
|
.action((_command, cliOptions) => {
|
|
249
200
|
const command = program.args.join(' ');
|
|
250
201
|
executeCommand(command, cliOptions);
|
package/lib/converter/ast.js
CHANGED
|
@@ -188,7 +188,9 @@ const getJsAstInfo = (item, coverageList) => {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
// runtime code should be parsed successful
|
|
191
|
-
Util.logInfo(`
|
|
191
|
+
Util.logInfo(`Unparsable source: ${item.sourcePath} ${err.message}`);
|
|
192
|
+
|
|
193
|
+
// it could be jsx even it is `.js`
|
|
192
194
|
|
|
193
195
|
// https://github.com/acornjs/acorn/tree/master/acorn-loose
|
|
194
196
|
// It is recommended to always try a parse with the regular acorn parser first,
|
|
@@ -369,7 +369,8 @@ const addJsBytesCoverage = (state, range) => {
|
|
|
369
369
|
// add bytes range
|
|
370
370
|
const byte = {
|
|
371
371
|
start: startOffset,
|
|
372
|
-
end
|
|
372
|
+
// the end could be > source.length
|
|
373
|
+
end: Math.min(endOffset, state.maxContentLength),
|
|
373
374
|
count
|
|
374
375
|
};
|
|
375
376
|
// for debug
|
|
@@ -982,6 +983,7 @@ const initOriginalList = (state, originalDecodedMap, options) => {
|
|
|
982
983
|
}
|
|
983
984
|
|
|
984
985
|
const locator = new Locator(sourceContent);
|
|
986
|
+
const maxContentLength = sourceContent.length;
|
|
985
987
|
|
|
986
988
|
const decodedMappings = getOriginalDecodedMappings(originalDecodedMap, sourceIndex, locator);
|
|
987
989
|
|
|
@@ -997,6 +999,7 @@ const initOriginalList = (state, originalDecodedMap, options) => {
|
|
|
997
999
|
source: sourceContent,
|
|
998
1000
|
sourcePath,
|
|
999
1001
|
locator,
|
|
1002
|
+
maxContentLength,
|
|
1000
1003
|
decodedMappings,
|
|
1001
1004
|
// coverage info
|
|
1002
1005
|
bytes: [],
|
|
@@ -1411,6 +1414,7 @@ const convertV8List = (v8list, options) => {
|
|
|
1411
1414
|
|
|
1412
1415
|
// source mapping
|
|
1413
1416
|
const locator = new Locator(source);
|
|
1417
|
+
const maxContentLength = source.length;
|
|
1414
1418
|
|
|
1415
1419
|
// ============================
|
|
1416
1420
|
// move sourceMap
|
|
@@ -1453,6 +1457,7 @@ const convertV8List = (v8list, options) => {
|
|
|
1453
1457
|
sourcePath,
|
|
1454
1458
|
sourceMap,
|
|
1455
1459
|
locator,
|
|
1460
|
+
maxContentLength,
|
|
1456
1461
|
decodedMappings: [],
|
|
1457
1462
|
// coverage info
|
|
1458
1463
|
bytes: [],
|
package/lib/default/options.js
CHANGED
|
@@ -3,11 +3,8 @@ module.exports = {
|
|
|
3
3
|
// {string} logging levels: off, error, info, debug
|
|
4
4
|
logging: 'info',
|
|
5
5
|
|
|
6
|
-
// {string}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// {string|string[]} input raw dir(s)
|
|
10
|
-
inputDir: null,
|
|
6
|
+
// {string} Report name. Defaults to "Coverage Report".
|
|
7
|
+
name: 'Coverage Report',
|
|
11
8
|
|
|
12
9
|
// {string} v8 or html for istanbul by default
|
|
13
10
|
// {array} multiple reports with options
|
|
@@ -21,17 +18,11 @@ module.exports = {
|
|
|
21
18
|
// ],
|
|
22
19
|
reports: '',
|
|
23
20
|
|
|
24
|
-
// {string}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// (V8 only) {string} Output [sub dir/]filename. Defaults to "index.html"
|
|
28
|
-
outputFile: 'index.html',
|
|
29
|
-
|
|
30
|
-
// (V8 only) {boolean} Inline all scripts to the single HTML file. Defaults to false.
|
|
31
|
-
inline: false,
|
|
21
|
+
// {string} output dir
|
|
22
|
+
outputDir: './coverage-reports',
|
|
32
23
|
|
|
33
|
-
//
|
|
34
|
-
|
|
24
|
+
// {string|string[]} input raw dir(s)
|
|
25
|
+
inputDir: null,
|
|
35
26
|
|
|
36
27
|
// (V8 only) {function} A filter function to execute for each element in the V8 list.
|
|
37
28
|
// entryFilter: (entry) => {
|
|
@@ -46,6 +37,24 @@ module.exports = {
|
|
|
46
37
|
// sourceFilter: (sourcePath) => sourcePath.search(/src\/.+/) !== -1,
|
|
47
38
|
sourceFilter: null,
|
|
48
39
|
|
|
40
|
+
// {function} Source path handler.
|
|
41
|
+
// sourcePath: (filePath) => `wwwroot/${filePath}`,
|
|
42
|
+
sourcePath: null,
|
|
43
|
+
|
|
44
|
+
// (V8 only) {string} Output [sub dir/]filename. Defaults to "index.html"
|
|
45
|
+
outputFile: 'index.html',
|
|
46
|
+
|
|
47
|
+
// (V8 only) {boolean} Inline all scripts to the single HTML file. Defaults to false.
|
|
48
|
+
inline: false,
|
|
49
|
+
|
|
50
|
+
// (V8 only) {string} Assets path if not inline. Defaults to "./assets"
|
|
51
|
+
assetsPath: './assets',
|
|
52
|
+
|
|
53
|
+
// (Istanbul only) defaultSummarizer, sourceFinder
|
|
54
|
+
|
|
55
|
+
// {boolean} Generate lcov.info file, same as lcovonly report. Defaults to false.
|
|
56
|
+
lcov: false,
|
|
57
|
+
|
|
49
58
|
// options for adding empty coverage for all files
|
|
50
59
|
// all: {
|
|
51
60
|
// dir: ['src'],
|
|
@@ -56,15 +65,6 @@ module.exports = {
|
|
|
56
65
|
// (V8 only) {boolean} Enable/Disable ignoring uncovered codes with the special comments: v8 ignore next/next N/start/stop
|
|
57
66
|
v8Ignore: true,
|
|
58
67
|
|
|
59
|
-
// (Istanbul only) defaultSummarizer, sourceFinder
|
|
60
|
-
|
|
61
|
-
// {boolean} Generate lcov.info file, same as lcovonly report. Defaults to false.
|
|
62
|
-
lcov: false,
|
|
63
|
-
|
|
64
|
-
// {function} Source path handler.
|
|
65
|
-
// sourcePath: (filePath) => `wwwroot/${filePath}`,
|
|
66
|
-
sourcePath: null,
|
|
67
|
-
|
|
68
68
|
// {string|function} Specify the report path, especially when there are multiple reports. Defaults to outputDir/index.html.
|
|
69
69
|
reportPath: null,
|
|
70
70
|
|
|
@@ -78,6 +78,10 @@ module.exports = {
|
|
|
78
78
|
// {boolean} Indicates whether to clean previous cache in output dir before generating report. Defaults to false.
|
|
79
79
|
cleanCache: false,
|
|
80
80
|
|
|
81
|
+
// {function} onEntry hook
|
|
82
|
+
// onEntry: async (entry) => {}
|
|
83
|
+
onEntry: null,
|
|
84
|
+
|
|
81
85
|
// {function} onEnd hook
|
|
82
86
|
// onEnd: async (reportData) => {}
|
|
83
87
|
onEnd: null
|
package/lib/generate.js
CHANGED
|
@@ -21,20 +21,16 @@ const { getGroupedRows } = require('./utils/snapshot.js');
|
|
|
21
21
|
// maybe v8 or to istanbul reports
|
|
22
22
|
const generateV8ListReports = async (v8list, coverageData, fileSources, options) => {
|
|
23
23
|
|
|
24
|
-
let
|
|
24
|
+
let istanbulReportPath;
|
|
25
25
|
// v8 to istanbul reports
|
|
26
26
|
if (options.reportGroup.istanbul) {
|
|
27
|
-
istanbulCoverageResults = await saveIstanbulReports(coverageData, fileSources, options);
|
|
27
|
+
const istanbulCoverageResults = await saveIstanbulReports(coverageData, fileSources, options);
|
|
28
|
+
istanbulReportPath = istanbulCoverageResults.reportPath;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
// v8 reports and v8 coverage results
|
|
31
32
|
// could be no v8 or v8-json, but requires v8 coverage results
|
|
32
|
-
const v8CoverageResults = await saveV8Report(v8list, options);
|
|
33
|
-
|
|
34
|
-
// fix reportPath
|
|
35
|
-
if (!v8CoverageResults.reportPath && istanbulCoverageResults) {
|
|
36
|
-
v8CoverageResults.reportPath = istanbulCoverageResults.reportPath;
|
|
37
|
-
}
|
|
33
|
+
const v8CoverageResults = await saveV8Report(v8list, options, istanbulReportPath);
|
|
38
34
|
|
|
39
35
|
return v8CoverageResults;
|
|
40
36
|
};
|
|
@@ -292,12 +288,15 @@ const handleConsoleDetailsReport = (reportData, reportOptions, options) => {
|
|
|
292
288
|
} = reportData;
|
|
293
289
|
|
|
294
290
|
if (name) {
|
|
295
|
-
EC.
|
|
291
|
+
Util.logInfo(EC.cyan(name));
|
|
296
292
|
}
|
|
297
293
|
|
|
298
294
|
const metrics = Util.getMetrics(cdOptions.metrics, type);
|
|
299
295
|
const rows = getDetailsRows(files, metrics, cdOptions);
|
|
300
296
|
const summaryRow = getRowData('Summary', summary, metrics);
|
|
297
|
+
if (summaryRow.nameStatus) {
|
|
298
|
+
summaryRow.name = Util.getColorStrByStatus(summaryRow.name, summaryRow.nameStatus);
|
|
299
|
+
}
|
|
301
300
|
// no rows if skipped all by skipPercent
|
|
302
301
|
if (rows.length) {
|
|
303
302
|
rows.push({
|
|
@@ -343,7 +342,7 @@ const handleConsoleSummaryReport = (reportData, reportOptions, options) => {
|
|
|
343
342
|
} = reportData;
|
|
344
343
|
|
|
345
344
|
if (name) {
|
|
346
|
-
EC.
|
|
345
|
+
Util.logInfo(EC.cyan(name));
|
|
347
346
|
}
|
|
348
347
|
|
|
349
348
|
const metrics = Util.getMetrics(csOptions.metrics, type);
|