monocart-coverage-reports 2.5.9 → 2.6.1
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/LICENSE +21 -21
- package/README.md +791 -778
- package/lib/cli.js +250 -215
- package/lib/converter/ast-visitor.js +675 -666
- package/lib/converter/ast.js +353 -353
- package/lib/converter/collect-source-maps.js +201 -201
- package/lib/converter/converter.js +1487 -1429
- package/lib/converter/find-original-range.js +737 -737
- package/lib/converter/ignore.js +163 -163
- package/lib/converter/info-branch.js +93 -93
- package/lib/converter/info-function.js +63 -63
- package/lib/converter/info-statement.js +43 -43
- package/lib/default/options.js +84 -84
- package/lib/default/template.html +47 -47
- package/lib/generate.js +720 -532
- package/lib/index.d.ts +360 -324
- package/lib/index.js +187 -180
- package/lib/index.mjs +5 -3
- package/lib/istanbul/istanbul-summary.js +70 -63
- package/lib/istanbul/istanbul.js +146 -146
- package/lib/packages/monocart-coverage-v8.js +1 -1
- package/lib/platform/concurrency.js +74 -74
- package/lib/platform/share.js +484 -484
- package/lib/utils/dedupe.js +118 -118
- package/lib/utils/request.js +62 -62
- package/lib/utils/snapshot.js +381 -0
- package/lib/utils/source-path.js +179 -179
- package/lib/utils/util.js +526 -526
- package/lib/v8/v8-summary.js +138 -138
- package/lib/v8/v8.js +400 -630
- package/package.json +81 -80
package/README.md
CHANGED
|
@@ -1,779 +1,792 @@
|
|
|
1
|
-
# Monocart Coverage Reports
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/monocart-coverage-reports)
|
|
4
|
-
[](https://www.npmjs.com/package/monocart-coverage-reports)
|
|
5
|
-

|
|
6
|
-

|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
> Code coverage tool to generate native [V8](https://v8.dev/blog/javascript-code-coverage) reports or [Istanbul](https://istanbul.js.org/) reports.
|
|
11
|
-
|
|
12
|
-
* [Usage](#usage)
|
|
13
|
-
* [Default Options](#default-options)
|
|
14
|
-
* [Available Reports](#available-reports)
|
|
15
|
-
* [Using `entryFilter` and `sourceFilter` to filter the results for V8 report](#using-entryfilter-and-sourcefilter-to-filter-the-results-for-v8-report)
|
|
16
|
-
* [onEnd Hook](#onend-hook)
|
|
17
|
-
* [`mcr` CLI](#mcr-cli)
|
|
18
|
-
* [Compare Reports](#compare-reports)
|
|
19
|
-
* [Compare Workflows](#compare-workflows)
|
|
20
|
-
* [Collecting Istanbul Coverage Data](#collecting-istanbul-coverage-data)
|
|
21
|
-
* [Collecting V8 Coverage Data](#collecting-v8-coverage-data)
|
|
22
|
-
* [Manually Resolve the Sourcemap](#manually-resolve-the-sourcemap)
|
|
23
|
-
* [Collecting Raw V8 Coverage Data with Puppeteer](#collecting-raw-v8-coverage-data-with-puppeteer)
|
|
24
|
-
* [Node.js V8 Coverage Report for Server Side](#nodejs-v8-coverage-report-for-server-side)
|
|
25
|
-
* [Multiprocessing Support](#multiprocessing-support)
|
|
26
|
-
* [Merge Coverage Reports](#merge-coverage-reports)
|
|
27
|
-
* [Resolve `sourcePath` for the Source Files](#resolve-sourcepath-for-the-source-files)
|
|
28
|
-
* [Adding Empty Coverage for Untested Files](#adding-empty-coverage-for-untested-files)
|
|
29
|
-
* [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)
|
|
36
|
-
* [Integration](#integration)
|
|
37
|
-
- [Playwright](#playwright)
|
|
38
|
-
- [Jest](#jest)
|
|
39
|
-
- [Vitest](#vitest)
|
|
40
|
-
- [CodeceptJS](#codeceptjs)
|
|
41
|
-
- [WebdriverIO](#webdriverio)
|
|
42
|
-
- [
|
|
43
|
-
- [
|
|
44
|
-
- [
|
|
45
|
-
- [
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
coverageReport
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
await coverageReport.add(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
//
|
|
66
|
-
// const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- [example
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
- `
|
|
92
|
-
- `
|
|
93
|
-
-
|
|
94
|
-
- [Istanbul
|
|
95
|
-
|
|
96
|
-
-
|
|
97
|
-
|
|
98
|
-
- `json`
|
|
99
|
-
- `
|
|
100
|
-
- `
|
|
101
|
-
-
|
|
102
|
-
- [
|
|
103
|
-
|
|
104
|
-
- `
|
|
105
|
-
- `
|
|
106
|
-
- `text`
|
|
107
|
-
- `text-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
- `
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}]
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
'
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
[
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
> src/
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
```js
|
|
205
|
-
const coverageOptions = {
|
|
206
|
-
entryFilter: "
|
|
207
|
-
sourceFilter:
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
-
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
--
|
|
282
|
-
--
|
|
283
|
-
--
|
|
284
|
-
--
|
|
285
|
-
--
|
|
286
|
-
--
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
|
309
|
-
|
|
|
310
|
-
|
|
|
311
|
-
|
|
|
312
|
-
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
-
|
|
328
|
-
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
-
|
|
336
|
-
|
|
337
|
-
- [
|
|
338
|
-
|
|
339
|
-
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
- [
|
|
344
|
-
-
|
|
345
|
-
-
|
|
346
|
-
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
>
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
await
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
]);
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
- [
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
const coverageOptions = {
|
|
564
|
-
all: {
|
|
565
|
-
dir: ['./src'],
|
|
566
|
-
filter:
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
- Ignoring
|
|
589
|
-
```js
|
|
590
|
-
/* v8 ignore
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
- [
|
|
709
|
-
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
- [
|
|
713
|
-
|
|
714
|
-
### [
|
|
715
|
-
- [
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
[
|
|
722
|
-
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
-
|
|
776
|
-
-
|
|
777
|
-
|
|
778
|
-
|
|
1
|
+
# Monocart Coverage Reports
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/monocart-coverage-reports)
|
|
4
|
+
[](https://www.npmjs.com/package/monocart-coverage-reports)
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
> Code coverage tool to generate native [V8](https://v8.dev/blog/javascript-code-coverage) reports or [Istanbul](https://istanbul.js.org/) reports.
|
|
11
|
+
|
|
12
|
+
* [Usage](#usage)
|
|
13
|
+
* [Default Options](#default-options)
|
|
14
|
+
* [Available Reports](#available-reports)
|
|
15
|
+
* [Using `entryFilter` and `sourceFilter` to filter the results for V8 report](#using-entryfilter-and-sourcefilter-to-filter-the-results-for-v8-report)
|
|
16
|
+
* [onEnd Hook](#onend-hook)
|
|
17
|
+
* [`mcr` CLI](#mcr-cli)
|
|
18
|
+
* [Compare Reports](#compare-reports)
|
|
19
|
+
* [Compare Workflows](#compare-workflows)
|
|
20
|
+
* [Collecting Istanbul Coverage Data](#collecting-istanbul-coverage-data)
|
|
21
|
+
* [Collecting V8 Coverage Data](#collecting-v8-coverage-data)
|
|
22
|
+
* [Manually Resolve the Sourcemap](#manually-resolve-the-sourcemap)
|
|
23
|
+
* [Collecting Raw V8 Coverage Data with Puppeteer](#collecting-raw-v8-coverage-data-with-puppeteer)
|
|
24
|
+
* [Node.js V8 Coverage Report for Server Side](#nodejs-v8-coverage-report-for-server-side)
|
|
25
|
+
* [Multiprocessing Support](#multiprocessing-support)
|
|
26
|
+
* [Merge Coverage Reports](#merge-coverage-reports)
|
|
27
|
+
* [Resolve `sourcePath` for the Source Files](#resolve-sourcepath-for-the-source-files)
|
|
28
|
+
* [Adding Empty Coverage for Untested Files](#adding-empty-coverage-for-untested-files)
|
|
29
|
+
* [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)
|
|
36
|
+
* [Integration](#integration)
|
|
37
|
+
- [Playwright](#playwright)
|
|
38
|
+
- [Jest](#jest)
|
|
39
|
+
- [Vitest](#vitest)
|
|
40
|
+
- [CodeceptJS](#codeceptjs)
|
|
41
|
+
- [WebdriverIO](#webdriverio)
|
|
42
|
+
- [Storybook Test Runner](#storybook-test-runner)
|
|
43
|
+
- [Codecov](#codecov)
|
|
44
|
+
- [Coveralls](#coveralls)
|
|
45
|
+
- [Sonar Cloud](#sonar-cloud)
|
|
46
|
+
- [Integration with Any Testing Framework](#integration-with-any-testing-framework)
|
|
47
|
+
* [Thanks](#thanks)
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
```js
|
|
51
|
+
const MCR = require('monocart-coverage-reports');
|
|
52
|
+
const coverageOptions = {
|
|
53
|
+
name: 'My Coverage Report - 2024-02-28',
|
|
54
|
+
outputDir: './coverage-reports',
|
|
55
|
+
reports: ["v8", "console-details"]
|
|
56
|
+
}
|
|
57
|
+
const coverageReport = MCR(coverageOptions);
|
|
58
|
+
coverageReport.cleanCache();
|
|
59
|
+
|
|
60
|
+
await coverageReport.add(coverageData1);
|
|
61
|
+
await coverageReport.add(coverageData2);
|
|
62
|
+
|
|
63
|
+
await coverageReport.generate();
|
|
64
|
+
|
|
65
|
+
// Or
|
|
66
|
+
// const { CoverageReport } = require('monocart-coverage-reports');
|
|
67
|
+
// const coverageReport = new CoverageReport(coverageOptions);
|
|
68
|
+
```
|
|
69
|
+
- [example v8](https://github.com/cenfun/monocart-coverage-reports/blob/main/test/test-v8.js)
|
|
70
|
+
- [example istanbul](https://github.com/cenfun/monocart-coverage-reports/blob/main/test/test-istanbul.js)
|
|
71
|
+
|
|
72
|
+
## Default Options
|
|
73
|
+
- [lib/default/options.js](https://github.com/cenfun/monocart-coverage-reports/blob/main/lib/default/options.js)
|
|
74
|
+
|
|
75
|
+
## Available Reports
|
|
76
|
+
|
|
77
|
+
> V8 build-in reports (V8 data only):
|
|
78
|
+
|
|
79
|
+
- `v8`
|
|
80
|
+
- 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/)
|
|
81
|
+
- 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/)
|
|
82
|
+
|
|
83
|
+

|
|
84
|
+
|
|
85
|
+
- `v8-json`
|
|
86
|
+
- [V8 coverage-report.json](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)
|
|
87
|
+
|
|
88
|
+
> Istanbul build-in reports (both V8 and istanbul data):
|
|
89
|
+
|
|
90
|
+
- `clover`
|
|
91
|
+
- `cobertura`
|
|
92
|
+
- `html`
|
|
93
|
+
- [Istanbul html](https://cenfun.github.io/monocart-coverage-reports/istanbul/)
|
|
94
|
+
- [V8 to Istanbul](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/istanbul)
|
|
95
|
+
- `html-spa`
|
|
96
|
+
- [Istanbul html-spa](https://cenfun.github.io/monocart-coverage-reports/istanbul/html-spa/)
|
|
97
|
+
- `json`
|
|
98
|
+
- `json-summary`
|
|
99
|
+
- `lcov`
|
|
100
|
+
- `lcovonly`
|
|
101
|
+
- [V8 lcov.info](https://cenfun.github.io/monocart-coverage-reports/v8/lcov.info)
|
|
102
|
+
- [Istanbul lcov.info](https://cenfun.github.io/monocart-coverage-reports/istanbul/lcov.info)
|
|
103
|
+
- `none`
|
|
104
|
+
- `teamcity`
|
|
105
|
+
- `text`
|
|
106
|
+
- `text-lcov`
|
|
107
|
+
- `text-summary`
|
|
108
|
+
|
|
109
|
+
> Other build-in reports (both V8 and istanbul data):
|
|
110
|
+
|
|
111
|
+
- `codecov`
|
|
112
|
+
- coverage data for [Codecov](https://docs.codecov.com/docs/codecov-custom-coverage-format), see [example](https://app.codecov.io/github/cenfun/monocart-coverage-reports)
|
|
113
|
+
|
|
114
|
+
- `console-summary` shows coverage summary in the console
|
|
115
|
+
|
|
116
|
+

|
|
117
|
+
|
|
118
|
+
- `console-details` Show file coverage and uncovered lines in the console. Like `text`, but for V8. For Github actions, we can enforce color with env: `FORCE_COLOR: true`.
|
|
119
|
+
|
|
120
|
+

|
|
121
|
+
|
|
122
|
+
- `raw` only keep all original data, which can be used for other reports input with `inputDir`
|
|
123
|
+
- see [Merge Coverage Reports](#merge-coverage-reports)
|
|
124
|
+
|
|
125
|
+
- Custom Reporter
|
|
126
|
+
```js
|
|
127
|
+
{
|
|
128
|
+
reports: [
|
|
129
|
+
[path.resolve('./test/custom-istanbul-reporter.js'), {
|
|
130
|
+
type: 'istanbul',
|
|
131
|
+
file: 'custom-istanbul-coverage.text'
|
|
132
|
+
}],
|
|
133
|
+
[path.resolve('./test/custom-v8-reporter.js'), {
|
|
134
|
+
type: 'v8',
|
|
135
|
+
outputFile: 'custom-v8-coverage.json'
|
|
136
|
+
}],
|
|
137
|
+
[path.resolve('./test/custom-v8-reporter.mjs'), {
|
|
138
|
+
type: 'both'
|
|
139
|
+
}]
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
- istanbul custom reporter
|
|
144
|
+
> 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.
|
|
145
|
+
- v8 custom reporter
|
|
146
|
+
> example: [./test/custom-v8-reporter.js](./test/custom-v8-reporter.js)
|
|
147
|
+
|
|
148
|
+
### Multiple Reports:
|
|
149
|
+
```js
|
|
150
|
+
const MCR = require('monocart-coverage-reports');
|
|
151
|
+
const coverageOptions = {
|
|
152
|
+
outputDir: './coverage-reports',
|
|
153
|
+
reports: [
|
|
154
|
+
// build-in reports
|
|
155
|
+
['console-summary'],
|
|
156
|
+
['v8'],
|
|
157
|
+
['html', {
|
|
158
|
+
subdir: 'istanbul'
|
|
159
|
+
}],
|
|
160
|
+
['json', {
|
|
161
|
+
file: 'my-json-file.json'
|
|
162
|
+
}],
|
|
163
|
+
'lcovonly',
|
|
164
|
+
|
|
165
|
+
// custom reports
|
|
166
|
+
// Specify reporter name with the NPM package
|
|
167
|
+
["custom-reporter-1"],
|
|
168
|
+
["custom-reporter-2", {
|
|
169
|
+
type: "istanbul",
|
|
170
|
+
key: "value"
|
|
171
|
+
}],
|
|
172
|
+
// Specify reporter name with local path
|
|
173
|
+
['/absolute/path/to/custom-reporter.js']
|
|
174
|
+
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
const coverageReport = MCR(coverageOptions);
|
|
178
|
+
coverageReport.cleanCache();
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Using `entryFilter` and `sourceFilter` to filter the results for V8 report
|
|
182
|
+
When V8 coverage data collected, it actually contains the data of all entry files, for example:
|
|
183
|
+
```
|
|
184
|
+
dist/main.js
|
|
185
|
+
dist/vendor.js
|
|
186
|
+
dist/something-else.js
|
|
187
|
+
```
|
|
188
|
+
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.
|
|
189
|
+
```
|
|
190
|
+
dist/main.js
|
|
191
|
+
```
|
|
192
|
+
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`.
|
|
193
|
+
```
|
|
194
|
+
> src/index.js
|
|
195
|
+
> src/components/app.js
|
|
196
|
+
> node_modules/dependency/dist/dependency.js
|
|
197
|
+
```
|
|
198
|
+
We can use `sourceFilter` to filter the source files. For example, we should remove `dependency.js` if it is not in our coverage scope.
|
|
199
|
+
```
|
|
200
|
+
> src/index.js
|
|
201
|
+
> src/components/app.js
|
|
202
|
+
```
|
|
203
|
+
For example:
|
|
204
|
+
```js
|
|
205
|
+
const coverageOptions = {
|
|
206
|
+
entryFilter: (entry) => entry.url.indexOf("main.js") !== -1,
|
|
207
|
+
sourceFilter: (sourcePath) => sourcePath.search(/src\//) !== -1
|
|
208
|
+
};
|
|
209
|
+
```
|
|
210
|
+
Or using `minimatch` pattern:
|
|
211
|
+
```js
|
|
212
|
+
const coverageOptions = {
|
|
213
|
+
entryFilter: "**/main.js",
|
|
214
|
+
sourceFilter: "**/src/**"
|
|
215
|
+
};
|
|
216
|
+
// supports multiple patterns:
|
|
217
|
+
const coverageOptions = {
|
|
218
|
+
entryFilter: {
|
|
219
|
+
'**/vendor.js': false,
|
|
220
|
+
'**/main.js': true
|
|
221
|
+
},
|
|
222
|
+
sourceFilter: {
|
|
223
|
+
'**/src/**': true
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## onEnd Hook
|
|
229
|
+
For example, checking thresholds:
|
|
230
|
+
```js
|
|
231
|
+
const EC = require('eight-colors');
|
|
232
|
+
const coverageOptions = {
|
|
233
|
+
name: 'My Coverage Report',
|
|
234
|
+
outputDir: './coverage-reports',
|
|
235
|
+
onEnd: (coverageResults) => {
|
|
236
|
+
const thresholds = {
|
|
237
|
+
bytes: 80,
|
|
238
|
+
lines: 60
|
|
239
|
+
};
|
|
240
|
+
console.log('check thresholds ...', thresholds);
|
|
241
|
+
const errors = [];
|
|
242
|
+
const { summary } = coverageResults;
|
|
243
|
+
Object.keys(thresholds).forEach((k) => {
|
|
244
|
+
const pct = summary[k].pct;
|
|
245
|
+
if (pct < thresholds[k]) {
|
|
246
|
+
errors.push(`Coverage threshold for ${k} (${pct} %) not met: ${thresholds[k]} %`);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
if (errors.length) {
|
|
250
|
+
const errMsg = errors.join('\n');
|
|
251
|
+
console.log(EC.red(errMsg));
|
|
252
|
+
// throw new Error(errMsg);
|
|
253
|
+
// process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## `mcr` CLI
|
|
260
|
+
> 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`.
|
|
261
|
+
- Global mode
|
|
262
|
+
```sh
|
|
263
|
+
npm i monocart-coverage-reports -g
|
|
264
|
+
mcr "node ./test/test-node-env.js" -r v8,console-summary --lcov
|
|
265
|
+
```
|
|
266
|
+
- Current working directory mode
|
|
267
|
+
```sh
|
|
268
|
+
npm i monocart-coverage-reports
|
|
269
|
+
npx mcr "node ./test/test-node-env.js" -r v8,console-summary --lcov
|
|
270
|
+
```
|
|
271
|
+
- CLI Options
|
|
272
|
+
```sh
|
|
273
|
+
Usage: mcr [options] <command>
|
|
274
|
+
|
|
275
|
+
CLI to generate coverage reports
|
|
276
|
+
|
|
277
|
+
Arguments:
|
|
278
|
+
command command to execute
|
|
279
|
+
|
|
280
|
+
Options:
|
|
281
|
+
-V, --version output the version number
|
|
282
|
+
-c, --config <path> custom config path
|
|
283
|
+
-o, --outputDir <dir> output dir for reports
|
|
284
|
+
-r, --reports <name[,name]> coverage reports to use
|
|
285
|
+
-n, --name <name> report name for title
|
|
286
|
+
-i, --inputDir <dir> input dir for merging raw files
|
|
287
|
+
--entryFilter <pattern> entry url filter
|
|
288
|
+
--sourceFilter <pattern> source path filter
|
|
289
|
+
--outputFile <path> output file for v8 report
|
|
290
|
+
--inline inline html for v8 report
|
|
291
|
+
--assetsPath <path> assets path if not inline
|
|
292
|
+
--lcov generate lcov.info file
|
|
293
|
+
--logging <logging> off, error, info, debug
|
|
294
|
+
-h, --help display help for command
|
|
295
|
+
```
|
|
296
|
+
- Supports loading default configuration file
|
|
297
|
+
- `.mcrrc`
|
|
298
|
+
- `mcr.config.json`
|
|
299
|
+
- `mcr.config.mjs`
|
|
300
|
+
- `mcr.config.cjs`
|
|
301
|
+
- `mcr.config.js`
|
|
302
|
+
- Specify custom configuration file
|
|
303
|
+
```sh
|
|
304
|
+
mcr "node ./test.js" -c path-to/my-custom-config.js
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Compare Reports
|
|
308
|
+
| | Istanbul | V8 | V8 to Istanbul |
|
|
309
|
+
| :--------------| :------ | :------ | :---------------------- |
|
|
310
|
+
| Coverage data | [Istanbul](https://github.com/gotwarlost/istanbul/blob/master/coverage.json.md) (Object) | [V8](#v8-coverage-data-format) (Array) | [V8](#v8-coverage-data-format) (Array) |
|
|
311
|
+
| Output | [Istanbul reports](#available-reports) | [V8 reports](#available-reports) | [Istanbul reports](#available-reports) |
|
|
312
|
+
| - Bytes | ❌ | ✅ | ❌ |
|
|
313
|
+
| - Statements | ✅ | ✅ | ✅ |
|
|
314
|
+
| - Branches | ✅ | ✅ | ✅ |
|
|
315
|
+
| - Functions | ✅ | ✅ | ✅ |
|
|
316
|
+
| - Lines | ✅ | ✅ | ✅ |
|
|
317
|
+
| - Execution counts | ✅ | ✅ | ✅ |
|
|
318
|
+
| CSS coverage | ❌ | ✅ | ✅ |
|
|
319
|
+
| Minified code | ❌ | ✅ | ❌ |
|
|
320
|
+
|
|
321
|
+
## Compare Workflows
|
|
322
|
+
- Istanbul Workflows
|
|
323
|
+
- 1, [Collecting Istanbul coverage data](#collecting-istanbul-coverage-data)
|
|
324
|
+
- 2, Adding coverage data and generating coverage report
|
|
325
|
+
|
|
326
|
+
- V8 Workflows
|
|
327
|
+
- 1, [Collecting V8 coverage data](#collecting-v8-coverage-data)
|
|
328
|
+
- 3, Adding coverage data and generating coverage report
|
|
329
|
+
|
|
330
|
+
## Collecting Istanbul Coverage Data
|
|
331
|
+
- Instrumenting source code
|
|
332
|
+
> Before collecting Istanbul coverage data, It requires your source code is instrumented with Istanbul
|
|
333
|
+
- 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)
|
|
334
|
+
- rollup: [rollup-plugin-istanbul](https://github.com/artberri/rollup-plugin-istanbul)
|
|
335
|
+
- vite: [vite-plugin-istanbul](https://github.com/ifaxity/vite-plugin-istanbul)
|
|
336
|
+
- Browser
|
|
337
|
+
- Collecting coverage data from `window.__coverage__`, example: [test-istanbul.js](https://github.com/cenfun/monocart-coverage-reports/blob/main/test/test-istanbul.js)
|
|
338
|
+
- Node.js
|
|
339
|
+
- Collecting coverage data from `global.__coverage__`
|
|
340
|
+
|
|
341
|
+
## Collecting V8 Coverage Data
|
|
342
|
+
- For source code: enable `sourcemap` and do not compress/minify:
|
|
343
|
+
- [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)
|
|
344
|
+
- [rollup](https://rollupjs.org/configuration-options/): `sourcemap: true`
|
|
345
|
+
- [vite](https://vitejs.dev/config/build-options.html): `sourcemap: true` and `minify: false`
|
|
346
|
+
- [esbuild](https://esbuild.github.io/api/): `sourcemap: true` and `minify: false`
|
|
347
|
+
- [Manually Resolve the Sourcemap](#manually-resolve-the-sourcemap)
|
|
348
|
+
- Browser (Chromium Only)
|
|
349
|
+
> Collecting coverage data with [Chromium Coverage API](#chromium-coverage-api):
|
|
350
|
+
- [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)
|
|
351
|
+
- see [Collecting Raw V8 Coverage Data with Puppeteer](#collecting-raw-v8-coverage-data-with-puppeteer)
|
|
352
|
+
- Node.js
|
|
353
|
+
- see [Node.js V8 Coverage Report for Server Side](#nodejs-v8-coverage-report-for-server-side)
|
|
354
|
+
|
|
355
|
+
## Manually Resolve the Sourcemap
|
|
356
|
+
> 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.
|
|
357
|
+
```js
|
|
358
|
+
const jsCoverage = await page.coverage.stopJSCoverage();
|
|
359
|
+
jsCoverage.forEach((entry) => {
|
|
360
|
+
// read sourcemap for the my-dist.js manually
|
|
361
|
+
if (entry.url.endsWith('my-dist.js')) {
|
|
362
|
+
entry.sourceMap = JSON.parse(fs.readFileSync('dist/my-dist.js.map').toString('utf-8'));
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
await MCR(coverageOptions).add(jsCoverage);
|
|
367
|
+
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Collecting Raw V8 Coverage Data with Puppeteer
|
|
371
|
+
> 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)
|
|
372
|
+
```js
|
|
373
|
+
await Promise.all([
|
|
374
|
+
page.coverage.startJSCoverage({
|
|
375
|
+
resetOnNavigation: false,
|
|
376
|
+
// provide raw v8 coverage data
|
|
377
|
+
includeRawScriptCoverage: true
|
|
378
|
+
}),
|
|
379
|
+
page.coverage.startCSSCoverage({
|
|
380
|
+
resetOnNavigation: false
|
|
381
|
+
})
|
|
382
|
+
]);
|
|
383
|
+
|
|
384
|
+
await page.goto(url);
|
|
385
|
+
|
|
386
|
+
const [jsCoverage, cssCoverage] = await Promise.all([
|
|
387
|
+
page.coverage.stopJSCoverage(),
|
|
388
|
+
page.coverage.stopCSSCoverage()
|
|
389
|
+
]);
|
|
390
|
+
|
|
391
|
+
// to raw V8 script coverage
|
|
392
|
+
const coverageData = [... jsCoverage.map((it) => {
|
|
393
|
+
return {
|
|
394
|
+
source: it.text,
|
|
395
|
+
... it.rawScriptCoverage
|
|
396
|
+
};
|
|
397
|
+
}), ... cssCoverage];
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
## Node.js V8 Coverage Report for Server Side
|
|
401
|
+
Possible solutions:
|
|
402
|
+
- [NODE_V8_COVERAGE](https://nodejs.org/docs/latest/api/cli.html#node_v8_coveragedir)=`dir`
|
|
403
|
+
- 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.
|
|
404
|
+
- Read the JSON file(s) from the `dir` and generate coverage report.
|
|
405
|
+
- Example:
|
|
406
|
+
> cross-env NODE_V8_COVERAGE=`.temp/v8-coverage-env` node [./test/test-node-env.js](./test/test-node-env.js) && node [./test/generate-report.js](./test/generate-report.js)
|
|
407
|
+
|
|
408
|
+
- [V8](https://nodejs.org/docs/latest/api/v8.html#v8takecoverage) API + NODE_V8_COVERAGE
|
|
409
|
+
- Writing the coverage started by NODE_V8_COVERAGE to disk on demand with `v8.takeCoverage()`, it does not require waiting until the program exits gracefully.
|
|
410
|
+
- Example:
|
|
411
|
+
> cross-env NODE_V8_COVERAGE=`.temp/v8-coverage-api` node [./test/test-node-api.js](./test/test-node-api.js)
|
|
412
|
+
|
|
413
|
+
- [Inspector](https://nodejs.org/docs/latest/api/inspector.html) API
|
|
414
|
+
- Connecting to the V8 inspector and enable V8 coverage.
|
|
415
|
+
- Taking coverage data and adding it to the report.
|
|
416
|
+
- Example:
|
|
417
|
+
> node [./test/test-node-ins.js](./test/test-node-ins.js)
|
|
418
|
+
|
|
419
|
+
- [CDP](https://chromedevtools.github.io/devtools-protocol/) API
|
|
420
|
+
- Enabling [Node Debugging](https://nodejs.org/en/guides/debugging-getting-started/).
|
|
421
|
+
- Collecting coverage data with CDP API.
|
|
422
|
+
- Example:
|
|
423
|
+
> node --inspect=9229 [./test/test-node-cdp.js](./test/test-node-cdp.js)
|
|
424
|
+
|
|
425
|
+
- [Node Debugging](https://nodejs.org/en/guides/debugging-getting-started) + CDP + NODE_V8_COVERAGE + V8 API
|
|
426
|
+
- When the program starts a server, it will not exit on its own, thus requiring a manual invocation of the `v8.takeCoverage()` interface to manually collect coverage data. Remote invocation of the `v8.takeCoverage()` interface can be accomplished through the `Runtime.evaluate` of the CDP.
|
|
427
|
+
- Example for [koa](https://github.com/koajs/koa) web server:
|
|
428
|
+
> node [./test/test-node-koa.js](./test/test-node-koa.js)
|
|
429
|
+
|
|
430
|
+
- [Child Process](https://nodejs.org/docs/latest/api/child_process.html) + NODE_V8_COVERAGE
|
|
431
|
+
- see [`mcr` CLI](#mcr-cli)
|
|
432
|
+
|
|
433
|
+
## Multiprocessing Support
|
|
434
|
+
> 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)
|
|
435
|
+
- Main process, before the start of testing
|
|
436
|
+
```js
|
|
437
|
+
const MCR = require('monocart-coverage-reports');
|
|
438
|
+
const coverageOptions = require('path-to/same-options.js');
|
|
439
|
+
const coverageReport = MCR(coverageOptions);
|
|
440
|
+
// clean previous cache before the start of testing
|
|
441
|
+
// unless the running environment is new and no cache
|
|
442
|
+
coverageReport.cleanCache();
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
- Sub process 1, testing stage 1
|
|
446
|
+
```js
|
|
447
|
+
const MCR = require('monocart-coverage-reports');
|
|
448
|
+
const coverageOptions = require('path-to/same-options.js');
|
|
449
|
+
const coverageReport = MCR(coverageOptions);
|
|
450
|
+
// do not clean cache in the stage
|
|
451
|
+
await coverageReport.add(coverageData1);
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
- Sub process 2, testing stage 2
|
|
455
|
+
```js
|
|
456
|
+
const MCR = require('monocart-coverage-reports');
|
|
457
|
+
const coverageOptions = require('path-to/same-options.js');
|
|
458
|
+
const coverageReport = MCR(coverageOptions);
|
|
459
|
+
// do not clean cache in the stage
|
|
460
|
+
await coverageReport.add(coverageData2);
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
- Main process, after the completion of testing
|
|
464
|
+
```js
|
|
465
|
+
// generate coverage reports after the completion of testing
|
|
466
|
+
const MCR = require('monocart-coverage-reports');
|
|
467
|
+
const coverageOptions = require('path-to/same-options.js');
|
|
468
|
+
const coverageReport = MCR(coverageOptions);
|
|
469
|
+
// do not clean cache before generating reports
|
|
470
|
+
await coverageReport.generate();
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
## Merge Coverage Reports
|
|
474
|
+
The following usage scenarios may require merging coverage reports:
|
|
475
|
+
- 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.
|
|
476
|
+
- 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.
|
|
477
|
+
- 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.
|
|
478
|
+
|
|
479
|
+
If the reports cannot be merged automatically, then here is how to manually merge the reports.
|
|
480
|
+
First, using the `raw` report to export the original coverage data to the specified directory.
|
|
481
|
+
```js
|
|
482
|
+
const coverageOptions = {
|
|
483
|
+
name: 'My Unit Test Coverage Report',
|
|
484
|
+
outputDir: "./coverage-reports/unit",
|
|
485
|
+
reports: [
|
|
486
|
+
['raw', {
|
|
487
|
+
// relative path will be "./coverage-reports/unit/raw"
|
|
488
|
+
outputDir: "raw"
|
|
489
|
+
}],
|
|
490
|
+
['v8'],
|
|
491
|
+
['console-summary']
|
|
492
|
+
]
|
|
493
|
+
};
|
|
494
|
+
```
|
|
495
|
+
Then, after all the tests are completed, generate a merged report with option `inputDir`:
|
|
496
|
+
```js
|
|
497
|
+
// esm syntax
|
|
498
|
+
import fs from "fs";
|
|
499
|
+
import { CoverageReport } from 'monocart-coverage-reports';
|
|
500
|
+
const coverageOptions = {
|
|
501
|
+
name: 'My Merged Coverage Report',
|
|
502
|
+
inputDir: [
|
|
503
|
+
'./coverage-reports/unit/raw',
|
|
504
|
+
'./coverage-reports/e2e/raw'
|
|
505
|
+
],
|
|
506
|
+
outputDir: './coverage-reports/merged',
|
|
507
|
+
reports: [
|
|
508
|
+
['v8'],
|
|
509
|
+
['console-summary']
|
|
510
|
+
],
|
|
511
|
+
onEnd: () => {
|
|
512
|
+
// remove the raw files if it useless
|
|
513
|
+
fs.rmSync('./coverage-reports/unit/raw', {
|
|
514
|
+
recursive: true,
|
|
515
|
+
force: true
|
|
516
|
+
})
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
await new CoverageReport(coverageOptions).generate();
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
## Resolve `sourcePath` for the Source Files
|
|
523
|
+
If the source file comes from the sourcemap, then its path is a virtual path. Using the `sourcePath` option to resolve a custom path.
|
|
524
|
+
For example, we have tested multiple dist files, which contain some common files. We hope to merge the coverage of the same files, so we need to unify the `sourcePath` in order to be able to merge the coverage data.
|
|
525
|
+
```js
|
|
526
|
+
const coverageOptions = {
|
|
527
|
+
sourcePath: (filePath) => {
|
|
528
|
+
// Remove the virtual prefix
|
|
529
|
+
const list = ['my-dist-file1/', 'my-dist-file2/'];
|
|
530
|
+
for (const str of list) {
|
|
531
|
+
if (filePath.startsWith(str)) {
|
|
532
|
+
return filePath.slice(str.length);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return filePath;
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
```
|
|
539
|
+
It also supports simple key/value replacement:
|
|
540
|
+
```js
|
|
541
|
+
const coverageOptions = {
|
|
542
|
+
sourcePath: {
|
|
543
|
+
'my-dist-file1/': '',
|
|
544
|
+
'my-dist-file2/': ''
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
## Adding Empty Coverage for Untested Files
|
|
550
|
+
By default the untested files will not be included in the coverage report, we can add empty coverage data for all files with option `all`, the untested files will show 0% coverage.
|
|
551
|
+
```js
|
|
552
|
+
const coverageOptions = {
|
|
553
|
+
all: {
|
|
554
|
+
dir: ['./src'],
|
|
555
|
+
filter: (filePath) => {
|
|
556
|
+
return true;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
```
|
|
561
|
+
The filter also supports `minimatch` pattern:
|
|
562
|
+
```js
|
|
563
|
+
const coverageOptions = {
|
|
564
|
+
all: {
|
|
565
|
+
dir: ['./src'],
|
|
566
|
+
filter: '**/*.js'
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
// or multiple patterns
|
|
570
|
+
const coverageOptions = {
|
|
571
|
+
all: {
|
|
572
|
+
dir: ['./src'],
|
|
573
|
+
filter: {
|
|
574
|
+
// exclude files
|
|
575
|
+
'**/ignored-*.js': false,
|
|
576
|
+
'**/*.html': false,
|
|
577
|
+
'**/*.ts': false,
|
|
578
|
+
// empty css coverage
|
|
579
|
+
'**/*.scss': "css",
|
|
580
|
+
'**/*': true
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
## Ignoring Uncovered Codes
|
|
587
|
+
To ignore codes, use the special comment which starts with `v8 ignore `:
|
|
588
|
+
- Ignoring all until stop
|
|
589
|
+
```js
|
|
590
|
+
/* v8 ignore start */
|
|
591
|
+
function uncovered() {
|
|
592
|
+
}
|
|
593
|
+
/* v8 ignore stop */
|
|
594
|
+
```
|
|
595
|
+
- Ignoring the next line or next N lines
|
|
596
|
+
```js
|
|
597
|
+
/* v8 ignore next */
|
|
598
|
+
const os = platform === 'wind32' ? 'Windows' : 'Other';
|
|
599
|
+
|
|
600
|
+
const os = platform === 'wind32' ? 'Windows' /* v8 ignore next */ : 'Other';
|
|
601
|
+
|
|
602
|
+
// v8 ignore next 3
|
|
603
|
+
if (platform === 'linux') {
|
|
604
|
+
console.log('hello linux');
|
|
605
|
+
}
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
## Chromium Coverage API
|
|
609
|
+
- [V8 coverage report](https://v8.dev/blog/javascript-code-coverage) - Native support for JavaScript code coverage to V8. (Chromium only)
|
|
610
|
+
- [Playwright Coverage Class](https://playwright.dev/docs/api/class-coverage)
|
|
611
|
+
- [Puppeteer Coverage class](https://pptr.dev/api/puppeteer.coverage)
|
|
612
|
+
- [DevTools Protocol for Coverage](https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#method-startPreciseCoverage)
|
|
613
|
+
|
|
614
|
+
## V8 Coverage Data Format
|
|
615
|
+
```js
|
|
616
|
+
// Coverage data for a source range.
|
|
617
|
+
export interface CoverageRange {
|
|
618
|
+
// JavaScript script source offset for the range start.
|
|
619
|
+
startOffset: integer;
|
|
620
|
+
// JavaScript script source offset for the range end.
|
|
621
|
+
endOffset: integer;
|
|
622
|
+
// Collected execution count of the source range.
|
|
623
|
+
count: integer;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Coverage data for a JavaScript function.
|
|
627
|
+
/**
|
|
628
|
+
* @functionName can be an empty string.
|
|
629
|
+
* @ranges is always non-empty. The first range is called the "root range".
|
|
630
|
+
* @isBlockCoverage indicates if the function has block coverage information.
|
|
631
|
+
If this is false, it usually means that the functions was never called.
|
|
632
|
+
It seems to be equivalent to ranges.length === 1 && ranges[0].count === 0.
|
|
633
|
+
*/
|
|
634
|
+
export interface FunctionCoverage {
|
|
635
|
+
// JavaScript function name.
|
|
636
|
+
functionName: string;
|
|
637
|
+
// Source ranges inside the function with coverage data.
|
|
638
|
+
ranges: CoverageRange[];
|
|
639
|
+
// Whether coverage data for this function has block granularity.
|
|
640
|
+
isBlockCoverage: boolean;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// Coverage data for a JavaScript script.
|
|
644
|
+
export interface ScriptCoverage {
|
|
645
|
+
// JavaScript script id.
|
|
646
|
+
scriptId: Runtime.ScriptId;
|
|
647
|
+
// JavaScript script name or url.
|
|
648
|
+
url: string;
|
|
649
|
+
// Functions contained in the script that has coverage data.
|
|
650
|
+
functions: FunctionCoverage[];
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
export type V8CoverageData = ScriptCoverage[];
|
|
654
|
+
```
|
|
655
|
+
see devtools-protocol [ScriptCoverage](https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#type-ScriptCoverage) and [v8-coverage](https://github.com/bcoe/v8-coverage)
|
|
656
|
+
|
|
657
|
+
## How to convert V8 to Istanbul
|
|
658
|
+
### Using [v8-to-istanbul](https://github.com/istanbuljs/v8-to-istanbul)
|
|
659
|
+
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:
|
|
660
|
+
- 1, The source mapping does not work well if the position is between the two consecutive mappings. for example:
|
|
661
|
+
```js
|
|
662
|
+
const a = tf ? 'true' : 'false';
|
|
663
|
+
^ ^ ^
|
|
664
|
+
m1 p m2
|
|
665
|
+
```
|
|
666
|
+
> `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.
|
|
667
|
+
|
|
668
|
+
- 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.
|
|
669
|
+
|
|
670
|
+
### How Monocart Works
|
|
671
|
+
We implemented new converter:
|
|
672
|
+
- 1, Trying to fix the middle position if not found the exact mapping for the position.
|
|
673
|
+
- 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
|
+
|
|
675
|
+
| AST | V8 |
|
|
676
|
+
| :---------------------| :------------- |
|
|
677
|
+
| AssignmentPattern | 🛇 Not Support |
|
|
678
|
+
| ConditionalExpression | ✔ |
|
|
679
|
+
| IfStatement | ✔ |
|
|
680
|
+
| LogicalExpression | ✔ |
|
|
681
|
+
| SwitchStatement | ✔ |
|
|
682
|
+
|
|
683
|
+
## Debug for Coverage and Sourcemap
|
|
684
|
+
> 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.
|
|
685
|
+
- Start debugging for v8 report with option `logging: 'debug'`
|
|
686
|
+
```js
|
|
687
|
+
const coverageOptions = {
|
|
688
|
+
logging: 'debug',
|
|
689
|
+
reports: [
|
|
690
|
+
['v8'],
|
|
691
|
+
['console-summary']
|
|
692
|
+
]
|
|
693
|
+
};
|
|
694
|
+
```
|
|
695
|
+
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.
|
|
696
|
+

|
|
697
|
+
|
|
698
|
+
- Check sourcemap with [Source Map Visualization](https://evanw.github.io/source-map-visualization/)
|
|
699
|
+
|
|
700
|
+

|
|
701
|
+
|
|
702
|
+
## Integration
|
|
703
|
+
|
|
704
|
+
### [Playwright](https://github.com/microsoft/playwright)
|
|
705
|
+
- [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)
|
|
706
|
+
- Coverage for component testing:
|
|
707
|
+
- [playwright-ct-vue](https://github.com/cenfun/playwright-ct-vue)
|
|
708
|
+
- [playwright-ct-react](https://github.com/cenfun/playwright-ct-react)
|
|
709
|
+
- [playwright-ct-svelte](https://github.com/cenfun/playwright-ct-svelte)
|
|
710
|
+
- Coverage for Next.js, both server side and client side:
|
|
711
|
+
- [nextjs-with-playwright](https://github.com/cenfun/nextjs-with-playwright)
|
|
712
|
+
- [nextjs-with-playwright-istanbul](https://github.com/cenfun/nextjs-with-playwright-istanbul)
|
|
713
|
+
|
|
714
|
+
### [Jest](https://github.com/jestjs/jest/)
|
|
715
|
+
- [jest-monocart-coverage](https://github.com/cenfun/jest-monocart-coverage) - A Jest custom reporter for coverage reports
|
|
716
|
+
- Example for Jest (unit) + Puppeteer (e2e) + Codecov: [maplibre-gl-js](https://github.com/maplibre/maplibre-gl-js)
|
|
717
|
+
|
|
718
|
+
### [Vitest](https://github.com/vitest-dev/vitest)
|
|
719
|
+
- [vitest-monocart-coverage](https://github.com/cenfun/vitest-monocart-coverage) - A Vitest custom provider module for coverage reports
|
|
720
|
+
|
|
721
|
+
### [CodeceptJS](https://github.com/codeceptjs/CodeceptJS)
|
|
722
|
+
- [codeceptjs-monocart-coverage](https://github.com/cenfun/codeceptjs-monocart-coverage) - A CodeceptJS plugin for coverage reports
|
|
723
|
+
|
|
724
|
+
### [WebdriverIO](https://github.com/webdriverio/webdriverio)
|
|
725
|
+
- [wdio-monocart-service](https://github.com/cenfun/wdio-monocart-service) - A WebdriverIO service for coverage reports
|
|
726
|
+
|
|
727
|
+
### [Storybook Test Runner](https://github.com/storybookjs/test-runner)
|
|
728
|
+
- [storybook-monocart-coverage](https://github.com/cenfun/storybook-monocart-coverage) - Storybook V8 Coverage Example
|
|
729
|
+
|
|
730
|
+
### [Codecov](https://codecov.com/)
|
|
731
|
+
[](https://codecov.io/gh/cenfun/monocart-coverage-reports)
|
|
732
|
+
- Supports native `codecov` built-in report ([specification](https://docs.codecov.com/docs/codecov-custom-coverage-format))
|
|
733
|
+
```js
|
|
734
|
+
const coverageOptions = {
|
|
735
|
+
outputDir: "./coverage-reports",
|
|
736
|
+
reports: [
|
|
737
|
+
['codecov']
|
|
738
|
+
]
|
|
739
|
+
};
|
|
740
|
+
```
|
|
741
|
+
- Github actions example:
|
|
742
|
+
```yml
|
|
743
|
+
- name: Codecov
|
|
744
|
+
uses: codecov/codecov-action@v3
|
|
745
|
+
with:
|
|
746
|
+
files: ./coverage-reports/codecov.json
|
|
747
|
+
```
|
|
748
|
+
### [Coveralls](https://coveralls.io/)
|
|
749
|
+
[](https://coveralls.io/github/cenfun/monocart-coverage-reports?branch=main)
|
|
750
|
+
- Using `lcov` report:
|
|
751
|
+
```js
|
|
752
|
+
const coverageOptions = {
|
|
753
|
+
outputDir: "./coverage-reports",
|
|
754
|
+
lcov: true
|
|
755
|
+
};
|
|
756
|
+
```
|
|
757
|
+
- Github actions example:
|
|
758
|
+
```yml
|
|
759
|
+
- name: Coveralls
|
|
760
|
+
uses: coverallsapp/github-action@v2
|
|
761
|
+
with:
|
|
762
|
+
files: ./coverage-reports/lcov.info
|
|
763
|
+
```
|
|
764
|
+
### [Sonar Cloud](https://sonarcloud.io/)
|
|
765
|
+
[](https://sonarcloud.io/summary/new_code?id=monocart-coverage-reports)
|
|
766
|
+
- Using `lcov` report. Github actions example:
|
|
767
|
+
```yml
|
|
768
|
+
- name: Analyze with SonarCloud
|
|
769
|
+
uses: sonarsource/sonarcloud-github-action@master
|
|
770
|
+
env:
|
|
771
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
772
|
+
with:
|
|
773
|
+
projectBaseDir: ./
|
|
774
|
+
args: >
|
|
775
|
+
-Dsonar.organization=cenfun
|
|
776
|
+
-Dsonar.projectKey=monocart-coverage-reports
|
|
777
|
+
-Dsonar.projectName=monocart-coverage-reports
|
|
778
|
+
-Dsonar.javascript.lcov.reportPaths=docs/mcr/lcov.info
|
|
779
|
+
-Dsonar.sources=lib
|
|
780
|
+
-Dsonar.tests=test
|
|
781
|
+
-Dsonar.exclusions=dist/*,packages/*
|
|
782
|
+
```
|
|
783
|
+
### Integration with Any Testing Framework
|
|
784
|
+
- Collecting coverage data when any stage of the test is completed, and adding the coverage data to the coverage reporter.
|
|
785
|
+
- Generating the coverage reports after the completion of all tests.
|
|
786
|
+
- see [Multiprocessing Support](#multiprocessing-support)
|
|
787
|
+
|
|
788
|
+
### VSCode Extension
|
|
789
|
+
- [Coverage Gutters](https://github.com/ryanluker/vscode-coverage-gutters) - Display test coverage generated by lcov or xml in VSCode editor.
|
|
790
|
+
|
|
791
|
+
## Thanks
|
|
779
792
|
- Special thanks to [@edumserrano](https://github.com/edumserrano)
|