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 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
- - [Node.js V8 Coverage Report for Server Side](#nodejs-v8-coverage-report-for-server-side)
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
- - [API](#multiprocessing-support)
57
+ - API
57
58
  ```js
58
59
  const MCR = require('monocart-coverage-reports');
59
- const coverageOptions = {
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
- const mcr = MCR(coverageOptions);
65
- mcr.cleanCache();
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
- - [CLI](#command-line)
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 istanbul data):
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 istanbul data):
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
- - istanbul custom reporter
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
- - v8 custom reporter
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
- > Before collecting Istanbul coverage data, It requires your source code is instrumented with Istanbul
221
- - webpack: [babel-plugin-istanbul](https://github.com/istanbuljs/babel-plugin-istanbul), example: [webpack.config-istanbul.js](./test/webpack.config-istanbul.js)
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
- - Sourcemap for source code: enable `sourcemap` and do not compress/minify:
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
- - [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)
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
- see example: [./test/test-puppeteer.js](./test/test-puppeteer.js)
298
+ Example: [./test/test-puppeteer.js](./test/test-puppeteer.js)
298
299
 
299
- ### Node.js V8 Coverage Report for Server Side
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
- - [V8 coverage report](https://v8.dev/blog/javascript-code-coverage) - Native support for JavaScript code coverage to V8. (Chromium only)
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 class](https://pptr.dev/api/puppeteer.coverage)
380
- - [DevTools Protocol for Coverage](https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#method-startPreciseCoverage) see devtools-protocol [ScriptCoverage](https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#type-ScriptCoverage) and [v8-coverage](https://github.com/bcoe/v8-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)
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
- > src/index.js
436
- > src/components/app.js
437
- > node_modules/dependency/dist/dependency.js
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
- > src/index.js
442
- > src/components/app.js
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-summary --lcov
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-summary --lcov
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-summary']
736
+ ['console-details']
706
737
  ]
707
738
  };
708
739
  ```
709
- Then, after all the tests are completed, generate a merged report with option `inputDir`:
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
- fs.rmSync(p, {
746
- recursive: true,
747
- force: true
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 if not found the exact mapping for the position. However, for non-JS code, such as Vue template, JSX, etc., it might be hard to find a perfect solution.
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-summary']
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 (!isFeatureSupported(nv)) {
42
- Util.logInfo(EC.yellow(`The current Node.js version "${nv}" does NOT support "module.register", it requires "20.6.0" or higher.`));
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 = profileResponse.result;
135
- // console.log('coverageList', coverageList);
134
+ const jsCoverage = [];
136
135
 
137
- jsCoverage.forEach((entry) => {
138
- // anonymous url
139
- entry.url = entry.url || '';
140
- // add source
141
- const source = this.scriptSources.get(entry.scriptId);
142
- if (!source) {
143
- Util.logDebug(`Not found js source: ${entry.url}`);
144
- }
145
- entry.source = source || '';
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
- return [... jsCoverage, ... cssCoverage];
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
- // // enable and start v8 coverage
266
+ if (!this.session) {
267
+ return;
268
+ }
269
+
253
270
  await this.session.send('Runtime.enable');
254
271
 
255
- // write the coverage started by NODE_V8_COVERAGE to disk on demand
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: 'new Promise(resolve=>{ require("v8").takeCoverage(); resolve(process.env.NODE_V8_COVERAGE); })',
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.6",
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 ./scripts/build-test.js",
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": "npm run test-node-env && npm run test-node-api && npm run test-node-ins && npm run test-node-cdp && npm run test-node-vm && npm run test-node-koa",
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": "npm run test-istanbul && npm run test-v8 && npm run test-puppeteer && npm run test-anonymous && npm run test-css && npm run test-minify && npm run test-esbuild && npm run test-rollup && npm run test-v8-and-istanbul",
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": "npm run test-node && npm run test-browser && npm run test-cli && npm run test-tsx && npm run test-merge && node ./scripts/docs.js",
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.2.1",
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",