monocart-reporter 1.6.21 → 1.6.23
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 +22 -2
- package/lib/default/options.js +8 -0
- package/lib/generate-data.js +19 -1
- package/lib/generate-report.js +11 -3
- package/lib/index.js +4 -5
- package/lib/index.mjs +1 -2
- package/lib/merge-data.js +1 -1
- package/lib/platform/concurrency.js +74 -0
- package/lib/platform/share.js +33 -1
- package/lib/{helper → plugins/audit}/audit.js +2 -2
- package/lib/plugins/coverage/coverage.js +267 -0
- package/lib/plugins/coverage/istanbul/istanbul-summary.js +49 -0
- package/lib/plugins/coverage/istanbul/istanbul.js +132 -0
- package/lib/plugins/coverage/v8/dedupe.js +107 -0
- package/lib/plugins/coverage/v8/position-mapping.js +82 -0
- package/lib/plugins/coverage/v8/source-map.js +377 -0
- package/lib/plugins/coverage/v8/v8-summary.js +89 -0
- package/lib/plugins/coverage/v8/v8.js +265 -0
- package/lib/{helper → plugins/network}/network.js +7 -4
- package/lib/runtime/monocart-code-viewer.js +1 -1
- package/lib/runtime/monocart-coverage.js +12 -0
- package/lib/runtime/monocart-formatter.js +1 -1
- package/lib/runtime/monocart-network.js +1 -1
- package/lib/runtime/monocart-reporter.js +1 -1
- package/lib/runtime/monocart-v8.js +1 -1
- package/lib/runtime/monocart-vendor.js +2 -2
- package/lib/utils/util.js +37 -2
- package/lib/visitor.js +42 -6
- package/package.json +7 -9
- package/lib/helper/coverage.js +0 -498
- package/lib/runtime/monocart-istanbul.js +0 -3
- /package/lib/{helper → plugins}/comments.js +0 -0
- /package/lib/{helper → plugins}/email.js +0 -0
package/README.md
CHANGED
|
@@ -725,6 +725,27 @@ const report = await attachCoverageReport(coverageList, test.info(), {
|
|
|
725
725
|
| Minified code | N/A | ✅ | ❌ |
|
|
726
726
|
| Code formatting | N/A | ✅ | ❌ |
|
|
727
727
|
|
|
728
|
+
## Global Coverage Report
|
|
729
|
+
If you want to generate a global coverage report, you can use the API `addCoverageReport(v8list, testInfo)`. When all the tests are finished, all added reports will be automatically merged into a global report. Currently supported `V8` only. Here is an example for Playwright Component Testing [playwright-ct-vue](https://github.com/cenfun/playwright-ct-vue).
|
|
730
|
+
```js
|
|
731
|
+
// playwright.config.js
|
|
732
|
+
module.exports = {
|
|
733
|
+
reporter: [
|
|
734
|
+
['monocart-reporter', {
|
|
735
|
+
name: "My Test Report",
|
|
736
|
+
outputFile: './test-results/report.html',
|
|
737
|
+
// global coverage report options
|
|
738
|
+
coverage: {
|
|
739
|
+
unpackSourceMap: true,
|
|
740
|
+
excludeDistFile: true,
|
|
741
|
+
sourceFilter: (sourceName) => sourceName.search(/\/src\/.+/) !== -1,
|
|
742
|
+
entryFilter: (entry) => {}
|
|
743
|
+
}
|
|
744
|
+
}]
|
|
745
|
+
]
|
|
746
|
+
};
|
|
747
|
+
```
|
|
748
|
+
|
|
728
749
|
## Attach Network Report
|
|
729
750
|
Attach a network report with API `attachNetworkReport(har, testInfo)`. Arguments:
|
|
730
751
|
- `har` HAR path (String) or HAR file buffer (Buffer). see [HAR 1.2 Spec](http://www.softwareishard.com/blog/har-12-spec/)
|
|
@@ -954,10 +975,9 @@ Please create an [Incoming Webhooks](https://learn.microsoft.com/en-us/microsoft
|
|
|
954
975
|
- Lightweight UI Components [vine-ui](https://github.com/cenfun/vine-ui)
|
|
955
976
|
- High Performance Grid [turbogrid](https://github.com/cenfun/turbogrid)
|
|
956
977
|
- String compress/decompress [lz-utils](https://github.com/cenfun/lz-utils)
|
|
957
|
-
- Formatter and Code Viewer [monocart-components](https://github.com/cenfun/monocart-components)
|
|
958
978
|
- Packages
|
|
959
979
|
- `packages/app` Monocart report UI
|
|
960
|
-
- `packages/
|
|
980
|
+
- `packages/coverage` Coverage report libs
|
|
961
981
|
- `packages/network` Network HAR report libs
|
|
962
982
|
- `packages/v8` V8 HTML report UI
|
|
963
983
|
- `packages/vendor` Third-party libs
|
package/lib/default/options.js
CHANGED
|
@@ -9,6 +9,14 @@ module.exports = {
|
|
|
9
9
|
attachmentPath: null,
|
|
10
10
|
// attachmentPath: (currentPath, extras) => `https://cenfun.github.io/monocart-reporter/${currentPath}`,
|
|
11
11
|
|
|
12
|
+
// global coverage settings for addCoverageReport API
|
|
13
|
+
coverage: null,
|
|
14
|
+
// coverage: {
|
|
15
|
+
// unpackSourceMap: true,
|
|
16
|
+
// sourceFilter: (sourceName) => sourceName.search(/\/src\/.+/) !== -1,
|
|
17
|
+
// entryFilter: (entry) => {}
|
|
18
|
+
// },
|
|
19
|
+
|
|
12
20
|
// trend data handler
|
|
13
21
|
trend: null,
|
|
14
22
|
// trend: () => './test-results/report.json',
|
package/lib/generate-data.js
CHANGED
|
@@ -4,6 +4,7 @@ const Util = require('./utils/util.js');
|
|
|
4
4
|
const { getTickInfo } = require('./utils/system.js');
|
|
5
5
|
const Visitor = require('./visitor.js');
|
|
6
6
|
const { calculateSummary } = require('./common.js');
|
|
7
|
+
const { generateCoverageReport } = require('./plugins/coverage/coverage.js');
|
|
7
8
|
|
|
8
9
|
const getReportName = (options, config, metadata) => {
|
|
9
10
|
const reportName = options.name || config.name || metadata.name;
|
|
@@ -13,6 +14,18 @@ const getReportName = (options, config, metadata) => {
|
|
|
13
14
|
return 'Test Report';
|
|
14
15
|
};
|
|
15
16
|
|
|
17
|
+
const artifactsHandler = async (visitor, options) => {
|
|
18
|
+
const artifacts = [];
|
|
19
|
+
const { coverage } = visitor.artifacts;
|
|
20
|
+
visitor.artifacts = null;
|
|
21
|
+
if (coverage) {
|
|
22
|
+
const report = await generateCoverageReport(coverage, options);
|
|
23
|
+
report.name = 'coverage';
|
|
24
|
+
artifacts.push(report);
|
|
25
|
+
}
|
|
26
|
+
return artifacts;
|
|
27
|
+
};
|
|
28
|
+
|
|
16
29
|
const generateData = async (results) => {
|
|
17
30
|
|
|
18
31
|
console.log('[MCR] generating report data ...');
|
|
@@ -28,7 +41,7 @@ const generateData = async (results) => {
|
|
|
28
41
|
// console.log(config);
|
|
29
42
|
const cwd = Util.formatPath(process.cwd());
|
|
30
43
|
|
|
31
|
-
const outputFile = options.outputFile;
|
|
44
|
+
const outputFile = await Util.resolveOutputFile(options.outputFile);
|
|
32
45
|
// init outputDir
|
|
33
46
|
const outputDir = path.dirname(outputFile);
|
|
34
47
|
if (!fs.existsSync(outputDir)) {
|
|
@@ -74,6 +87,9 @@ const generateData = async (results) => {
|
|
|
74
87
|
});
|
|
75
88
|
|
|
76
89
|
const reportName = getReportName(options, config, metadata);
|
|
90
|
+
options.name = reportName;
|
|
91
|
+
|
|
92
|
+
const artifacts = await artifactsHandler(visitor, options);
|
|
77
93
|
|
|
78
94
|
system.cwd = cwd;
|
|
79
95
|
|
|
@@ -118,6 +134,8 @@ const generateData = async (results) => {
|
|
|
118
134
|
|
|
119
135
|
metadata,
|
|
120
136
|
system,
|
|
137
|
+
|
|
138
|
+
artifacts,
|
|
121
139
|
trends,
|
|
122
140
|
|
|
123
141
|
// columns, rows, formatters
|
package/lib/generate-report.js
CHANGED
|
@@ -5,7 +5,7 @@ const CG = require('console-grid');
|
|
|
5
5
|
const { deflateSync } = require('lz-utils');
|
|
6
6
|
const { nodemailer } = require('./runtime/monocart-vendor.js');
|
|
7
7
|
const Util = require('./utils/util.js');
|
|
8
|
-
const
|
|
8
|
+
const emailPlugin = require('./plugins/email.js');
|
|
9
9
|
|
|
10
10
|
// ===========================================================================
|
|
11
11
|
|
|
@@ -148,7 +148,15 @@ const generateReport = (reportData, onEnd) => {
|
|
|
148
148
|
showTestResults(reportData);
|
|
149
149
|
|
|
150
150
|
// console.log(config);
|
|
151
|
-
const {
|
|
151
|
+
const {
|
|
152
|
+
outputFile, outputDir, artifacts
|
|
153
|
+
} = reportData;
|
|
154
|
+
|
|
155
|
+
if (artifacts) {
|
|
156
|
+
artifacts.forEach((report) => {
|
|
157
|
+
console.log(`[MCR] ${report.name} report: ${EC.cyan(report.htmlPath)}`);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
152
160
|
|
|
153
161
|
// console.log(reportData);
|
|
154
162
|
const filename = path.basename(outputFile, '.html');
|
|
@@ -170,7 +178,7 @@ const generateReport = (reportData, onEnd) => {
|
|
|
170
178
|
});
|
|
171
179
|
|
|
172
180
|
// generate email data
|
|
173
|
-
|
|
181
|
+
emailPlugin(reportData);
|
|
174
182
|
|
|
175
183
|
// forEach rows API
|
|
176
184
|
const forEach = (callback) => {
|
package/lib/index.js
CHANGED
|
@@ -6,9 +6,9 @@ const defaultOptions = require('./default/options.js');
|
|
|
6
6
|
const { getTrends } = require('./common.js');
|
|
7
7
|
|
|
8
8
|
const merge = require('./merge-data.js');
|
|
9
|
-
const { attachAuditReport } = require('./
|
|
10
|
-
const { attachCoverageReport } = require('./
|
|
11
|
-
const { attachNetworkReport } = require('./
|
|
9
|
+
const { attachAuditReport } = require('./plugins/audit/audit.js');
|
|
10
|
+
const { addCoverageReport, attachCoverageReport } = require('./plugins/coverage/coverage.js');
|
|
11
|
+
const { attachNetworkReport } = require('./plugins/network/network.js');
|
|
12
12
|
|
|
13
13
|
// custom reporter
|
|
14
14
|
// https://playwright.dev/docs/test-reporters#custom-reporters
|
|
@@ -16,8 +16,7 @@ class Reporter {
|
|
|
16
16
|
|
|
17
17
|
static merge = merge;
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
static takeCoverage = attachCoverageReport;
|
|
19
|
+
static addCoverageReport = addCoverageReport;
|
|
21
20
|
|
|
22
21
|
static attachAuditReport = attachAuditReport;
|
|
23
22
|
static attachCoverageReport = attachCoverageReport;
|
package/lib/index.mjs
CHANGED
|
@@ -5,8 +5,7 @@ export { MonocartReporter };
|
|
|
5
5
|
|
|
6
6
|
export const merge = MonocartReporter.merge;
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
export const takeCoverage = MonocartReporter.attachCoverageReport;
|
|
8
|
+
export const addCoverageReport = MonocartReporter.addCoverageReport;
|
|
10
9
|
|
|
11
10
|
export const attachAuditReport = MonocartReporter.attachAuditReport;
|
|
12
11
|
export const attachCoverageReport = MonocartReporter.attachCoverageReport;
|
package/lib/merge-data.js
CHANGED
|
@@ -76,7 +76,7 @@ const mergeDataList = async (dataList, options) => {
|
|
|
76
76
|
|
|
77
77
|
const trends = await getTrends(options.trend);
|
|
78
78
|
|
|
79
|
-
const outputFile = options.outputFile;
|
|
79
|
+
const outputFile = await Util.resolveOutputFile(options.outputFile);
|
|
80
80
|
// init outputDir
|
|
81
81
|
const outputDir = path.dirname(outputFile);
|
|
82
82
|
if (!fs.existsSync(outputDir)) {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
class Concurrency {
|
|
2
|
+
|
|
3
|
+
constructor(maxCount = 10) {
|
|
4
|
+
this.maxCount = maxCount;
|
|
5
|
+
this.list = [];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
addItem(item) {
|
|
9
|
+
this.list.push(item);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
addList(list) {
|
|
13
|
+
this.list = this.list.concat(list);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
start(handler) {
|
|
17
|
+
// must be async function
|
|
18
|
+
if (typeof handler !== 'function') {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
this.handler = handler;
|
|
22
|
+
this.count = 0;
|
|
23
|
+
return new Promise((resolve) => {
|
|
24
|
+
this.resolve = resolve;
|
|
25
|
+
this.next();
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
next() {
|
|
30
|
+
// console.log(`list: ${this.list.length} count: ${this.count}`);
|
|
31
|
+
|
|
32
|
+
// if has clear
|
|
33
|
+
if (!this.resolve) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!this.list.length) {
|
|
38
|
+
// no list but has in progress count
|
|
39
|
+
if (this.count > 0) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// all finish
|
|
43
|
+
this.resolve();
|
|
44
|
+
this.clear();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// out of concurrency count, just wait
|
|
49
|
+
if (this.count >= this.maxCount) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const item = this.list.shift();
|
|
54
|
+
this.count += 1;
|
|
55
|
+
|
|
56
|
+
// async handler
|
|
57
|
+
this.handler(item).finally(() => {
|
|
58
|
+
this.count -= 1;
|
|
59
|
+
this.next();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
this.next();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
clear() {
|
|
66
|
+
this.list = [];
|
|
67
|
+
this.handler = null;
|
|
68
|
+
this.count = 0;
|
|
69
|
+
this.resolve = null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = Concurrency;
|
package/lib/platform/share.js
CHANGED
|
@@ -19,6 +19,11 @@ const Util = {
|
|
|
19
19
|
name: 'network',
|
|
20
20
|
contentType: 'text/html',
|
|
21
21
|
reportFile: 'network-report.json'
|
|
22
|
+
},
|
|
23
|
+
// artifact will be removed finally
|
|
24
|
+
artifact: {
|
|
25
|
+
name: 'artifact',
|
|
26
|
+
contentType: 'application/json'
|
|
22
27
|
}
|
|
23
28
|
},
|
|
24
29
|
|
|
@@ -164,7 +169,15 @@ const Util = {
|
|
|
164
169
|
});
|
|
165
170
|
}
|
|
166
171
|
});
|
|
167
|
-
flatRanges.sort((a, b) =>
|
|
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
|
+
});
|
|
168
181
|
}
|
|
169
182
|
return flatRanges;
|
|
170
183
|
},
|
|
@@ -186,6 +199,25 @@ const Util = {
|
|
|
186
199
|
});
|
|
187
200
|
},
|
|
188
201
|
|
|
202
|
+
// =============================================================================
|
|
203
|
+
|
|
204
|
+
generatePercentChart: function(percent) {
|
|
205
|
+
return `<div style="--mcr-percent:${percent}%;" class="mcr-percent-chart"></div>`;
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
getStatus: (value, watermarks) => {
|
|
209
|
+
if (!watermarks) {
|
|
210
|
+
return 'unknown';
|
|
211
|
+
}
|
|
212
|
+
if (value < watermarks[0]) {
|
|
213
|
+
return 'low';
|
|
214
|
+
}
|
|
215
|
+
if (value < watermarks[1]) {
|
|
216
|
+
return 'medium';
|
|
217
|
+
}
|
|
218
|
+
return 'high';
|
|
219
|
+
},
|
|
220
|
+
|
|
189
221
|
// =============================================================================
|
|
190
222
|
// svg
|
|
191
223
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const EC = require('eight-colors');
|
|
4
|
-
const Util = require('
|
|
4
|
+
const Util = require('../../utils/util.js');
|
|
5
5
|
|
|
6
6
|
const getStatus = (s) => {
|
|
7
7
|
if (s < 0.5) {
|
|
@@ -71,7 +71,7 @@ const attachAuditReport = async (runnerResult, testInfo, options = {}) => {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
options = {
|
|
74
|
-
outputDir: Util.
|
|
74
|
+
outputDir: Util.resolveOutputDir(testInfo),
|
|
75
75
|
outputName: `audit-${Util.shortTestId(testInfo.testId)}`,
|
|
76
76
|
|
|
77
77
|
... options
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const EC = require('eight-colors');
|
|
4
|
+
|
|
5
|
+
const Util = require('../../utils/util.js');
|
|
6
|
+
|
|
7
|
+
const { saveIstanbulReport, saveV8ToIstanbulReport } = require('./istanbul/istanbul.js');
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
initV8List, mergeV8List, saveV8Report
|
|
11
|
+
} = require('./v8/v8.js');
|
|
12
|
+
|
|
13
|
+
// ========================================================================================================
|
|
14
|
+
|
|
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
|
+
const defaultV8Options = {
|
|
24
|
+
toIstanbul: false,
|
|
25
|
+
|
|
26
|
+
unpackSourceMap: true,
|
|
27
|
+
excludeDistFile: true,
|
|
28
|
+
sourceFilter: defaultSourceFilter,
|
|
29
|
+
entryFilter: null
|
|
30
|
+
|
|
31
|
+
// watermarks: [50, 80],
|
|
32
|
+
// inline: false
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const defaultIstanbulOptions = {
|
|
36
|
+
entryFilter: null,
|
|
37
|
+
sourceFinder: null,
|
|
38
|
+
lcov: false
|
|
39
|
+
|
|
40
|
+
// watermarks: {},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// ========================================================================================================
|
|
44
|
+
|
|
45
|
+
const saveReportAttachment = (testInfo, report, htmlDir) => {
|
|
46
|
+
|
|
47
|
+
const definition = Util.attachments.coverage;
|
|
48
|
+
// save report
|
|
49
|
+
const reportPath = path.resolve(htmlDir, definition.reportFile);
|
|
50
|
+
Util.writeJSONSync(reportPath, report);
|
|
51
|
+
|
|
52
|
+
testInfo.attachments.push({
|
|
53
|
+
name: definition.name,
|
|
54
|
+
contentType: definition.contentType,
|
|
55
|
+
path: path.resolve(htmlDir, 'index.html')
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// ========================================================================================================
|
|
60
|
+
|
|
61
|
+
const generateIstanbulReport = (istanbulCoverage, testInfo, options) => {
|
|
62
|
+
|
|
63
|
+
options = {
|
|
64
|
+
... defaultIstanbulOptions,
|
|
65
|
+
... options
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const report = saveIstanbulReport(istanbulCoverage, options);
|
|
69
|
+
|
|
70
|
+
saveReportAttachment(testInfo, report, options.htmlDir);
|
|
71
|
+
|
|
72
|
+
return report;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// ========================================================================================================
|
|
76
|
+
|
|
77
|
+
const toIstanbulReport = async (v8list, testInfo, options) => {
|
|
78
|
+
|
|
79
|
+
options = {
|
|
80
|
+
... defaultIstanbulOptions,
|
|
81
|
+
... options
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const report = await saveV8ToIstanbulReport(v8list, options);
|
|
85
|
+
|
|
86
|
+
saveReportAttachment(testInfo, report, options.htmlDir);
|
|
87
|
+
|
|
88
|
+
return report;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// ========================================================================================================
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
const generateV8Report = async (v8list, testInfo, options) => {
|
|
95
|
+
|
|
96
|
+
options.title = `Coverage Report - ${testInfo.title}`;
|
|
97
|
+
|
|
98
|
+
const report = await saveV8Report(v8list, options);
|
|
99
|
+
|
|
100
|
+
saveReportAttachment(testInfo, report, options.htmlDir);
|
|
101
|
+
|
|
102
|
+
return report;
|
|
103
|
+
};
|
|
104
|
+
|
|
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
|
+
const attachCoverageReport = (coverageInput, testInfo, options = {}) => {
|
|
131
|
+
|
|
132
|
+
if (!coverageInput) {
|
|
133
|
+
EC.logRed('[MCR] invalid coverage input');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
options = {
|
|
138
|
+
outputDir: Util.resolveOutputDir(testInfo),
|
|
139
|
+
outputName: `coverage-${Util.shortTestId(testInfo.testId)}`,
|
|
140
|
+
... options
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const htmlDir = path.resolve(options.outputDir, options.outputName);
|
|
144
|
+
if (!fs.existsSync(htmlDir)) {
|
|
145
|
+
fs.mkdirSync(htmlDir, {
|
|
146
|
+
recursive: true
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
options.htmlDir = htmlDir;
|
|
150
|
+
|
|
151
|
+
if (Array.isArray(coverageInput)) {
|
|
152
|
+
return generateV8Coverage(coverageInput, testInfo, options);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return generateIstanbulReport(coverageInput, testInfo, options);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// ========================================================================================================
|
|
159
|
+
|
|
160
|
+
// add coverage report to global
|
|
161
|
+
const addCoverageReport = async (v8list, testInfo) => {
|
|
162
|
+
|
|
163
|
+
if (!Util.isList(v8list)) {
|
|
164
|
+
EC.logRed('[MCR] invalid coverage input');
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const reporterOptions = Util.resolveReporterOptions(testInfo);
|
|
169
|
+
const coverageOptions = reporterOptions.coverage || {};
|
|
170
|
+
|
|
171
|
+
// reporter outputFile
|
|
172
|
+
const outputFile = await Util.resolveOutputFile(reporterOptions.outputFile);
|
|
173
|
+
const outputDir = path.dirname(outputFile);
|
|
174
|
+
|
|
175
|
+
const options = {
|
|
176
|
+
// use reporter dir as output dir, NOT test output dir
|
|
177
|
+
outputDir,
|
|
178
|
+
outputName: 'coverage',
|
|
179
|
+
|
|
180
|
+
... defaultV8Options,
|
|
181
|
+
... coverageOptions
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// The source map must be fetched before page closed
|
|
185
|
+
// or it may be deleted
|
|
186
|
+
v8list = await initV8List(v8list, options);
|
|
187
|
+
|
|
188
|
+
const id = Util.shortTestId(testInfo.testId);
|
|
189
|
+
const filename = `artifact-${id}.json`;
|
|
190
|
+
const jsonDir = path.resolve(options.outputDir, options.outputName);
|
|
191
|
+
const jsonPath = path.resolve(jsonDir, filename);
|
|
192
|
+
|
|
193
|
+
const report = {
|
|
194
|
+
id,
|
|
195
|
+
title: testInfo.title,
|
|
196
|
+
outputFile: Util.relativePath(jsonPath),
|
|
197
|
+
// current v8 only
|
|
198
|
+
type: 'v8',
|
|
199
|
+
data: v8list
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const artifactContent = JSON.stringify({
|
|
203
|
+
type: 'coverage',
|
|
204
|
+
data: report
|
|
205
|
+
});
|
|
206
|
+
await Util.writeFile(jsonPath, artifactContent);
|
|
207
|
+
|
|
208
|
+
const definition = Util.attachments.artifact;
|
|
209
|
+
testInfo.attachments.push({
|
|
210
|
+
name: definition.name,
|
|
211
|
+
contentType: definition.contentType,
|
|
212
|
+
path: jsonPath
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
return report;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// global coverage report, run different process with addCoverageReport
|
|
219
|
+
const generateCoverageReport = async (dataList, reporterOptions) => {
|
|
220
|
+
|
|
221
|
+
// reporter outputFile
|
|
222
|
+
const outputFile = await Util.resolveOutputFile(reporterOptions.outputFile);
|
|
223
|
+
const outputDir = path.dirname(outputFile);
|
|
224
|
+
|
|
225
|
+
const coverageOptions = reporterOptions.coverage || {};
|
|
226
|
+
const options = {
|
|
227
|
+
outputDir,
|
|
228
|
+
outputName: 'coverage',
|
|
229
|
+
... coverageOptions
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const htmlDir = path.resolve(options.outputDir, options.outputName);
|
|
233
|
+
if (!fs.existsSync(htmlDir)) {
|
|
234
|
+
fs.mkdirSync(htmlDir, {
|
|
235
|
+
recursive: true
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
options.htmlDir = htmlDir;
|
|
239
|
+
|
|
240
|
+
let v8list = [];
|
|
241
|
+
dataList.forEach((item) => {
|
|
242
|
+
v8list = v8list.concat(item.data);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// merge list, 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);
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
type: report.type,
|
|
258
|
+
htmlPath: report.htmlPath,
|
|
259
|
+
summary: report.summary
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
module.exports = {
|
|
264
|
+
addCoverageReport,
|
|
265
|
+
generateCoverageReport,
|
|
266
|
+
attachCoverageReport
|
|
267
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const { istanbulLibReport } = require('../../../runtime/monocart-coverage.js');
|
|
2
|
+
|
|
3
|
+
const ReportBase = istanbulLibReport.ReportBase;
|
|
4
|
+
class IstanbulSummary extends ReportBase {
|
|
5
|
+
|
|
6
|
+
onStart(root, context) {
|
|
7
|
+
this.context = context;
|
|
8
|
+
this.summary = {};
|
|
9
|
+
this.files = [];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
addStatus(data) {
|
|
13
|
+
Object.keys(data).forEach((k) => {
|
|
14
|
+
const item = data[k];
|
|
15
|
+
// low, medium, high, unknown
|
|
16
|
+
item.status = this.context.classForPercent(k, item.pct);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
onSummary(node) {
|
|
21
|
+
if (!node.isRoot()) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
this.summary = node.getCoverageSummary().data;
|
|
25
|
+
this.addStatus(this.summary);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
onDetail(node) {
|
|
29
|
+
const fileSummary = node.getCoverageSummary().data;
|
|
30
|
+
this.addStatus(fileSummary);
|
|
31
|
+
fileSummary.name = node.getRelativeName();
|
|
32
|
+
this.files.push(fileSummary);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
onEnd() {
|
|
36
|
+
// console.log('onEnd');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getReport() {
|
|
40
|
+
return {
|
|
41
|
+
type: 'istanbul',
|
|
42
|
+
summary: this.summary,
|
|
43
|
+
files: this.files
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
module.exports = IstanbulSummary;
|