monocart-coverage-reports 2.12.10 → 2.12.11
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 +88 -16
- package/README.zh-Hans.md +83 -11
- package/lib/cli.js +16 -8
- package/lib/index.d.ts +9 -9
- package/lib/packages/monocart-coverage-vendor.js +14 -14
- package/lib/utils/util.js +18 -18
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* [Filtering Results](#filtering-results)
|
|
27
27
|
* [Resolve `sourcePath` for the Source Files](#resolve-sourcepath-for-the-source-files)
|
|
28
28
|
* [Adding Empty Coverage for Untested Files](#adding-empty-coverage-for-untested-files)
|
|
29
|
-
* [
|
|
29
|
+
* [Hooks](#hooks)
|
|
30
30
|
* [Ignoring Uncovered Codes](#ignoring-uncovered-codes)
|
|
31
31
|
* [Multiprocessing Support](#multiprocessing-support)
|
|
32
32
|
* [Command Line](#command-line)
|
|
@@ -102,9 +102,40 @@ For more information, see [Command Line](#command-line)
|
|
|
102
102
|
- Options declaration see `CoverageReportOptions` [lib/index.d.ts](./lib/index.d.ts)
|
|
103
103
|
- [Config file](#config-file)
|
|
104
104
|
|
|
105
|
+
| Option | Type | Default | Description |
|
|
106
|
+
| :-- | :-- | :-- | :-- |
|
|
107
|
+
| `logging` | `"off" \| "error" \| "info" \| "debug"` | `"info"` | Logging level. Use `"debug"` to keep raw cache and dump sourcemaps for troubleshooting. See [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap). |
|
|
108
|
+
| `name` | `string` | `"Coverage Report"` | Report title shown in the UI and summary reports. |
|
|
109
|
+
| `reports` | `string \| (string \| ReportDescription)[]` | `"v8"` (V8) / `"html"` (Istanbul) | Reports to generate. See [Available Reports](#available-reports). |
|
|
110
|
+
| `outputDir` | `string` | `"./coverage-reports"` | Output directory for all reports and the `.cache` folder. |
|
|
111
|
+
| `inputDir` | `string \| string[]` | `null` | Input directories of raw coverage data for [merging](#merge-coverage-reports). |
|
|
112
|
+
| `baseDir` | `string` | `process.cwd()` | Base dir used to normalize relative source paths. Set when the report is generated from a different working directory than the sources. |
|
|
113
|
+
| `dataDir` | `string` | `null` | Coverage data directory loaded automatically in `generate()` — alternative to `addFromDir()`. |
|
|
114
|
+
| `entryFilter` | `string \| object \| function` | `null` | (V8 only) Filter V8 entries by url. See [Filtering Results](#filtering-results). |
|
|
115
|
+
| `sourceFilter` | `string \| object \| function` | `null` | (V8 only) Filter sources unpacked from sourcemaps. |
|
|
116
|
+
| `filter` | `string \| object \| function` | `null` | Combined filter replacing both `entryFilter` and `sourceFilter`. |
|
|
117
|
+
| `sourcePath` | `object \| function` | `null` | Rewrite source paths; see [Resolve `sourcePath`](#resolve-sourcepath-for-the-source-files). |
|
|
118
|
+
| `all` | `string \| string[] \| object` | `null` | Include untested files as empty coverage. See [Adding Empty Coverage](#adding-empty-coverage-for-untested-files). |
|
|
119
|
+
| `outputFile` | `string` | `"index.html"` | (V8 only) Output `[sub dir/]filename` for the V8 report. |
|
|
120
|
+
| `inline` | `boolean` | `false` | (V8 only) Inline all assets into a single HTML file. |
|
|
121
|
+
| `assetsPath` | `string` | `"./assets"` | (V8 only) Assets directory when `inline` is false. |
|
|
122
|
+
| `lcov` | `boolean` | `false` | Also generate `lcov.info` (equivalent to adding the `lcovonly` report). |
|
|
123
|
+
| `v8Ignore` | `boolean` | `true` | (V8 only) Enable/disable comment-based ignoring (`v8 ignore …`). See [Ignoring Uncovered Codes](#ignoring-uncovered-codes). |
|
|
124
|
+
| `reportPath` | `string \| () => string` | `null` | Override the report entry path (defaults to `outputDir/index.html`). Useful when multiple reports share an `outputDir`. |
|
|
125
|
+
| `watermarks` | `[number, number] \| object` | `[50, 80]` | Low/high thresholds (percent). Accepts per-metric object like `{ bytes:[50,80], lines:[50,80] }`. |
|
|
126
|
+
| `clean` | `boolean` | `true` | Clean previous reports in `outputDir` before generating. |
|
|
127
|
+
| `cleanCache` | `boolean` | `false` | Clean the cache dir on start. |
|
|
128
|
+
| `gc` | `number` | `null` | Memory threshold in MB; force GC at critical stages when RSS exceeds it. Useful for very large data sets, see [JavaScript heap out of memory](#javascript-heap-out-of-memory). |
|
|
129
|
+
| `sourceMap` | `boolean` | `false` | Save source/sourcemap files to cache for debugging (requires `logging: "debug"`). |
|
|
130
|
+
| `sourceMapResolver` | `(url, defaultResolver) => Promise<string \| object>` | `null` | Custom sourcemap loader (e.g. from a build cache). Call `defaultResolver(url)` to fall back. |
|
|
131
|
+
| `onEntry` | `(entry) => void \| Promise<void>` | `null` | (V8 only) Per-entry hook; see [Hooks](#hooks). |
|
|
132
|
+
| `onEnd` | `(coverageResults) => void \| Promise<void>` | `null` | Hook invoked after report generation; see [Hooks](#hooks). |
|
|
133
|
+
| `onStart` | `(coverageReport) => void \| Promise<void>` | `null` | (CLI only) Before the child process starts; see [Hooks](#hooks). |
|
|
134
|
+
| `onReady` | `(coverageReport, nodeV8CoverageDir, subprocess) => void \| Promise<void>` | `null` | (CLI only) After the child exits, before MCR reads coverage data; see [Hooks](#hooks). |
|
|
135
|
+
|
|
105
136
|
## Available Reports
|
|
106
137
|
|
|
107
|
-
> V8
|
|
138
|
+
> V8 built-in reports (V8 data only):
|
|
108
139
|
|
|
109
140
|
- `v8`
|
|
110
141
|
- Features:
|
|
@@ -124,7 +155,7 @@ For more information, see [Command Line](#command-line)
|
|
|
124
155
|
|
|
125
156
|

|
|
126
157
|
|
|
127
|
-
> Istanbul
|
|
158
|
+
> Istanbul built-in reports (both V8 and Istanbul data):
|
|
128
159
|
|
|
129
160
|
- `clover`
|
|
130
161
|
- `cobertura`
|
|
@@ -144,7 +175,7 @@ For more information, see [Command Line](#command-line)
|
|
|
144
175
|
- `text-lcov`
|
|
145
176
|
- `text-summary`
|
|
146
177
|
|
|
147
|
-
> Other
|
|
178
|
+
> Other built-in reports (both V8 and Istanbul data):
|
|
148
179
|
|
|
149
180
|
- `codecov` Save coverage data to a json file with [Codecov](https://docs.codecov.com/docs/codecov-custom-coverage-format) format (defaults to `codecov.json`), see [example](https://app.codecov.io/github/cenfun/monocart-coverage-reports).
|
|
150
181
|
|
|
@@ -198,7 +229,7 @@ const MCR = require('monocart-coverage-reports');
|
|
|
198
229
|
const coverageOptions = {
|
|
199
230
|
outputDir: './coverage-reports',
|
|
200
231
|
reports: [
|
|
201
|
-
//
|
|
232
|
+
// built-in reports
|
|
202
233
|
['console-summary'],
|
|
203
234
|
['v8'],
|
|
204
235
|
['html', {
|
|
@@ -464,7 +495,7 @@ export interface CoverageRange {
|
|
|
464
495
|
* @functionName can be an empty string.
|
|
465
496
|
* @ranges is always non-empty. The first range is called the "root range".
|
|
466
497
|
* @isBlockCoverage indicates if the function has block coverage information.
|
|
467
|
-
If this is false, it usually means that the
|
|
498
|
+
If this is false, it usually means that the function was never called.
|
|
468
499
|
It seems to be equivalent to ranges.length === 1 && ranges[0].count === 0.
|
|
469
500
|
*/
|
|
470
501
|
export interface FunctionCoverage {
|
|
@@ -572,7 +603,7 @@ const coverageOptions = {
|
|
|
572
603
|
filter: {
|
|
573
604
|
'**/node_modules/**': false,
|
|
574
605
|
'**/vendor.js': false,
|
|
575
|
-
'**/src/**': true
|
|
606
|
+
'**/src/**': true,
|
|
576
607
|
'**/**': true
|
|
577
608
|
}
|
|
578
609
|
};
|
|
@@ -672,8 +703,10 @@ const coverageOptions = {
|
|
|
672
703
|
};
|
|
673
704
|
```
|
|
674
705
|
|
|
675
|
-
##
|
|
676
|
-
|
|
706
|
+
## Hooks
|
|
707
|
+
|
|
708
|
+
### `onEnd` — after the report is generated
|
|
709
|
+
Typical use case: enforce coverage thresholds.
|
|
677
710
|
```js
|
|
678
711
|
const EC = require('eight-colors');
|
|
679
712
|
const coverageOptions = {
|
|
@@ -703,6 +736,29 @@ const coverageOptions = {
|
|
|
703
736
|
}
|
|
704
737
|
```
|
|
705
738
|
|
|
739
|
+
### `onEntry` — before each V8 entry is processed (V8 only)
|
|
740
|
+
Use this to mutate the entry (for example, transform non-standard sources into valid ECMAScript before the AST parser runs). See [Unparsable source](#unparsable-source).
|
|
741
|
+
```js
|
|
742
|
+
const coverageOptions = {
|
|
743
|
+
onEntry: async (entry) => {
|
|
744
|
+
// entry.source, entry.sourceMap, entry.fake, ...
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
### `onStart` / `onReady` — CLI-only
|
|
750
|
+
Only available when using `mcr <command>`:
|
|
751
|
+
- `onStart(coverageReport)` — runs before the child process is spawned.
|
|
752
|
+
- `onReady(coverageReport, nodeV8CoverageDir, subprocess)` — runs after the child exits, before MCR reads coverage from `nodeV8CoverageDir`. Useful when the child hasn't finished flushing coverage data and needs to be waited on.
|
|
753
|
+
```js
|
|
754
|
+
// mcr.config.js
|
|
755
|
+
module.exports = {
|
|
756
|
+
onReady: async (coverageReport, nodeV8CoverageDir, subprocess) => {
|
|
757
|
+
// wait for something, or pre-process the raw files
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
```
|
|
761
|
+
|
|
706
762
|
## Ignoring Uncovered Codes
|
|
707
763
|
To ignore codes, use the special comment which starts with `v8 ignore `:
|
|
708
764
|
- Ignoring all until stop
|
|
@@ -715,9 +771,9 @@ function uncovered() {
|
|
|
715
771
|
- Ignoring the next line or next N lines
|
|
716
772
|
```js
|
|
717
773
|
/* v8 ignore next */
|
|
718
|
-
const os = platform === '
|
|
774
|
+
const os = platform === 'win32' ? 'Windows' : 'Other';
|
|
719
775
|
|
|
720
|
-
const os = platform === '
|
|
776
|
+
const os = platform === 'win32' ? 'Windows' /* v8 ignore next */ : 'Other';
|
|
721
777
|
|
|
722
778
|
// v8 ignore next 3
|
|
723
779
|
if (platform === 'linux') {
|
|
@@ -736,6 +792,7 @@ function uncovered() {
|
|
|
736
792
|
}
|
|
737
793
|
/* node:coverage enable */
|
|
738
794
|
```
|
|
795
|
+
- To disable comment-based ignoring entirely, set `v8Ignore: false`.
|
|
739
796
|
|
|
740
797
|
## Multiprocessing Support
|
|
741
798
|
> 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)
|
|
@@ -797,6 +854,16 @@ see all options with running `mcr` or `mcr --help`
|
|
|
797
854
|
mcr -c mcr.config.js -- sub-cli -c sub-cli.config.js
|
|
798
855
|
```
|
|
799
856
|
|
|
857
|
+
- `--import <module>` / `--require <module>`: forward a preload module to the child process via `NODE_OPTIONS`. Use this for TypeScript/JSX runtimes (`tsx`, `ts-node`, etc.) and also when loading a `mcr.config.ts`. Requires Node.js `>= 18.19`.
|
|
858
|
+
```sh
|
|
859
|
+
mcr --import tsx node ./test.ts
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
- `--env [path]`: load environment variables from a dotenv file before the child starts (defaults to `.env`). Requires `process.loadEnvFile`, added in Node.js `20.6`.
|
|
863
|
+
```sh
|
|
864
|
+
mcr --env .env.test node ./test.js
|
|
865
|
+
```
|
|
866
|
+
|
|
800
867
|
- Examples
|
|
801
868
|
- [Mocha](#mocha)
|
|
802
869
|
- [TypeScript](#typescript)
|
|
@@ -811,7 +878,12 @@ Loading config file by priority:
|
|
|
811
878
|
- `mcr.config.cjs`
|
|
812
879
|
- `mcr.config.mjs`
|
|
813
880
|
- `mcr.config.json` - json format
|
|
814
|
-
- `mcr.config.ts` (requires preloading the
|
|
881
|
+
- `mcr.config.ts` (requires preloading the TypeScript execution module, for example with `tsx`):
|
|
882
|
+
```sh
|
|
883
|
+
mcr --import tsx -c mcr.config.ts node ./test.js
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
> If no custom path is given, MCR walks up from the current working directory to find the default config file (via [`find-up`](https://github.com/sindresorhus/find-up)). Files outside the search path will be ignored.
|
|
815
887
|
|
|
816
888
|
## Merge Coverage Reports
|
|
817
889
|
The following usage scenarios may require merging coverage reports:
|
|
@@ -890,7 +962,7 @@ const coverageOptions = {
|
|
|
890
962
|
],
|
|
891
963
|
|
|
892
964
|
onEnd: () => {
|
|
893
|
-
// remove the raw files if
|
|
965
|
+
// remove the raw files if no longer needed
|
|
894
966
|
// inputDir.forEach((p) => {
|
|
895
967
|
// fs.rmSync(p, {
|
|
896
968
|
// recursive: true,
|
|
@@ -926,8 +998,8 @@ In the generated code, there is a position `p`, and we need to find out its corr
|
|
|
926
998
|
- Further understanding of sourcemap, try [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap)
|
|
927
999
|
|
|
928
1000
|
How `MCR` Works:
|
|
929
|
-
|
|
930
|
-
|
|
1001
|
+
1. Tries 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 templates or JSX, a perfect solution may not always be possible.
|
|
1002
|
+
2. Finds all functions, statements and branches by parsing the source code [AST](https://github.com/acornjs/acorn). (One small caveat: V8 cannot provide effective branch coverage information for `AssignmentPattern`.)
|
|
931
1003
|
|
|
932
1004
|
|
|
933
1005
|
### Unparsable source
|
|
@@ -971,7 +1043,7 @@ const coverageOptions = {
|
|
|
971
1043
|
]
|
|
972
1044
|
};
|
|
973
1045
|
```
|
|
974
|
-
When `logging` is `debug`, the raw report data
|
|
1046
|
+
When `logging` is `debug`, the raw report data is preserved in `[outputDir]/.cache` (or `[outputDir]/raw` if the `raw` report is used). The dist file is also kept in the V8 list, so you can open the browser's devtools and visually verify the coverage data.
|
|
975
1047
|

|
|
976
1048
|
|
|
977
1049
|
- Check sourcemap with [Source Map Visualization](https://evanw.github.io/source-map-visualization/)
|
package/README.zh-Hans.md
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* [过滤V8覆盖率数据](#filtering-results)
|
|
27
27
|
* [使用 `sourcePath` 修改源文件路径](#resolve-sourcepath-for-the-source-files)
|
|
28
28
|
* [为未测试的文件添加空的覆盖率报告](#adding-empty-coverage-for-untested-files)
|
|
29
|
-
* [
|
|
29
|
+
* [回调钩子 Hooks](#hooks)
|
|
30
30
|
* [如何忽略未覆盖的代码](#ignoring-uncovered-codes)
|
|
31
31
|
* [多进程支持](#multiprocessing-support)
|
|
32
32
|
* [如何使用CLI命令行](#command-line)
|
|
@@ -102,6 +102,37 @@ mcr node my-app.js -r v8,console-details
|
|
|
102
102
|
- 选项的类型描述,见 `CoverageReportOptions` [lib/index.d.ts](./lib/index.d.ts)
|
|
103
103
|
- [配置文件](#config-file)
|
|
104
104
|
|
|
105
|
+
| 选项 | 类型 | 默认值 | 说明 |
|
|
106
|
+
| :-- | :-- | :-- | :-- |
|
|
107
|
+
| `logging` | `"off" \| "error" \| "info" \| "debug"` | `"info"` | 日志级别。设为 `"debug"` 会保留原始缓存并输出 sourcemap,便于排查问题。参见 [调试覆盖率和sourcemap](#debug-for-coverage-and-sourcemap)。 |
|
|
108
|
+
| `name` | `string` | `"Coverage Report"` | 报告标题,显示在 UI 以及 summary 报告中。 |
|
|
109
|
+
| `reports` | `string \| (string \| ReportDescription)[]` | V8 默认 `"v8"` / Istanbul 默认 `"html"` | 生成哪些报告,参见 [所有支持的报告类型](#available-reports)。 |
|
|
110
|
+
| `outputDir` | `string` | `"./coverage-reports"` | 所有报告以及 `.cache` 的输出目录。 |
|
|
111
|
+
| `inputDir` | `string \| string[]` | `null` | 导入的原始覆盖率数据目录(用于 [合并](#merge-coverage-reports))。 |
|
|
112
|
+
| `baseDir` | `string` | `process.cwd()` | 规范化相对源路径的基准目录。当生成报告的工作目录和源码目录不一致时需要设置。 |
|
|
113
|
+
| `dataDir` | `string` | `null` | `generate()` 阶段自动加载的覆盖率数据目录,作为 `addFromDir()` 的替代。 |
|
|
114
|
+
| `entryFilter` | `string \| object \| function` | `null` | (仅 V8)按 URL 过滤入口文件,参见 [过滤V8覆盖率数据](#filtering-results)。 |
|
|
115
|
+
| `sourceFilter` | `string \| object \| function` | `null` | (仅 V8)过滤从 sourcemap 解包出的源文件。 |
|
|
116
|
+
| `filter` | `string \| object \| function` | `null` | 合并 `entryFilter` 和 `sourceFilter` 的统一过滤器。 |
|
|
117
|
+
| `sourcePath` | `object \| function` | `null` | 修改源文件路径,参见 [使用 `sourcePath`](#resolve-sourcepath-for-the-source-files)。 |
|
|
118
|
+
| `all` | `string \| string[] \| object` | `null` | 为未测试文件添加空覆盖率,参见 [为未测试的文件添加空的覆盖率报告](#adding-empty-coverage-for-untested-files)。 |
|
|
119
|
+
| `outputFile` | `string` | `"index.html"` | (仅 V8)V8 报告的 `[子目录/]文件名`。 |
|
|
120
|
+
| `inline` | `boolean` | `false` | (仅 V8)将所有资源内联到单一 HTML 文件。 |
|
|
121
|
+
| `assetsPath` | `string` | `"./assets"` | (仅 V8)非内联模式下的资源目录。 |
|
|
122
|
+
| `lcov` | `boolean` | `false` | 额外生成 `lcov.info`,等同于添加 `lcovonly` 报告。 |
|
|
123
|
+
| `v8Ignore` | `boolean` | `true` | (仅 V8)启用/禁用基于注释的忽略(`v8 ignore …`),参见 [忽略未覆盖代码](#ignoring-uncovered-codes)。 |
|
|
124
|
+
| `reportPath` | `string \| () => string` | `null` | 覆盖默认的报告入口路径(默认 `outputDir/index.html`)。多个报告共用同一 `outputDir` 时很有用。 |
|
|
125
|
+
| `watermarks` | `[number, number] \| object` | `[50, 80]` | 覆盖率高/低阈值百分比。也支持按指标配置:`{ bytes:[50,80], lines:[50,80] }`。 |
|
|
126
|
+
| `clean` | `boolean` | `true` | 生成报告前清理 `outputDir` 中的旧报告。 |
|
|
127
|
+
| `cleanCache` | `boolean` | `false` | 启动时清理缓存目录。 |
|
|
128
|
+
| `gc` | `number` | `null` | 内存阈值(MB),在关键阶段若 RSS 超过阈值则强制触发 GC,适用于超大数据集,参见 [JavaScript heap out of memory](#javascript-heap-out-of-memory)。 |
|
|
129
|
+
| `sourceMap` | `boolean` | `false` | 将源文件和 sourcemap 也保存到 cache 便于调试(需要 `logging: "debug"`)。 |
|
|
130
|
+
| `sourceMapResolver` | `(url, defaultResolver) => Promise<string \| object>` | `null` | 自定义 sourcemap 加载逻辑(例如从构建缓存中读取),可调用 `defaultResolver(url)` 回退到默认解析。 |
|
|
131
|
+
| `onEntry` | `(entry) => void \| Promise<void>` | `null` | (仅 V8)每个入口文件处理前触发,参见 [Hooks](#hooks)。 |
|
|
132
|
+
| `onEnd` | `(coverageResults) => void \| Promise<void>` | `null` | 报告生成完成后触发,参见 [Hooks](#hooks)。 |
|
|
133
|
+
| `onStart` | `(coverageReport) => void \| Promise<void>` | `null` | (仅 CLI)子进程启动前触发,参见 [Hooks](#hooks)。 |
|
|
134
|
+
| `onReady` | `(coverageReport, nodeV8CoverageDir, subprocess) => void \| Promise<void>` | `null` | (仅 CLI)子进程退出后、MCR 读取覆盖率数据前触发,参见 [Hooks](#hooks)。 |
|
|
135
|
+
|
|
105
136
|
## Available Reports
|
|
106
137
|
|
|
107
138
|
> 内置V8报告(仅V8格式数据支持):
|
|
@@ -199,7 +230,7 @@ const MCR = require('monocart-coverage-reports');
|
|
|
199
230
|
const coverageOptions = {
|
|
200
231
|
outputDir: './coverage-reports',
|
|
201
232
|
reports: [
|
|
202
|
-
//
|
|
233
|
+
// built-in reports
|
|
203
234
|
['console-summary'],
|
|
204
235
|
['v8'],
|
|
205
236
|
['html', {
|
|
@@ -468,7 +499,7 @@ export interface CoverageRange {
|
|
|
468
499
|
* @functionName can be an empty string.
|
|
469
500
|
* @ranges is always non-empty. The first range is called the "root range".
|
|
470
501
|
* @isBlockCoverage indicates if the function has block coverage information.
|
|
471
|
-
If this is false, it usually means that the
|
|
502
|
+
If this is false, it usually means that the function was never called.
|
|
472
503
|
It seems to be equivalent to ranges.length === 1 && ranges[0].count === 0.
|
|
473
504
|
*/
|
|
474
505
|
export interface FunctionCoverage {
|
|
@@ -502,7 +533,7 @@ export type V8CoverageData = ScriptCoverage[];
|
|
|
502
533
|
| Bun | ❌ | |
|
|
503
534
|
|
|
504
535
|
## Filtering Results
|
|
505
|
-
|
|
536
|
+
### Using `entryFilter` and `sourceFilter` to filter the results for V8 report
|
|
506
537
|
当收集到V8的覆盖数据时,它实际上包含了所有的入口文件的覆盖率数据, 比如有以下3个文件:
|
|
507
538
|
|
|
508
539
|
- *dist/main.js*
|
|
@@ -576,7 +607,7 @@ const coverageOptions = {
|
|
|
576
607
|
filter: {
|
|
577
608
|
'**/node_modules/**': false,
|
|
578
609
|
'**/vendor.js': false,
|
|
579
|
-
'**/src/**': true
|
|
610
|
+
'**/src/**': true,
|
|
580
611
|
'**/**': true
|
|
581
612
|
}
|
|
582
613
|
};
|
|
@@ -675,8 +706,10 @@ const coverageOptions = {
|
|
|
675
706
|
};
|
|
676
707
|
```
|
|
677
708
|
|
|
678
|
-
##
|
|
679
|
-
|
|
709
|
+
## Hooks
|
|
710
|
+
|
|
711
|
+
### `onEnd` — 报告生成后触发
|
|
712
|
+
典型用法:检测覆盖率是否达标,低于 threshold 时抛错退出。
|
|
680
713
|
```js
|
|
681
714
|
const EC = require('eight-colors');
|
|
682
715
|
const coverageOptions = {
|
|
@@ -706,6 +739,29 @@ const coverageOptions = {
|
|
|
706
739
|
}
|
|
707
740
|
```
|
|
708
741
|
|
|
742
|
+
### `onEntry` — 每个V8入口在处理前触发(仅V8)
|
|
743
|
+
可以在进入AST解析前改写 entry(例如对非标准语法的源码做预编译),参见 [Unparsable source](#unparsable-source)
|
|
744
|
+
```js
|
|
745
|
+
const coverageOptions = {
|
|
746
|
+
onEntry: async (entry) => {
|
|
747
|
+
// entry.source, entry.sourceMap, entry.fake, ...
|
|
748
|
+
}
|
|
749
|
+
};
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
### `onStart` / `onReady` — 仅CLI可用
|
|
753
|
+
只在使用 `mcr <command>` 时有效:
|
|
754
|
+
- `onStart(coverageReport)` — 子进程启动前触发
|
|
755
|
+
- `onReady(coverageReport, nodeV8CoverageDir, subprocess)` — 子进程退出后、MCR 读取 `nodeV8CoverageDir` 之前触发。用于子进程尚未写完覆盖数据需要等待的场景
|
|
756
|
+
```js
|
|
757
|
+
// mcr.config.js
|
|
758
|
+
module.exports = {
|
|
759
|
+
onReady: async (coverageReport, nodeV8CoverageDir, subprocess) => {
|
|
760
|
+
// 等待某个信号,或先对 raw 文件做一些预处理
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
```
|
|
764
|
+
|
|
709
765
|
## Ignoring Uncovered Codes
|
|
710
766
|
使用特定的注释,以`v8 ignore `开头可以忽略未覆盖的代码:
|
|
711
767
|
- 忽略开始到结束
|
|
@@ -718,9 +774,9 @@ function uncovered() {
|
|
|
718
774
|
- 忽略接下来一行或者多行
|
|
719
775
|
```js
|
|
720
776
|
/* v8 ignore next */
|
|
721
|
-
const os = platform === '
|
|
777
|
+
const os = platform === 'win32' ? 'Windows' : 'Other';
|
|
722
778
|
|
|
723
|
-
const os = platform === '
|
|
779
|
+
const os = platform === 'win32' ? 'Windows' /* v8 ignore next */ : 'Other';
|
|
724
780
|
|
|
725
781
|
// v8 ignore next 3
|
|
726
782
|
if (platform === 'linux') {
|
|
@@ -739,6 +795,7 @@ function uncovered() {
|
|
|
739
795
|
}
|
|
740
796
|
/* node:coverage enable */
|
|
741
797
|
```
|
|
798
|
+
- 可以设置 `v8Ignore: false` 完全禁用基于注释的忽略机制。
|
|
742
799
|
|
|
743
800
|
## Multiprocessing Support
|
|
744
801
|
> 多进程支持可以很好的解决异步并行的情况。所有的覆盖率数据会保存到`[outputDir]/.cache`,在报告生成之后,这些缓存数据会被清除。除非开启了[调试模式](#debug-for-coverage-and-sourcemap),或者使用了`raw`报告
|
|
@@ -800,6 +857,16 @@ npx mcr node ./test/specs/node.test.js -r v8,console-details --lcov
|
|
|
800
857
|
mcr -c mcr.config.js -- sub-cli -c sub-cli.config.js
|
|
801
858
|
```
|
|
802
859
|
|
|
860
|
+
- `--import <module>` / `--require <module>`: 通过 `NODE_OPTIONS` 把一个预加载模块传给子进程。常用于 TypeScript/JSX 运行时(`tsx`、`ts-node` 等),也可用于加载 `mcr.config.ts`。要求 Node.js `>= 18.19`
|
|
861
|
+
```sh
|
|
862
|
+
mcr --import tsx node ./test.ts
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
- `--env [path]`: 子进程启动前从 dotenv 文件加载环境变量(默认 `.env`)。依赖 `process.loadEnvFile`,Node.js `20.6` 起支持
|
|
866
|
+
```sh
|
|
867
|
+
mcr --env .env.test node ./test.js
|
|
868
|
+
```
|
|
869
|
+
|
|
803
870
|
- 参见例子
|
|
804
871
|
- [Mocha](#mocha)
|
|
805
872
|
- [TypeScript](#typescript)
|
|
@@ -814,7 +881,12 @@ mcr -c mcr.config.js -- sub-cli -c sub-cli.config.js
|
|
|
814
881
|
- `mcr.config.cjs`
|
|
815
882
|
- `mcr.config.mjs`
|
|
816
883
|
- `mcr.config.json` - json format
|
|
817
|
-
- `mcr.config.ts`
|
|
884
|
+
- `mcr.config.ts` (需要预加载 TypeScript 执行模块,比如 `tsx`):
|
|
885
|
+
```sh
|
|
886
|
+
mcr --import tsx -c mcr.config.ts node ./test.js
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
> 未指定自定义路径时,MCR 会从当前工作目录向上查找默认配置文件(通过 [`find-up`](https://github.com/sindresorhus/find-up))。不在搜索路径内的文件会被忽略
|
|
818
890
|
|
|
819
891
|
## Merge Coverage Reports
|
|
820
892
|
以下这些使用场景可能需要使用合并覆盖率报告:
|
|
@@ -892,7 +964,7 @@ const coverageOptions = {
|
|
|
892
964
|
],
|
|
893
965
|
|
|
894
966
|
onEnd: () => {
|
|
895
|
-
// remove the raw files if
|
|
967
|
+
// remove the raw files if no longer needed
|
|
896
968
|
// inputDir.forEach((p) => {
|
|
897
969
|
// fs.rmSync(p, {
|
|
898
970
|
// recursive: true,
|
package/lib/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const path = require('path');
|
|
4
|
+
const { pathToFileURL } = require('url');
|
|
4
5
|
const EC = require('eight-colors');
|
|
5
6
|
|
|
6
7
|
const { program } = require('commander');
|
|
@@ -11,12 +12,18 @@ const Util = require('./utils/util.js');
|
|
|
11
12
|
|
|
12
13
|
const version = require('../package.json').version;
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
// quote NODE_OPTIONS argument if it contains whitespace so child processes
|
|
16
|
+
// inheriting the env var can parse it correctly
|
|
17
|
+
const quoteNodeOption = (v) => ((/\s/).test(v) ? `"${v}"` : v);
|
|
18
|
+
|
|
19
|
+
// absolute path so NODE_OPTIONS keeps resolving when child processes are
|
|
20
|
+
// spawned with a different cwd than the mcr parent process
|
|
21
|
+
const getRequirePath = () => {
|
|
22
|
+
return quoteNodeOption(path.resolve(__dirname, 'register', 'register.js'));
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const getImportPath = () => {
|
|
26
|
+
return quoteNodeOption(pathToFileURL(path.resolve(__dirname, 'register', 'register.mjs')).href);
|
|
20
27
|
};
|
|
21
28
|
|
|
22
29
|
const getInitNodeOptions = async (cliOptions) => {
|
|
@@ -92,10 +99,10 @@ const initNodeOptions = async (cliOptions) => {
|
|
|
92
99
|
|
|
93
100
|
// export source after
|
|
94
101
|
if (preloadType === '--import') {
|
|
95
|
-
const importPath =
|
|
102
|
+
const importPath = getImportPath();
|
|
96
103
|
nodeOptions.unshift(`--import ${importPath}`);
|
|
97
104
|
} else {
|
|
98
|
-
const requirePath =
|
|
105
|
+
const requirePath = getRequirePath();
|
|
99
106
|
nodeOptions.unshift(`--require ${requirePath}`);
|
|
100
107
|
}
|
|
101
108
|
|
|
@@ -183,6 +190,7 @@ const executeCommand = async (command, cliOptions) => {
|
|
|
183
190
|
process.on('uncaughtException', function(err) {
|
|
184
191
|
Util.logError(`Process uncaughtException: ${err.message}`);
|
|
185
192
|
console.log(err.stack);
|
|
193
|
+
process.exit(1);
|
|
186
194
|
});
|
|
187
195
|
|
|
188
196
|
// the -- separator
|
package/lib/index.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ declare namespace MCR {
|
|
|
36
36
|
export type Watermarks = [number, number] | {
|
|
37
37
|
/** V8 only */
|
|
38
38
|
bytes?: [number, number];
|
|
39
|
-
statements
|
|
39
|
+
statements?: [number, number];
|
|
40
40
|
branches?: [number, number];
|
|
41
41
|
functions?: [number, number];
|
|
42
42
|
lines?: [number, number];
|
|
@@ -134,7 +134,7 @@ declare namespace MCR {
|
|
|
134
134
|
} | ((file: CoverageFile) => boolean);
|
|
135
135
|
}] |
|
|
136
136
|
['markdown-summary'] | ['markdown-summary', {
|
|
137
|
-
color
|
|
137
|
+
color?: 'unicode' | 'html' | 'tex' | string;
|
|
138
138
|
metrics?: Array<"bytes" | "statements" | "branches" | "functions" | "lines">;
|
|
139
139
|
/**
|
|
140
140
|
* defaults to `coverage-summary.md`
|
|
@@ -143,7 +143,7 @@ declare namespace MCR {
|
|
|
143
143
|
}] |
|
|
144
144
|
['markdown-details'] | ['markdown-details', {
|
|
145
145
|
baseUrl?: string;
|
|
146
|
-
color
|
|
146
|
+
color?: 'unicode' | 'html' | 'tex' | string;
|
|
147
147
|
maxCols?: number;
|
|
148
148
|
skipPercent?: number;
|
|
149
149
|
metrics?: Array<"bytes" | "statements" | "branches" | "functions" | "lines">;
|
|
@@ -207,7 +207,7 @@ declare namespace MCR {
|
|
|
207
207
|
*/
|
|
208
208
|
none?: boolean;
|
|
209
209
|
/** function only, function name */
|
|
210
|
-
name?:
|
|
210
|
+
name?: string;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
export interface IgnoredRange {
|
|
@@ -422,10 +422,10 @@ declare namespace MCR {
|
|
|
422
422
|
sourceMapResolver?: (url: string, defaultResolver: Function) => Promise<any>;
|
|
423
423
|
|
|
424
424
|
/** (V8 only) {function} onEntry hook */
|
|
425
|
-
onEntry?: (entry: V8CoverageEntry) => Promise<void>;
|
|
425
|
+
onEntry?: (entry: V8CoverageEntry) => void | Promise<void>;
|
|
426
426
|
|
|
427
427
|
/** {function} onEnd hook */
|
|
428
|
-
onEnd?: (coverageResults: CoverageResults | undefined) => Promise<void>;
|
|
428
|
+
onEnd?: (coverageResults: CoverageResults | undefined) => void | Promise<void>;
|
|
429
429
|
|
|
430
430
|
[key: string]: any;
|
|
431
431
|
}
|
|
@@ -433,13 +433,13 @@ declare namespace MCR {
|
|
|
433
433
|
export interface McrCliOptions extends CoverageReportOptions {
|
|
434
434
|
|
|
435
435
|
/** (CLI only) {function} onStart hook */
|
|
436
|
-
onStart?: (coverageReport: CoverageReport) => Promise<void>;
|
|
436
|
+
onStart?: (coverageReport: CoverageReport) => void | Promise<void>;
|
|
437
437
|
|
|
438
438
|
/** (CLI only) {function} onReady hook before adding coverage data.
|
|
439
|
-
*
|
|
439
|
+
*
|
|
440
440
|
* Sometimes, the child process has not yet finished writing the coverage data, and it needs to wait here.
|
|
441
441
|
*/
|
|
442
|
-
onReady?: (coverageReport: CoverageReport, nodeV8CoverageDir: string, subprocess: any) => Promise<void>;
|
|
442
|
+
onReady?: (coverageReport: CoverageReport, nodeV8CoverageDir: string, subprocess: any) => void | Promise<void>;
|
|
443
443
|
|
|
444
444
|
}
|
|
445
445
|
|