monocart-coverage-reports 2.7.3 → 2.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,6 +42,7 @@
42
42
  - [CodeceptJS](#codeceptjs)
43
43
  - [WebdriverIO](#webdriverio)
44
44
  - [Storybook Test Runner](#storybook-test-runner)
45
+ - [TestCafe](#testcafe)
45
46
  - [Codecov](#codecov)
46
47
  - [Coveralls](#coveralls)
47
48
  - [Sonar Cloud](#sonar-cloud)
@@ -829,6 +830,9 @@ const coverageOptions = {
829
830
  ### [Storybook Test Runner](https://github.com/storybookjs/test-runner)
830
831
  - [storybook-monocart-coverage](https://github.com/cenfun/storybook-monocart-coverage) - Storybook V8 Coverage Example
831
832
 
833
+ ### [TestCafe](https://github.com/DevExpress/testcafe)
834
+ - [testcafe-reporter-coverage](https://github.com/cenfun/testcafe-reporter-coverage) - A TestCafe custom reporter for coverage reports
835
+
832
836
  ### [Codecov](https://codecov.com/)
833
837
  [![codecov](https://codecov.io/gh/cenfun/monocart-coverage-reports/graph/badge.svg?token=H0LW7UKYU3)](https://codecov.io/gh/cenfun/monocart-coverage-reports)
834
838
  - Supports native `codecov` built-in report ([specification](https://docs.codecov.com/docs/codecov-custom-coverage-format))
@@ -8,6 +8,12 @@ const BranchTypes = {
8
8
  AssignmentPattern: 'AssignmentPattern'
9
9
  };
10
10
 
11
+ const setGeneratedOnly = (block, generatedOnly) => {
12
+ if (block && generatedOnly) {
13
+ block.generatedOnly = true;
14
+ }
15
+ };
16
+
11
17
  const getParentFunctionState = (reverseParents) => {
12
18
  const parentFunction = reverseParents.find((it) => it._state && it._state.isFunction);
13
19
  if (!parentFunction) {
@@ -266,6 +272,7 @@ const updateBranchCount = (group) => {
266
272
  const groupBlock = getFunctionBlock(group.start, group.end, functionState);
267
273
  if (groupBlock) {
268
274
  parentCount = groupBlock.count;
275
+ setGeneratedOnly(groupBlock, group.generatedOnly);
269
276
  }
270
277
 
271
278
  // calculate branches count
@@ -277,6 +284,7 @@ const updateBranchCount = (group) => {
277
284
  return;
278
285
  }
279
286
  item.block = getFunctionBlock(start, end, functionState);
287
+ setGeneratedOnly(item.block, group.generatedOnly);
280
288
  });
281
289
 
282
290
 
@@ -314,12 +322,16 @@ const generateBranches = (branchMap) => {
314
322
  }
315
323
  });
316
324
 
317
- branches.push({
325
+ const branch = {
318
326
  type: group.type,
319
327
  start: group.start,
320
328
  end: group.end,
321
329
  locations: group.locations
322
- });
330
+ };
331
+
332
+ setGeneratedOnly(branch, group.generatedOnly);
333
+
334
+ branches.push(branch);
323
335
  });
324
336
 
325
337
  // sort branches
@@ -395,6 +407,34 @@ const generateStatements = (statementNodes) => {
395
407
  return statements;
396
408
  };
397
409
 
410
+ // =======================================================================================
411
+ // handle special generated codes for original coverage
412
+
413
+ const webpackWrapHandler = (node) => {
414
+ // ignore webpack wrap for original function
415
+ // id: { type: 'Identifier', name: '__webpack_modules__' },
416
+ const name = node.id && node.id.name;
417
+ if (name === '__webpack_modules__' && node.init && node.init.properties) {
418
+ // mark all as wrap function
419
+ node.init.properties.forEach((it) => {
420
+ it.value._webpackWrapKey = it.key && it.key.value;
421
+ });
422
+ // console.log('==========================', node.type);
423
+ // console.log(name, parents.length);
424
+ }
425
+ };
426
+
427
+ const viteImportDefaultHandler = (node, group) => {
428
+ // ignore vite conditional expression for __esModule default
429
+ const testObj = node.test.object;
430
+ const testName = testObj && testObj.name;
431
+ if (testName && testName.startsWith('__vite__cjsImport')) {
432
+ setGeneratedOnly(group, true);
433
+ }
434
+
435
+ };
436
+
437
+
398
438
  // =======================================================================================
399
439
 
400
440
  const collectNodes = (ast) => {
@@ -409,18 +449,7 @@ const collectNodes = (ast) => {
409
449
 
410
450
  VariableDeclarator(node, parents) {
411
451
 
412
- // =============================================================
413
- // id: { type: 'Identifier', name: '__webpack_modules__' },
414
- const name = node.id && node.id.name;
415
- if (name === '__webpack_modules__' && node.init && node.init.properties) {
416
- // mark all as wrap function
417
- node.init.properties.forEach((it) => {
418
- it.value._wrapKey = it.key && it.key.value;
419
- });
420
- // console.log('==========================', node.type);
421
- // console.log(name, parents.length);
422
- }
423
- // =============================================================
452
+ webpackWrapHandler(node);
424
453
 
425
454
  },
426
455
 
@@ -473,10 +502,14 @@ const collectNodes = (ast) => {
473
502
  // Ternary
474
503
  // var b = a ? 'consequent' : 'alternate';
475
504
  ConditionalExpression: (node, parents) => {
505
+
476
506
  const { consequent, alternate } = node;
477
507
  const group = createBranchGroup(BranchTypes.ConditionalExpression, node, parents, branchMap);
478
508
  addBranch(group, consequent, locationMap);
479
509
  addBranch(group, alternate, locationMap);
510
+
511
+ viteImportDefaultHandler(node, group);
512
+
480
513
  },
481
514
 
482
515
  // if an if statement; can also be else if.
@@ -619,7 +652,7 @@ const collectAstInfo = (ast, coverageInfo) => {
619
652
  const bodyStart = node.body.start;
620
653
  const bodyEnd = node.body.end;
621
654
  const functionName = id && id.name;
622
- const isWrap = Boolean(node._wrapKey);
655
+ const _webpackWrapKey = node._webpackWrapKey;
623
656
 
624
657
  const functionItem = {
625
658
  start,
@@ -629,9 +662,9 @@ const collectAstInfo = (ast, coverageInfo) => {
629
662
  functionName,
630
663
  count: rootState.count
631
664
  };
632
- if (isWrap) {
633
- functionItem.wrap = true;
634
- }
665
+
666
+ setGeneratedOnly(functionItem, _webpackWrapKey);
667
+
635
668
  functions.push(functionItem);
636
669
 
637
670
  const functionState = {
@@ -641,9 +674,9 @@ const collectAstInfo = (ast, coverageInfo) => {
641
674
 
642
675
  const functionRange = findFunctionRange(item, coverageInfo);
643
676
  if (functionRange) {
644
- if (isWrap) {
645
- functionRange.wrap = true;
646
- }
677
+
678
+ setGeneratedOnly(functionRange, _webpackWrapKey);
679
+
647
680
  functionState.range = functionRange;
648
681
  functionState.count = functionRange.count;
649
682
  functionItem.count = functionRange.count;
@@ -28,7 +28,14 @@ const loadSourceMap = async (url = '') => {
28
28
  return;
29
29
  }
30
30
 
31
- return res.data;
31
+ const content = res.data;
32
+
33
+ // could be string not json, if Content-Type is application/octet-stream
34
+ if (typeof content === 'string') {
35
+ return JSON.parse(content);
36
+ }
37
+
38
+ return content;
32
39
  };
33
40
 
34
41
  const getSourceMapUrl = (content, url) => {
@@ -510,6 +510,11 @@ const handleOriginalBytesCoverage = (state) => {
510
510
 
511
511
  const handleGeneratedBytesCoverage = (state) => {
512
512
 
513
+ // it could be a dist file, do not handle twice
514
+ if (state.addedGeneratedBytes) {
515
+ return;
516
+ }
517
+
513
518
  const { js, coverageList } = state;
514
519
 
515
520
  if (js) {
@@ -524,6 +529,8 @@ const handleGeneratedBytesCoverage = (state) => {
524
529
  });
525
530
  }
526
531
 
532
+ state.addedGeneratedBytes = true;
533
+
527
534
  };
528
535
 
529
536
  // ========================================================================================================
@@ -551,15 +558,16 @@ const handleOriginalFunctionsCoverage = (state, originalStateMap) => {
551
558
 
552
559
  // function count
553
560
  state.astInfo.functions.forEach((it) => {
554
- const {
555
- start, end, bodyStart, bodyEnd, wrap
556
- } = it;
557
561
 
558
562
  // remove webpack wrap functions for functions count, not for ranges here
559
- if (wrap) {
563
+ if (it.generatedOnly) {
560
564
  return;
561
565
  }
562
566
 
567
+ const {
568
+ start, end, bodyStart, bodyEnd
569
+ } = it;
570
+
563
571
  const result = findOriginalRange(start, end, state, originalStateMap);
564
572
  if (result.error) {
565
573
  logMappingErrors('function', result);
@@ -598,6 +606,10 @@ const handleOriginalBranchesCoverage = (state, originalStateMap) => {
598
606
  // function count
599
607
  state.astInfo.branches.forEach((group) => {
600
608
 
609
+ if (group.generatedOnly) {
610
+ return;
611
+ }
612
+
601
613
  const { type, locations } = group;
602
614
 
603
615
  // start
@@ -668,6 +680,11 @@ const handleOriginalStatementsCoverage = (state, originalStateMap) => {
668
680
 
669
681
  // statement count
670
682
  state.astInfo.statements.forEach((it) => {
683
+
684
+ if (it.generatedOnly) {
685
+ return;
686
+ }
687
+
671
688
  const { start, end } = it;
672
689
 
673
690
  const result = findOriginalRange(start, end, state, originalStateMap);
@@ -799,11 +816,10 @@ const handleAllOriginalBytesCoverage = (state, originalStateMap) => {
799
816
 
800
817
  // v8 coverage
801
818
  coverageList.forEach((block) => {
802
- block.ranges.forEach((range, index) => {
819
+ block.ranges.forEach((range) => {
803
820
 
804
821
  // remove wrap functions for original files
805
- if (range.wrap) {
806
- // console.log(range);
822
+ if (range.generatedOnly) {
807
823
  return;
808
824
  }
809
825
 
@@ -1405,7 +1421,7 @@ const convertV8List = (v8list, options) => {
1405
1421
  // console.log([item.id]);
1406
1422
 
1407
1423
  const {
1408
- type, source, sourcePath
1424
+ type, source, fake, sourcePath
1409
1425
  } = item;
1410
1426
 
1411
1427
  // for source file, type could be ts or vue as extname, but js = true
@@ -1454,6 +1470,7 @@ const convertV8List = (v8list, options) => {
1454
1470
  js,
1455
1471
  type,
1456
1472
  source,
1473
+ fake,
1457
1474
  sourcePath,
1458
1475
  sourceMap,
1459
1476
  locator,
@@ -1,3 +1,4 @@
1
+ const { diff } = require('../packages/monocart-coverage-vendor');
1
2
  const Util = require('../utils/util.js');
2
3
  const EC = Util.EC;
3
4
 
@@ -38,6 +39,144 @@ const findMapping = (list, offset) => {
38
39
 
39
40
  // ========================================================================================================
40
41
 
42
+ const alignText = (gt, ot) => {
43
+
44
+ const toList = (s) => {
45
+ return s.split('').map((v, i) => {
46
+ return {
47
+ index: i,
48
+ value: v
49
+ };
50
+ });
51
+ };
52
+
53
+ const mergeList = (gList, oList) => {
54
+ const oLen = oList.length;
55
+ if (!oLen) {
56
+ return;
57
+ }
58
+ const gLen = gList.length;
59
+ if (gLen === oLen) {
60
+ gList.forEach((item, i) => {
61
+ item.original = oList[i];
62
+ });
63
+ }
64
+ };
65
+
66
+ const gl = toList(gt);
67
+ const ol = toList(ot);
68
+
69
+ // console.log(gl);
70
+ // console.log(ol);
71
+
72
+ const commonItems = [];
73
+ diff(gl.length, ol.length, (gi, oi) => {
74
+ return gl[gi].value === ol[oi].value;
75
+ }, (len, gi, oi) => {
76
+ commonItems.push([gi, oi, len]);
77
+ });
78
+
79
+ // console.log(commonItems);
80
+ // console.log('================================================================');
81
+ // merge list
82
+ // previous index
83
+ let gpi = 0;
84
+ let opi = 0;
85
+ commonItems.forEach(([gi, oi, len]) => {
86
+
87
+ if (gpi !== gi) {
88
+ const gList = gl.slice(gpi, gi);
89
+ const oList = ol.slice(opi, oi);
90
+ mergeList(gList, oList);
91
+ }
92
+
93
+ for (let i = 0; i < len; i++) {
94
+
95
+ const gii = gi + i;
96
+ const oii = oi + i;
97
+ const gItem = gl[gii];
98
+ gItem.original = ol[oii];
99
+
100
+ // matching a word end
101
+ if (i === len - 1 && len > 1) {
102
+ gItem.wordEnd = true;
103
+ }
104
+
105
+ }
106
+ gpi = gi + len;
107
+ opi = oi + len;
108
+ });
109
+
110
+ // console.log(JSON.stringify(data.gt));
111
+ // console.log(JSON.stringify(data.ot));
112
+ if (gpi < gl.length && opi < ol.length) {
113
+ const gList = gl.slice(gpi);
114
+ const oList = ol.slice(opi);
115
+ mergeList(gList, oList);
116
+ }
117
+
118
+ // console.log(gl);
119
+ return gl;
120
+ };
121
+
122
+ const getWordEndPosition = (list, gp, direction) => {
123
+ // for end only
124
+ if (direction !== 'end') {
125
+ return;
126
+ }
127
+
128
+ const prev = list[gp - 1];
129
+ if (prev && prev.original && prev.wordEnd) {
130
+ const op = prev.original.index + 1;
131
+ // console.log(gp, JSON.stringify(gt));
132
+ // console.log(op, JSON.stringify(ot));
133
+ return {
134
+ pos: op
135
+ };
136
+ }
137
+ };
138
+
139
+ const getAlignPosition = (gt, gp, ot, direction) => {
140
+
141
+ // there is no need to align for long text
142
+ const maxLength = 500;
143
+ if (gt.length > maxLength || ot.length > maxLength) {
144
+ // console.log(gt.length, ot.length, gp);
145
+ return;
146
+ }
147
+
148
+ // generatedText: '"false";\n',
149
+ // originalText: "'false';\r\n ",
150
+ // generatedPos: 7
151
+
152
+ // left matched
153
+
154
+ // originalText: '1;',
155
+ // generatedText: '1;else',
156
+ // generatedLeft: '1;'
157
+
158
+ // generatedText: ' var id = options.base ? item[0] + options.base : item[0];\r\n',
159
+ // originalText: ' var id = options.base ? item[0] + options.base : item[0];\n',
160
+
161
+ // right matched
162
+ // only for original first line text
163
+
164
+ // exclusive
165
+ const list = alignText(gt, ot);
166
+ const item = list[gp];
167
+ if (item && item.original) {
168
+ return {
169
+ pos: item.original.index
170
+ };
171
+ }
172
+
173
+ // inclusive, for end only
174
+ return getWordEndPosition(list, gp, direction);
175
+
176
+ };
177
+
178
+ // ========================================================================================================
179
+
41
180
  const getBlockStartPosition = (originalLineText) => {
42
181
  // originalText: 'argument) {',
43
182
  // generatedLeft: 'o',
@@ -117,87 +256,62 @@ const getBlockEndPosition = (originalLineText) => {
117
256
 
118
257
  };
119
258
 
259
+ // ========================================================================================================
260
+
120
261
  const getComparedPosition = (info, direction) => {
121
262
 
122
- let gt = info.generatedText;
263
+ const gt = info.generatedText;
123
264
  const gp = info.generatedPos;
124
- let ot = info.originalText;
125
-
126
- // before trim
127
- const oLen = ot.length;
128
-
129
- gt = gt.trimEnd();
130
- ot = ot.trimEnd();
131
-
132
- // no original content after trim
133
- if (!ot) {
134
- return {
135
- pos: direction === 'start' ? oLen : 0
136
- };
137
- }
265
+ const ot = info.originalText;
266
+ const olt = info.originalLineText;
138
267
 
139
- // no generated content after trim
140
- if (!gt) {
268
+ // seems direction is start only
269
+ if (gp === 0) {
141
270
  return;
142
271
  }
143
272
 
144
- // same content
145
- if (gt === ot) {
273
+ // whole generated text
274
+ if (gp >= gt.length) {
275
+ // console.log(JSON.stringify(gt), gt.length, gp);
276
+ // console.log(JSON.stringify(ot));
146
277
  return {
147
- pos: gp
278
+ pos: olt.length
148
279
  };
149
280
  }
150
281
 
151
282
  // =============================
283
+ // trim right
284
+ const gtt = gt.trimEnd();
285
+ const ott = ot.trimEnd();
152
286
 
153
- // generatedText: '"false";\n',
154
- // originalText: "'false';\r\n ",
155
- // generatedPos: 7
156
-
157
- // length not change, replace " to '
158
- gt = gt.replace(/"/g, "'");
159
- ot = ot.replace(/"/g, "'");
160
-
161
-
162
- // same content too
163
- if (gt === ot) {
287
+ // no original content after trim
288
+ if (!ott) {
164
289
  return {
165
- pos: gp
290
+ pos: direction === 'start' ? ot.length : 0
166
291
  };
167
292
  }
168
293
 
169
- // ============================
170
- // left matched
171
-
172
- // originalText: '1;',
173
- // generatedText: '1;else',
174
- // generatedLeft: '1;'
175
-
176
- // generatedText: ' var id = options.base ? item[0] + options.base : item[0];\r\n',
177
- // originalText: ' var id = options.base ? item[0] + options.base : item[0];\n',
294
+ // no generated content after trim
295
+ if (!gtt) {
296
+ return;
297
+ }
178
298
 
179
- const left = gt.slice(0, gp);
180
- if (ot.startsWith(left)) {
299
+ // same content
300
+ if (gtt === ott) {
181
301
  return {
182
302
  pos: gp
183
303
  };
184
304
  }
185
305
 
186
- // ============================
187
- // right matched
188
- // only for original first line text
306
+ // =============================
189
307
 
190
- const olt = info.originalLineText;
191
- const right = gt.slice(gp);
192
- if (olt.endsWith(right)) {
193
- return {
194
- pos: olt.length - right.length
195
- };
196
- }
308
+ return getAlignPosition(gt, gp, ot, direction);
197
309
 
198
310
  };
199
311
 
200
- const initOriginalLineText = (info) => {
312
+
313
+ const getSimilarPosition = (info, direction) => {
314
+
201
315
  const originalText = info.originalText;
202
316
  // never cross line, using first line of original text
203
317
  // trim end remove \r\n and \n
@@ -205,44 +319,27 @@ const initOriginalLineText = (info) => {
205
319
  if (originalLines.length === 1) {
206
320
  // already single line
207
321
  info.originalLineText = originalText.trimEnd();
208
- info.originalSingle = true;
209
- return;
322
+ } else {
323
+ // multiple liens
324
+ info.originalLineText = originalLines[0].trimEnd();
210
325
  }
211
- // multiple liens
212
- info.originalLineText = originalLines[0].trimEnd();
213
- };
214
326
 
215
- const getSimilarPosition = (info, direction) => {
216
-
217
- initOriginalLineText(info);
327
+ // no need comparison for fake source
328
+ if (info.fake) {
329
+ return;
330
+ }
218
331
 
219
332
  const textPos = getComparedPosition(info, direction);
220
333
  if (textPos) {
221
334
  return textPos;
222
335
  }
223
336
 
224
- if (info.originalSingle) {
225
- return;
226
- }
227
-
228
- // multiple lines
229
- const { generatedPos, originalLineText } = info;
230
- // generatedPos not in first line
231
- if (generatedPos > originalLineText.length) {
232
- return;
233
- }
234
-
235
- const linePos = getComparedPosition(info, direction);
236
- if (linePos) {
237
- return linePos;
238
- }
239
-
240
337
  // console.log('====================================================================');
241
- // console.log(`${EC.magenta(direction)} similar position can NOT be fixed`);
338
+ // console.log(`${EC.magenta(direction)} similar position can NOT be fixed`, info.originalState.sourcePath);
242
339
  // console.log({
243
- // sourcePath: info.originalState.sourcePath,
244
- // generatedText,
245
- // generatedPos,
340
+ // direction,
341
+ // generatedText: info.generatedText,
342
+ // generatedPos: info.generatedPos,
246
343
  // originalText
247
344
  // });
248
345
 
@@ -402,11 +499,13 @@ const getFixedOriginalStart = (start, mappings, state, cache) => {
402
499
  };
403
500
  }
404
501
 
405
- const direction = 'start';
502
+
406
503
  const { originalText, originalOffset } = getOriginalText(m1, m2, cache);
407
504
  const { generatedText, generatedPos } = getGeneratedText(m1, m2, state, start);
505
+ const direction = 'start';
408
506
 
409
507
  const info = {
508
+ fake: state.fake,
410
509
  generatedText,
411
510
  generatedPos,
412
511
  originalText,
@@ -453,11 +552,13 @@ const getFixedOriginalEnd = (end, mappings, state, cache) => {
453
552
  };
454
553
  }
455
554
 
456
- const direction = 'end';
555
+
457
556
  const { originalText, originalOffset } = getOriginalText(m1, m2, cache);
458
557
  const { generatedText, generatedPos } = getGeneratedText(m1, m2, state, end);
558
+ const direction = 'end';
459
559
 
460
560
  const info = {
561
+ fake: state.fake,
461
562
  offset: end,
462
563
  generatedText,
463
564
  generatedPos,