monocart-reporter 1.6.24 → 1.6.26

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
@@ -18,8 +18,8 @@
18
18
  * [Playwright Config](#playwright-config)
19
19
  * [Examples](#examples)
20
20
  * [Output](#output) HTML and JSON
21
- * [View Trace Online](#view-trace-online)
22
21
  * [Reporter Options](#reporter-options)
22
+ * [View Trace Online](#view-trace-online)
23
23
  * [Custom Columns](#custom-columns) (Extra properties for suite/case/step)
24
24
  - [Custom Formatter](#custom-formatter)
25
25
  - [Searchable Fields](#searchable-fields)
@@ -105,12 +105,6 @@ module.exports = {
105
105
  - path-to/your-filename.json
106
106
  Separated metadata file (Already included in the above HTML and compressed, it can be deleted). Can be used for debugging or custom data collection.
107
107
 
108
- ## View Trace Online
109
- > The [Trace Viewer](https://trace.playwright.dev/) requires that the trace file must be loaded over the http:// or https:// protocols without [CORS](https://developer.mozilla.org/en-US/docs/Glossary/CORS) issue, try following start a local web server:
110
- ```sh
111
- npx monocart show-report <your-outputFile-path>
112
- ```
113
-
114
108
  ## Reporter Options
115
109
  ```js
116
110
  {
@@ -124,6 +118,17 @@ npx monocart show-report <your-outputFile-path>
124
118
  attachmentPath: null,
125
119
  // attachmentPath: (currentPath, extras) => `https://another-path/${currentPath}`,
126
120
 
121
+ traceViewerUrl: 'https://trace.playwright.dev/?trace={traceUrl}',
122
+
123
+ // global coverage settings for addCoverageReport API
124
+ coverage: null,
125
+ // coverage: {
126
+ // entryFilter: (entry) => true,
127
+ // unpackSourceMap: true,
128
+ // excludeDistFile: true,
129
+ // sourceFilter: (sourceName) => sourceName.search(/\/src\/.+/) !== -1,
130
+ // },
131
+
127
132
  // trend data handler
128
133
  trend: null,
129
134
  // trend: () => './test-results/report.json',
@@ -153,6 +158,13 @@ npx monocart show-report <your-outputFile-path>
153
158
  }
154
159
  ```
155
160
 
161
+ ## View Trace Online
162
+ > The [Trace Viewer](https://trace.playwright.dev/) requires that the trace file must be loaded over the http:// or https:// protocols without [CORS](https://developer.mozilla.org/en-US/docs/Glossary/CORS) issue, try following start a local web server:
163
+ ```sh
164
+ npx monocart show-report <your-outputFile-path>
165
+ ```
166
+ Or customize your own trace viewer url with option `traceViewerUrl` defaults to `https://trace.playwright.dev/?trace={traceUrl}`
167
+
156
168
  ## Custom Columns
157
169
  The report will be displayed in a `Tree Grid`. The `columns` function is used to customize the grid columns. The column properties following:
158
170
  - `id` (String) Column id (required)
@@ -624,8 +636,17 @@ Attach a code coverage report with API `attachCoverageReport(data, testInfo, opt
624
636
  - `data` There are two supported data inputs `Istanbul` (Object) or `V8` (Array)
625
637
  - `testInfo` see [TestInfo](https://playwright.dev/docs/api/class-testinfo)
626
638
  - `options` (Object)
627
- - `watermarks` By default, watermarks of Istanbul see [here](https://github.com/istanbuljs/istanbuljs/tree/master/packages/istanbul-lib-report) (Object), watermarks of V8 is `[50, 80]` (Array)
628
- - `toIstanbul` (Boolean) for V8 data conversion
639
+ - Istanbul only:
640
+ - `watermarks` (Object) Istanbul watermarks, see [here](https://github.com/istanbuljs/istanbuljs/tree/master/packages/istanbul-lib-report)
641
+ - `lcov` (Boolean) Whether to create `lcov.info`
642
+ - V8 only:
643
+ - `toIstanbul` (Boolean) Whether to convert to Istanbul report
644
+ - `watermarks` (Array) Defaults to `[50, 80]`
645
+ - `entryFilter` (Function) A filter function to execute for each element in the V8 list.
646
+ - `unpackSourceMap` (Boolean) Whether to unpack all sources from the source map if a related source map file is found.
647
+ - `excludeDistFile` (Boolean) Whether to exclude the dist file (usually minified) if the sources are successfully unpacked from the source map.
648
+ - `sourceFilter` (Function) A filter function to execute for each element in the sources which unpacked from the source map.
649
+ - `inline` (Boolean) Whether inline all scripts to the single HTML file.
629
650
 
630
651
  (see example: [report-coverage.spec.js](https://github.com/cenfun/monocart-reporter/blob/main/tests/report-coverage/report-coverage.spec.js))
631
652
 
@@ -737,10 +758,10 @@ module.exports = {
737
758
  outputFile: './test-results/report.html',
738
759
  // global coverage report options
739
760
  coverage: {
761
+ entryFilter: (entry) => true,
740
762
  unpackSourceMap: true,
741
763
  excludeDistFile: true,
742
764
  sourceFilter: (sourceName) => sourceName.search(/\/src\/.+/) !== -1,
743
- entryFilter: (entry) => {}
744
765
  }
745
766
  }]
746
767
  ]
@@ -9,12 +9,15 @@ module.exports = {
9
9
  attachmentPath: null,
10
10
  // attachmentPath: (currentPath, extras) => `https://cenfun.github.io/monocart-reporter/${currentPath}`,
11
11
 
12
+ traceViewerUrl: 'https://trace.playwright.dev/?trace={traceUrl}',
13
+
12
14
  // global coverage settings for addCoverageReport API
13
15
  coverage: null,
14
16
  // coverage: {
17
+ // entryFilter: (entry) => true,
15
18
  // unpackSourceMap: true,
19
+ // excludeDistFile: true,
16
20
  // sourceFilter: (sourceName) => sourceName.search(/\/src\/.+/) !== -1,
17
- // entryFilter: (entry) => {}
18
21
  // },
19
22
 
20
23
  // trend data handler
@@ -2,11 +2,46 @@
2
2
  <html>
3
3
  <head>
4
4
  <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <link rel="icon" href="data:,">
7
7
  <title>{title}</title>
8
+ <style>
9
+ @keyframes fs-loading-animation {
10
+ 0% {
11
+ transform: rotate(0deg);
12
+ }
13
+
14
+ 100% {
15
+ transform: rotate(360deg);
16
+ }
17
+ }
18
+
19
+ .fs-loading {
20
+ position: absolute;
21
+ top: 50%;
22
+ left: 50%;
23
+ z-index: 100;
24
+ width: 50px;
25
+ height: 50px;
26
+ margin-top: -25px;
27
+ margin-left: -25px;
28
+ animation: 0.382s fs-loading-animation linear infinite;
29
+ }
30
+
31
+ .fs-loading svg {
32
+ display: block;
33
+ width: 100%;
34
+ height: 100%;
35
+ pointer-events: none;
36
+ }
37
+ </style>
8
38
  </head>
9
39
  <body>
40
+ <div class="fs-loading">
41
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
42
+ <path d="M1,8 A7 7 0 1 1 8 15" stroke="#999" stroke-width="2" stroke-linecap="round" fill="none"/>
43
+ </svg>
44
+ </div>
10
45
  {content}
11
46
  </body>
12
47
  </html>
@@ -74,6 +74,7 @@ const generateData = async (results) => {
74
74
  // suite and case types
75
75
  data.suiteTypes = ['project', 'file', 'describe', 'shard'];
76
76
  data.caseTypes = ['passed', 'flaky', 'skipped', 'failed'];
77
+ data.traceViewerUrl = options.traceViewerUrl;
77
78
 
78
79
  calculateSummary(data, options);
79
80
 
@@ -158,30 +158,6 @@ const Util = {
158
158
  return info;
159
159
  },
160
160
 
161
- getFlatRanges: (functions) => {
162
- const flatRanges = [];
163
- if (functions && functions.length) {
164
- functions.forEach((fun) => {
165
- const ranges = fun.ranges;
166
- if (ranges && ranges.length) {
167
- ranges.forEach((range) => {
168
- flatRanges.push(range);
169
- });
170
- }
171
- });
172
- flatRanges.sort((a, b) => {
173
- if (a.startOffset === b.startOffset) {
174
- if (a.endOffset === b.endOffset) {
175
- return a.count - b.count;
176
- }
177
- return a.endOffset - b.endOffset;
178
- }
179
- return a.startOffset - b.startOffset;
180
- });
181
- }
182
- return flatRanges;
183
- },
184
-
185
161
  isTagItem: (item) => {
186
162
  if (item.type === 'case' || (item.type === 'suite' && item.suiteType === 'describe')) {
187
163
  return true;
@@ -6,10 +6,14 @@ const Util = require('../utils/util.js');
6
6
  const cacheMap = new Map();
7
7
 
8
8
  function getEmptyLines(lines) {
9
- return lines.map((line, i) => ({
10
- code: line.trim(),
11
- num: i + 1
12
- })).filter((line) => !line.code).map((line) => line.num);
9
+ const emptyLines = [];
10
+ const reg = /\S/;
11
+ lines.forEach((text, i) => {
12
+ if (!reg.test(text)) {
13
+ emptyLines.push(i + 1);
14
+ }
15
+ });
16
+ return emptyLines;
13
17
  }
14
18
 
15
19
  const getFileComments = (filePath, parserOptions = {}) => {
@@ -0,0 +1,154 @@
1
+ const Util = require('../../utils/util.js');
2
+ const Concurrency = require('../../platform/concurrency.js');
3
+ const { convertSourceMap, axios } = require('../../runtime/monocart-coverage.js');
4
+
5
+ const sortRanges = (ranges) => {
6
+ ranges.sort((a, b) => {
7
+ if (a.start === b.start) {
8
+ return a.end - b.end;
9
+ }
10
+ return a.start - b.start;
11
+ });
12
+ };
13
+
14
+ const resolveUrl = (input) => {
15
+ let url;
16
+ try {
17
+ url = new URL(input);
18
+ } catch (e) {
19
+ // console.error('error url', input);
20
+ return;
21
+ }
22
+ return url;
23
+ };
24
+
25
+ const filterPath = (str) => {
26
+ str = decodeURI(str);
27
+ // remove / of start, end or double, ./ ../
28
+ const ls = str.split('/').map((it) => {
29
+ it = it.trim();
30
+ // remove illegal characters except /
31
+ it = it.replace(/[\\:*?"<>|]/g, '');
32
+ // space
33
+ it = it.replace(/\s+/g, '-');
34
+ return it;
35
+ }).filter((item) => {
36
+ if (!item || item === '.' || item === '..') {
37
+ return false;
38
+ }
39
+ return true;
40
+ });
41
+ return ls.join('/');
42
+ };
43
+
44
+ const getSourcePath = (url, index = '', type = '') => {
45
+
46
+ if (!url) {
47
+ // anonymous scripts will have __playwright_evaluation_script__ as their URL.
48
+ url = ['file://anonymous', index ? `-${index}` : '', type ? `.${type}` : ''].join('');
49
+ }
50
+
51
+ const u = resolveUrl(url);
52
+ if (u) {
53
+ const host = [u.hostname, u.port].filter((it) => it).join('-');
54
+ // always start with '/'
55
+ const pathname = u.pathname;
56
+
57
+ let p = host + pathname;
58
+ // webpack://monocart-v8/packages/v8/src/app.vue?5cc4
59
+ if (u.search) {
60
+ p += `/${u.search}`;
61
+ }
62
+
63
+ return filterPath(p);
64
+ }
65
+
66
+ const relPath = Util.relativePath(url);
67
+ return filterPath(relPath);
68
+ };
69
+
70
+ // ================================================================================================
71
+
72
+ const request = async (options) => {
73
+ if (typeof options === 'string') {
74
+ options = {
75
+ url: options
76
+ };
77
+ }
78
+ let err;
79
+ const res = await axios(options).catch((e) => {
80
+ err = e;
81
+ });
82
+ return [err, res];
83
+ };
84
+
85
+ const getSourceMapUrl = (content, url) => {
86
+
87
+ const m = content.match(convertSourceMap.mapFileCommentRegex);
88
+ if (!m) {
89
+ return;
90
+ }
91
+
92
+ const comment = m.pop();
93
+ const r = convertSourceMap.mapFileCommentRegex.exec(comment);
94
+ // for some odd reason //# .. captures in 1 and /* .. */ in 2
95
+ const filename = r[1] || r[2];
96
+
97
+ let mapUrl;
98
+
99
+ try {
100
+ mapUrl = new URL(filename, url);
101
+ } catch (e) {
102
+ // console.log(e)
103
+ }
104
+ if (mapUrl) {
105
+ return mapUrl.toString();
106
+ }
107
+ };
108
+
109
+ const resolveSourceMap = (data) => {
110
+ if (data) {
111
+ const { sources, sourcesContent } = data;
112
+ if (!sources || !sourcesContent) {
113
+ return;
114
+ }
115
+ return data;
116
+ }
117
+ };
118
+
119
+ const collectSourceMaps = async (v8list) => {
120
+ const concurrency = new Concurrency();
121
+ for (const item of v8list) {
122
+ // useless for css
123
+ if (item.type === 'css') {
124
+ continue;
125
+ }
126
+
127
+ const source = item.source;
128
+ const converter = convertSourceMap.fromSource(source);
129
+ if (converter) {
130
+ item.sourceMap = resolveSourceMap(converter.sourcemap);
131
+ continue;
132
+ }
133
+ const sourceMapUrl = getSourceMapUrl(source, item.url);
134
+ if (sourceMapUrl) {
135
+ item.sourceMapUrl = sourceMapUrl;
136
+ concurrency.addItem(item);
137
+ }
138
+ }
139
+ await concurrency.start(async (item) => {
140
+ const [err, res] = await request({
141
+ url: item.sourceMapUrl
142
+ });
143
+ if (!err && res) {
144
+ item.sourceMap = resolveSourceMap(res.data);
145
+ }
146
+ });
147
+ };
148
+
149
+
150
+ module.exports = {
151
+ sortRanges,
152
+ getSourcePath,
153
+ collectSourceMaps
154
+ };
@@ -4,7 +4,9 @@ const EC = require('eight-colors');
4
4
 
5
5
  const Util = require('../../utils/util.js');
6
6
 
7
- const { saveIstanbulReport, saveV8ToIstanbulReport } = require('./istanbul/istanbul.js');
7
+ const {
8
+ convertV8ToIstanbul, mergeIstanbulList, saveIstanbulReport
9
+ } = require('./istanbul/istanbul.js');
8
10
 
9
11
  const {
10
12
  initV8List, mergeV8List, saveV8Report
@@ -12,31 +14,40 @@ const {
12
14
 
13
15
  // ========================================================================================================
14
16
 
15
- // high performance
16
- // str.search(reg) -> index
17
- // reg.test(str) -> boolean
18
- const defaultSourceFilter = (sourceName) => {
19
- // sourceName.search(/\/src\/.+/) !== -1
20
- return true;
21
- };
22
-
23
17
  const defaultV8Options = {
18
+ // (Boolean) Whether to convert to Istanbul report
24
19
  toIstanbul: false,
25
20
 
21
+ // (Function) A filter function to execute for each element in the V8 list.
22
+ entryFilter: null,
23
+ // (Boolean) Whether to unpack all sources from the source map if a related source map file is found.
26
24
  unpackSourceMap: true,
25
+ // (Boolean) Whether to exclude the dist file (usually minified) if the sources are successfully unpacked from the source map.
27
26
  excludeDistFile: true,
28
- sourceFilter: defaultSourceFilter,
29
- entryFilter: null
27
+ // (Function) A filter function to execute for each element in the sources which unpacked from the source map.
28
+ sourceFilter: null
30
29
 
30
+ // (Array) Defaults to `[50, 80]`
31
31
  // watermarks: [50, 80],
32
+
33
+ // (Boolean) Whether inline all scripts to the single HTML file.
32
34
  // inline: false
33
35
  };
34
36
 
35
37
  const defaultIstanbulOptions = {
38
+
39
+ // when toIstanbul = true
36
40
  entryFilter: null,
41
+ unpackSourceMap: true,
42
+ sourceFilter: null,
43
+
44
+ // (usually not used) source finder for Istanbul HTML report
37
45
  sourceFinder: null,
46
+
47
+ // (Boolean) Whether to create `lcov.info`
38
48
  lcov: false
39
49
 
50
+ // (Object) Istanbul watermarks, see [here](https://github.com/istanbuljs/istanbuljs/tree/master/packages/istanbul-lib-report)
40
51
  // watermarks: {},
41
52
  };
42
53
 
@@ -58,42 +69,51 @@ const saveReportAttachment = (testInfo, report, htmlDir) => {
58
69
 
59
70
  // ========================================================================================================
60
71
 
61
- const generateIstanbulReport = (istanbulCoverage, testInfo, options) => {
72
+ const generateIstanbulReport = (coverageData, testInfo, options) => {
62
73
 
63
74
  options = {
64
75
  ... defaultIstanbulOptions,
65
76
  ... options
66
77
  };
67
78
 
68
- const report = saveIstanbulReport(istanbulCoverage, options);
79
+ const report = saveIstanbulReport(coverageData, options.fileSources, options);
69
80
 
70
81
  saveReportAttachment(testInfo, report, options.htmlDir);
71
82
 
72
83
  return report;
73
84
  };
74
85
 
86
+
75
87
  // ========================================================================================================
76
88
 
77
- const toIstanbulReport = async (v8list, testInfo, options) => {
89
+ const generateV8Coverage = async (v8list, testInfo, options) => {
78
90
 
91
+ // v8list options, also for init / source map handler
79
92
  options = {
80
- ... defaultIstanbulOptions,
93
+ ... defaultV8Options,
81
94
  ... options
82
95
  };
83
96
 
84
- const report = await saveV8ToIstanbulReport(v8list, options);
97
+ // ================================================================
85
98
 
86
- saveReportAttachment(testInfo, report, options.htmlDir);
99
+ if (options.toIstanbul) {
100
+ options = {
101
+ ... defaultIstanbulOptions,
102
+ ... options
103
+ };
87
104
 
88
- return report;
89
- };
105
+ const { coverageData, fileSources } = await convertV8ToIstanbul(v8list, options);
90
106
 
91
- // ========================================================================================================
107
+ const report = await saveIstanbulReport(coverageData, fileSources, options);
92
108
 
109
+ saveReportAttachment(testInfo, report, options.htmlDir);
93
110
 
94
- const generateV8Report = async (v8list, testInfo, options) => {
111
+ return report;
112
+ }
95
113
 
96
- options.title = `Coverage Report - ${testInfo.title}`;
114
+ // ================================================================
115
+
116
+ v8list = await initV8List(v8list, options);
97
117
 
98
118
  const report = await saveV8Report(v8list, options);
99
119
 
@@ -102,31 +122,6 @@ const generateV8Report = async (v8list, testInfo, options) => {
102
122
  return report;
103
123
  };
104
124
 
105
- // ========================================================================================================
106
-
107
- const generateV8Coverage = async (v8list, testInfo, options) => {
108
-
109
- // v8list options, also for init / source map handler
110
- options = {
111
- ... defaultV8Options,
112
- ... options
113
- };
114
-
115
- v8list = await initV8List(v8list, options);
116
-
117
- if (options.toIstanbul) {
118
- return toIstanbulReport(v8list, testInfo, options);
119
- }
120
-
121
- return generateV8Report(v8list, testInfo, options);
122
- };
123
-
124
- /**
125
- * @parameters
126
- * (@input istanbul.__coverage__: Object, testInfo, options: { watermarks: {} }) -> @output istanbul report
127
- * (@input v8list: Array, testInfo, options: { toIstanbul: true, watermarks: {} }) -> @output istanbul report (without css supported)
128
- * (@input v8list: Array, testInfo, options: { watermarks: [], inline: Boolean }) -> @output v8 report (css supported and minified code formatting)
129
- */
130
125
  const attachCoverageReport = (coverageInput, testInfo, options = {}) => {
131
126
 
132
127
  if (!coverageInput) {
@@ -135,6 +130,7 @@ const attachCoverageReport = (coverageInput, testInfo, options = {}) => {
135
130
  }
136
131
 
137
132
  options = {
133
+ title: `Coverage Report - ${testInfo.title}`,
138
134
  outputDir: Util.resolveOutputDir(testInfo),
139
135
  outputName: `coverage-${Util.shortTestId(testInfo.testId)}`,
140
136
  ... options
@@ -157,10 +153,25 @@ const attachCoverageReport = (coverageInput, testInfo, options = {}) => {
157
153
 
158
154
  // ========================================================================================================
159
155
 
160
- // add coverage report to global
161
- const addCoverageReport = async (v8list, testInfo) => {
156
+ const generateArtifactData = (v8list, options) => {
157
+ options = {
158
+ ... defaultV8Options,
159
+ ... options
160
+ };
161
+ if (options.toIstanbul) {
162
+ options = {
163
+ ... defaultIstanbulOptions,
164
+ ... options
165
+ };
166
+ return convertV8ToIstanbul(v8list, options);
167
+ }
168
+ return initV8List(v8list, options);
169
+ };
162
170
 
163
- if (!Util.isList(v8list)) {
171
+ // add coverage report to global, v8list only
172
+ const addCoverageReport = async (coverageInput, testInfo) => {
173
+
174
+ if (!coverageInput) {
164
175
  EC.logRed('[MCR] invalid coverage input');
165
176
  return;
166
177
  }
@@ -176,33 +187,29 @@ const addCoverageReport = async (v8list, testInfo) => {
176
187
  // use reporter dir as output dir, NOT test output dir
177
188
  outputDir,
178
189
  outputName: 'coverage',
179
-
180
- ... defaultV8Options,
181
190
  ... coverageOptions
182
191
  };
183
192
 
184
- // The source map must be fetched before page closed
185
- // or it may be deleted
186
- v8list = await initV8List(v8list, options);
187
-
188
193
  const id = Util.shortTestId(testInfo.testId);
189
194
  const filename = `artifact-${id}.json`;
190
195
  const jsonDir = path.resolve(options.outputDir, options.outputName);
191
196
  const jsonPath = path.resolve(jsonDir, filename);
192
197
 
198
+ const data = await generateArtifactData(coverageInput, options);
199
+
200
+ // console.log('addCoverageReport keys', Object.keys(data.coverageData));
201
+
193
202
  const report = {
194
203
  id,
195
- title: testInfo.title,
196
204
  outputFile: Util.relativePath(jsonPath),
197
- // current v8 only
198
- type: 'v8',
199
- data: v8list
205
+ data
200
206
  };
201
207
 
202
208
  const artifactContent = JSON.stringify({
203
209
  type: 'coverage',
204
210
  data: report
205
211
  });
212
+
206
213
  await Util.writeFile(jsonPath, artifactContent);
207
214
 
208
215
  const definition = Util.attachments.artifact;
@@ -215,6 +222,34 @@ const addCoverageReport = async (v8list, testInfo) => {
215
222
  return report;
216
223
  };
217
224
 
225
+ // ========================================================================================================
226
+
227
+ const generateGlobalCoverageReport = async (dataList, options) => {
228
+
229
+ options = {
230
+ ... defaultV8Options,
231
+ ... options
232
+ };
233
+
234
+ if (options.toIstanbul) {
235
+ options = {
236
+ ... defaultIstanbulOptions,
237
+ ... options
238
+ };
239
+ const istanbulList = dataList.map((it) => it.data);
240
+ const { coverageData, fileSources } = mergeIstanbulList(istanbulList);
241
+ return saveIstanbulReport(coverageData, fileSources, options);
242
+ }
243
+
244
+ let v8list = [];
245
+ dataList.forEach((item) => {
246
+ v8list = v8list.concat(item.data);
247
+ });
248
+ // merge list again for multiple v8list, maybe collected multiple times
249
+ v8list = await mergeV8List(v8list, options);
250
+ return saveV8Report(v8list, options);
251
+ };
252
+
218
253
  // global coverage report, run different process with addCoverageReport
219
254
  const generateCoverageReport = async (dataList, reporterOptions) => {
220
255
 
@@ -224,6 +259,7 @@ const generateCoverageReport = async (dataList, reporterOptions) => {
224
259
 
225
260
  const coverageOptions = reporterOptions.coverage || {};
226
261
  const options = {
262
+ title: `Coverage Report - ${reporterOptions.name}`,
227
263
  outputDir,
228
264
  outputName: 'coverage',
229
265
  ... coverageOptions
@@ -237,21 +273,7 @@ const generateCoverageReport = async (dataList, reporterOptions) => {
237
273
  }
238
274
  options.htmlDir = htmlDir;
239
275
 
240
- let v8list = [];
241
- dataList.forEach((item) => {
242
- v8list = v8list.concat(item.data);
243
- });
244
-
245
- // merge list again for multiple v8list, maybe collected multiple times
246
- v8list = await mergeV8List(v8list, options);
247
-
248
- // const v8Path = path.resolve(__dirname, '../../.temp/v8-data.js');
249
- // const v8Data = `module.exports = ${JSON.stringify(v8list, null, 4)};`;
250
- // fs.writeFileSync(v8Path, v8Data);
251
-
252
- options.title = `Coverage Report - ${reporterOptions.name}`;
253
-
254
- const report = await saveV8Report(v8list, options);
276
+ const report = await generateGlobalCoverageReport(dataList, options);
255
277
 
256
278
  return {
257
279
  type: 'coverage',