monocart-coverage-reports 2.7.5 → 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 CHANGED
@@ -9,32 +9,31 @@
9
9
  > A code coverage tool to generate native [V8](https://v8.dev/blog/javascript-code-coverage) reports or [Istanbul](https://istanbul.js.org/) reports.
10
10
 
11
11
  * [Usage](#usage)
12
- * [Default Options](#default-options)
12
+ * [Options](#options)
13
13
  * [Available Reports](#available-reports)
14
- * [Using `entryFilter` and `sourceFilter` to filter the results for V8 report](#using-entryfilter-and-sourcefilter-to-filter-the-results-for-v8-report)
15
- * [onEnd Hook](#onend-hook)
16
- * [Command Line](#command-line)
17
14
  * [Compare Reports](#compare-reports)
18
- * [Compare Workflows](#compare-workflows)
19
15
  * [Collecting Istanbul Coverage Data](#collecting-istanbul-coverage-data)
20
16
  * [Collecting V8 Coverage Data](#collecting-v8-coverage-data)
21
- * [Manually Resolve the Sourcemap](#manually-resolve-the-sourcemap)
22
- * [Collecting Raw V8 Coverage Data with Puppeteer](#collecting-raw-v8-coverage-data-with-puppeteer)
23
- * [Node.js V8 Coverage Report for Server Side](#nodejs-v8-coverage-report-for-server-side)
24
- * [Collecting V8 Coverage Data with `CDPClient` API](#collecting-v8-coverage-data-with-cdpclient-api)
25
- * [Multiprocessing Support](#multiprocessing-support)
26
- * [Merge Coverage Reports](#merge-coverage-reports)
17
+ - [Collecting V8 Coverage Data with Playwright](#collecting-v8-coverage-data-with-playwright)
18
+ - [Collecting Raw V8 Coverage Data with Puppeteer](#collecting-raw-v8-coverage-data-with-puppeteer)
19
+ - [Collecting V8 Coverage Data from Node.js](#collecting-v8-coverage-data-from-nodejs)
20
+ - [Collecting V8 Coverage Data with `CDPClient` API](#collecting-v8-coverage-data-with-cdpclient-api)
21
+ - [V8 Coverage Data API](#v8-coverage-data-api)
22
+ * [Using `entryFilter` and `sourceFilter` to filter the results for V8 report](#using-entryfilter-and-sourcefilter-to-filter-the-results-for-v8-report)
27
23
  * [Resolve `sourcePath` for the Source Files](#resolve-sourcepath-for-the-source-files)
28
24
  * [Adding Empty Coverage for Untested Files](#adding-empty-coverage-for-untested-files)
25
+ * [onEnd Hook](#onend-hook)
29
26
  * [Ignoring Uncovered Codes](#ignoring-uncovered-codes)
30
- * [Chromium Coverage API](#chromium-coverage-api)
31
- * [V8 Coverage Data Format](#v8-coverage-data-format)
32
- * [How to convert V8 to Istanbul](#how-to-convert-v8-to-istanbul)
33
- - [Using `v8-to-istanbul`](#using-v8-to-istanbul)
34
- - [How Monocart Works](#how-monocart-works)
35
- * [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap)
27
+ * [Multiprocessing Support](#multiprocessing-support)
28
+ * [Command Line](#command-line)
29
+ * [Config File](#config-file)
30
+ * [Merge Coverage Reports](#merge-coverage-reports)
36
31
  * [Common issues](#common-issues)
37
- * [Integration](#integration)
32
+ - [Unexpected coverage](#unexpected-coverage)
33
+ - [Unparsable source](#unparsable-source)
34
+ * [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap)
35
+ * [Integration with Any Testing Framework](#integration-with-any-testing-framework)
36
+ * [Integration Examples](#integration-examples)
38
37
  - [Playwright](#playwright)
39
38
  - [Jest](#jest)
40
39
  - [Vitest](#vitest)
@@ -43,37 +42,46 @@
43
42
  - [WebdriverIO](#webdriverio)
44
43
  - [Storybook Test Runner](#storybook-test-runner)
45
44
  - [TestCafe](#testcafe)
45
+ - [Selenium Webdriver](#selenium-webdriver)
46
+ - [Mocha](#mocha)
47
+ - [tsx](#tsx)
48
+ - [ts-node](#ts-node)
49
+ - [AVA](#ava)
46
50
  - [Codecov](#codecov)
47
51
  - [Coveralls](#coveralls)
48
52
  - [Sonar Cloud](#sonar-cloud)
49
- - [Integration with Any Testing Framework](#integration-with-any-testing-framework)
50
53
  * [Thanks](#thanks)
51
54
 
52
55
  ## Usage
56
+ > It's recommended to use [Node.js 20+](https://nodejs.org/).
57
+ - API
53
58
  ```js
54
59
  const MCR = require('monocart-coverage-reports');
55
- const coverageOptions = {
60
+ const mcr = MCR({
56
61
  name: 'My Coverage Report - 2024-02-28',
57
62
  outputDir: './coverage-reports',
58
- reports: ["v8", "console-details"]
59
- }
60
- const coverageReport = MCR(coverageOptions);
61
- coverageReport.cleanCache();
62
-
63
- await coverageReport.add(coverageData1);
64
- await coverageReport.add(coverageData2);
65
-
66
- await coverageReport.generate();
63
+ reports: ["v8", "console-details"],
64
+ cleanCache: true
65
+ });
66
+ await mcr.add(coverageData);
67
+ await mcr.generate();
68
+ ```
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)
67
76
 
68
- // Or
69
- // const { CoverageReport } = require('monocart-coverage-reports');
70
- // const coverageReport = new CoverageReport(coverageOptions);
77
+ - CLI
78
+ ```sh
79
+ mcr node my-app.js -r v8,console-details
71
80
  ```
72
- - [example v8](https://github.com/cenfun/monocart-coverage-reports/blob/main/test/test-v8.js)
73
- - [example istanbul](https://github.com/cenfun/monocart-coverage-reports/blob/main/test/test-istanbul.js)
81
+ For more information, see [Command Line](#command-line)
74
82
 
75
- ## Default Options
76
- - [lib/default/options.js](https://github.com/cenfun/monocart-coverage-reports/blob/main/lib/default/options.js)
83
+ ## Options
84
+ - Default Options: [lib/default/options.js](./lib/default/options.js)
77
85
  - `reports` [Available Reports](#available-reports)
78
86
  - `entryFilter` and `sourceFilter` [Using `entryFilter` and `sourceFilter` to filter the results for V8 report](#using-entryfilter-and-sourcefilter-to-filter-the-results-for-v8-report)
79
87
  - `sourcePath` [Resolve `sourcePath` for the Source Files](#resolve-sourcepath-for-the-source-files)
@@ -82,7 +90,8 @@ await coverageReport.generate();
82
90
  - `logging` [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap)
83
91
  - `onEnd` [onEnd Hook](#onend-hook)
84
92
 
85
- - Declaration [lib/index.d.ts](https://github.com/cenfun/monocart-coverage-reports/blob/main/lib/index.d.ts)
93
+ - Declaration: [lib/index.d.ts](./lib/index.d.ts)
94
+ - [Config file](#config-file)
86
95
 
87
96
  ## Available Reports
88
97
 
@@ -95,16 +104,14 @@ await coverageReport.generate();
95
104
  - Coverage for Any Runtime Code
96
105
  - CSS Coverage Support
97
106
  - Better Support for Sourcemap Conversion
98
- - Demos:
99
- - Browser: Build with webpack [V8](https://cenfun.github.io/monocart-coverage-reports/v8) and [Minify](https://cenfun.github.io/monocart-coverage-reports/minify); Build with [Rollup](https://cenfun.github.io/monocart-coverage-reports/rollup) and [Esbuild](https://cenfun.github.io/monocart-coverage-reports/esbuild); Collect with [puppeteer](https://cenfun.github.io/monocart-coverage-reports/puppeteer/); [anonymous](https://cenfun.github.io/monocart-coverage-reports/anonymous/) and [css](https://cenfun.github.io/monocart-coverage-reports/css/)
100
- - Node.js: Collect with [env](https://cenfun.github.io/monocart-coverage-reports/node-env), and also V8 [API](https://cenfun.github.io/monocart-coverage-reports/node-api), [Inspector](https://cenfun.github.io/monocart-coverage-reports/node-ins) and [CDP](https://cenfun.github.io/monocart-coverage-reports/node-cdp); Web server example: [koa](https://cenfun.github.io/monocart-coverage-reports/node-koa/)
107
+ - Demos: [V8](https://cenfun.github.io/monocart-coverage-reports/v8) and [more](https://cenfun.github.io/monocart-coverage-reports/)
101
108
 
102
109
  ![](./assets/v8.gif)
103
110
 
104
111
  - `v8-json`
105
112
  - [V8 coverage-report.json](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)
106
113
 
107
- > Istanbul build-in reports (both V8 and istanbul data):
114
+ > Istanbul build-in reports (both V8 and Istanbul data):
108
115
 
109
116
  - `clover`
110
117
  - `cobertura`
@@ -112,7 +119,6 @@ await coverageReport.generate();
112
119
  - [Istanbul html](https://cenfun.github.io/monocart-coverage-reports/istanbul/)
113
120
  - [V8 to Istanbul](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/istanbul)
114
121
  - `html-spa`
115
- - [Istanbul html-spa](https://cenfun.github.io/monocart-coverage-reports/istanbul/html-spa/)
116
122
  - `json`
117
123
  - `json-summary`
118
124
  - `lcov`
@@ -125,7 +131,7 @@ await coverageReport.generate();
125
131
  - `text-lcov`
126
132
  - `text-summary`
127
133
 
128
- > Other build-in reports (both V8 and istanbul data):
134
+ > Other build-in reports (both V8 and Istanbul data):
129
135
 
130
136
  - `codecov`
131
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)
@@ -159,9 +165,9 @@ await coverageReport.generate();
159
165
  ]
160
166
  }
161
167
  ```
162
- - istanbul custom reporter
168
+ - Istanbul custom reporter
163
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.
164
- - v8 custom reporter
170
+ - V8 custom reporter
165
171
  > example: [./test/custom-v8-reporter.js](./test/custom-v8-reporter.js)
166
172
 
167
173
  ### Multiple Reports:
@@ -190,151 +196,11 @@ const coverageOptions = {
190
196
  }],
191
197
  // Specify reporter name with local path
192
198
  ['/absolute/path/to/custom-reporter.js']
193
-
194
199
  ]
195
200
  }
196
- const coverageReport = MCR(coverageOptions);
197
- coverageReport.cleanCache();
198
- ```
199
-
200
- ## Using `entryFilter` and `sourceFilter` to filter the results for V8 report
201
- When V8 coverage data collected, it actually contains the data of all entry files, for example:
202
- ```
203
- dist/main.js
204
- dist/vendor.js
205
- dist/something-else.js
206
- ```
207
- 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.
208
- ```
209
- dist/main.js
210
- ```
211
- 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`.
212
- ```
213
- > src/index.js
214
- > src/components/app.js
215
- > node_modules/dependency/dist/dependency.js
216
- ```
217
- We can use `sourceFilter` to filter the source files. For example, we should remove `dependency.js` if it is not in our coverage scope.
218
- ```
219
- > src/index.js
220
- > src/components/app.js
221
- ```
222
- For example:
223
- ```js
224
- const coverageOptions = {
225
- entryFilter: (entry) => entry.url.indexOf("main.js") !== -1,
226
- sourceFilter: (sourcePath) => sourcePath.search(/src\//) !== -1
227
- };
228
- ```
229
- Or using `minimatch` pattern:
230
- ```js
231
- const coverageOptions = {
232
- entryFilter: "**/main.js",
233
- sourceFilter: "**/src/**"
234
- };
235
- // supports multiple patterns:
236
- const coverageOptions = {
237
- entryFilter: {
238
- '**/vendor.js': false,
239
- '**/main.js': true
240
- },
241
- sourceFilter: {
242
- '**/src/**': true
243
- }
244
- };
245
- ```
246
-
247
- ## onEnd Hook
248
- For example, checking thresholds:
249
- ```js
250
- const EC = require('eight-colors');
251
- const coverageOptions = {
252
- name: 'My Coverage Report',
253
- outputDir: './coverage-reports',
254
- onEnd: (coverageResults) => {
255
- const thresholds = {
256
- bytes: 80,
257
- lines: 60
258
- };
259
- console.log('check thresholds ...', thresholds);
260
- const errors = [];
261
- const { summary } = coverageResults;
262
- Object.keys(thresholds).forEach((k) => {
263
- const pct = summary[k].pct;
264
- if (pct < thresholds[k]) {
265
- errors.push(`Coverage threshold for ${k} (${pct} %) not met: ${thresholds[k]} %`);
266
- }
267
- });
268
- if (errors.length) {
269
- const errMsg = errors.join('\n');
270
- console.log(EC.red(errMsg));
271
- // throw new Error(errMsg);
272
- // process.exit(1);
273
- }
274
- }
275
- }
276
- ```
277
-
278
- ## Command Line
279
- > 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`.
280
-
281
- - Installing globally
282
- ```sh
283
- npm i monocart-coverage-reports -g
284
- mcr node ./test/specs/node.test.js -r v8,console-summary --lcov
285
- ```
286
-
287
- - Locally in your project
288
- ```sh
289
- npm i monocart-coverage-reports
290
- npx mcr node ./test/specs/node.test.js -r v8,console-summary --lcov
291
- ```
292
-
293
- - CLI Options
294
- ```sh
295
- Usage: mcr [options] <command>
296
-
297
- CLI to generate coverage reports
298
-
299
- Arguments:
300
- command command to execute
301
-
302
- Options:
303
- -V, --version output the version number
304
- -c, --config <path> custom config file path
305
- --logging <logging> off, error, info, debug
306
- -n, --name <name> report name for title
307
- -r, --reports <name[,name]> coverage reports to use
308
- -o, --outputDir <dir> output dir for reports
309
- -i, --inputDir <dir> input dir for merging raw files
310
- --entryFilter <pattern> entry url filter
311
- --sourceFilter <pattern> source path filter
312
- --outputFile <path> output file for v8 report
313
- --inline inline html for v8 report
314
- --assetsPath <path> assets path if not inline
315
- --lcov generate lcov.info file
316
- --import <module> preload module at startup
317
- --require <module> preload module at startup
318
- -h, --help display help for command
201
+ const mcr = MCR(coverageOptions);
319
202
  ```
320
203
 
321
- - Loading config file by priority:
322
- - Custom config file with `-c` or `--config`
323
- - `mcr.config.js`
324
- - `mcr.config.cjs`
325
- - `mcr.config.mjs`
326
- - `mcr.config.json` - json format
327
- - `mcr.config.ts` (requires preloading the ts execution module)
328
- - `.mcrrc.js`
329
- - `.mcrrc` - json format
330
-
331
- - Working with `tsx`, see [mcr-tsx](https://github.com/cenfun/mcr-tsx)
332
- ```sh
333
- npx mcr --import tsx tsx ./src/example.ts
334
- ```
335
-
336
- - Working with `ts-node`, see [mcr-ts-node](https://github.com/cenfun/mcr-ts-node)
337
-
338
204
  ## Compare Reports
339
205
  | | Istanbul | V8 | V8 to Istanbul |
340
206
  | :--------------| :------ | :------ | :---------------------- |
@@ -349,59 +215,59 @@ Options:
349
215
  | CSS coverage | ❌ | ✅ | ✅ |
350
216
  | Minified code | ❌ | ✅ | ❌ |
351
217
 
352
- ## Compare Workflows
353
- - Istanbul Workflows
354
- - 1, [Collecting Istanbul coverage data](#collecting-istanbul-coverage-data)
355
- - 2, Adding coverage data and generating coverage report
356
-
357
- - V8 Workflows
358
- - 1, [Collecting V8 coverage data](#collecting-v8-coverage-data)
359
- - 3, Adding coverage data and generating coverage report
360
-
361
218
  ## Collecting Istanbul Coverage Data
362
- - Instrumenting source code
363
- > Before collecting Istanbul coverage data, It requires your source code is instrumented with Istanbul
364
- - webpack: [babel-plugin-istanbul](https://github.com/istanbuljs/babel-plugin-istanbul), example: [webpack.config-istanbul.js](https://github.com/cenfun/monocart-coverage-reports/blob/main/test/webpack.config-istanbul.js)
365
- - 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)
366
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)
367
225
  - Browser
368
- - Collecting coverage data from `window.__coverage__`, example: [test-istanbul.js](https://github.com/cenfun/monocart-coverage-reports/blob/main/test/test-istanbul.js)
226
+ - Collecting coverage data from `window.__coverage__`, example: [test-istanbul.js](./test/test-istanbul.js)
369
227
  - Node.js
370
228
  - Collecting coverage data from `global.__coverage__`
371
229
 
372
230
  ## Collecting V8 Coverage Data
373
- - For source code: enable `sourcemap` and do not compress/minify:
374
- - [webpack](https://webpack.js.org/configuration/): `devtool: source-map` and `mode: development`, example [webpack.config-v8.js](https://github.com/cenfun/monocart-coverage-reports/blob/main/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)
375
233
  - [rollup](https://rollupjs.org/configuration-options/): `sourcemap: true`
376
234
  - [vite](https://vitejs.dev/config/build-options.html): `sourcemap: true` and `minify: false`
377
235
  - [esbuild](https://esbuild.github.io/api/): `sourcemap: true` and `minify: false`
378
- - [Manually Resolve the Sourcemap](#manually-resolve-the-sourcemap)
236
+
379
237
  - Browser (Chromium Only)
380
- > Collecting coverage data with [Chromium Coverage API](#chromium-coverage-api):
381
- - [Playwright example](https://github.com/cenfun/monocart-coverage-reports/blob/main/test/test-v8.js), and [anonymous](https://github.com/cenfun/monocart-coverage-reports/blob/main/test/test-anonymous.js), [css](https://github.com/cenfun/monocart-coverage-reports/blob/main/test/test-css.js)
382
- - see [Collecting Raw V8 Coverage Data with Puppeteer](#collecting-raw-v8-coverage-data-with-puppeteer)
238
+ - [Collecting V8 Coverage Data with Playwright](#collecting-v8-coverage-data-with-playwright)
239
+ - [Collecting Raw V8 Coverage Data with Puppeteer](#collecting-raw-v8-coverage-data-with-puppeteer)
240
+
383
241
  - Node.js
384
- - see [Node.js V8 Coverage Report for Server Side](#nodejs-v8-coverage-report-for-server-side)
242
+ - [Collecting V8 Coverage Data from Node.js](#collecting-v8-coverage-data-from-nodejs)
243
+
385
244
  - CDP
386
- - see [Collecting V8 Coverage Data with `CDPClient` API](#collecting-v8-coverage-data-with-cdpclient-api)
245
+ - [Collecting V8 Coverage Data with `CDPClient` API](#collecting-v8-coverage-data-with-cdpclient-api)
387
246
 
388
- ## Manually Resolve the Sourcemap
389
- > Sometimes, the sourcemap file cannot be successfully loaded with the `sourceMappingURL`, you can try to manually read the sourcemap file before the coverage data is added to the report.
247
+ ### Collecting V8 Coverage Data with Playwright
390
248
  ```js
391
- const jsCoverage = await page.coverage.stopJSCoverage();
392
- jsCoverage.forEach((entry) => {
393
- // read sourcemap for the my-dist.js manually
394
- if (entry.url.endsWith('my-dist.js')) {
395
- entry.sourceMap = JSON.parse(fs.readFileSync('dist/my-dist.js.map').toString('utf-8'));
396
- }
397
- });
249
+ await Promise.all([
250
+ page.coverage.startJSCoverage({
251
+ resetOnNavigation: false
252
+ }),
253
+ page.coverage.startCSSCoverage({
254
+ resetOnNavigation: false
255
+ })
256
+ ]);
398
257
 
399
- await MCR(coverageOptions).add(jsCoverage);
258
+ await page.goto("your page url");
259
+
260
+ const [jsCoverage, cssCoverage] = await Promise.all([
261
+ page.coverage.stopJSCoverage(),
262
+ page.coverage.stopCSSCoverage()
263
+ ]);
264
+
265
+ const coverageData = [... jsCoverage, ... cssCoverage];
400
266
 
401
267
  ```
268
+ For more examples, see [./test/test-v8.js](./test/test-v8.js), and [anonymous](./test/test-anonymous.js), [css](./test/test-css.js)
402
269
 
403
- ## Collecting Raw V8 Coverage Data with Puppeteer
404
- > Puppeteer does not provide raw v8 coverage data by default. A simple conversion is required, see example: [./test/test-puppeteer.js](./test/test-puppeteer.js)
270
+ ### Collecting Raw V8 Coverage Data with Puppeteer
405
271
  ```js
406
272
  await Promise.all([
407
273
  page.coverage.startJSCoverage({
@@ -414,7 +280,7 @@ await Promise.all([
414
280
  })
415
281
  ]);
416
282
 
417
- await page.goto(url);
283
+ await page.goto("your page url");
418
284
 
419
285
  const [jsCoverage, cssCoverage] = await Promise.all([
420
286
  page.coverage.stopJSCoverage(),
@@ -429,8 +295,9 @@ const coverageData = [... jsCoverage.map((it) => {
429
295
  };
430
296
  }), ... cssCoverage];
431
297
  ```
298
+ Example: [./test/test-puppeteer.js](./test/test-puppeteer.js)
432
299
 
433
- ## Node.js V8 Coverage Report for Server Side
300
+ ### Collecting V8 Coverage Data from Node.js
434
301
  Possible solutions:
435
302
  - [NODE_V8_COVERAGE](https://nodejs.org/docs/latest/api/cli.html#node_v8_coveragedir)=`dir`
436
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.
@@ -463,8 +330,8 @@ Possible solutions:
463
330
  - [Child Process](https://nodejs.org/docs/latest/api/child_process.html) + NODE_V8_COVERAGE
464
331
  - see [Command Line](#command-line)
465
332
 
466
- ## Collecting V8 Coverage Data with `CDPClient` API
467
- - Work with node debugger `--inspect=9229`
333
+ ### Collecting V8 Coverage Data with `CDPClient` API
334
+ - Work with node debugger port `--inspect=9229`
468
335
  ```js
469
336
  const MCR = require('monocart-coverage-reports');
470
337
  const client = await MCR.CDPClient({
@@ -506,94 +373,129 @@ await client.startCoverage();
506
373
  await page.goto("your page url");
507
374
  const coverageData = await client.stopCoverage();
508
375
  ```
509
-
510
- ## Multiprocessing Support
511
- > The data will be added to `[outputDir]/.cache`, After the generation of the report, this data will be removed unless debugging has been enabled or a raw report has been used, see [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap)
512
- - Main process, before the start of testing
376
+ - Work with [Selenium Webdriver](https://www.selenium.dev/documentation/webdriver/) WebSocket (Chrome/Edge Browser)
513
377
  ```js
378
+ const { Builder, Browser } = require('selenium-webdriver');
514
379
  const MCR = require('monocart-coverage-reports');
515
- const coverageOptions = require('path-to/same-options.js');
516
- const coverageReport = MCR(coverageOptions);
517
- // clean previous cache before the start of testing
518
- // unless the running environment is new and no cache
519
- coverageReport.cleanCache();
520
- ```
521
-
522
- - Sub process 1, testing stage 1
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
+ ```
410
+
411
+ ### V8 Coverage Data API
412
+ - [JavaScript code coverage in V8](https://v8.dev/blog/javascript-code-coverage)
413
+ - [Playwright Coverage Class](https://playwright.dev/docs/api/class-coverage)
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)
523
416
  ```js
524
- const MCR = require('monocart-coverage-reports');
525
- const coverageOptions = require('path-to/same-options.js');
526
- const coverageReport = MCR(coverageOptions);
527
- // do not clean cache in the stage
528
- await coverageReport.add(coverageData1);
417
+ // Coverage data for a source range.
418
+ export interface CoverageRange {
419
+ // JavaScript script source offset for the range start.
420
+ startOffset: integer;
421
+ // JavaScript script source offset for the range end.
422
+ endOffset: integer;
423
+ // Collected execution count of the source range.
424
+ count: integer;
425
+ }
426
+ // Coverage data for a JavaScript function.
427
+ /**
428
+ * @functionName can be an empty string.
429
+ * @ranges is always non-empty. The first range is called the "root range".
430
+ * @isBlockCoverage indicates if the function has block coverage information.
431
+ If this is false, it usually means that the functions was never called.
432
+ It seems to be equivalent to ranges.length === 1 && ranges[0].count === 0.
433
+ */
434
+ export interface FunctionCoverage {
435
+ // JavaScript function name.
436
+ functionName: string;
437
+ // Source ranges inside the function with coverage data.
438
+ ranges: CoverageRange[];
439
+ // Whether coverage data for this function has block granularity.
440
+ isBlockCoverage: boolean;
441
+ }
442
+ // Coverage data for a JavaScript script.
443
+ export interface ScriptCoverage {
444
+ // JavaScript script id.
445
+ scriptId: Runtime.ScriptId;
446
+ // JavaScript script name or url.
447
+ url: string;
448
+ // Functions contained in the script that has coverage data.
449
+ functions: FunctionCoverage[];
450
+ }
451
+ export type V8CoverageData = ScriptCoverage[];
529
452
  ```
530
453
 
531
- - Sub process 2, testing stage 2
532
- ```js
533
- const MCR = require('monocart-coverage-reports');
534
- const coverageOptions = require('path-to/same-options.js');
535
- const coverageReport = MCR(coverageOptions);
536
- // do not clean cache in the stage
537
- await coverageReport.add(coverageData2);
538
- ```
454
+ ## Using `entryFilter` and `sourceFilter` to filter the results for V8 report
455
+ When V8 coverage data collected, it actually contains the data of all entry files, for example:
539
456
 
540
- - Main process, after the completion of testing
541
- ```js
542
- // generate coverage reports after the completion of testing
543
- const MCR = require('monocart-coverage-reports');
544
- const coverageOptions = require('path-to/same-options.js');
545
- const coverageReport = MCR(coverageOptions);
546
- // do not clean cache before generating reports
547
- await coverageReport.generate();
548
- ```
457
+ - *dist/main.js*
458
+ - *dist/vendor.js*
459
+ - *dist/something-else.js*
549
460
 
550
- ## Merge Coverage Reports
551
- The following usage scenarios may require merging coverage reports:
552
- - When the code is executed in different environments, like Node.js Server Side and browser Client Side (Next.js for instance). Each environment may generate its own coverage report. Merging them can give a more comprehensive view of the test coverage. see example [nextjs-with-playwright](https://github.com/cenfun/nextjs-with-playwright) for automatic report merging.
553
- - When the code is subjected to different kinds of testing. For example, unit tests with Jest might cover certain parts of the code, while end-to-end tests with Playwright might cover other parts. Merging these different coverage reports can provide a holistic view of what code has been tested.
554
- - When tests are run on different machines or different shards, each might produce its own coverage report. Merging these can give a complete picture of the test coverage across all machines or shards.
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.
555
462
 
556
- If the reports cannot be merged automatically, then here is how to manually merge the reports.
557
- First, using the `raw` report to export the original coverage data to the specified directory.
463
+ - *dist/main.js*
464
+
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`.
466
+
467
+ - *src/index.js*
468
+ - *src/components/app.js*
469
+ - *node_modules/dependency/dist/dependency.js*
470
+
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.
472
+
473
+ - *src/index.js*
474
+ - *src/components/app.js*
475
+
476
+ For example:
558
477
  ```js
559
478
  const coverageOptions = {
560
- name: 'My Unit Test Coverage Report',
561
- outputDir: "./coverage-reports/unit",
562
- reports: [
563
- ['raw', {
564
- // relative path will be "./coverage-reports/unit/raw"
565
- outputDir: "raw"
566
- }],
567
- ['v8'],
568
- ['console-summary']
569
- ]
479
+ entryFilter: (entry) => entry.url.indexOf("main.js") !== -1,
480
+ sourceFilter: (sourcePath) => sourcePath.search(/src\//) !== -1
570
481
  };
571
482
  ```
572
- Then, after all the tests are completed, generate a merged report with option `inputDir`:
483
+ Or using `minimatch` pattern:
573
484
  ```js
574
- // esm syntax
575
- import fs from "fs";
576
- import { CoverageReport } from 'monocart-coverage-reports';
577
485
  const coverageOptions = {
578
- name: 'My Merged Coverage Report',
579
- inputDir: [
580
- './coverage-reports/unit/raw',
581
- './coverage-reports/e2e/raw'
582
- ],
583
- outputDir: './coverage-reports/merged',
584
- reports: [
585
- ['v8'],
586
- ['console-summary']
587
- ],
588
- onEnd: () => {
589
- // remove the raw files if it useless
590
- fs.rmSync('./coverage-reports/unit/raw', {
591
- recursive: true,
592
- force: true
593
- })
486
+ entryFilter: "**/main.js",
487
+ sourceFilter: "**/src/**"
488
+ };
489
+ // supports multiple patterns:
490
+ const coverageOptions = {
491
+ entryFilter: {
492
+ '**/vendor.js': false,
493
+ '**/main.js': true
494
+ },
495
+ sourceFilter: {
496
+ '**/src/**': true
594
497
  }
595
498
  };
596
- await new CoverageReport(coverageOptions).generate();
597
499
  ```
598
500
 
599
501
  ## Resolve `sourcePath` for the Source Files
@@ -660,6 +562,37 @@ const coverageOptions = {
660
562
  };
661
563
  ```
662
564
 
565
+ ## onEnd Hook
566
+ For example, checking thresholds:
567
+ ```js
568
+ const EC = require('eight-colors');
569
+ const coverageOptions = {
570
+ name: 'My Coverage Report',
571
+ outputDir: './coverage-reports',
572
+ onEnd: (coverageResults) => {
573
+ const thresholds = {
574
+ bytes: 80,
575
+ lines: 60
576
+ };
577
+ console.log('check thresholds ...', thresholds);
578
+ const errors = [];
579
+ const { summary } = coverageResults;
580
+ Object.keys(thresholds).forEach((k) => {
581
+ const pct = summary[k].pct;
582
+ if (pct < thresholds[k]) {
583
+ errors.push(`Coverage threshold for ${k} (${pct} %) not met: ${thresholds[k]} %`);
584
+ }
585
+ });
586
+ if (errors.length) {
587
+ const errMsg = errors.join('\n');
588
+ console.log(EC.red(errMsg));
589
+ // throw new Error(errMsg);
590
+ // process.exit(1);
591
+ }
592
+ }
593
+ }
594
+ ```
595
+
663
596
  ## Ignoring Uncovered Codes
664
597
  To ignore codes, use the special comment which starts with `v8 ignore `:
665
598
  - Ignoring all until stop
@@ -682,103 +615,196 @@ if (platform === 'linux') {
682
615
  }
683
616
  ```
684
617
 
685
- ## Chromium Coverage API
686
- - [V8 coverage report](https://v8.dev/blog/javascript-code-coverage) - Native support for JavaScript code coverage to V8. (Chromium only)
687
- - [Playwright Coverage Class](https://playwright.dev/docs/api/class-coverage)
688
- - [Puppeteer Coverage class](https://pptr.dev/api/puppeteer.coverage)
689
- - [DevTools Protocol for Coverage](https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#method-startPreciseCoverage)
618
+ ## Multiprocessing Support
619
+ > The data will be added to `[outputDir]/.cache`, After the generation of the report, this data will be removed unless debugging has been enabled or a raw report has been used, see [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap)
620
+ - Main process, before the start of testing
621
+ ```js
622
+ const MCR = require('monocart-coverage-reports');
623
+ const coverageOptions = require('path-to/same-options.js');
624
+ const mcr = MCR(coverageOptions);
625
+ // clean previous cache before the start of testing
626
+ // unless the running environment is new and no cache
627
+ mcr.cleanCache();
628
+ ```
690
629
 
691
- ## V8 Coverage Data Format
630
+ - Sub process 1, testing stage 1
692
631
  ```js
693
- // Coverage data for a source range.
694
- export interface CoverageRange {
695
- // JavaScript script source offset for the range start.
696
- startOffset: integer;
697
- // JavaScript script source offset for the range end.
698
- endOffset: integer;
699
- // Collected execution count of the source range.
700
- count: integer;
701
- }
632
+ const MCR = require('monocart-coverage-reports');
633
+ const coverageOptions = require('path-to/same-options.js');
634
+ const mcr = MCR(coverageOptions);
635
+ await mcr.add(coverageData1);
636
+ ```
702
637
 
703
- // Coverage data for a JavaScript function.
704
- /**
705
- * @functionName can be an empty string.
706
- * @ranges is always non-empty. The first range is called the "root range".
707
- * @isBlockCoverage indicates if the function has block coverage information.
708
- If this is false, it usually means that the functions was never called.
709
- It seems to be equivalent to ranges.length === 1 && ranges[0].count === 0.
710
- */
711
- export interface FunctionCoverage {
712
- // JavaScript function name.
713
- functionName: string;
714
- // Source ranges inside the function with coverage data.
715
- ranges: CoverageRange[];
716
- // Whether coverage data for this function has block granularity.
717
- isBlockCoverage: boolean;
718
- }
638
+ - Sub process 2, testing stage 2
639
+ ```js
640
+ const MCR = require('monocart-coverage-reports');
641
+ const coverageOptions = require('path-to/same-options.js');
642
+ const mcr = MCR(coverageOptions);
643
+ await mcr.add(coverageData2);
644
+ ```
719
645
 
720
- // Coverage data for a JavaScript script.
721
- export interface ScriptCoverage {
722
- // JavaScript script id.
723
- scriptId: Runtime.ScriptId;
724
- // JavaScript script name or url.
725
- url: string;
726
- // Functions contained in the script that has coverage data.
727
- functions: FunctionCoverage[];
728
- }
646
+ - Main process, after the completion of testing
647
+ ```js
648
+ // generate coverage reports after the completion of testing
649
+ const MCR = require('monocart-coverage-reports');
650
+ const coverageOptions = require('path-to/same-options.js');
651
+ const mcr = MCR(coverageOptions);
652
+ await mcr.generate();
653
+ ```
729
654
 
730
- export type V8CoverageData = ScriptCoverage[];
655
+ ## Command Line
656
+ > 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`.
657
+
658
+ - Installing globally
659
+ ```sh
660
+ npm i monocart-coverage-reports -g
661
+ mcr node ./test/specs/node.test.js -r v8,console-details --lcov
731
662
  ```
732
- see devtools-protocol [ScriptCoverage](https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#type-ScriptCoverage) and [v8-coverage](https://github.com/bcoe/v8-coverage)
733
663
 
734
- ## How to convert V8 to Istanbul
735
- ### Using [v8-to-istanbul](https://github.com/istanbuljs/v8-to-istanbul)
736
- It is a popular library which is used to convert V8 coverage format to istanbul's coverage format. Most test frameworks are using it, such as [Jest](https://github.com/jestjs/jest/), [Vitest](https://github.com/vitest-dev/vitest), but it has two major problems:
737
- - 1, The source mapping does not work well if the position is between the two consecutive mappings. for example:
738
- ```js
739
- const a = tf ? 'true' : 'false';
740
- ^ ^ ^
741
- m1 p m2
664
+ - Locally in your project
665
+ ```sh
666
+ npm i monocart-coverage-reports
667
+ npx mcr node ./test/specs/node.test.js -r v8,console-details --lcov
742
668
  ```
743
- > `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.
744
669
 
745
- - 2, The coverage of functions and branches is incorrect. V8 only provided coverage at functions and it's blocks. But if a function is uncovered (count = 0), there is no information for it's blocks and sub-level functions. And also there are some problems about counting the functions and branches.
670
+ - CLI Options
671
+ ```sh
672
+ Usage: mcr [options] [command]
746
673
 
747
- ### How Monocart Works
748
- We implemented new converter:
749
- - 1, Trying to fix the middle position if not found the exact mapping for the position.
750
- - 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`.
674
+ CLI to generate coverage reports
751
675
 
752
- | AST | V8 |
753
- | :---------------------| :------------- |
754
- | AssignmentPattern | 🛇 Not Support |
755
- | ConditionalExpression | ✔ |
756
- | IfStatement | ✔ |
757
- | LogicalExpression | ✔ |
758
- | SwitchStatement | ✔ |
676
+ Arguments:
677
+ command command to execute
759
678
 
760
- ## Debug for Coverage and Sourcemap
761
- > Sometimes, the coverage is not what we expect. The next step is to figure out why, and we can easily find out the answer step by step through debugging.
762
- - Start debugging for v8 report with option `logging: 'debug'`
679
+ Options:
680
+ -V, --version output the version number
681
+ -c, --config <path> custom config file path
682
+ -l, --logging <logging> off, error, info, debug
683
+ -n, --name <name> report name for title
684
+ -r, --reports <name[,name]> coverage reports to use
685
+ -o, --outputDir <dir> output dir for reports
686
+ -i, --inputDir <dir> input dir for merging raw files
687
+ --entryFilter <pattern> entry url filter
688
+ --sourceFilter <pattern> source path filter
689
+ --outputFile <path> output file for v8 report
690
+ --inline inline html for v8 report
691
+ --assetsPath <path> assets path if not inline
692
+ --lcov generate lcov.info file
693
+ --import <module> preload module at startup
694
+ --require <module> preload module at startup
695
+ -h, --help display help for command
696
+ ```
697
+
698
+ - Use `--` to separate sub CLI args
699
+ ```sh
700
+ mcr -c mcr.config.js -- sub-cli -c sub-cli.config.js
701
+ ```
702
+
703
+ ## Config File
704
+ Loading config file by priority:
705
+ - Custom config file:
706
+ - CLI: `mcr --config <my-config-file-path>`
707
+ - API: `await mcr.loadConfig("my-config-file-path")`
708
+ - `mcr.config.js`
709
+ - `mcr.config.cjs`
710
+ - `mcr.config.mjs`
711
+ - `mcr.config.json` - json format
712
+ - `mcr.config.ts` (requires preloading the ts execution module)
713
+ - `.mcrrc.js`
714
+ - `.mcrrc` - json format
715
+
716
+ ## Merge Coverage Reports
717
+ The following usage scenarios may require merging coverage reports:
718
+ - When the code is executed in different environments, like Node.js Server Side and browser Client Side (Next.js for instance). Each environment may generate its own coverage report. Merging them can give a more comprehensive view of the test coverage. see example [nextjs-with-playwright](https://github.com/cenfun/nextjs-with-playwright) for automatic report merging.
719
+ - When the code is subjected to different kinds of testing. For example, unit tests with Jest might cover certain parts of the code, while end-to-end tests with Playwright might cover other parts. Merging these different coverage reports can provide a holistic view of what code has been tested.
720
+ - When tests are run on different machines or different shards, each might produce its own coverage report. Merging these can give a complete picture of the test coverage across all machines or shards.
721
+
722
+ If the reports cannot be merged automatically, then here is how to manually merge the reports.
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:
763
725
  ```js
764
726
  const coverageOptions = {
765
- logging: 'debug',
727
+ name: 'My Unit Test Coverage Report',
728
+ outputDir: "./coverage-reports/unit",
766
729
  reports: [
730
+ ['raw', {
731
+ // relative path will be "./coverage-reports/unit/raw"
732
+ // defaults to raw
733
+ outputDir: "raw"
734
+ }],
767
735
  ['v8'],
768
- ['console-summary']
736
+ ['console-details']
769
737
  ]
770
738
  };
771
739
  ```
772
- When `logging` is `debug`, the raw report data will be preserved in `[outputDir]/.cache` or `[outputDir]/raw` if `raw` report is used. And the dist file will be preserved in the V8 list, and by opening the browser's devtool, it makes data verification visualization effortless.
773
- ![](./assets/debug-coverage.png)
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`:
742
+ ```js
743
+ // merge-coverage.js
744
+ const fs = require('fs');
745
+ const { CoverageReport } = require('monocart-coverage-reports');
746
+ const inputDir = [
747
+ './coverage-reports/unit/raw',
748
+ './coverage-reports/e2e/raw'
749
+ ];
750
+ const coverageOptions = {
751
+ name: 'My Merged Coverage Report',
752
+ inputDir,
753
+ outputDir: './coverage-reports/merged',
774
754
 
775
- - Check sourcemap with [Source Map Visualization](https://evanw.github.io/source-map-visualization/)
755
+ // filter for both unit and e2e
756
+ entryFilter: {
757
+ '**/node_modules/**': false,
758
+ '**/*': true
759
+ },
760
+ sourceFilter: {
761
+ '**/node_modules/**': false,
762
+ '**/src/**': true
763
+ },
764
+
765
+ sourcePath: (filePath, info) => {
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/", "")
771
+ return filePath;
772
+ },
776
773
 
777
- ![](./assets/debug-sourcemap.png)
774
+ reports: [
775
+ ['v8'],
776
+ ['console-details']
777
+ ],
778
+
779
+ onEnd: () => {
780
+ // remove the raw files if it useless
781
+ // inputDir.forEach((p) => {
782
+ // fs.rmSync(p, {
783
+ // recursive: true,
784
+ // force: true
785
+ // });
786
+ // });
787
+ }
788
+ };
789
+ await new CoverageReport(coverageOptions).generate();
790
+ ```
778
791
 
779
792
  ## Common issues
780
- - `Unparsable source`
793
+ ### Unexpected coverage
794
+ In most cases, it happens when the coverage of the generated code is converted to the coverage of the original code through a sourcemap. In other words, it's an issue with the sourcemap. Most of the time, we can solve this by setting `minify` to `false` in the build tools configuration. Let's take a look at an example:
795
+ ```js
796
+ const a = tf ? 'true' : 'false';
797
+ ^ ^ ^
798
+ m1 p m2
799
+ ```
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)
801
+
802
+ How `MCR` Works:
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.
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`.
781
805
 
806
+
807
+ ### Unparsable source
782
808
  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.
783
809
  ```js
784
810
  import * as fs from "fs";
@@ -798,9 +824,38 @@ const coverageOptions = {
798
824
  }
799
825
  ```
800
826
 
801
- ## Integration
827
+ ## Debug for Coverage and Sourcemap
828
+ > Sometimes, the coverage is not what we expect. The next step is to figure out why, and we can easily find out the answer step by step through debugging.
829
+ - Start debugging for v8 report with option `logging: 'debug'`
830
+ ```js
831
+ const coverageOptions = {
832
+ logging: 'debug',
833
+ reports: [
834
+ ['v8'],
835
+ ['console-details']
836
+ ]
837
+ };
838
+ ```
839
+ When `logging` is `debug`, the raw report data will be preserved in `[outputDir]/.cache` or `[outputDir]/raw` if `raw` report is used. And the dist file will be preserved in the V8 list, and by opening the browser's devtool, it makes data verification visualization effortless.
840
+ ![](./assets/debug-coverage.png)
841
+
842
+ - Check sourcemap with [Source Map Visualization](https://evanw.github.io/source-map-visualization/)
843
+
844
+ ![](./assets/debug-sourcemap.png)
845
+
846
+ ## Integration with Any Testing Framework
847
+ - API
848
+ - Collecting coverage data when any stage of the test is completed, and adding the coverage data to the coverage reporter. `await mcr.add(coverageData)`
849
+ - Generating the coverage reports after the completion of all tests. `await mcr.generate()`
850
+ - see [Multiprocessing Support](#multiprocessing-support)
851
+ - CLI
852
+ - Wrapping with any CLI. `mcr your-cli --your-arguments`
853
+ - see [Command line](#command-line)
854
+
855
+ ## Integration Examples
802
856
 
803
857
  ### [Playwright](https://github.com/microsoft/playwright)
858
+ - [playwright-coverage](https://github.com/cenfun/playwright-coverage) - A Example for Playwright Coverage Reports
804
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)
805
860
  - Coverage for component testing:
806
861
  - [playwright-ct-vue](https://github.com/cenfun/playwright-ct-vue)
@@ -812,6 +867,7 @@ const coverageOptions = {
812
867
 
813
868
  ### [Jest](https://github.com/jestjs/jest/)
814
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
815
871
  - Example for Jest (unit) + Puppeteer (e2e) + Codecov: [maplibre-gl-js](https://github.com/maplibre/maplibre-gl-js)
816
872
 
817
873
  ### [Vitest](https://github.com/vitest-dev/vitest)
@@ -833,6 +889,32 @@ const coverageOptions = {
833
889
  ### [TestCafe](https://github.com/DevExpress/testcafe)
834
890
  - [testcafe-reporter-coverage](https://github.com/cenfun/testcafe-reporter-coverage) - A TestCafe custom reporter for coverage reports
835
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
+
895
+ ### [Mocha](https://github.com/mochajs/mocha)
896
+ ```sh
897
+ mcr mocha ./test/**/*.js
898
+ ```
899
+ ```sh
900
+ mcr --import tsx mocha ./test/**/*.ts
901
+ ```
902
+ - see [mcr-tsx](https://github.com/cenfun/mcr-tsx)
903
+
904
+ ### [tsx](https://github.com/privatenumber/tsx)
905
+ ```sh
906
+ mcr --import tsx tsx ./src/example.ts
907
+ ```
908
+ - see [mcr-tsx](https://github.com/cenfun/mcr-tsx)
909
+
910
+ ### [ts-node](https://github.com/TypeStrong/ts-node)
911
+ - see [mcr-ts-node](https://github.com/cenfun/mcr-ts-node)
912
+
913
+ ### [AVA](https://github.com/avajs/ava)
914
+ ```sh
915
+ mcr ava
916
+ ```
917
+
836
918
  ### [Codecov](https://codecov.com/)
837
919
  [![codecov](https://codecov.io/gh/cenfun/monocart-coverage-reports/graph/badge.svg?token=H0LW7UKYU3)](https://codecov.io/gh/cenfun/monocart-coverage-reports)
838
920
  - Supports native `codecov` built-in report ([specification](https://docs.codecov.com/docs/codecov-custom-coverage-format))
@@ -886,10 +968,6 @@ const coverageOptions = {
886
968
  -Dsonar.tests=test
887
969
  -Dsonar.exclusions=dist/*,packages/*
888
970
  ```
889
- ### Integration with Any Testing Framework
890
- - Collecting coverage data when any stage of the test is completed, and adding the coverage data to the coverage reporter.
891
- - Generating the coverage reports after the completion of all tests.
892
- - see [Multiprocessing Support](#multiprocessing-support)
893
971
 
894
972
  ### VSCode Extension
895
973
  - [Coverage Gutters](https://github.com/ryanluker/vscode-coverage-gutters) - Display test coverage generated by lcov or xml in VSCode editor.