monocart-coverage-reports 2.7.6 → 2.7.7
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 +113 -71
- package/lib/cli.js +4 -17
- package/lib/client/coverage-client.js +61 -19
- package/lib/index.d.ts +12 -7
- package/lib/utils/util.js +12 -0
- package/package.json +6 -7
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* [Collecting V8 Coverage Data](#collecting-v8-coverage-data)
|
|
17
17
|
- [Collecting V8 Coverage Data with Playwright](#collecting-v8-coverage-data-with-playwright)
|
|
18
18
|
- [Collecting Raw V8 Coverage Data with Puppeteer](#collecting-raw-v8-coverage-data-with-puppeteer)
|
|
19
|
-
- [
|
|
19
|
+
- [Collecting V8 Coverage Data from Node.js](#collecting-v8-coverage-data-from-nodejs)
|
|
20
20
|
- [Collecting V8 Coverage Data with `CDPClient` API](#collecting-v8-coverage-data-with-cdpclient-api)
|
|
21
21
|
- [V8 Coverage Data API](#v8-coverage-data-api)
|
|
22
22
|
* [Using `entryFilter` and `sourceFilter` to filter the results for V8 report](#using-entryfilter-and-sourcefilter-to-filter-the-results-for-v8-report)
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
- [WebdriverIO](#webdriverio)
|
|
43
43
|
- [Storybook Test Runner](#storybook-test-runner)
|
|
44
44
|
- [TestCafe](#testcafe)
|
|
45
|
+
- [Selenium Webdriver](#selenium-webdriver)
|
|
45
46
|
- [Mocha](#mocha)
|
|
46
47
|
- [tsx](#tsx)
|
|
47
48
|
- [ts-node](#ts-node)
|
|
@@ -53,30 +54,31 @@
|
|
|
53
54
|
|
|
54
55
|
## Usage
|
|
55
56
|
> It's recommended to use [Node.js 20+](https://nodejs.org/).
|
|
56
|
-
-
|
|
57
|
+
- API
|
|
57
58
|
```js
|
|
58
59
|
const MCR = require('monocart-coverage-reports');
|
|
59
|
-
const
|
|
60
|
+
const mcr = MCR({
|
|
60
61
|
name: 'My Coverage Report - 2024-02-28',
|
|
61
62
|
outputDir: './coverage-reports',
|
|
62
|
-
reports: ["v8", "console-details"]
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
mcr.
|
|
66
|
-
|
|
67
|
-
await mcr.add(coverageData1);
|
|
68
|
-
await mcr.add(coverageData2);
|
|
69
|
-
|
|
63
|
+
reports: ["v8", "console-details"],
|
|
64
|
+
cleanCache: true
|
|
65
|
+
});
|
|
66
|
+
await mcr.add(coverageData);
|
|
70
67
|
await mcr.generate();
|
|
71
|
-
|
|
72
|
-
// Or
|
|
73
|
-
// const { CoverageReport } = require('monocart-coverage-reports');
|
|
74
|
-
// const mcr = new CoverageReport(coverageOptions);
|
|
75
68
|
```
|
|
76
|
-
|
|
69
|
+
Using `import` and load options from [config file](#config-file)
|
|
70
|
+
```js
|
|
71
|
+
import { CoverageReport } from 'monocart-coverage-reports';
|
|
72
|
+
const mcr = new CoverageReport();
|
|
73
|
+
await mcr.loadConfig();
|
|
74
|
+
```
|
|
75
|
+
For more information, see [Multiprocessing Support](#multiprocessing-support)
|
|
76
|
+
|
|
77
|
+
- CLI
|
|
77
78
|
```sh
|
|
78
79
|
mcr node my-app.js -r v8,console-details
|
|
79
80
|
```
|
|
81
|
+
For more information, see [Command Line](#command-line)
|
|
80
82
|
|
|
81
83
|
## Options
|
|
82
84
|
- Default Options: [lib/default/options.js](./lib/default/options.js)
|
|
@@ -109,7 +111,7 @@ mcr node my-app.js -r v8,console-details
|
|
|
109
111
|
- `v8-json`
|
|
110
112
|
- [V8 coverage-report.json](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)
|
|
111
113
|
|
|
112
|
-
> Istanbul build-in reports (both V8 and
|
|
114
|
+
> Istanbul build-in reports (both V8 and Istanbul data):
|
|
113
115
|
|
|
114
116
|
- `clover`
|
|
115
117
|
- `cobertura`
|
|
@@ -129,7 +131,7 @@ mcr node my-app.js -r v8,console-details
|
|
|
129
131
|
- `text-lcov`
|
|
130
132
|
- `text-summary`
|
|
131
133
|
|
|
132
|
-
> Other build-in reports (both V8 and
|
|
134
|
+
> Other build-in reports (both V8 and Istanbul data):
|
|
133
135
|
|
|
134
136
|
- `codecov`
|
|
135
137
|
- coverage data for [Codecov](https://docs.codecov.com/docs/codecov-custom-coverage-format), see [example](https://app.codecov.io/github/cenfun/monocart-coverage-reports)
|
|
@@ -163,9 +165,9 @@ mcr node my-app.js -r v8,console-details
|
|
|
163
165
|
]
|
|
164
166
|
}
|
|
165
167
|
```
|
|
166
|
-
-
|
|
168
|
+
- Istanbul custom reporter
|
|
167
169
|
> example: [./test/custom-istanbul-reporter.js](./test/custom-istanbul-reporter.js), see [istanbul built-in reporters' implementation](https://github.com/istanbuljs/istanbuljs/tree/master/packages/istanbul-reports/lib) for reference.
|
|
168
|
-
-
|
|
170
|
+
- V8 custom reporter
|
|
169
171
|
> example: [./test/custom-v8-reporter.js](./test/custom-v8-reporter.js)
|
|
170
172
|
|
|
171
173
|
### Multiple Reports:
|
|
@@ -194,11 +196,9 @@ const coverageOptions = {
|
|
|
194
196
|
}],
|
|
195
197
|
// Specify reporter name with local path
|
|
196
198
|
['/absolute/path/to/custom-reporter.js']
|
|
197
|
-
|
|
198
199
|
]
|
|
199
200
|
}
|
|
200
201
|
const mcr = MCR(coverageOptions);
|
|
201
|
-
mcr.cleanCache();
|
|
202
202
|
```
|
|
203
203
|
|
|
204
204
|
## Compare Reports
|
|
@@ -216,19 +216,20 @@ mcr.cleanCache();
|
|
|
216
216
|
| Minified code | ❌ | ✅ | ❌ |
|
|
217
217
|
|
|
218
218
|
## Collecting Istanbul Coverage Data
|
|
219
|
-
- Instrumenting source code
|
|
220
|
-
|
|
221
|
-
-
|
|
222
|
-
- rollup: [rollup-plugin-istanbul](https://github.com/artberri/rollup-plugin-istanbul)
|
|
219
|
+
- Before coverage collection: Instrumenting source code with Istanbul
|
|
220
|
+
- webpack with babel loader: [babel-plugin-istanbul](https://github.com/istanbuljs/babel-plugin-istanbul), see example: [webpack.config-istanbul.js](./test/build/webpack.config-istanbul.js)
|
|
221
|
+
- CLI: [nyc instrument](https://github.com/istanbuljs/nyc/blob/master/docs/instrument.md) or API: [istanbul-lib-instrument](https://github.com/istanbuljs/istanbuljs/blob/main/packages/istanbul-lib-instrument/api.md)
|
|
223
222
|
- vite: [vite-plugin-istanbul](https://github.com/ifaxity/vite-plugin-istanbul)
|
|
223
|
+
- rollup: [rollup-plugin-istanbul](https://github.com/artberri/rollup-plugin-istanbul)
|
|
224
|
+
- swc: [swc-plugin-coverage-instrument](https://github.com/kwonoj/swc-plugin-coverage-instrument)
|
|
224
225
|
- Browser
|
|
225
226
|
- Collecting coverage data from `window.__coverage__`, example: [test-istanbul.js](./test/test-istanbul.js)
|
|
226
227
|
- Node.js
|
|
227
228
|
- Collecting coverage data from `global.__coverage__`
|
|
228
229
|
|
|
229
230
|
## Collecting V8 Coverage Data
|
|
230
|
-
-
|
|
231
|
-
- [webpack](https://webpack.js.org/configuration/): `devtool: source-map` and `mode: development`, example [webpack.config-v8.js](./test/webpack.config-v8.js)
|
|
231
|
+
- Before coverage collection: Enabling `sourcemap` for source code
|
|
232
|
+
- [webpack](https://webpack.js.org/configuration/): `devtool: source-map` and `mode: development`, example [webpack.config-v8.js](./test/build/webpack.config-v8.js)
|
|
232
233
|
- [rollup](https://rollupjs.org/configuration-options/): `sourcemap: true`
|
|
233
234
|
- [vite](https://vitejs.dev/config/build-options.html): `sourcemap: true` and `minify: false`
|
|
234
235
|
- [esbuild](https://esbuild.github.io/api/): `sourcemap: true` and `minify: false`
|
|
@@ -238,7 +239,7 @@ mcr.cleanCache();
|
|
|
238
239
|
- [Collecting Raw V8 Coverage Data with Puppeteer](#collecting-raw-v8-coverage-data-with-puppeteer)
|
|
239
240
|
|
|
240
241
|
- Node.js
|
|
241
|
-
- [
|
|
242
|
+
- [Collecting V8 Coverage Data from Node.js](#collecting-v8-coverage-data-from-nodejs)
|
|
242
243
|
|
|
243
244
|
- CDP
|
|
244
245
|
- [Collecting V8 Coverage Data with `CDPClient` API](#collecting-v8-coverage-data-with-cdpclient-api)
|
|
@@ -264,7 +265,7 @@ const [jsCoverage, cssCoverage] = await Promise.all([
|
|
|
264
265
|
const coverageData = [... jsCoverage, ... cssCoverage];
|
|
265
266
|
|
|
266
267
|
```
|
|
267
|
-
see [./test/test-v8.js](./test/test-v8.js), and [anonymous](./test/test-anonymous.js), [css](./test/test-css.js)
|
|
268
|
+
For more examples, see [./test/test-v8.js](./test/test-v8.js), and [anonymous](./test/test-anonymous.js), [css](./test/test-css.js)
|
|
268
269
|
|
|
269
270
|
### Collecting Raw V8 Coverage Data with Puppeteer
|
|
270
271
|
```js
|
|
@@ -294,9 +295,9 @@ const coverageData = [... jsCoverage.map((it) => {
|
|
|
294
295
|
};
|
|
295
296
|
}), ... cssCoverage];
|
|
296
297
|
```
|
|
297
|
-
|
|
298
|
+
Example: [./test/test-puppeteer.js](./test/test-puppeteer.js)
|
|
298
299
|
|
|
299
|
-
###
|
|
300
|
+
### Collecting V8 Coverage Data from Node.js
|
|
300
301
|
Possible solutions:
|
|
301
302
|
- [NODE_V8_COVERAGE](https://nodejs.org/docs/latest/api/cli.html#node_v8_coveragedir)=`dir`
|
|
302
303
|
- Sets Node.js env `NODE_V8_COVERAGE`=`dir` before the program running, the coverage data will be saved to the `dir` after the program exits gracefully.
|
|
@@ -330,7 +331,7 @@ Possible solutions:
|
|
|
330
331
|
- see [Command Line](#command-line)
|
|
331
332
|
|
|
332
333
|
### Collecting V8 Coverage Data with `CDPClient` API
|
|
333
|
-
- Work with node debugger `--inspect=9229`
|
|
334
|
+
- Work with node debugger port `--inspect=9229`
|
|
334
335
|
```js
|
|
335
336
|
const MCR = require('monocart-coverage-reports');
|
|
336
337
|
const client = await MCR.CDPClient({
|
|
@@ -372,12 +373,46 @@ await client.startCoverage();
|
|
|
372
373
|
await page.goto("your page url");
|
|
373
374
|
const coverageData = await client.stopCoverage();
|
|
374
375
|
```
|
|
376
|
+
- Work with [Selenium Webdriver](https://www.selenium.dev/documentation/webdriver/) WebSocket (Chrome/Edge Browser)
|
|
377
|
+
```js
|
|
378
|
+
const { Builder, Browser } = require('selenium-webdriver');
|
|
379
|
+
const MCR = require('monocart-coverage-reports');
|
|
380
|
+
const driver = await new Builder().forBrowser(Browser.CHROME).build();
|
|
381
|
+
const pageCdpConnection = await driver.createCDPConnection('page');
|
|
382
|
+
const session = new MCR.WSSession(pageCdpConnection._wsConnection);
|
|
383
|
+
const client = await MCR.CDPClient({
|
|
384
|
+
session
|
|
385
|
+
})
|
|
386
|
+
```
|
|
387
|
+
- `CDPClient` available APIs
|
|
388
|
+
```js
|
|
389
|
+
/** start js coverage */
|
|
390
|
+
startJSCoverage: () => Promise<void>;
|
|
391
|
+
/** stop and return js coverage */
|
|
392
|
+
stopJSCoverage: () => Promise<V8CoverageEntry[]>;
|
|
393
|
+
|
|
394
|
+
/** start css coverage */
|
|
395
|
+
startCSSCoverage: () => Promise<void>;
|
|
396
|
+
/** stop and return css coverage */
|
|
397
|
+
stopCSSCoverage: () => Promise<V8CoverageEntry[]>;
|
|
398
|
+
|
|
399
|
+
/** start both js and css coverage */
|
|
400
|
+
startCoverage: () => Promise<void>;
|
|
401
|
+
/** stop and return both js and css coverage */
|
|
402
|
+
stopCoverage: () => Promise<V8CoverageEntry[]>;
|
|
403
|
+
|
|
404
|
+
/** write the coverage started by NODE_V8_COVERAGE to disk on demand, returns v8 coverage dir */
|
|
405
|
+
writeCoverage: () => Promise<string>;
|
|
406
|
+
|
|
407
|
+
/** get istanbul coverage data */
|
|
408
|
+
getIstanbulCoverage: (coverageKey?: string) => Promise<any>;
|
|
409
|
+
```
|
|
375
410
|
|
|
376
411
|
### V8 Coverage Data API
|
|
377
|
-
- [
|
|
412
|
+
- [JavaScript code coverage in V8](https://v8.dev/blog/javascript-code-coverage)
|
|
378
413
|
- [Playwright Coverage Class](https://playwright.dev/docs/api/class-coverage)
|
|
379
|
-
- [Puppeteer Coverage
|
|
380
|
-
- [DevTools Protocol for Coverage](https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#method-startPreciseCoverage) see
|
|
414
|
+
- [Puppeteer Coverage Class](https://pptr.dev/api/puppeteer.coverage)
|
|
415
|
+
- [DevTools Protocol for Coverage](https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#method-startPreciseCoverage) see [ScriptCoverage](https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#type-ScriptCoverage) and [v8-coverage](https://github.com/bcoe/v8-coverage)
|
|
381
416
|
```js
|
|
382
417
|
// Coverage data for a source range.
|
|
383
418
|
export interface CoverageRange {
|
|
@@ -388,7 +423,6 @@ export interface CoverageRange {
|
|
|
388
423
|
// Collected execution count of the source range.
|
|
389
424
|
count: integer;
|
|
390
425
|
}
|
|
391
|
-
|
|
392
426
|
// Coverage data for a JavaScript function.
|
|
393
427
|
/**
|
|
394
428
|
* @functionName can be an empty string.
|
|
@@ -405,7 +439,6 @@ export interface FunctionCoverage {
|
|
|
405
439
|
// Whether coverage data for this function has block granularity.
|
|
406
440
|
isBlockCoverage: boolean;
|
|
407
441
|
}
|
|
408
|
-
|
|
409
442
|
// Coverage data for a JavaScript script.
|
|
410
443
|
export interface ScriptCoverage {
|
|
411
444
|
// JavaScript script id.
|
|
@@ -415,32 +448,31 @@ export interface ScriptCoverage {
|
|
|
415
448
|
// Functions contained in the script that has coverage data.
|
|
416
449
|
functions: FunctionCoverage[];
|
|
417
450
|
}
|
|
418
|
-
|
|
419
451
|
export type V8CoverageData = ScriptCoverage[];
|
|
420
452
|
```
|
|
421
453
|
|
|
422
454
|
## Using `entryFilter` and `sourceFilter` to filter the results for V8 report
|
|
423
455
|
When V8 coverage data collected, it actually contains the data of all entry files, for example:
|
|
424
|
-
|
|
425
|
-
dist/main.js
|
|
426
|
-
dist/vendor.js
|
|
427
|
-
dist/something-else.js
|
|
428
|
-
|
|
456
|
+
|
|
457
|
+
- *dist/main.js*
|
|
458
|
+
- *dist/vendor.js*
|
|
459
|
+
- *dist/something-else.js*
|
|
460
|
+
|
|
429
461
|
We can use `entryFilter` to filter the entry files. For example, we should remove `vendor.js` and `something-else.js` if they are not in our coverage scope.
|
|
430
|
-
|
|
431
|
-
dist/main.js
|
|
432
|
-
|
|
462
|
+
|
|
463
|
+
- *dist/main.js*
|
|
464
|
+
|
|
433
465
|
When inline or linked sourcemap exists to the entry file, the source files will be extracted from the sourcemap for the entry file, and the entry file will be removed if `logging` is not `debug`.
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
466
|
+
|
|
467
|
+
- *src/index.js*
|
|
468
|
+
- *src/components/app.js*
|
|
469
|
+
- *node_modules/dependency/dist/dependency.js*
|
|
470
|
+
|
|
439
471
|
We can use `sourceFilter` to filter the source files. For example, we should remove `dependency.js` if it is not in our coverage scope.
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
472
|
+
|
|
473
|
+
- *src/index.js*
|
|
474
|
+
- *src/components/app.js*
|
|
475
|
+
|
|
444
476
|
For example:
|
|
445
477
|
```js
|
|
446
478
|
const coverageOptions = {
|
|
@@ -600,7 +632,6 @@ mcr.cleanCache();
|
|
|
600
632
|
const MCR = require('monocart-coverage-reports');
|
|
601
633
|
const coverageOptions = require('path-to/same-options.js');
|
|
602
634
|
const mcr = MCR(coverageOptions);
|
|
603
|
-
// do not clean cache in the stage
|
|
604
635
|
await mcr.add(coverageData1);
|
|
605
636
|
```
|
|
606
637
|
|
|
@@ -609,7 +640,6 @@ await mcr.add(coverageData1);
|
|
|
609
640
|
const MCR = require('monocart-coverage-reports');
|
|
610
641
|
const coverageOptions = require('path-to/same-options.js');
|
|
611
642
|
const mcr = MCR(coverageOptions);
|
|
612
|
-
// do not clean cache in the stage
|
|
613
643
|
await mcr.add(coverageData2);
|
|
614
644
|
```
|
|
615
645
|
|
|
@@ -619,7 +649,6 @@ await mcr.add(coverageData2);
|
|
|
619
649
|
const MCR = require('monocart-coverage-reports');
|
|
620
650
|
const coverageOptions = require('path-to/same-options.js');
|
|
621
651
|
const mcr = MCR(coverageOptions);
|
|
622
|
-
// do not clean cache before generating reports
|
|
623
652
|
await mcr.generate();
|
|
624
653
|
```
|
|
625
654
|
|
|
@@ -629,13 +658,13 @@ await mcr.generate();
|
|
|
629
658
|
- Installing globally
|
|
630
659
|
```sh
|
|
631
660
|
npm i monocart-coverage-reports -g
|
|
632
|
-
mcr node ./test/specs/node.test.js -r v8,console-
|
|
661
|
+
mcr node ./test/specs/node.test.js -r v8,console-details --lcov
|
|
633
662
|
```
|
|
634
663
|
|
|
635
664
|
- Locally in your project
|
|
636
665
|
```sh
|
|
637
666
|
npm i monocart-coverage-reports
|
|
638
|
-
npx mcr node ./test/specs/node.test.js -r v8,console-
|
|
667
|
+
npx mcr node ./test/specs/node.test.js -r v8,console-details --lcov
|
|
639
668
|
```
|
|
640
669
|
|
|
641
670
|
- CLI Options
|
|
@@ -692,6 +721,7 @@ The following usage scenarios may require merging coverage reports:
|
|
|
692
721
|
|
|
693
722
|
If the reports cannot be merged automatically, then here is how to manually merge the reports.
|
|
694
723
|
First, using the `raw` report to export the original coverage data to the specified directory.
|
|
724
|
+
For example, we have `raw` coverage data from unit tests:
|
|
695
725
|
```js
|
|
696
726
|
const coverageOptions = {
|
|
697
727
|
name: 'My Unit Test Coverage Report',
|
|
@@ -699,15 +729,18 @@ const coverageOptions = {
|
|
|
699
729
|
reports: [
|
|
700
730
|
['raw', {
|
|
701
731
|
// relative path will be "./coverage-reports/unit/raw"
|
|
732
|
+
// defaults to raw
|
|
702
733
|
outputDir: "raw"
|
|
703
734
|
}],
|
|
704
735
|
['v8'],
|
|
705
|
-
['console-
|
|
736
|
+
['console-details']
|
|
706
737
|
]
|
|
707
738
|
};
|
|
708
739
|
```
|
|
709
|
-
|
|
740
|
+
We also have `raw` coverage data from e2e tests, which is output to `./coverage-reports/e2e/raw`.
|
|
741
|
+
After all the tests are completed, generate a merged report with option `inputDir`:
|
|
710
742
|
```js
|
|
743
|
+
// merge-coverage.js
|
|
711
744
|
const fs = require('fs');
|
|
712
745
|
const { CoverageReport } = require('monocart-coverage-reports');
|
|
713
746
|
const inputDir = [
|
|
@@ -731,6 +764,10 @@ const coverageOptions = {
|
|
|
731
764
|
|
|
732
765
|
sourcePath: (filePath, info) => {
|
|
733
766
|
// Unify the file path for the same files
|
|
767
|
+
// For example, the file index.js has different paths:
|
|
768
|
+
// unit: unit-dist/src/index.js
|
|
769
|
+
// e2e: e2e-dist/src/index.js
|
|
770
|
+
// return filePath.replace("unit-dist/", "").replace("e2e-dist/", "")
|
|
734
771
|
return filePath;
|
|
735
772
|
},
|
|
736
773
|
|
|
@@ -741,12 +778,12 @@ const coverageOptions = {
|
|
|
741
778
|
|
|
742
779
|
onEnd: () => {
|
|
743
780
|
// remove the raw files if it useless
|
|
744
|
-
inputDir.forEach((p) => {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
});
|
|
781
|
+
// inputDir.forEach((p) => {
|
|
782
|
+
// fs.rmSync(p, {
|
|
783
|
+
// recursive: true,
|
|
784
|
+
// force: true
|
|
785
|
+
// });
|
|
786
|
+
// });
|
|
750
787
|
}
|
|
751
788
|
};
|
|
752
789
|
await new CoverageReport(coverageOptions).generate();
|
|
@@ -763,7 +800,7 @@ const a = tf ? 'true' : 'false';
|
|
|
763
800
|
`m1` and `m2` are two consecutive mappings, `p` is the position we looking for. However, we can only get the position of the `m1` or `m2` if we don't fix it to `p`. Especially the generated code is different from the original code, such as the code was minified, compressed or converted, it is difficult to find the exact position. You can try [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap)
|
|
764
801
|
|
|
765
802
|
How `MCR` Works:
|
|
766
|
-
- 1, Trying to fix the middle position
|
|
803
|
+
- 1, Trying to fix the middle original position with string comparison and [`diff-sequences`](https://github.com/jestjs/jest/tree/main/packages/diff-sequences). However, for non-JS code, such as Vue template, JSX, etc., it might be hard to find a perfect solution.
|
|
767
804
|
- 2, Finding all functions, statements and branches by parsing the source code [AST](https://github.com/acornjs/acorn). However, there's a small issue, which is the V8 cannot provide effective branch coverage information for `AssignmentPattern`.
|
|
768
805
|
|
|
769
806
|
|
|
@@ -795,7 +832,7 @@ const coverageOptions = {
|
|
|
795
832
|
logging: 'debug',
|
|
796
833
|
reports: [
|
|
797
834
|
['v8'],
|
|
798
|
-
['console-
|
|
835
|
+
['console-details']
|
|
799
836
|
]
|
|
800
837
|
};
|
|
801
838
|
```
|
|
@@ -818,6 +855,7 @@ When `logging` is `debug`, the raw report data will be preserved in `[outputDir]
|
|
|
818
855
|
## Integration Examples
|
|
819
856
|
|
|
820
857
|
### [Playwright](https://github.com/microsoft/playwright)
|
|
858
|
+
- [playwright-coverage](https://github.com/cenfun/playwright-coverage) - A Example for Playwright Coverage Reports
|
|
821
859
|
- [monocart-reporter](https://github.com/cenfun/monocart-reporter) - A Playwright custom reporter, supports generating [Code Coverage Report](https://github.com/cenfun/monocart-reporter?#code-coverage-report)
|
|
822
860
|
- Coverage for component testing:
|
|
823
861
|
- [playwright-ct-vue](https://github.com/cenfun/playwright-ct-vue)
|
|
@@ -829,6 +867,7 @@ When `logging` is `debug`, the raw report data will be preserved in `[outputDir]
|
|
|
829
867
|
|
|
830
868
|
### [Jest](https://github.com/jestjs/jest/)
|
|
831
869
|
- [jest-monocart-coverage](https://github.com/cenfun/jest-monocart-coverage) - A Jest custom reporter for coverage reports
|
|
870
|
+
- [jest-puppeteer-coverage](https://github.com/cenfun/jest-puppeteer-coverage) - A Jest Puppeteer Coverage Example
|
|
832
871
|
- Example for Jest (unit) + Puppeteer (e2e) + Codecov: [maplibre-gl-js](https://github.com/maplibre/maplibre-gl-js)
|
|
833
872
|
|
|
834
873
|
### [Vitest](https://github.com/vitest-dev/vitest)
|
|
@@ -850,6 +889,9 @@ When `logging` is `debug`, the raw report data will be preserved in `[outputDir]
|
|
|
850
889
|
### [TestCafe](https://github.com/DevExpress/testcafe)
|
|
851
890
|
- [testcafe-reporter-coverage](https://github.com/cenfun/testcafe-reporter-coverage) - A TestCafe custom reporter for coverage reports
|
|
852
891
|
|
|
892
|
+
### [Selenium Webdriver](https://github.com/seleniumhq/selenium)
|
|
893
|
+
- [selenium-webdriver-coverage](https://github.com/cenfun/selenium-webdriver-coverage) - Selenium Webdriver V8 Coverage Example
|
|
894
|
+
|
|
853
895
|
### [Mocha](https://github.com/mochajs/mocha)
|
|
854
896
|
```sh
|
|
855
897
|
mcr mocha ./test/**/*.js
|
package/lib/cli.js
CHANGED
|
@@ -21,25 +21,12 @@ const getRegisterPath = (filename) => {
|
|
|
21
21
|
return `./${rel}`;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
const isFeatureSupported = (nv) => {
|
|
25
|
-
// module register added in Node.js: v20.6.0
|
|
26
|
-
const [major, minor] = nv.split('.').map((s) => parseInt(s));
|
|
27
|
-
if (major < 20) {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
if (major > 20) {
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
if (minor < 6) {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
return true;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
24
|
const initNodeOptions = async (cliOptions) => {
|
|
25
|
+
|
|
26
|
+
// module register added in Node.js: v20.6.0
|
|
40
27
|
const nv = process.versions.node;
|
|
41
|
-
if (
|
|
42
|
-
Util.logInfo(
|
|
28
|
+
if (Util.cmpVersion(nv, '20.6.0') < 0) {
|
|
29
|
+
Util.logInfo(`The current Node.js version "${nv}" does NOT support "module.register", it requires "20.6.0" or higher.`);
|
|
43
30
|
return;
|
|
44
31
|
}
|
|
45
32
|
|
|
@@ -131,19 +131,22 @@ class CoverageClient {
|
|
|
131
131
|
unbindEvents(this.session, this.jsEvents);
|
|
132
132
|
this.jsEvents = null;
|
|
133
133
|
|
|
134
|
-
const jsCoverage =
|
|
135
|
-
// console.log('coverageList', coverageList);
|
|
134
|
+
const jsCoverage = [];
|
|
136
135
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
136
|
+
// console.log('coverageList', coverageList);
|
|
137
|
+
if (profileResponse && profileResponse.result) {
|
|
138
|
+
profileResponse.result.forEach((entry) => {
|
|
139
|
+
// anonymous url
|
|
140
|
+
entry.url = entry.url || '';
|
|
141
|
+
// add source
|
|
142
|
+
const source = this.scriptSources.get(entry.scriptId);
|
|
143
|
+
if (!source) {
|
|
144
|
+
Util.logDebug(`Not found js source: ${entry.url}`);
|
|
145
|
+
}
|
|
146
|
+
entry.source = source || '';
|
|
147
|
+
jsCoverage.push(entry);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
147
150
|
|
|
148
151
|
this.scriptSources.clear();
|
|
149
152
|
this.enabledJS = false;
|
|
@@ -239,22 +242,39 @@ class CoverageClient {
|
|
|
239
242
|
}
|
|
240
243
|
|
|
241
244
|
async stopCoverage() {
|
|
245
|
+
if (!this.session) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
242
248
|
const [jsCoverage, cssCoverage] = await Promise.all([
|
|
243
249
|
this.stopJSCoverage(),
|
|
244
250
|
this.stopCSSCoverage()
|
|
245
251
|
]);
|
|
246
|
-
|
|
252
|
+
// could be undefined
|
|
253
|
+
let coverageList = [];
|
|
254
|
+
if (jsCoverage) {
|
|
255
|
+
coverageList = coverageList.concat(jsCoverage);
|
|
256
|
+
}
|
|
257
|
+
if (cssCoverage) {
|
|
258
|
+
coverageList = coverageList.concat(cssCoverage);
|
|
259
|
+
}
|
|
260
|
+
return coverageList;
|
|
247
261
|
}
|
|
248
262
|
|
|
249
263
|
// =================================================================================================
|
|
250
264
|
// write the coverage started by NODE_V8_COVERAGE to disk on demand
|
|
251
265
|
async writeCoverage() {
|
|
252
|
-
|
|
266
|
+
if (!this.session) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
253
270
|
await this.session.send('Runtime.enable');
|
|
254
271
|
|
|
255
|
-
//
|
|
272
|
+
// write the coverage started by NODE_V8_COVERAGE to disk on demand
|
|
256
273
|
const res = await this.session.send('Runtime.evaluate', {
|
|
257
|
-
expression:
|
|
274
|
+
expression: `new Promise((resolve) => {
|
|
275
|
+
require("v8").takeCoverage();
|
|
276
|
+
resolve(process.env.NODE_V8_COVERAGE);
|
|
277
|
+
})`,
|
|
258
278
|
includeCommandLineAPI: true,
|
|
259
279
|
returnByValue: true,
|
|
260
280
|
awaitPromise: true
|
|
@@ -262,7 +282,31 @@ class CoverageClient {
|
|
|
262
282
|
|
|
263
283
|
await this.session.send('Runtime.disable');
|
|
264
284
|
|
|
265
|
-
return res.result.value;
|
|
285
|
+
return res && res.result && res.result.value;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// get istanbul coverage data
|
|
289
|
+
async getIstanbulCoverage(coverageKey = '__coverage__') {
|
|
290
|
+
if (!this.session) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
await this.session.send('Runtime.enable');
|
|
295
|
+
|
|
296
|
+
// both browser and Node.js
|
|
297
|
+
const res = await this.session.send('Runtime.evaluate', {
|
|
298
|
+
expression: `new Promise((resolve) => {
|
|
299
|
+
const globalTarget = typeof window !== 'undefined' ? window : global;
|
|
300
|
+
resolve(globalTarget['${coverageKey}']);
|
|
301
|
+
})`,
|
|
302
|
+
includeCommandLineAPI: true,
|
|
303
|
+
returnByValue: true,
|
|
304
|
+
awaitPromise: true
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
await this.session.send('Runtime.disable');
|
|
308
|
+
|
|
309
|
+
return res && res.result && res.result.value;
|
|
266
310
|
}
|
|
267
311
|
|
|
268
312
|
// =================================================================================================
|
|
@@ -270,10 +314,8 @@ class CoverageClient {
|
|
|
270
314
|
if (!this.session) {
|
|
271
315
|
return;
|
|
272
316
|
}
|
|
273
|
-
|
|
274
317
|
await this.session.detach();
|
|
275
318
|
this.session = null;
|
|
276
|
-
|
|
277
319
|
}
|
|
278
320
|
}
|
|
279
321
|
|
package/lib/index.d.ts
CHANGED
|
@@ -119,7 +119,7 @@ declare namespace MCR {
|
|
|
119
119
|
outputDir?: string;
|
|
120
120
|
}] |
|
|
121
121
|
[string] | [string, {
|
|
122
|
-
type?: "v8" | "istanbul" | "both";
|
|
122
|
+
type?: "v8" | "istanbul" | "both" | string;
|
|
123
123
|
[key: string]: any;
|
|
124
124
|
}];
|
|
125
125
|
|
|
@@ -192,7 +192,7 @@ declare namespace MCR {
|
|
|
192
192
|
ignores?: IgnoredRange[];
|
|
193
193
|
/** codecov json format */
|
|
194
194
|
lines: {
|
|
195
|
-
[key: string]: number | string
|
|
195
|
+
[key: string]: number | string;
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
198
|
}
|
|
@@ -287,7 +287,7 @@ declare namespace MCR {
|
|
|
287
287
|
*/
|
|
288
288
|
filter?: string | {
|
|
289
289
|
[pattern: string]: "js" | "css" | boolean;
|
|
290
|
-
} | ((filePath: string) => "js" | "css" | boolean)
|
|
290
|
+
} | ((filePath: string) => "js" | "css" | boolean);
|
|
291
291
|
};
|
|
292
292
|
|
|
293
293
|
/** (V8 only) {boolean} Enable/Disable ignoring uncovered codes with the special comments: v8 ignore next/next N/start/stop */
|
|
@@ -320,6 +320,7 @@ declare namespace MCR {
|
|
|
320
320
|
/** {function} onEnd hook */
|
|
321
321
|
onEnd?: (coverageResults: CoverageResults) => Promise<void>;
|
|
322
322
|
|
|
323
|
+
[key: string]: any;
|
|
323
324
|
}
|
|
324
325
|
|
|
325
326
|
export interface McrCliOptions extends CoverageReportOptions {
|
|
@@ -441,15 +442,19 @@ declare namespace MCR {
|
|
|
441
442
|
stopCoverage: () => Promise<V8CoverageEntry[]>;
|
|
442
443
|
|
|
443
444
|
/** write the coverage started by NODE_V8_COVERAGE to disk on demand, returns v8 coverage dir */
|
|
444
|
-
writeCoverage: () => Promise<string
|
|
445
|
+
writeCoverage: () => Promise<string>;
|
|
445
446
|
|
|
447
|
+
/** get istanbul coverage data
|
|
448
|
+
* @param coverageKey defaults to `__coverage__`
|
|
449
|
+
*/
|
|
450
|
+
getIstanbulCoverage: (coverageKey?: string) => Promise<any>;
|
|
446
451
|
}
|
|
447
452
|
|
|
448
453
|
/** Adapt to the CDPSession of Playwright or Puppeteer */
|
|
449
454
|
export interface CDPSession {
|
|
450
455
|
send: (method: string, params?: any) => Promise<any>;
|
|
451
456
|
on: (type: string, handler: (e: any) => void) => void;
|
|
452
|
-
detach: () => Promise<void
|
|
457
|
+
detach: () => Promise<void>;
|
|
453
458
|
}
|
|
454
459
|
|
|
455
460
|
/** custom websocket CDPSession */
|
|
@@ -457,7 +462,7 @@ declare namespace MCR {
|
|
|
457
462
|
constructor(ws: any);
|
|
458
463
|
send: (method: string, params?: any) => Promise<any>;
|
|
459
464
|
on: (type: string, handler: (e: any) => void) => void;
|
|
460
|
-
detach: () => Promise<void
|
|
465
|
+
detach: () => Promise<void>;
|
|
461
466
|
}
|
|
462
467
|
|
|
463
468
|
export interface CDPOptions {
|
|
@@ -472,7 +477,7 @@ declare namespace MCR {
|
|
|
472
477
|
/** enable https, defaults to false (http) */
|
|
473
478
|
secure?: boolean;
|
|
474
479
|
/** target filter, defaults to first page */
|
|
475
|
-
target?: (targets) => any;
|
|
480
|
+
target?: (targets: any) => any;
|
|
476
481
|
/** websocket options */
|
|
477
482
|
ws?: any;
|
|
478
483
|
/** timeout, defaults to 10 * 1000 */
|
package/lib/utils/util.js
CHANGED
|
@@ -442,6 +442,18 @@ const Util = {
|
|
|
442
442
|
return str;
|
|
443
443
|
},
|
|
444
444
|
|
|
445
|
+
cmpVersion: (v1, v2) => {
|
|
446
|
+
const [major1, minor1, patch1] = `${v1}`.split('.').map((s) => parseInt(s));
|
|
447
|
+
const [major2, minor2, patch2] = `${v2}`.split('.').map((s) => parseInt(s));
|
|
448
|
+
if (major1 === major2) {
|
|
449
|
+
if (minor1 === minor2) {
|
|
450
|
+
return Util.toNum(patch1) - Util.toNum(patch2);
|
|
451
|
+
}
|
|
452
|
+
return Util.toNum(minor1) - Util.toNum(minor2);
|
|
453
|
+
}
|
|
454
|
+
return Util.toNum(major1) - Util.toNum(major2);
|
|
455
|
+
},
|
|
456
|
+
|
|
445
457
|
// ==========================================================================================
|
|
446
458
|
|
|
447
459
|
loggingLevels: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "monocart-coverage-reports",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.7",
|
|
4
4
|
"description": "A code coverage tool to generate native V8 reports or Istanbul reports.",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"types": "./lib/index.d.ts",
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build-test": "node ./
|
|
27
|
+
"build-test": "node ./test/build/build-test.js",
|
|
28
28
|
"build": "sf lint && sf b -p && npm run build-test",
|
|
29
29
|
"test-node-env": "cross-env NODE_V8_COVERAGE=.temp/v8-coverage-env node ./test/test-node-env.js && node ./test/generate-report.js",
|
|
30
30
|
"test-node-api": "cross-env NODE_V8_COVERAGE=.temp/v8-coverage-api node ./test/test-node-api.js",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"test-node-vm": "node ./test/test-node-vm.js",
|
|
34
34
|
"test-node-koa": "node ./test/test-node-koa.js",
|
|
35
35
|
"test-node-fgc": "node ./test/test-node-fgc.js",
|
|
36
|
-
"test-node": "
|
|
36
|
+
"test-node": "node ./test/test.js --node",
|
|
37
37
|
"test-istanbul": "node ./test/test-istanbul.js",
|
|
38
38
|
"test-v8": "node ./test/test-v8.js",
|
|
39
39
|
"test-puppeteer": "node ./test/test-puppeteer.js",
|
|
@@ -43,15 +43,14 @@
|
|
|
43
43
|
"test-esbuild": "node ./test/test-esbuild.js",
|
|
44
44
|
"test-rollup": "node ./test/test-rollup.js",
|
|
45
45
|
"test-v8-and-istanbul": "node ./test/test-v8-and-istanbul.js",
|
|
46
|
-
"test-browser": "
|
|
46
|
+
"test-browser": "node ./test/test.js --browser",
|
|
47
47
|
"test-cli": "npx mcr node ./test/specs/node.test.js -c test/mcr.config.cli.js",
|
|
48
48
|
"test-tsx": "npx mcr tsx ./test/specs/tsx.test.ts -c test/mcr.config.tsx.js",
|
|
49
49
|
"test-demo": "node ./test/test-demo.js",
|
|
50
50
|
"test-merge": "node ./test/test-merge.js",
|
|
51
51
|
"test-merge-istanbul": "node ./test/test-merge-istanbul.js",
|
|
52
52
|
"test-client": "node ./test/test-client.js",
|
|
53
|
-
"test-all": "
|
|
54
|
-
"test-node-14": "npm run test-node && npm run test-v8 && npm run test-anonymous && npm run test-css && npm run test-minify && npm run test-esbuild && npm run test-v8-and-istanbul && npm run test-cli",
|
|
53
|
+
"test-all": "node ./test/test.js && node ./scripts/docs.js",
|
|
55
54
|
"test": "npx mcr npm run test-all -c test/mcr.config.mcr.js",
|
|
56
55
|
"test:snap": "cross-env TEST_SNAPSHOT=true npm run test",
|
|
57
56
|
"dev": "sf d v8",
|
|
@@ -89,7 +88,7 @@
|
|
|
89
88
|
"eslint-plugin-html": "^8.0.0",
|
|
90
89
|
"eslint-plugin-vue": "^9.23.0",
|
|
91
90
|
"minimatch": "^9.0.3",
|
|
92
|
-
"stylelint": "^16.
|
|
91
|
+
"stylelint": "^16.3.0",
|
|
93
92
|
"stylelint-config-plus": "^1.1.0",
|
|
94
93
|
"supports-color": "^9.4.0",
|
|
95
94
|
"tsx": "^4.7.1",
|