monocart-coverage-reports 2.7.6 → 2.7.8
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 +141 -74
- package/lib/cli.js +4 -17
- package/lib/client/cdp-client.js +1 -4
- package/lib/client/coverage-client.js +61 -19
- package/lib/converter/collect-source-maps.js +1 -3
- package/lib/converter/converter.js +13 -1
- package/lib/generate.js +5 -0
- package/lib/index.d.ts +12 -7
- package/lib/index.js +3 -1
- package/lib/packages/monocart-coverage-v8.js +1 -1
- package/lib/packages/monocart-coverage-vendor.js +2 -2
- package/lib/utils/request.js +26 -7
- package/lib/utils/source-path.js +15 -5
- package/lib/utils/util.js +26 -0
- package/lib/v8/v8.js +5 -6
- package/package.json +14 -12
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)
|
|
@@ -49,34 +50,37 @@
|
|
|
49
50
|
- [Codecov](#codecov)
|
|
50
51
|
- [Coveralls](#coveralls)
|
|
51
52
|
- [Sonar Cloud](#sonar-cloud)
|
|
53
|
+
* [Contributing](#contributing)
|
|
54
|
+
* [Changelog](CHANGELOG.md)
|
|
52
55
|
* [Thanks](#thanks)
|
|
53
56
|
|
|
54
57
|
## Usage
|
|
55
58
|
> It's recommended to use [Node.js 20+](https://nodejs.org/).
|
|
56
|
-
-
|
|
59
|
+
- API
|
|
57
60
|
```js
|
|
58
61
|
const MCR = require('monocart-coverage-reports');
|
|
59
|
-
const
|
|
62
|
+
const mcr = MCR({
|
|
60
63
|
name: 'My Coverage Report - 2024-02-28',
|
|
61
64
|
outputDir: './coverage-reports',
|
|
62
|
-
reports: ["v8", "console-details"]
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
mcr.
|
|
66
|
-
|
|
67
|
-
await mcr.add(coverageData1);
|
|
68
|
-
await mcr.add(coverageData2);
|
|
69
|
-
|
|
65
|
+
reports: ["v8", "console-details"],
|
|
66
|
+
cleanCache: true
|
|
67
|
+
});
|
|
68
|
+
await mcr.add(coverageData);
|
|
70
69
|
await mcr.generate();
|
|
71
|
-
|
|
72
|
-
// Or
|
|
73
|
-
// const { CoverageReport } = require('monocart-coverage-reports');
|
|
74
|
-
// const mcr = new CoverageReport(coverageOptions);
|
|
75
70
|
```
|
|
76
|
-
|
|
71
|
+
Using `import` and load options from [config file](#config-file)
|
|
72
|
+
```js
|
|
73
|
+
import { CoverageReport } from 'monocart-coverage-reports';
|
|
74
|
+
const mcr = new CoverageReport();
|
|
75
|
+
await mcr.loadConfig();
|
|
76
|
+
```
|
|
77
|
+
For more information, see [Multiprocessing Support](#multiprocessing-support)
|
|
78
|
+
|
|
79
|
+
- CLI
|
|
77
80
|
```sh
|
|
78
81
|
mcr node my-app.js -r v8,console-details
|
|
79
82
|
```
|
|
83
|
+
For more information, see [Command Line](#command-line)
|
|
80
84
|
|
|
81
85
|
## Options
|
|
82
86
|
- Default Options: [lib/default/options.js](./lib/default/options.js)
|
|
@@ -109,7 +113,7 @@ mcr node my-app.js -r v8,console-details
|
|
|
109
113
|
- `v8-json`
|
|
110
114
|
- [V8 coverage-report.json](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)
|
|
111
115
|
|
|
112
|
-
> Istanbul build-in reports (both V8 and
|
|
116
|
+
> Istanbul build-in reports (both V8 and Istanbul data):
|
|
113
117
|
|
|
114
118
|
- `clover`
|
|
115
119
|
- `cobertura`
|
|
@@ -129,7 +133,7 @@ mcr node my-app.js -r v8,console-details
|
|
|
129
133
|
- `text-lcov`
|
|
130
134
|
- `text-summary`
|
|
131
135
|
|
|
132
|
-
> Other build-in reports (both V8 and
|
|
136
|
+
> Other build-in reports (both V8 and Istanbul data):
|
|
133
137
|
|
|
134
138
|
- `codecov`
|
|
135
139
|
- 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 +167,9 @@ mcr node my-app.js -r v8,console-details
|
|
|
163
167
|
]
|
|
164
168
|
}
|
|
165
169
|
```
|
|
166
|
-
-
|
|
170
|
+
- Istanbul custom reporter
|
|
167
171
|
> 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
|
-
-
|
|
172
|
+
- V8 custom reporter
|
|
169
173
|
> example: [./test/custom-v8-reporter.js](./test/custom-v8-reporter.js)
|
|
170
174
|
|
|
171
175
|
### Multiple Reports:
|
|
@@ -194,11 +198,9 @@ const coverageOptions = {
|
|
|
194
198
|
}],
|
|
195
199
|
// Specify reporter name with local path
|
|
196
200
|
['/absolute/path/to/custom-reporter.js']
|
|
197
|
-
|
|
198
201
|
]
|
|
199
202
|
}
|
|
200
203
|
const mcr = MCR(coverageOptions);
|
|
201
|
-
mcr.cleanCache();
|
|
202
204
|
```
|
|
203
205
|
|
|
204
206
|
## Compare Reports
|
|
@@ -216,29 +218,35 @@ mcr.cleanCache();
|
|
|
216
218
|
| Minified code | ❌ | ✅ | ❌ |
|
|
217
219
|
|
|
218
220
|
## Collecting Istanbul Coverage Data
|
|
219
|
-
- Instrumenting source code
|
|
220
|
-
|
|
221
|
-
-
|
|
222
|
-
- rollup: [rollup-plugin-istanbul](https://github.com/artberri/rollup-plugin-istanbul)
|
|
221
|
+
- Before coverage collection: Instrumenting source code with Istanbul
|
|
222
|
+
- 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)
|
|
223
|
+
- 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
224
|
- vite: [vite-plugin-istanbul](https://github.com/ifaxity/vite-plugin-istanbul)
|
|
225
|
+
- rollup: [rollup-plugin-istanbul](https://github.com/artberri/rollup-plugin-istanbul)
|
|
226
|
+
- swc: [swc-plugin-coverage-instrument](https://github.com/kwonoj/swc-plugin-coverage-instrument)
|
|
227
|
+
|
|
224
228
|
- Browser
|
|
225
229
|
- Collecting coverage data from `window.__coverage__`, example: [test-istanbul.js](./test/test-istanbul.js)
|
|
230
|
+
|
|
226
231
|
- Node.js
|
|
227
232
|
- Collecting coverage data from `global.__coverage__`
|
|
228
233
|
|
|
234
|
+
- CDP
|
|
235
|
+
- `getIstanbulCoverage()` see [`CDPClient` API](#collecting-v8-coverage-data-with-cdpclient-api)
|
|
236
|
+
|
|
229
237
|
## 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)
|
|
232
|
-
- [rollup](https://rollupjs.org/configuration-options/): `sourcemap: true`
|
|
238
|
+
- Before coverage collection: Enabling `sourcemap` for source code
|
|
239
|
+
- [webpack](https://webpack.js.org/configuration/): `devtool: source-map` and `mode: development`, example [webpack.config-v8.js](./test/build/webpack.config-v8.js)
|
|
240
|
+
- [rollup](https://rollupjs.org/configuration-options/): `sourcemap: true` and `treeshake: false`
|
|
241
|
+
- [esbuild](https://esbuild.github.io/api/): `sourcemap: true`, `treeShaking: false` and `minify: false`
|
|
233
242
|
- [vite](https://vitejs.dev/config/build-options.html): `sourcemap: true` and `minify: false`
|
|
234
|
-
- [esbuild](https://esbuild.github.io/api/): `sourcemap: true` and `minify: false`
|
|
235
243
|
|
|
236
|
-
- Browser (Chromium Only)
|
|
244
|
+
- Browser (Chromium-based Only)
|
|
237
245
|
- [Collecting V8 Coverage Data with Playwright](#collecting-v8-coverage-data-with-playwright)
|
|
238
246
|
- [Collecting Raw V8 Coverage Data with Puppeteer](#collecting-raw-v8-coverage-data-with-puppeteer)
|
|
239
247
|
|
|
240
248
|
- Node.js
|
|
241
|
-
- [
|
|
249
|
+
- [Collecting V8 Coverage Data from Node.js](#collecting-v8-coverage-data-from-nodejs)
|
|
242
250
|
|
|
243
251
|
- CDP
|
|
244
252
|
- [Collecting V8 Coverage Data with `CDPClient` API](#collecting-v8-coverage-data-with-cdpclient-api)
|
|
@@ -264,7 +272,7 @@ const [jsCoverage, cssCoverage] = await Promise.all([
|
|
|
264
272
|
const coverageData = [... jsCoverage, ... cssCoverage];
|
|
265
273
|
|
|
266
274
|
```
|
|
267
|
-
see [./test/test-v8.js](./test/test-v8.js), and [anonymous](./test/test-anonymous.js), [css](./test/test-css.js)
|
|
275
|
+
For more examples, see [./test/test-v8.js](./test/test-v8.js), and [anonymous](./test/test-anonymous.js), [css](./test/test-css.js)
|
|
268
276
|
|
|
269
277
|
### Collecting Raw V8 Coverage Data with Puppeteer
|
|
270
278
|
```js
|
|
@@ -294,9 +302,9 @@ const coverageData = [... jsCoverage.map((it) => {
|
|
|
294
302
|
};
|
|
295
303
|
}), ... cssCoverage];
|
|
296
304
|
```
|
|
297
|
-
|
|
305
|
+
Example: [./test/test-puppeteer.js](./test/test-puppeteer.js)
|
|
298
306
|
|
|
299
|
-
###
|
|
307
|
+
### Collecting V8 Coverage Data from Node.js
|
|
300
308
|
Possible solutions:
|
|
301
309
|
- [NODE_V8_COVERAGE](https://nodejs.org/docs/latest/api/cli.html#node_v8_coveragedir)=`dir`
|
|
302
310
|
- 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 +338,27 @@ Possible solutions:
|
|
|
330
338
|
- see [Command Line](#command-line)
|
|
331
339
|
|
|
332
340
|
### Collecting V8 Coverage Data with `CDPClient` API
|
|
333
|
-
-
|
|
341
|
+
- `CDPClient` available APIs
|
|
342
|
+
```js
|
|
343
|
+
startJSCoverage: () => Promise<void>;
|
|
344
|
+
stopJSCoverage: () => Promise<V8CoverageEntry[]>;
|
|
345
|
+
|
|
346
|
+
startCSSCoverage: () => Promise<void>;
|
|
347
|
+
stopCSSCoverage: () => Promise<V8CoverageEntry[]>;
|
|
348
|
+
|
|
349
|
+
/** start both js and css coverage */
|
|
350
|
+
startCoverage: () => Promise<void>;
|
|
351
|
+
/** stop and return both js and css coverage */
|
|
352
|
+
stopCoverage: () => Promise<V8CoverageEntry[]>;
|
|
353
|
+
|
|
354
|
+
/** write the coverage started by NODE_V8_COVERAGE to disk on demand, returns v8 coverage dir */
|
|
355
|
+
writeCoverage: () => Promise<string>;
|
|
356
|
+
|
|
357
|
+
/** get istanbul coverage data */
|
|
358
|
+
getIstanbulCoverage: (coverageKey?: string) => Promise<any>;
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
- Work with node debugger port `--inspect=9229` or browser debugging port `--remote-debugging-port=9229`
|
|
334
362
|
```js
|
|
335
363
|
const MCR = require('monocart-coverage-reports');
|
|
336
364
|
const client = await MCR.CDPClient({
|
|
@@ -340,6 +368,7 @@ await client.startJSCoverage();
|
|
|
340
368
|
// run your test here
|
|
341
369
|
const coverageData = await client.stopJSCoverage();
|
|
342
370
|
```
|
|
371
|
+
|
|
343
372
|
- Work with [Playwright CDPSession](https://playwright.dev/docs/api/class-cdpsession)
|
|
344
373
|
```js
|
|
345
374
|
const { chromium } = require('playwright');
|
|
@@ -356,6 +385,7 @@ await client.startCoverage();
|
|
|
356
385
|
await page.goto("your page url");
|
|
357
386
|
const coverageData = await client.stopCoverage();
|
|
358
387
|
```
|
|
388
|
+
|
|
359
389
|
- Work with [Puppeteer CDPSession](https://pptr.dev/api/puppeteer.cdpsession)
|
|
360
390
|
```js
|
|
361
391
|
const puppeteer = require('puppeteer');
|
|
@@ -373,11 +403,23 @@ await page.goto("your page url");
|
|
|
373
403
|
const coverageData = await client.stopCoverage();
|
|
374
404
|
```
|
|
375
405
|
|
|
406
|
+
- Work with [Selenium Webdriver](https://www.selenium.dev/documentation/webdriver/) WebSocket (Chrome/Edge Browser)
|
|
407
|
+
```js
|
|
408
|
+
const { Builder, Browser } = require('selenium-webdriver');
|
|
409
|
+
const MCR = require('monocart-coverage-reports');
|
|
410
|
+
const driver = await new Builder().forBrowser(Browser.CHROME).build();
|
|
411
|
+
const pageCdpConnection = await driver.createCDPConnection('page');
|
|
412
|
+
const session = new MCR.WSSession(pageCdpConnection._wsConnection);
|
|
413
|
+
const client = await MCR.CDPClient({
|
|
414
|
+
session
|
|
415
|
+
})
|
|
416
|
+
```
|
|
417
|
+
|
|
376
418
|
### V8 Coverage Data API
|
|
377
|
-
- [
|
|
419
|
+
- [JavaScript code coverage in V8](https://v8.dev/blog/javascript-code-coverage)
|
|
378
420
|
- [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
|
|
421
|
+
- [Puppeteer Coverage Class](https://pptr.dev/api/puppeteer.coverage)
|
|
422
|
+
- [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
423
|
```js
|
|
382
424
|
// Coverage data for a source range.
|
|
383
425
|
export interface CoverageRange {
|
|
@@ -388,7 +430,6 @@ export interface CoverageRange {
|
|
|
388
430
|
// Collected execution count of the source range.
|
|
389
431
|
count: integer;
|
|
390
432
|
}
|
|
391
|
-
|
|
392
433
|
// Coverage data for a JavaScript function.
|
|
393
434
|
/**
|
|
394
435
|
* @functionName can be an empty string.
|
|
@@ -405,7 +446,6 @@ export interface FunctionCoverage {
|
|
|
405
446
|
// Whether coverage data for this function has block granularity.
|
|
406
447
|
isBlockCoverage: boolean;
|
|
407
448
|
}
|
|
408
|
-
|
|
409
449
|
// Coverage data for a JavaScript script.
|
|
410
450
|
export interface ScriptCoverage {
|
|
411
451
|
// JavaScript script id.
|
|
@@ -415,32 +455,31 @@ export interface ScriptCoverage {
|
|
|
415
455
|
// Functions contained in the script that has coverage data.
|
|
416
456
|
functions: FunctionCoverage[];
|
|
417
457
|
}
|
|
418
|
-
|
|
419
458
|
export type V8CoverageData = ScriptCoverage[];
|
|
420
459
|
```
|
|
421
460
|
|
|
422
461
|
## Using `entryFilter` and `sourceFilter` to filter the results for V8 report
|
|
423
462
|
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
|
-
|
|
463
|
+
|
|
464
|
+
- *dist/main.js*
|
|
465
|
+
- *dist/vendor.js*
|
|
466
|
+
- *dist/something-else.js*
|
|
467
|
+
|
|
429
468
|
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
|
-
|
|
469
|
+
|
|
470
|
+
- *dist/main.js*
|
|
471
|
+
|
|
433
472
|
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
|
-
|
|
473
|
+
|
|
474
|
+
- *src/index.js*
|
|
475
|
+
- *src/components/app.js*
|
|
476
|
+
- *node_modules/dependency/dist/dependency.js*
|
|
477
|
+
|
|
439
478
|
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
|
-
|
|
479
|
+
|
|
480
|
+
- *src/index.js*
|
|
481
|
+
- *src/components/app.js*
|
|
482
|
+
|
|
444
483
|
For example:
|
|
445
484
|
```js
|
|
446
485
|
const coverageOptions = {
|
|
@@ -600,7 +639,6 @@ mcr.cleanCache();
|
|
|
600
639
|
const MCR = require('monocart-coverage-reports');
|
|
601
640
|
const coverageOptions = require('path-to/same-options.js');
|
|
602
641
|
const mcr = MCR(coverageOptions);
|
|
603
|
-
// do not clean cache in the stage
|
|
604
642
|
await mcr.add(coverageData1);
|
|
605
643
|
```
|
|
606
644
|
|
|
@@ -609,7 +647,6 @@ await mcr.add(coverageData1);
|
|
|
609
647
|
const MCR = require('monocart-coverage-reports');
|
|
610
648
|
const coverageOptions = require('path-to/same-options.js');
|
|
611
649
|
const mcr = MCR(coverageOptions);
|
|
612
|
-
// do not clean cache in the stage
|
|
613
650
|
await mcr.add(coverageData2);
|
|
614
651
|
```
|
|
615
652
|
|
|
@@ -619,7 +656,6 @@ await mcr.add(coverageData2);
|
|
|
619
656
|
const MCR = require('monocart-coverage-reports');
|
|
620
657
|
const coverageOptions = require('path-to/same-options.js');
|
|
621
658
|
const mcr = MCR(coverageOptions);
|
|
622
|
-
// do not clean cache before generating reports
|
|
623
659
|
await mcr.generate();
|
|
624
660
|
```
|
|
625
661
|
|
|
@@ -629,13 +665,13 @@ await mcr.generate();
|
|
|
629
665
|
- Installing globally
|
|
630
666
|
```sh
|
|
631
667
|
npm i monocart-coverage-reports -g
|
|
632
|
-
mcr node ./test/specs/node.test.js -r v8,console-
|
|
668
|
+
mcr node ./test/specs/node.test.js -r v8,console-details --lcov
|
|
633
669
|
```
|
|
634
670
|
|
|
635
671
|
- Locally in your project
|
|
636
672
|
```sh
|
|
637
673
|
npm i monocart-coverage-reports
|
|
638
|
-
npx mcr node ./test/specs/node.test.js -r v8,console-
|
|
674
|
+
npx mcr node ./test/specs/node.test.js -r v8,console-details --lcov
|
|
639
675
|
```
|
|
640
676
|
|
|
641
677
|
- CLI Options
|
|
@@ -671,6 +707,12 @@ Options:
|
|
|
671
707
|
mcr -c mcr.config.js -- sub-cli -c sub-cli.config.js
|
|
672
708
|
```
|
|
673
709
|
|
|
710
|
+
- Examples
|
|
711
|
+
- [Mocha](#mocha)
|
|
712
|
+
- [tsx](#tsx)
|
|
713
|
+
- [ts-node](#ts-node)
|
|
714
|
+
- [AVA](#ava)
|
|
715
|
+
|
|
674
716
|
## Config File
|
|
675
717
|
Loading config file by priority:
|
|
676
718
|
- Custom config file:
|
|
@@ -692,6 +734,7 @@ The following usage scenarios may require merging coverage reports:
|
|
|
692
734
|
|
|
693
735
|
If the reports cannot be merged automatically, then here is how to manually merge the reports.
|
|
694
736
|
First, using the `raw` report to export the original coverage data to the specified directory.
|
|
737
|
+
For example, we have `raw` coverage data from unit tests:
|
|
695
738
|
```js
|
|
696
739
|
const coverageOptions = {
|
|
697
740
|
name: 'My Unit Test Coverage Report',
|
|
@@ -699,15 +742,18 @@ const coverageOptions = {
|
|
|
699
742
|
reports: [
|
|
700
743
|
['raw', {
|
|
701
744
|
// relative path will be "./coverage-reports/unit/raw"
|
|
745
|
+
// defaults to raw
|
|
702
746
|
outputDir: "raw"
|
|
703
747
|
}],
|
|
704
748
|
['v8'],
|
|
705
|
-
['console-
|
|
749
|
+
['console-details']
|
|
706
750
|
]
|
|
707
751
|
};
|
|
708
752
|
```
|
|
709
|
-
|
|
753
|
+
We also have `raw` coverage data from e2e tests, which is output to `./coverage-reports/e2e/raw`.
|
|
754
|
+
After all the tests are completed, generate a merged report with option `inputDir`:
|
|
710
755
|
```js
|
|
756
|
+
// merge-coverage.js
|
|
711
757
|
const fs = require('fs');
|
|
712
758
|
const { CoverageReport } = require('monocart-coverage-reports');
|
|
713
759
|
const inputDir = [
|
|
@@ -731,6 +777,10 @@ const coverageOptions = {
|
|
|
731
777
|
|
|
732
778
|
sourcePath: (filePath, info) => {
|
|
733
779
|
// Unify the file path for the same files
|
|
780
|
+
// For example, the file index.js has different paths:
|
|
781
|
+
// unit: unit-dist/src/index.js
|
|
782
|
+
// e2e: e2e-dist/src/index.js
|
|
783
|
+
// return filePath.replace("unit-dist/", "").replace("e2e-dist/", "")
|
|
734
784
|
return filePath;
|
|
735
785
|
},
|
|
736
786
|
|
|
@@ -741,12 +791,12 @@ const coverageOptions = {
|
|
|
741
791
|
|
|
742
792
|
onEnd: () => {
|
|
743
793
|
// remove the raw files if it useless
|
|
744
|
-
inputDir.forEach((p) => {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
});
|
|
794
|
+
// inputDir.forEach((p) => {
|
|
795
|
+
// fs.rmSync(p, {
|
|
796
|
+
// recursive: true,
|
|
797
|
+
// force: true
|
|
798
|
+
// });
|
|
799
|
+
// });
|
|
750
800
|
}
|
|
751
801
|
};
|
|
752
802
|
await new CoverageReport(coverageOptions).generate();
|
|
@@ -763,7 +813,7 @@ const a = tf ? 'true' : 'false';
|
|
|
763
813
|
`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
814
|
|
|
765
815
|
How `MCR` Works:
|
|
766
|
-
- 1, Trying to fix the middle position
|
|
816
|
+
- 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
817
|
- 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
818
|
|
|
769
819
|
|
|
@@ -795,7 +845,7 @@ const coverageOptions = {
|
|
|
795
845
|
logging: 'debug',
|
|
796
846
|
reports: [
|
|
797
847
|
['v8'],
|
|
798
|
-
['console-
|
|
848
|
+
['console-details']
|
|
799
849
|
]
|
|
800
850
|
};
|
|
801
851
|
```
|
|
@@ -818,6 +868,7 @@ When `logging` is `debug`, the raw report data will be preserved in `[outputDir]
|
|
|
818
868
|
## Integration Examples
|
|
819
869
|
|
|
820
870
|
### [Playwright](https://github.com/microsoft/playwright)
|
|
871
|
+
- [playwright-coverage](https://github.com/cenfun/playwright-coverage) - A Example for Playwright Coverage Reports
|
|
821
872
|
- [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
873
|
- Coverage for component testing:
|
|
823
874
|
- [playwright-ct-vue](https://github.com/cenfun/playwright-ct-vue)
|
|
@@ -829,6 +880,7 @@ When `logging` is `debug`, the raw report data will be preserved in `[outputDir]
|
|
|
829
880
|
|
|
830
881
|
### [Jest](https://github.com/jestjs/jest/)
|
|
831
882
|
- [jest-monocart-coverage](https://github.com/cenfun/jest-monocart-coverage) - A Jest custom reporter for coverage reports
|
|
883
|
+
- [jest-puppeteer-coverage](https://github.com/cenfun/jest-puppeteer-coverage) - A Jest Puppeteer Coverage Example
|
|
832
884
|
- Example for Jest (unit) + Puppeteer (e2e) + Codecov: [maplibre-gl-js](https://github.com/maplibre/maplibre-gl-js)
|
|
833
885
|
|
|
834
886
|
### [Vitest](https://github.com/vitest-dev/vitest)
|
|
@@ -850,6 +902,9 @@ When `logging` is `debug`, the raw report data will be preserved in `[outputDir]
|
|
|
850
902
|
### [TestCafe](https://github.com/DevExpress/testcafe)
|
|
851
903
|
- [testcafe-reporter-coverage](https://github.com/cenfun/testcafe-reporter-coverage) - A TestCafe custom reporter for coverage reports
|
|
852
904
|
|
|
905
|
+
### [Selenium Webdriver](https://github.com/seleniumhq/selenium)
|
|
906
|
+
- [selenium-webdriver-coverage](https://github.com/cenfun/selenium-webdriver-coverage) - Selenium Webdriver V8 Coverage Example
|
|
907
|
+
|
|
853
908
|
### [Mocha](https://github.com/mochajs/mocha)
|
|
854
909
|
```sh
|
|
855
910
|
mcr mocha ./test/**/*.js
|
|
@@ -927,6 +982,18 @@ const coverageOptions = {
|
|
|
927
982
|
-Dsonar.exclusions=dist/*,packages/*
|
|
928
983
|
```
|
|
929
984
|
|
|
985
|
+
## Contributing
|
|
986
|
+
```sh
|
|
987
|
+
# Node.js 20+
|
|
988
|
+
npm install starfall-cli -g
|
|
989
|
+
npm install
|
|
990
|
+
|
|
991
|
+
npm run build
|
|
992
|
+
npm run test
|
|
993
|
+
|
|
994
|
+
npm run dev
|
|
995
|
+
```
|
|
996
|
+
|
|
930
997
|
### VSCode Extension
|
|
931
998
|
- [Coverage Gutters](https://github.com/ryanluker/vscode-coverage-gutters) - Display test coverage generated by lcov or xml in VSCode editor.
|
|
932
999
|
|
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
|
|
package/lib/client/cdp-client.js
CHANGED
|
@@ -12,10 +12,7 @@ const getDebuggerUrl = async (options) => {
|
|
|
12
12
|
const protocol = options.secure ? 'https' : 'http';
|
|
13
13
|
|
|
14
14
|
const url = `${protocol}://${options.host}:${options.port}/json/list`;
|
|
15
|
-
const [err, res] = await Util.request(
|
|
16
|
-
url,
|
|
17
|
-
timeout: options.timeout
|
|
18
|
-
});
|
|
15
|
+
const [err, res] = await Util.request(url);
|
|
19
16
|
if (err) {
|
|
20
17
|
return [err];
|
|
21
18
|
}
|
|
@@ -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
|
|