monocart-reporter 2.6.5 → 2.7.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/README.md +14 -7
- package/lib/cli.js +1 -1
- package/lib/generate-data.js +32 -1
- package/lib/generate-report.js +3 -1
- package/lib/merge-data.js +119 -18
- package/lib/packages/monocart-reporter-assets.js +1 -1
- package/lib/plugins/coverage/coverage.js +39 -3
- package/lib/visitor.js +48 -0
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1087,24 +1087,20 @@ npx playwright test --shard=2/3
|
|
|
1087
1087
|
npx playwright test --shard=3/3
|
|
1088
1088
|
```
|
|
1089
1089
|
There are 3 reports will be generated. Using `merge(reportDataList, options)` API to merge all reports into one.
|
|
1090
|
-
> Note: One more suite level "shard" will be added, its title will be the machine hostname, and the summary will be restated.
|
|
1090
|
+
> Note: One more suite level "shard" will be added, its title will be the machine hostname, and the summary will be restated. All attachments will be copied to the merged output directory.
|
|
1091
1091
|
```js
|
|
1092
1092
|
import { merge } from 'monocart-reporter';
|
|
1093
1093
|
|
|
1094
|
+
// json file path
|
|
1094
1095
|
const reportDataList = [
|
|
1095
|
-
// json file path
|
|
1096
1096
|
'path-to/shard1/index.json',
|
|
1097
1097
|
'path-to/shard2/index.json',
|
|
1098
|
-
|
|
1099
|
-
JSON.parse(fs.readFileSync(path.resolve('path-to/shard3/index.json')))
|
|
1098
|
+
'path-to/shard3/index.json'
|
|
1100
1099
|
];
|
|
1101
1100
|
|
|
1102
1101
|
await merge(reportDataList, {
|
|
1103
1102
|
name: 'My Merged Report',
|
|
1104
1103
|
outputFile: 'merged-report/index.html',
|
|
1105
|
-
attachmentPath: (currentPath, extras) => {
|
|
1106
|
-
// return `https://cenfun.github.io/monocart-reporter/${currentPath}`;
|
|
1107
|
-
},
|
|
1108
1104
|
onEnd: async (reportData, helper) => {
|
|
1109
1105
|
// send email or third party integration
|
|
1110
1106
|
}
|
|
@@ -1112,6 +1108,17 @@ await merge(reportDataList, {
|
|
|
1112
1108
|
```
|
|
1113
1109
|
see example [merge.js](https://github.com/cenfun/monocart-reporter-examples/blob/main/scripts/merge.js)
|
|
1114
1110
|
|
|
1111
|
+
> Note: The coverage reports will be merged automatically if we specify the `raw` report in coverage options:
|
|
1112
|
+
```js
|
|
1113
|
+
// global coverage options
|
|
1114
|
+
coverage: {
|
|
1115
|
+
reports: [
|
|
1116
|
+
// for merging coverage reports
|
|
1117
|
+
'raw'
|
|
1118
|
+
]
|
|
1119
|
+
}
|
|
1120
|
+
```
|
|
1121
|
+
|
|
1115
1122
|
## onEnd Hook
|
|
1116
1123
|
The `onEnd` function will be executed after report generated. Arguments:
|
|
1117
1124
|
- `reportData` all report data, properties:
|
package/lib/cli.js
CHANGED
package/lib/generate-data.js
CHANGED
|
@@ -33,6 +33,37 @@ const getReportDate = (timestampStart, timezoneOffset = 0) => {
|
|
|
33
33
|
return timestampStart + offset * 60 * 1000;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
const generateMermaid = (options) => {
|
|
37
|
+
const mermaidOptions = options.mermaid;
|
|
38
|
+
if (mermaidOptions) {
|
|
39
|
+
const scriptSrc = mermaidOptions.scriptSrc;
|
|
40
|
+
if (!scriptSrc) {
|
|
41
|
+
// try to copy and load from local
|
|
42
|
+
let mp;
|
|
43
|
+
try {
|
|
44
|
+
mp = require.resolve('mermaid');
|
|
45
|
+
} catch (e) {
|
|
46
|
+
// ignore error
|
|
47
|
+
}
|
|
48
|
+
// console.log(mp);
|
|
49
|
+
if (mp) {
|
|
50
|
+
const filename = 'mermaid.min.js';
|
|
51
|
+
const filePath = path.resolve(path.dirname(mp), filename);
|
|
52
|
+
if (fs.existsSync(filePath)) {
|
|
53
|
+
const assetPath = path.resolve(options.outputDir, 'assets', filename);
|
|
54
|
+
fs.cpSync(filePath, assetPath, {
|
|
55
|
+
recursive: true,
|
|
56
|
+
force: true
|
|
57
|
+
});
|
|
58
|
+
mermaidOptions.scriptSrc = `assets/${filename}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// console.log(mermaidOptions);
|
|
64
|
+
return mermaidOptions;
|
|
65
|
+
};
|
|
66
|
+
|
|
36
67
|
const generateData = async (results) => {
|
|
37
68
|
|
|
38
69
|
Util.logInfo('generating report data ...');
|
|
@@ -78,7 +109,7 @@ const generateData = async (results) => {
|
|
|
78
109
|
data.suiteTypes = ['project', 'file', 'describe', 'shard'];
|
|
79
110
|
data.caseTypes = ['passed', 'flaky', 'skipped', 'failed'];
|
|
80
111
|
data.traceViewerUrl = options.traceViewerUrl;
|
|
81
|
-
data.mermaid = options
|
|
112
|
+
data.mermaid = generateMermaid(options);
|
|
82
113
|
data.groupOptions = options.groupOptions;
|
|
83
114
|
|
|
84
115
|
calculateSummary(data, options);
|
package/lib/generate-report.js
CHANGED
|
@@ -197,7 +197,9 @@ const generateReport = async (reportData, options) => {
|
|
|
197
197
|
const g = report.global ? `${EC.magenta('(global)')}` : '';
|
|
198
198
|
Util.logInfo(`${report.type}: ${EC.cyan(report.path)} ${report.name} ${g}`);
|
|
199
199
|
// convert path to relative reporter
|
|
200
|
-
|
|
200
|
+
if (report.path) {
|
|
201
|
+
report.path = Util.relativePath(report.path, outputDir);
|
|
202
|
+
}
|
|
201
203
|
});
|
|
202
204
|
|
|
203
205
|
reportData.summary.artifacts = {
|
package/lib/merge-data.js
CHANGED
|
@@ -4,10 +4,11 @@ const Util = require('./utils/util.js');
|
|
|
4
4
|
const generateReport = require('./generate-report.js');
|
|
5
5
|
const getDefaultOptions = require('./default/options.js');
|
|
6
6
|
const { calculateSummary, getTrends } = require('./common.js');
|
|
7
|
+
const { mergeGlobalCoverageReport } = require('./plugins/coverage/coverage.js');
|
|
7
8
|
|
|
8
9
|
const checkReportData = (item) => {
|
|
9
10
|
if (item && typeof item === 'object') {
|
|
10
|
-
if (
|
|
11
|
+
if (item.rows && item.columns && item.summary) {
|
|
11
12
|
return true;
|
|
12
13
|
}
|
|
13
14
|
}
|
|
@@ -30,6 +31,10 @@ const initDataList = (reportDataList) => {
|
|
|
30
31
|
Util.logError(`failed to read report data file: ${item}`);
|
|
31
32
|
continue;
|
|
32
33
|
}
|
|
34
|
+
|
|
35
|
+
// for finding attachments
|
|
36
|
+
data.jsonDir = path.dirname(item);
|
|
37
|
+
|
|
33
38
|
list.push(data);
|
|
34
39
|
Util.logInfo(`report data loaded: ${item}`);
|
|
35
40
|
continue;
|
|
@@ -39,6 +44,9 @@ const initDataList = (reportDataList) => {
|
|
|
39
44
|
Util.logError(`unmatched report data format: ${item}`);
|
|
40
45
|
return;
|
|
41
46
|
}
|
|
47
|
+
|
|
48
|
+
item.jsonDir = item.outputDir;
|
|
49
|
+
|
|
42
50
|
list.push(item);
|
|
43
51
|
}
|
|
44
52
|
|
|
@@ -49,26 +57,99 @@ const initDataList = (reportDataList) => {
|
|
|
49
57
|
return list;
|
|
50
58
|
};
|
|
51
59
|
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
60
|
+
const copyTarget = (targetPath, fromDir, toDir) => {
|
|
61
|
+
const oldPath = path.resolve(fromDir, targetPath);
|
|
62
|
+
if (fs.existsSync(oldPath)) {
|
|
63
|
+
const newPath = path.resolve(toDir, targetPath);
|
|
64
|
+
if (oldPath !== newPath) {
|
|
65
|
+
fs.cpSync(oldPath, newPath, {
|
|
66
|
+
force: true,
|
|
67
|
+
recursive: true
|
|
68
|
+
});
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
55
71
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const attachmentsHandler = (item, outputDir, attachmentPathHandler) => {
|
|
75
|
+
|
|
76
|
+
const jsonDir = item.jsonDir;
|
|
77
|
+
|
|
78
|
+
const extras = Util.getAttachmentPathExtras(item);
|
|
79
|
+
Util.forEach(item.rows, (row) => {
|
|
80
|
+
if (row.type !== 'case' || !row.attachments) {
|
|
59
81
|
return;
|
|
60
82
|
}
|
|
61
|
-
|
|
83
|
+
row.attachments.forEach((attachment) => {
|
|
62
84
|
if (!attachment.path) {
|
|
63
85
|
return;
|
|
64
86
|
}
|
|
65
|
-
|
|
66
|
-
|
|
87
|
+
|
|
88
|
+
// copy attachment
|
|
89
|
+
const done = copyTarget(attachment.path, jsonDir, outputDir);
|
|
90
|
+
if (!done) {
|
|
91
|
+
Util.logError(`failed to copy: ${attachment.path}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (attachmentPathHandler) {
|
|
95
|
+
const newPath = attachmentPathHandler(attachment.path, extras);
|
|
96
|
+
if (newPath) {
|
|
97
|
+
attachment.path = newPath;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const mergeArtifacts = async (artifactsList, options) => {
|
|
105
|
+
|
|
106
|
+
const outputDir = options.outputDir;
|
|
107
|
+
|
|
108
|
+
const artifacts = [];
|
|
109
|
+
const coverageRawList = [];
|
|
110
|
+
artifactsList.forEach((item) => {
|
|
111
|
+
const jsonDir = item.jsonDir;
|
|
112
|
+
let hasAssets = false;
|
|
113
|
+
item.artifacts.forEach((art) => {
|
|
114
|
+
|
|
115
|
+
// merge global coverage
|
|
116
|
+
if (art.global && art.type === 'coverage') {
|
|
117
|
+
|
|
118
|
+
const rawDir = path.resolve(jsonDir, art.rawDir);
|
|
119
|
+
if (fs.existsSync(rawDir)) {
|
|
120
|
+
coverageRawList.push(rawDir);
|
|
121
|
+
}
|
|
67
122
|
return;
|
|
123
|
+
|
|
68
124
|
}
|
|
69
|
-
|
|
125
|
+
|
|
126
|
+
const targetDirName = path.dirname(art.path);
|
|
127
|
+
// copy all files in art dir, like network, audit
|
|
128
|
+
copyTarget(targetDirName, jsonDir, outputDir);
|
|
129
|
+
hasAssets = true;
|
|
130
|
+
|
|
131
|
+
// update path relative to cwd/root
|
|
132
|
+
art.path = Util.relativePath(path.resolve(outputDir, art.path));
|
|
133
|
+
|
|
134
|
+
artifacts.push(art);
|
|
135
|
+
|
|
70
136
|
});
|
|
137
|
+
|
|
138
|
+
// copy assets dir
|
|
139
|
+
if (hasAssets) {
|
|
140
|
+
copyTarget('assets', jsonDir, outputDir);
|
|
141
|
+
}
|
|
142
|
+
|
|
71
143
|
});
|
|
144
|
+
|
|
145
|
+
if (coverageRawList.length) {
|
|
146
|
+
const coverage = await mergeGlobalCoverageReport(coverageRawList, options);
|
|
147
|
+
if (coverage) {
|
|
148
|
+
artifacts.push(coverage);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return artifacts;
|
|
72
153
|
};
|
|
73
154
|
|
|
74
155
|
const mergeDataList = async (dataList, options) => {
|
|
@@ -78,11 +159,18 @@ const mergeDataList = async (dataList, options) => {
|
|
|
78
159
|
const outputFile = await Util.resolveOutputFile(options.outputFile);
|
|
79
160
|
// init outputDir
|
|
80
161
|
const outputDir = path.dirname(outputFile);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
162
|
+
// clean
|
|
163
|
+
if (fs.existsSync(outputDir)) {
|
|
164
|
+
fs.rmSync(outputDir, {
|
|
165
|
+
recursive: true,
|
|
166
|
+
force: true,
|
|
167
|
+
maxRetries: 10
|
|
84
168
|
});
|
|
85
169
|
}
|
|
170
|
+
|
|
171
|
+
fs.mkdirSync(outputDir, {
|
|
172
|
+
recursive: true
|
|
173
|
+
});
|
|
86
174
|
// for attachment path handler
|
|
87
175
|
options.outputDir = outputDir;
|
|
88
176
|
|
|
@@ -93,10 +181,11 @@ const mergeDataList = async (dataList, options) => {
|
|
|
93
181
|
const metadata = {};
|
|
94
182
|
const system = [];
|
|
95
183
|
const rows = [];
|
|
184
|
+
const artifactsList = [];
|
|
96
185
|
|
|
97
|
-
|
|
186
|
+
for (const item of dataList) {
|
|
98
187
|
|
|
99
|
-
attachmentsHandler(item, attachmentPathHandler);
|
|
188
|
+
attachmentsHandler(item, outputDir, attachmentPathHandler);
|
|
100
189
|
|
|
101
190
|
dates.push(item.date);
|
|
102
191
|
endDates.push(item.date + item.duration);
|
|
@@ -117,7 +206,16 @@ const mergeDataList = async (dataList, options) => {
|
|
|
117
206
|
subs: item.rows
|
|
118
207
|
});
|
|
119
208
|
|
|
120
|
-
|
|
209
|
+
if (item.artifacts) {
|
|
210
|
+
artifactsList.push({
|
|
211
|
+
jsonDir: item.jsonDir,
|
|
212
|
+
artifacts: item.artifacts
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const artifacts = await mergeArtifacts(artifactsList, options);
|
|
121
219
|
|
|
122
220
|
// base on first one
|
|
123
221
|
const mergedData = {
|
|
@@ -158,7 +256,9 @@ const mergeDataList = async (dataList, options) => {
|
|
|
158
256
|
system,
|
|
159
257
|
trends,
|
|
160
258
|
|
|
161
|
-
rows
|
|
259
|
+
rows,
|
|
260
|
+
|
|
261
|
+
artifacts
|
|
162
262
|
});
|
|
163
263
|
|
|
164
264
|
// tag style can be rewrite with new options tags
|
|
@@ -185,6 +285,7 @@ module.exports = async (reportDataList, userOptions = {}) => {
|
|
|
185
285
|
};
|
|
186
286
|
|
|
187
287
|
const reportData = await mergeDataList(dataList, options);
|
|
288
|
+
// console.log(reportData.artifacts);
|
|
188
289
|
|
|
189
290
|
return generateReport(reportData, options);
|
|
190
291
|
|