monocart-coverage-reports 2.7.7 → 2.7.9
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 +116 -52
- package/lib/cli.js +55 -28
- package/lib/client/cdp-client.js +1 -4
- 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.js +3 -1
- package/lib/packages/monocart-coverage-v8.js +1 -1
- package/lib/packages/monocart-coverage-vendor.js +2 -2
- package/lib/register/hooks.js +58 -58
- package/lib/register/hooks.mjs +3 -3
- package/lib/utils/request.js +26 -7
- package/lib/utils/source-path.js +15 -5
- package/lib/utils/util.js +27 -6
- package/lib/v8/v8.js +7 -8
- package/package.json +13 -10
package/README.md
CHANGED
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
* [Command Line](#command-line)
|
|
29
29
|
* [Config File](#config-file)
|
|
30
30
|
* [Merge Coverage Reports](#merge-coverage-reports)
|
|
31
|
+
- [Automatic Merging](#automatic-merging)
|
|
32
|
+
- [Manual Merging](#manual-merging)
|
|
31
33
|
* [Common issues](#common-issues)
|
|
32
34
|
- [Unexpected coverage](#unexpected-coverage)
|
|
33
35
|
- [Unparsable source](#unparsable-source)
|
|
@@ -50,10 +52,16 @@
|
|
|
50
52
|
- [Codecov](#codecov)
|
|
51
53
|
- [Coveralls](#coveralls)
|
|
52
54
|
- [Sonar Cloud](#sonar-cloud)
|
|
55
|
+
* [Contributing](#contributing)
|
|
56
|
+
* [Changelog](CHANGELOG.md)
|
|
53
57
|
* [Thanks](#thanks)
|
|
54
58
|
|
|
55
59
|
## Usage
|
|
56
60
|
> It's recommended to use [Node.js 20+](https://nodejs.org/).
|
|
61
|
+
- Install
|
|
62
|
+
```sh
|
|
63
|
+
npm install monocart-coverage-reports
|
|
64
|
+
```
|
|
57
65
|
- API
|
|
58
66
|
```js
|
|
59
67
|
const MCR = require('monocart-coverage-reports');
|
|
@@ -81,16 +89,8 @@ mcr node my-app.js -r v8,console-details
|
|
|
81
89
|
For more information, see [Command Line](#command-line)
|
|
82
90
|
|
|
83
91
|
## Options
|
|
84
|
-
- Default
|
|
85
|
-
|
|
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)
|
|
87
|
-
- `sourcePath` [Resolve `sourcePath` for the Source Files](#resolve-sourcepath-for-the-source-files)
|
|
88
|
-
- `all` [Adding Empty Coverage for Untested Files](#adding-empty-coverage-for-untested-files)
|
|
89
|
-
- `inputDir` [Merge Coverage Reports](#merge-coverage-reports)
|
|
90
|
-
- `logging` [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap)
|
|
91
|
-
- `onEnd` [onEnd Hook](#onend-hook)
|
|
92
|
-
|
|
93
|
-
- Declaration: [lib/index.d.ts](./lib/index.d.ts)
|
|
92
|
+
- Default options: [lib/default/options.js](./lib/default/options.js)
|
|
93
|
+
- Options declaration see `CoverageReportOptions` [lib/index.d.ts](./lib/index.d.ts)
|
|
94
94
|
- [Config file](#config-file)
|
|
95
95
|
|
|
96
96
|
## Available Reports
|
|
@@ -222,19 +222,24 @@ const mcr = MCR(coverageOptions);
|
|
|
222
222
|
- vite: [vite-plugin-istanbul](https://github.com/ifaxity/vite-plugin-istanbul)
|
|
223
223
|
- rollup: [rollup-plugin-istanbul](https://github.com/artberri/rollup-plugin-istanbul)
|
|
224
224
|
- swc: [swc-plugin-coverage-instrument](https://github.com/kwonoj/swc-plugin-coverage-instrument)
|
|
225
|
+
|
|
225
226
|
- Browser
|
|
226
227
|
- Collecting coverage data from `window.__coverage__`, example: [test-istanbul.js](./test/test-istanbul.js)
|
|
228
|
+
|
|
227
229
|
- Node.js
|
|
228
230
|
- Collecting coverage data from `global.__coverage__`
|
|
229
231
|
|
|
232
|
+
- CDP
|
|
233
|
+
- `getIstanbulCoverage()` see [`CDPClient` API](#collecting-v8-coverage-data-with-cdpclient-api)
|
|
234
|
+
|
|
230
235
|
## Collecting V8 Coverage Data
|
|
231
236
|
- Before coverage collection: Enabling `sourcemap` for source code
|
|
232
237
|
- [webpack](https://webpack.js.org/configuration/): `devtool: source-map` and `mode: development`, example [webpack.config-v8.js](./test/build/webpack.config-v8.js)
|
|
233
|
-
- [rollup](https://rollupjs.org/configuration-options/): `sourcemap: true`
|
|
238
|
+
- [rollup](https://rollupjs.org/configuration-options/): `sourcemap: true` and `treeshake: false`
|
|
239
|
+
- [esbuild](https://esbuild.github.io/api/): `sourcemap: true`, `treeShaking: false` and `minify: false`
|
|
234
240
|
- [vite](https://vitejs.dev/config/build-options.html): `sourcemap: true` and `minify: false`
|
|
235
|
-
- [esbuild](https://esbuild.github.io/api/): `sourcemap: true` and `minify: false`
|
|
236
241
|
|
|
237
|
-
- Browser (Chromium Only)
|
|
242
|
+
- Browser (Chromium-based Only)
|
|
238
243
|
- [Collecting V8 Coverage Data with Playwright](#collecting-v8-coverage-data-with-playwright)
|
|
239
244
|
- [Collecting Raw V8 Coverage Data with Puppeteer](#collecting-raw-v8-coverage-data-with-puppeteer)
|
|
240
245
|
|
|
@@ -248,9 +253,11 @@ const mcr = MCR(coverageOptions);
|
|
|
248
253
|
```js
|
|
249
254
|
await Promise.all([
|
|
250
255
|
page.coverage.startJSCoverage({
|
|
256
|
+
// reportAnonymousScripts: true,
|
|
251
257
|
resetOnNavigation: false
|
|
252
258
|
}),
|
|
253
259
|
page.coverage.startCSSCoverage({
|
|
260
|
+
// Note, anonymous styles (without sourceURLs) are not supported, alternatively, you can use CDPClient
|
|
254
261
|
resetOnNavigation: false
|
|
255
262
|
})
|
|
256
263
|
]);
|
|
@@ -267,10 +274,12 @@ const coverageData = [... jsCoverage, ... cssCoverage];
|
|
|
267
274
|
```
|
|
268
275
|
For more examples, see [./test/test-v8.js](./test/test-v8.js), and [anonymous](./test/test-anonymous.js), [css](./test/test-css.js)
|
|
269
276
|
|
|
277
|
+
|
|
270
278
|
### Collecting Raw V8 Coverage Data with Puppeteer
|
|
271
279
|
```js
|
|
272
280
|
await Promise.all([
|
|
273
281
|
page.coverage.startJSCoverage({
|
|
282
|
+
// reportAnonymousScripts: true,
|
|
274
283
|
resetOnNavigation: false,
|
|
275
284
|
// provide raw v8 coverage data
|
|
276
285
|
includeRawScriptCoverage: true
|
|
@@ -331,7 +340,27 @@ Possible solutions:
|
|
|
331
340
|
- see [Command Line](#command-line)
|
|
332
341
|
|
|
333
342
|
### Collecting V8 Coverage Data with `CDPClient` API
|
|
334
|
-
-
|
|
343
|
+
- `CDPClient` available APIs
|
|
344
|
+
```js
|
|
345
|
+
startJSCoverage: () => Promise<void>;
|
|
346
|
+
stopJSCoverage: () => Promise<V8CoverageEntry[]>;
|
|
347
|
+
|
|
348
|
+
startCSSCoverage: () => Promise<void>;
|
|
349
|
+
stopCSSCoverage: () => Promise<V8CoverageEntry[]>;
|
|
350
|
+
|
|
351
|
+
/** start both js and css coverage */
|
|
352
|
+
startCoverage: () => Promise<void>;
|
|
353
|
+
/** stop and return both js and css coverage */
|
|
354
|
+
stopCoverage: () => Promise<V8CoverageEntry[]>;
|
|
355
|
+
|
|
356
|
+
/** write the coverage started by NODE_V8_COVERAGE to disk on demand, returns v8 coverage dir */
|
|
357
|
+
writeCoverage: () => Promise<string>;
|
|
358
|
+
|
|
359
|
+
/** get istanbul coverage data */
|
|
360
|
+
getIstanbulCoverage: (coverageKey?: string) => Promise<any>;
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
- Work with node debugger port `--inspect=9229` or browser debugging port `--remote-debugging-port=9229`
|
|
335
364
|
```js
|
|
336
365
|
const MCR = require('monocart-coverage-reports');
|
|
337
366
|
const client = await MCR.CDPClient({
|
|
@@ -341,6 +370,7 @@ await client.startJSCoverage();
|
|
|
341
370
|
// run your test here
|
|
342
371
|
const coverageData = await client.stopJSCoverage();
|
|
343
372
|
```
|
|
373
|
+
|
|
344
374
|
- Work with [Playwright CDPSession](https://playwright.dev/docs/api/class-cdpsession)
|
|
345
375
|
```js
|
|
346
376
|
const { chromium } = require('playwright');
|
|
@@ -357,6 +387,7 @@ await client.startCoverage();
|
|
|
357
387
|
await page.goto("your page url");
|
|
358
388
|
const coverageData = await client.stopCoverage();
|
|
359
389
|
```
|
|
390
|
+
|
|
360
391
|
- Work with [Puppeteer CDPSession](https://pptr.dev/api/puppeteer.cdpsession)
|
|
361
392
|
```js
|
|
362
393
|
const puppeteer = require('puppeteer');
|
|
@@ -373,6 +404,7 @@ await client.startCoverage();
|
|
|
373
404
|
await page.goto("your page url");
|
|
374
405
|
const coverageData = await client.stopCoverage();
|
|
375
406
|
```
|
|
407
|
+
|
|
376
408
|
- Work with [Selenium Webdriver](https://www.selenium.dev/documentation/webdriver/) WebSocket (Chrome/Edge Browser)
|
|
377
409
|
```js
|
|
378
410
|
const { Builder, Browser } = require('selenium-webdriver');
|
|
@@ -384,29 +416,6 @@ const client = await MCR.CDPClient({
|
|
|
384
416
|
session
|
|
385
417
|
})
|
|
386
418
|
```
|
|
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
419
|
|
|
411
420
|
### V8 Coverage Data API
|
|
412
421
|
- [JavaScript code coverage in V8](https://v8.dev/blog/javascript-code-coverage)
|
|
@@ -480,23 +489,42 @@ const coverageOptions = {
|
|
|
480
489
|
sourceFilter: (sourcePath) => sourcePath.search(/src\//) !== -1
|
|
481
490
|
};
|
|
482
491
|
```
|
|
483
|
-
Or using `minimatch` pattern:
|
|
492
|
+
Or using [`minimatch`](https://github.com/isaacs/minimatch) pattern:
|
|
484
493
|
```js
|
|
485
494
|
const coverageOptions = {
|
|
486
495
|
entryFilter: "**/main.js",
|
|
487
496
|
sourceFilter: "**/src/**"
|
|
488
497
|
};
|
|
489
|
-
|
|
498
|
+
```
|
|
499
|
+
Supports multiple patterns:
|
|
500
|
+
```js
|
|
490
501
|
const coverageOptions = {
|
|
491
502
|
entryFilter: {
|
|
503
|
+
'**/node_modules/**': false,
|
|
492
504
|
'**/vendor.js': false,
|
|
493
|
-
'**/
|
|
505
|
+
'**/src/**': true
|
|
494
506
|
},
|
|
495
507
|
sourceFilter: {
|
|
496
|
-
'**/
|
|
508
|
+
'**/node_modules/**': false,
|
|
509
|
+
'**/**': true
|
|
497
510
|
}
|
|
498
511
|
};
|
|
499
512
|
```
|
|
513
|
+
In fact, the `minimatch` patterns will be transformed to a function like:
|
|
514
|
+
```js
|
|
515
|
+
const coverageOptions = {
|
|
516
|
+
// '**/node_modules/**': false,
|
|
517
|
+
// '**/vendor.js': false,
|
|
518
|
+
// '**/src/**': true
|
|
519
|
+
entryFilter: (entry) => {
|
|
520
|
+
if (minimatch(entry.url, '**/node_modules/**')) { return false; }
|
|
521
|
+
if (minimatch(entry.url, '**/vendor.js')) { return false; }
|
|
522
|
+
if (minimatch(entry.url, '**/src/**')) { return true; }
|
|
523
|
+
return false; // else unmatched
|
|
524
|
+
}
|
|
525
|
+
// Note, the order of the patterns will impact the results
|
|
526
|
+
};
|
|
527
|
+
```
|
|
500
528
|
|
|
501
529
|
## Resolve `sourcePath` for the Source Files
|
|
502
530
|
If the source file comes from the sourcemap, then its path is a virtual path. Using the `sourcePath` option to resolve a custom path.
|
|
@@ -537,7 +565,7 @@ const coverageOptions = {
|
|
|
537
565
|
}
|
|
538
566
|
};
|
|
539
567
|
```
|
|
540
|
-
The filter also supports `minimatch` pattern:
|
|
568
|
+
The filter also supports [`minimatch`](https://github.com/isaacs/minimatch) pattern:
|
|
541
569
|
```js
|
|
542
570
|
const coverageOptions = {
|
|
543
571
|
all: {
|
|
@@ -677,7 +705,7 @@ Arguments:
|
|
|
677
705
|
command command to execute
|
|
678
706
|
|
|
679
707
|
Options:
|
|
680
|
-
-
|
|
708
|
+
-v, --version output the current version
|
|
681
709
|
-c, --config <path> custom config file path
|
|
682
710
|
-l, --logging <logging> off, error, info, debug
|
|
683
711
|
-n, --name <name> report name for title
|
|
@@ -700,6 +728,12 @@ Options:
|
|
|
700
728
|
mcr -c mcr.config.js -- sub-cli -c sub-cli.config.js
|
|
701
729
|
```
|
|
702
730
|
|
|
731
|
+
- Examples
|
|
732
|
+
- [Mocha](#mocha)
|
|
733
|
+
- [tsx](#tsx)
|
|
734
|
+
- [ts-node](#ts-node)
|
|
735
|
+
- [AVA](#ava)
|
|
736
|
+
|
|
703
737
|
## Config File
|
|
704
738
|
Loading config file by priority:
|
|
705
739
|
- Custom config file:
|
|
@@ -715,13 +749,19 @@ Loading config file by priority:
|
|
|
715
749
|
|
|
716
750
|
## Merge Coverage Reports
|
|
717
751
|
The following usage scenarios may require merging coverage reports:
|
|
718
|
-
- When the code is executed in different environments, like Node.js
|
|
752
|
+
- 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.
|
|
719
753
|
- 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
|
|
754
|
+
- When tests are run on different machines or containers, each might produce its own coverage report. Merging these can give a complete picture of the test coverage across all machines or shards.
|
|
755
|
+
|
|
756
|
+
### Automatic Merging
|
|
757
|
+
- `MCR` will automatically merge all the added coverage data when executing `generate()`. And it supports adding coverage data asynchronously across processes, see [Multiprocessing Support](#multiprocessing-support)
|
|
758
|
+
- For Next.js, it can actually add coverage data including both server side and client side before executing `generate()`, see example [nextjs-with-playwright](https://github.com/cenfun/nextjs-with-playwright)
|
|
759
|
+
- Use Codecov, a popular online code coverage service, which supports automatic merging of reports. Please use report `codecov`, it will generate report file `codecov.json`. If multiple `codecov.json` files are generated, upload all these files, they will be automatically merged. see [Codecov](#codecov) and [merging reports](https://docs.codecov.com/docs/merging-reports)
|
|
721
760
|
|
|
761
|
+
### Manual Merging
|
|
722
762
|
If the reports cannot be merged automatically, then here is how to manually merge the reports.
|
|
723
763
|
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
|
|
764
|
+
- For example, we have `raw` coverage data from unit tests, which is output to `./coverage-reports/unit/raw`
|
|
725
765
|
```js
|
|
726
766
|
const coverageOptions = {
|
|
727
767
|
name: 'My Unit Test Coverage Report',
|
|
@@ -737,8 +777,8 @@ const coverageOptions = {
|
|
|
737
777
|
]
|
|
738
778
|
};
|
|
739
779
|
```
|
|
740
|
-
We also have `raw` coverage data from e2e tests, which is output to `./coverage-reports/e2e/raw
|
|
741
|
-
|
|
780
|
+
- We also have `raw` coverage data from e2e tests, which is output to `./coverage-reports/e2e/raw`
|
|
781
|
+
- Create a script `merge-coverage.js` to generate a merged report with option `inputDir`. After all the tests are completed, running script `node path/to/merge-coverage.js`
|
|
742
782
|
```js
|
|
743
783
|
// merge-coverage.js
|
|
744
784
|
const fs = require('fs');
|
|
@@ -788,20 +828,32 @@ const coverageOptions = {
|
|
|
788
828
|
};
|
|
789
829
|
await new CoverageReport(coverageOptions).generate();
|
|
790
830
|
```
|
|
831
|
+
- All the command scripts are probably like following:
|
|
832
|
+
```json
|
|
833
|
+
{
|
|
834
|
+
"scripts": {
|
|
835
|
+
"test:unit": "jest",
|
|
836
|
+
"test:e2e": "playwright test",
|
|
837
|
+
"merge-coverage": "node path/to/merge-coverage.js",
|
|
838
|
+
"test": "npm run test:unit && npm run test:e2e && npm run merge-coverage"
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
```
|
|
791
842
|
|
|
792
843
|
## Common issues
|
|
793
844
|
### 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
|
|
845
|
+
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 configuration of build tools. Let's take a look at an example:
|
|
795
846
|
```js
|
|
796
847
|
const a = tf ? 'true' : 'false';
|
|
797
848
|
^ ^ ^
|
|
798
849
|
m1 p m2
|
|
799
850
|
```
|
|
800
|
-
|
|
851
|
+
In the generated code, there is a position `p`, and we need to find out its corresponding position in the original code. Unfortunately, there is no matched mapping for the position `p`. Instead, it has two adjacent upstream and downstream mappings `m1` and `m2`, so, the original position of `p` that we are looking for, might not be able to be precisely located. 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 original position without matched mapping.
|
|
852
|
+
- Further understanding of sourcemap, try [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap)
|
|
801
853
|
|
|
802
854
|
How `MCR` Works:
|
|
803
|
-
- 1, Trying to fix the
|
|
804
|
-
- 2, Finding all functions, statements and branches by parsing the source code [AST](https://github.com/acornjs/acorn).
|
|
855
|
+
- 1, Trying to fix the 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.
|
|
856
|
+
- 2, Finding all functions, statements and branches by parsing the source code [AST](https://github.com/acornjs/acorn). (There is a small issue is the V8 cannot provide effective branch coverage information for `AssignmentPattern`)
|
|
805
857
|
|
|
806
858
|
|
|
807
859
|
### Unparsable source
|
|
@@ -969,6 +1021,18 @@ const coverageOptions = {
|
|
|
969
1021
|
-Dsonar.exclusions=dist/*,packages/*
|
|
970
1022
|
```
|
|
971
1023
|
|
|
1024
|
+
## Contributing
|
|
1025
|
+
```sh
|
|
1026
|
+
# Node.js 20+
|
|
1027
|
+
npm install starfall-cli -g
|
|
1028
|
+
npm install
|
|
1029
|
+
|
|
1030
|
+
npm run build
|
|
1031
|
+
npm run test
|
|
1032
|
+
|
|
1033
|
+
npm run dev
|
|
1034
|
+
```
|
|
1035
|
+
|
|
972
1036
|
### VSCode Extension
|
|
973
1037
|
- [Coverage Gutters](https://github.com/ryanluker/vscode-coverage-gutters) - Display test coverage generated by lcov or xml in VSCode editor.
|
|
974
1038
|
|
package/lib/cli.js
CHANGED
|
@@ -21,53 +21,78 @@ const getRegisterPath = (filename) => {
|
|
|
21
21
|
return `./${rel}`;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
// module register added in Node.js: v20.6.0
|
|
27
|
-
const nv = process.versions.node;
|
|
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.`);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
24
|
+
const getInitNodeOptions = async (cliOptions) => {
|
|
33
25
|
const nodeOptions = [];
|
|
34
26
|
if (process.env.NODE_OPTIONS) {
|
|
35
27
|
nodeOptions.push(process.env.NODE_OPTIONS);
|
|
36
28
|
}
|
|
37
29
|
|
|
38
30
|
if (cliOptions.import) {
|
|
39
|
-
nodeOptions.push(
|
|
40
|
-
|
|
31
|
+
nodeOptions.push(`--import ${cliOptions.import}`);
|
|
32
|
+
// for load mcr.config.ts
|
|
41
33
|
await import(cliOptions.import);
|
|
42
34
|
} else if (cliOptions.require) {
|
|
43
|
-
nodeOptions.push(
|
|
44
|
-
|
|
35
|
+
nodeOptions.push(`--require ${cliOptions.require}`);
|
|
36
|
+
// for load mcr.config.ts
|
|
45
37
|
await import(cliOptions.require);
|
|
46
38
|
}
|
|
47
39
|
|
|
40
|
+
return nodeOptions;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const getPreloadType = (nodeOptions) => {
|
|
44
|
+
const hasImport = nodeOptions.find((it) => it.includes('--import'));
|
|
45
|
+
if (hasImport) {
|
|
46
|
+
return '--import';
|
|
47
|
+
}
|
|
48
|
+
return '--require';
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const checkRegisterFeature = () => {
|
|
52
|
+
const nv = process.versions.node;
|
|
53
|
+
|
|
54
|
+
// "module.register" added in Node.js: v20.6.0
|
|
55
|
+
// if (Util.cmpVersion(nv, '20.6.0') >= 0) {
|
|
56
|
+
// return true;
|
|
57
|
+
// }
|
|
58
|
+
// but also added in: v18.19.0
|
|
59
|
+
const requiredNV = '18.19.0';
|
|
60
|
+
if (Util.cmpVersion(nv, requiredNV) < 0) {
|
|
61
|
+
Util.logInfo(`The current Node.js version "${nv}" does NOT support "module.register", it requires "${requiredNV}" or higher.`);
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// could be < 20.6.0 but just ignore it, please using latest minor version
|
|
66
|
+
|
|
67
|
+
return true;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const initNodeOptions = async (cliOptions) => {
|
|
71
|
+
|
|
72
|
+
const supportRegister = checkRegisterFeature();
|
|
73
|
+
if (!supportRegister) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const nodeOptions = await getInitNodeOptions(cliOptions);
|
|
48
78
|
// console.log(nodeOptions);
|
|
49
79
|
|
|
80
|
+
const preloadType = getPreloadType(nodeOptions);
|
|
81
|
+
|
|
50
82
|
// export source after
|
|
51
|
-
|
|
52
|
-
if (hasImport) {
|
|
83
|
+
if (preloadType === '--import') {
|
|
53
84
|
const importPath = getRegisterPath('register.mjs');
|
|
54
|
-
|
|
55
|
-
if (!hasImportPath) {
|
|
56
|
-
nodeOptions.push('--import');
|
|
57
|
-
nodeOptions.push(importPath);
|
|
58
|
-
}
|
|
85
|
+
nodeOptions.push(`--import ${importPath}`);
|
|
59
86
|
} else {
|
|
60
87
|
const requirePath = getRegisterPath('register.js');
|
|
61
|
-
|
|
62
|
-
if (!hasRequirePath) {
|
|
63
|
-
nodeOptions.push('--require');
|
|
64
|
-
nodeOptions.push(requirePath);
|
|
65
|
-
}
|
|
88
|
+
nodeOptions.push(`--require ${requirePath}`);
|
|
66
89
|
}
|
|
67
90
|
|
|
68
91
|
// console.log(nodeOptions);
|
|
92
|
+
const nodeOptionsStr = nodeOptions.join(' ');
|
|
93
|
+
Util.logDebug(`node options: ${EC.cyan(nodeOptionsStr)}`);
|
|
69
94
|
|
|
70
|
-
process.env.NODE_OPTIONS =
|
|
95
|
+
process.env.NODE_OPTIONS = nodeOptionsStr;
|
|
71
96
|
|
|
72
97
|
};
|
|
73
98
|
|
|
@@ -86,6 +111,7 @@ const executeCommand = async (command, cliOptions) => {
|
|
|
86
111
|
|
|
87
112
|
Util.logInfo(`Execute: ${EC.cyan(command)}`);
|
|
88
113
|
|
|
114
|
+
// before load config
|
|
89
115
|
await initNodeOptions(cliOptions);
|
|
90
116
|
|
|
91
117
|
// console.log(options);
|
|
@@ -133,7 +159,8 @@ const executeCommand = async (command, cliOptions) => {
|
|
|
133
159
|
};
|
|
134
160
|
|
|
135
161
|
process.on('uncaughtException', function(err) {
|
|
136
|
-
Util.logError(`Process uncaughtException: ${err.message
|
|
162
|
+
Util.logError(`Process uncaughtException: ${err.message}`);
|
|
163
|
+
console.log(err.stack);
|
|
137
164
|
});
|
|
138
165
|
|
|
139
166
|
// the -- separator
|
|
@@ -154,7 +181,7 @@ process.argv.forEach((it) => {
|
|
|
154
181
|
program
|
|
155
182
|
.name('mcr')
|
|
156
183
|
.description('CLI to generate coverage reports')
|
|
157
|
-
.version(version)
|
|
184
|
+
.version(version, '-v, --version', 'output the current version')
|
|
158
185
|
.argument('[command]', 'command to execute')
|
|
159
186
|
.allowUnknownOption()
|
|
160
187
|
.option('-c, --config <path>', 'custom config file path')
|
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
|
}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const EC = require('eight-colors');
|
|
8
|
-
const { Locator } = require('monocart-formatter');
|
|
9
8
|
|
|
9
|
+
const { Locator } = require('monocart-locator');
|
|
10
10
|
const Util = require('../utils/util.js');
|
|
11
11
|
|
|
12
12
|
const findOriginalRange = require('./find-original-range.js');
|
|
@@ -984,9 +984,13 @@ const initOriginalList = (state, originalDecodedMap, options) => {
|
|
|
984
984
|
|
|
985
985
|
const { sources, sourcesContent } = state.sourceMap;
|
|
986
986
|
|
|
987
|
+
const lengthBefore = sources.length;
|
|
988
|
+
let lengthAfter = 0;
|
|
989
|
+
|
|
987
990
|
sources.forEach((sourcePath, sourceIndex) => {
|
|
988
991
|
|
|
989
992
|
// filter
|
|
993
|
+
// do not change for sourceIndex
|
|
990
994
|
if (!sourceFilter(sourcePath)) {
|
|
991
995
|
// console.log('-', sourcePath);
|
|
992
996
|
return;
|
|
@@ -1034,8 +1038,11 @@ const initOriginalList = (state, originalDecodedMap, options) => {
|
|
|
1034
1038
|
};
|
|
1035
1039
|
|
|
1036
1040
|
originalStateMap.set(sourceIndex, originalState);
|
|
1041
|
+
lengthAfter += 1;
|
|
1037
1042
|
});
|
|
1038
1043
|
|
|
1044
|
+
Util.logFilter(`source filter (${state.sourcePath}):`, lengthBefore, lengthAfter);
|
|
1045
|
+
|
|
1039
1046
|
return originalStateMap;
|
|
1040
1047
|
};
|
|
1041
1048
|
|
|
@@ -1044,6 +1051,8 @@ const collectOriginalList = (state, originalStateMap) => {
|
|
|
1044
1051
|
const { fileUrls } = state;
|
|
1045
1052
|
const distFile = state.sourcePath;
|
|
1046
1053
|
|
|
1054
|
+
let added = 0;
|
|
1055
|
+
|
|
1047
1056
|
// collect original files
|
|
1048
1057
|
originalStateMap.forEach((originalState) => {
|
|
1049
1058
|
|
|
@@ -1070,8 +1079,11 @@ const collectOriginalList = (state, originalStateMap) => {
|
|
|
1070
1079
|
// save v8 data and add to originalList
|
|
1071
1080
|
originalState.v8Data = sourceItem;
|
|
1072
1081
|
state.originalList.push(originalState);
|
|
1082
|
+
added += 1;
|
|
1073
1083
|
});
|
|
1074
1084
|
|
|
1085
|
+
Util.logDebug(`added source files: ${EC.yellow(added)}`);
|
|
1086
|
+
|
|
1075
1087
|
};
|
|
1076
1088
|
|
|
1077
1089
|
// ========================================================================================================
|
package/lib/generate.js
CHANGED
|
@@ -686,6 +686,7 @@ const getInputData = async (inputList, all, cacheDir, addHandler) => {
|
|
|
686
686
|
// dataList for data type, before `add` we don't which one is tested, because using hash id
|
|
687
687
|
const emptyData = getEmptyData(all, dataList);
|
|
688
688
|
if (emptyData) {
|
|
689
|
+
Util.logDebug(`added empty files for all: ${EC.yellow(emptyData.length)}`);
|
|
689
690
|
const coverageResults = await addHandler(emptyData);
|
|
690
691
|
// after `add`
|
|
691
692
|
if (coverageResults) {
|
|
@@ -782,7 +783,11 @@ const readCoverageData = (filePath, entryFilter, sourceCache) => {
|
|
|
782
783
|
|
|
783
784
|
// filter node internal files, should no anonymous for nodejs
|
|
784
785
|
coverageData = coverageData.filter((entry) => entry.url && entry.url.startsWith('file:'));
|
|
786
|
+
|
|
787
|
+
const lengthBefore = coverageData.length;
|
|
785
788
|
coverageData = coverageData.filter(entryFilter);
|
|
789
|
+
const lengthAfter = coverageData.length;
|
|
790
|
+
Util.logFilter('entry filter (addFromDir):', lengthBefore, lengthAfter);
|
|
786
791
|
|
|
787
792
|
if (!Util.isList(coverageData)) {
|
|
788
793
|
// Util.logDebug('No coverage data after filter');
|
package/lib/index.js
CHANGED
|
@@ -61,6 +61,9 @@ class CoverageReport {
|
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// before clean cache, do no call initOptions again in hasCache
|
|
65
|
+
this.fixedOptions = true;
|
|
66
|
+
|
|
64
67
|
// init logging for clean after generated
|
|
65
68
|
this.logging = Util.initLoggingLevel(this.options.logging);
|
|
66
69
|
|
|
@@ -79,7 +82,6 @@ class CoverageReport {
|
|
|
79
82
|
this.cleanCache();
|
|
80
83
|
}
|
|
81
84
|
|
|
82
|
-
this.fixedOptions = true;
|
|
83
85
|
}
|
|
84
86
|
|
|
85
87
|
// add coverage data: {array} V8 format, {object} Istanbul format
|