monocart-reporter 2.8.4 → 2.9.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 +18 -1
- package/lib/default/options.js +6 -0
- package/lib/generate-report.js +101 -28
- package/lib/index.d.ts +8 -0
- package/lib/index.js +3 -2
- package/lib/merge-data.js +117 -69
- package/lib/packages/monocart-reporter-assets.js +1 -1
- package/lib/packages/monocart-reporter-vendor.js +25 -25
- package/lib/plugins/audit/audit.js +1 -1
- package/lib/plugins/coverage/coverage.js +10 -7
- package/lib/plugins/network/network.js +1 -1
- package/lib/utils/util.js +60 -7
- package/package.json +10 -7
package/README.md
CHANGED
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|

|
|
60
60
|
|
|
61
61
|

|
|
62
|
+
(For Github actions, we can enforce color with env: `FORCE_COLOR: true`)
|
|
62
63
|
|
|
63
64
|
## Install
|
|
64
65
|
```sh
|
|
@@ -90,8 +91,10 @@ Playwright Docs [https://playwright.dev/docs/test-reporters](https://playwright.
|
|
|
90
91
|
- path-to/your-filename.html
|
|
91
92
|
Single HTML file (data compressed), easy to transfer/deploy or open directly anywhere
|
|
92
93
|
> Note: All attachments (screenshots images/videos) will be linked with relative path in report.
|
|
93
|
-
- path-to/your-filename.json
|
|
94
|
+
- path-to/your-filename.json (requires option `json` is true)
|
|
94
95
|
Separated data file which can be used for debugging or data provider (It's included in the above HTML and compressed).
|
|
96
|
+
- path-to/your-filename.zip (requires option `zip` is true)
|
|
97
|
+
Zip file for merging reports
|
|
95
98
|
|
|
96
99
|
## Reporter Options
|
|
97
100
|
- Default options: [lib/default/options.js](./lib/default/options.js)
|
|
@@ -1025,6 +1028,11 @@ const reportDataList = [
|
|
|
1025
1028
|
'path-to/shard1/index.json',
|
|
1026
1029
|
'path-to/shard2/index.json',
|
|
1027
1030
|
'path-to/shard3/index.json'
|
|
1031
|
+
|
|
1032
|
+
// Or load zip file directly if the output files is zipped
|
|
1033
|
+
// 'path-to/shard1/index.zip',
|
|
1034
|
+
// 'path-to/shard2/index.zip',
|
|
1035
|
+
// 'path-to/shard3/index.zip'
|
|
1028
1036
|
];
|
|
1029
1037
|
|
|
1030
1038
|
await merge(reportDataList, {
|
|
@@ -1035,6 +1043,7 @@ await merge(reportDataList, {
|
|
|
1035
1043
|
}
|
|
1036
1044
|
});
|
|
1037
1045
|
```
|
|
1046
|
+
|
|
1038
1047
|
> Note: The coverage reports will be merged automatically if we specify the `raw` report in coverage options:
|
|
1039
1048
|
```js
|
|
1040
1049
|
// global coverage options
|
|
@@ -1042,6 +1051,8 @@ coverage: {
|
|
|
1042
1051
|
reports: [
|
|
1043
1052
|
// for merging coverage reports
|
|
1044
1053
|
'raw'
|
|
1054
|
+
// we can merge and zip the raw report files
|
|
1055
|
+
// ['raw', { merge: true, zip: true }]
|
|
1045
1056
|
]
|
|
1046
1057
|
}
|
|
1047
1058
|
```
|
|
@@ -1064,6 +1075,12 @@ The default config files (In order of priority)
|
|
|
1064
1075
|
- mr.config.json
|
|
1065
1076
|
- mr.config.ts
|
|
1066
1077
|
|
|
1078
|
+
Preload for TypeScript config file:
|
|
1079
|
+
- It requires node 18.19.0+
|
|
1080
|
+
- Installing tsx: `npm i -D tsx`
|
|
1081
|
+
- Using the `--import tsx` flag
|
|
1082
|
+
- see [comment](https://github.com/cenfun/monocart-reporter/issues/145#issuecomment-2365460013)
|
|
1083
|
+
|
|
1067
1084
|
|
|
1068
1085
|
## onEnd Hook
|
|
1069
1086
|
The `onEnd` function will be executed after report generated. Arguments:
|
package/lib/default/options.js
CHANGED
|
@@ -8,6 +8,9 @@ module.exports = () => ({
|
|
|
8
8
|
// the output html file path (relative process.cwd)
|
|
9
9
|
outputFile: './monocart-report/index.html',
|
|
10
10
|
|
|
11
|
+
json: true,
|
|
12
|
+
zip: false,
|
|
13
|
+
|
|
11
14
|
// whether to copy attachments to the reporter output dir, defaults to true
|
|
12
15
|
// it is useful when there are multiple html reports being output.
|
|
13
16
|
copyAttachments: true,
|
|
@@ -22,6 +25,9 @@ module.exports = () => ({
|
|
|
22
25
|
// timezone offset in minutes, GMT+0800 = -480
|
|
23
26
|
timezoneOffset: 0,
|
|
24
27
|
|
|
28
|
+
// normal or exclude-idle
|
|
29
|
+
durationStrategy: null,
|
|
30
|
+
|
|
25
31
|
// global coverage settings for addCoverageReport API
|
|
26
32
|
coverage: null,
|
|
27
33
|
// coverage: {
|
package/lib/generate-report.js
CHANGED
|
@@ -1,26 +1,92 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
1
2
|
const path = require('path');
|
|
2
3
|
const EC = require('eight-colors');
|
|
3
4
|
const nodemailer = require('nodemailer');
|
|
4
5
|
const Util = require('./utils/util.js');
|
|
5
6
|
const emailPlugin = require('./plugins/email.js');
|
|
6
7
|
const Assets = require('./assets.js');
|
|
7
|
-
|
|
8
|
+
const { ZipFile } = require('./packages/monocart-reporter-vendor.js');
|
|
8
9
|
// ===========================================================================
|
|
9
10
|
|
|
10
|
-
const generateJson = (outputDir,
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const generateJson = (outputDir, filename, reportData, options) => {
|
|
12
|
+
if (!options.json) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const jsonPath = path.resolve(outputDir, `${filename}.json`);
|
|
13
17
|
Util.writeJSONSync(jsonPath, reportData);
|
|
14
|
-
jsonPath = Util.relativePath(jsonPath);
|
|
15
|
-
|
|
18
|
+
reportData.jsonPath = Util.relativePath(jsonPath);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const forEachFile = (dir, callback) => {
|
|
22
|
+
if (!fs.existsSync(dir)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const dirs = [];
|
|
26
|
+
fs.readdirSync(dir, {
|
|
27
|
+
withFileTypes: true
|
|
28
|
+
}).forEach((it) => {
|
|
29
|
+
|
|
30
|
+
if (it.isFile()) {
|
|
31
|
+
callback(it.name, dir);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (it.isDirectory()) {
|
|
36
|
+
dirs.push(path.resolve(dir, it.name));
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
for (const subDir of dirs) {
|
|
41
|
+
forEachFile(subDir, callback);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const generateZip = (outputDir, filename, reportData, options) => {
|
|
47
|
+
|
|
48
|
+
if (!options.zip) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const zipPath = path.resolve(outputDir, `${filename}.zip`);
|
|
53
|
+
const reportFiles = [];
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const zipFile = new ZipFile();
|
|
56
|
+
zipFile.outputStream.pipe(fs.createWriteStream(zipPath)).on('close', function() {
|
|
57
|
+
|
|
58
|
+
// remove files after zip
|
|
59
|
+
reportData.reportFiles = reportFiles;
|
|
60
|
+
reportData.zipPath = Util.relativePath(zipPath);
|
|
61
|
+
|
|
62
|
+
resolve();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
forEachFile(outputDir, (name, dir) => {
|
|
66
|
+
const absPath = path.resolve(dir, name);
|
|
67
|
+
const relPath = Util.relativePath(absPath, outputDir);
|
|
68
|
+
reportFiles.push(relPath);
|
|
69
|
+
// console.log(relPath);
|
|
70
|
+
zipFile.addFile(absPath, relPath);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
zipFile.end();
|
|
74
|
+
});
|
|
16
75
|
};
|
|
17
76
|
|
|
18
|
-
const generateHtml = async (outputDir,
|
|
77
|
+
const generateHtml = async (outputDir, filename, reportData, options) => {
|
|
78
|
+
|
|
79
|
+
// generate html
|
|
80
|
+
let inline = true;
|
|
81
|
+
if (typeof options.inline === 'boolean') {
|
|
82
|
+
inline = options.inline;
|
|
83
|
+
}
|
|
19
84
|
|
|
20
85
|
// deps
|
|
21
86
|
const jsFiles = ['monocart-reporter-app'];
|
|
87
|
+
const htmlFile = `${filename}.html`;
|
|
22
88
|
|
|
23
|
-
const
|
|
89
|
+
const htmlPath = await Assets.saveHtmlReport({
|
|
24
90
|
inline,
|
|
25
91
|
reportData,
|
|
26
92
|
jsFiles,
|
|
@@ -29,11 +95,10 @@ const generateHtml = async (outputDir, htmlFile, reportData, inline) => {
|
|
|
29
95
|
htmlFile,
|
|
30
96
|
|
|
31
97
|
reportDataFile: 'report-data.js'
|
|
32
|
-
};
|
|
98
|
+
});
|
|
33
99
|
|
|
34
|
-
|
|
100
|
+
reportData.htmlPath = htmlPath;
|
|
35
101
|
|
|
36
|
-
return htmlPath;
|
|
37
102
|
};
|
|
38
103
|
|
|
39
104
|
const showTestResults = (reportData) => {
|
|
@@ -221,30 +286,38 @@ const generateReport = async (reportData, options, rawData) => {
|
|
|
221
286
|
await onDataHandler(reportData, options, rawData);
|
|
222
287
|
|
|
223
288
|
// console.log(reportData);
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
// generate json
|
|
227
|
-
const jsonPath = await generateJson(outputDir, htmlFile, reportData);
|
|
228
|
-
|
|
229
|
-
// generate html
|
|
230
|
-
let inline = true;
|
|
231
|
-
if (typeof options.inline === 'boolean') {
|
|
232
|
-
inline = options.inline;
|
|
233
|
-
}
|
|
234
|
-
const htmlPath = await generateHtml(outputDir, htmlFile, reportData, inline);
|
|
289
|
+
const filename = path.basename(outputFile, '.html');
|
|
235
290
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
jsonPath
|
|
240
|
-
});
|
|
291
|
+
await generateHtml(outputDir, filename, reportData, options);
|
|
292
|
+
await generateJson(outputDir, filename, reportData, options);
|
|
293
|
+
await generateZip(outputDir, filename, reportData, options);
|
|
241
294
|
|
|
242
295
|
await onEndHandler(reportData, options);
|
|
243
296
|
|
|
244
297
|
// after onEnd for summary changes
|
|
245
298
|
showTestResults(reportData);
|
|
246
299
|
|
|
247
|
-
|
|
300
|
+
// clean .cache for merge
|
|
301
|
+
if (options.cacheDir) {
|
|
302
|
+
Util.rmSync(options.cacheDir);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const {
|
|
306
|
+
htmlPath, jsonPath, zipPath
|
|
307
|
+
} = reportData;
|
|
308
|
+
|
|
309
|
+
const assets = [];
|
|
310
|
+
if (jsonPath) {
|
|
311
|
+
assets.push(`json: ${EC.cyan(jsonPath)}`);
|
|
312
|
+
}
|
|
313
|
+
if (zipPath) {
|
|
314
|
+
assets.push(`zip: ${EC.cyan(zipPath)}`);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (assets.length) {
|
|
318
|
+
Util.logInfo(assets.join(' '));
|
|
319
|
+
}
|
|
320
|
+
|
|
248
321
|
Util.logInfo(`view report: ${EC.cyan(`npx monocart show-report ${htmlPath}`)}`);
|
|
249
322
|
|
|
250
323
|
};
|
package/lib/index.d.ts
CHANGED
|
@@ -54,6 +54,11 @@ export type MonocartReporterOptions = {
|
|
|
54
54
|
/** the output file path (relative process.cwd) */
|
|
55
55
|
outputFile?: string;
|
|
56
56
|
|
|
57
|
+
/** output json file for data only */
|
|
58
|
+
json?: boolean;
|
|
59
|
+
/** output zip file for all report files */
|
|
60
|
+
zip?: boolean;
|
|
61
|
+
|
|
57
62
|
/**
|
|
58
63
|
* whether to copy attachments to the reporter output dir, defaults to true
|
|
59
64
|
* it is useful when there are multiple html reports being output
|
|
@@ -73,6 +78,9 @@ export type MonocartReporterOptions = {
|
|
|
73
78
|
/** timezone offset in minutes, For example: GMT+0800 = -480 */
|
|
74
79
|
timezoneOffset?: number;
|
|
75
80
|
|
|
81
|
+
/** normal or exclude-idle */
|
|
82
|
+
durationStrategy?: 'normal' | 'exclude-idle',
|
|
83
|
+
|
|
76
84
|
/** global coverage options: https://github.com/cenfun/monocart-reporter?#code-coverage-report
|
|
77
85
|
* ```js
|
|
78
86
|
* coverage: {
|
package/lib/index.js
CHANGED
|
@@ -55,6 +55,7 @@ class MonocartReporter {
|
|
|
55
55
|
this.tickTime = this.options.tickTime || 1000;
|
|
56
56
|
this.tickStart();
|
|
57
57
|
|
|
58
|
+
this.trends = [];
|
|
58
59
|
// read trends from json before clean dir
|
|
59
60
|
getTrends(this.options.trend).then((trends) => {
|
|
60
61
|
// console.log('=========================== ', 'trends', trends.length);
|
|
@@ -65,12 +66,12 @@ class MonocartReporter {
|
|
|
65
66
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
init() {
|
|
69
70
|
|
|
70
71
|
this.options.cwd = Util.formatPath(process.cwd());
|
|
71
72
|
|
|
72
73
|
// init outputDir
|
|
73
|
-
const outputFile =
|
|
74
|
+
const outputFile = Util.resolveOutputFile(this.options.outputFile);
|
|
74
75
|
this.options.outputFile = outputFile;
|
|
75
76
|
|
|
76
77
|
const outputDir = path.dirname(outputFile);
|
package/lib/merge-data.js
CHANGED
|
@@ -5,6 +5,7 @@ const generateReport = require('./generate-report.js');
|
|
|
5
5
|
const getDefaultOptions = require('./default/options.js');
|
|
6
6
|
const { calculateSummary, getTrends } = require('./common.js');
|
|
7
7
|
const { mergeGlobalCoverageReport } = require('./plugins/coverage/coverage.js');
|
|
8
|
+
const { StreamZip } = require('./packages/monocart-reporter-vendor.js');
|
|
8
9
|
|
|
9
10
|
const checkReportData = (item) => {
|
|
10
11
|
if (item && typeof item === 'object') {
|
|
@@ -14,7 +15,71 @@ const checkReportData = (item) => {
|
|
|
14
15
|
}
|
|
15
16
|
};
|
|
16
17
|
|
|
17
|
-
const
|
|
18
|
+
const unzipDataFile = async (item, num, options) => {
|
|
19
|
+
|
|
20
|
+
if (!options.cacheDir) {
|
|
21
|
+
options.cacheDir = path.resolve(options.outputDir, '.cache');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const unzipDir = path.resolve(options.cacheDir, `extracted-${num}`);
|
|
25
|
+
|
|
26
|
+
fs.mkdirSync(unzipDir, {
|
|
27
|
+
recursive: true
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const zip = new StreamZip({
|
|
31
|
+
file: item
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await zip.extract(null, unzipDir);
|
|
35
|
+
|
|
36
|
+
// Do not forget to close the file once you're done
|
|
37
|
+
await zip.close();
|
|
38
|
+
|
|
39
|
+
const filename = path.basename(item, '.zip');
|
|
40
|
+
return path.resolve(unzipDir, `${filename}.json`);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const getReportData = async (item, num, options) => {
|
|
44
|
+
if (typeof item === 'string') {
|
|
45
|
+
|
|
46
|
+
// json or zip path
|
|
47
|
+
const extname = path.extname(item);
|
|
48
|
+
if (extname === '.zip') {
|
|
49
|
+
item = await unzipDataFile(item, num, options);
|
|
50
|
+
// console.log(item);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// json path
|
|
54
|
+
const data = Util.readJSONSync(item);
|
|
55
|
+
if (!data) {
|
|
56
|
+
Util.logError(`failed to read report data file: ${item}`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// for finding attachments
|
|
61
|
+
const jsonDir = Util.relativePath(path.dirname(item));
|
|
62
|
+
|
|
63
|
+
Util.logInfo(`report data loaded: ${item}`);
|
|
64
|
+
return {
|
|
65
|
+
jsonDir,
|
|
66
|
+
data
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!checkReportData(item)) {
|
|
71
|
+
Util.logError(`unmatched report data format: ${item}`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// json
|
|
76
|
+
return {
|
|
77
|
+
jsonDir: item.outputDir,
|
|
78
|
+
data: item
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const initDataList = async (reportDataList, options) => {
|
|
18
83
|
if (!Util.isList(reportDataList)) {
|
|
19
84
|
Util.logError(`invalid report data list: ${reportDataList}`);
|
|
20
85
|
return;
|
|
@@ -23,31 +88,17 @@ const initDataList = (reportDataList) => {
|
|
|
23
88
|
let hasError = false;
|
|
24
89
|
const list = [];
|
|
25
90
|
|
|
91
|
+
let num = 1;
|
|
26
92
|
for (const item of reportDataList) {
|
|
27
|
-
if (typeof item === 'string') {
|
|
28
|
-
const data = Util.readJSONSync(item);
|
|
29
|
-
if (!data) {
|
|
30
|
-
hasError = true;
|
|
31
|
-
Util.logError(`failed to read report data file: ${item}`);
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// for finding attachments
|
|
36
|
-
data.jsonDir = Util.relativePath(path.dirname(item));
|
|
37
93
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
94
|
+
const data = await getReportData(item, num, options);
|
|
95
|
+
if (!data) {
|
|
96
|
+
hasError = true;
|
|
97
|
+
break;
|
|
41
98
|
}
|
|
99
|
+
num += 1;
|
|
42
100
|
|
|
43
|
-
|
|
44
|
-
Util.logError(`unmatched report data format: ${item}`);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
item.jsonDir = item.outputDir;
|
|
49
|
-
|
|
50
|
-
list.push(item);
|
|
101
|
+
list.push(data);
|
|
51
102
|
}
|
|
52
103
|
|
|
53
104
|
if (hasError) {
|
|
@@ -82,12 +133,10 @@ const copyTarget = (targetPath, fromDir, toDir) => {
|
|
|
82
133
|
}
|
|
83
134
|
};
|
|
84
135
|
|
|
85
|
-
const attachmentsHandler = (
|
|
136
|
+
const attachmentsHandler = (data, jsonDir, outputDir, attachmentPathHandler) => {
|
|
86
137
|
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
const extras = Util.getAttachmentPathExtras(item);
|
|
90
|
-
Util.forEach(item.rows, (row) => {
|
|
138
|
+
const extras = Util.getAttachmentPathExtras(data);
|
|
139
|
+
Util.forEach(data.rows, (row) => {
|
|
91
140
|
if (row.type !== 'case' || !row.attachments) {
|
|
92
141
|
return;
|
|
93
142
|
}
|
|
@@ -195,62 +244,51 @@ const mergeArtifacts = async (artifactsList, options) => {
|
|
|
195
244
|
|
|
196
245
|
const mergeDataList = async (dataList, options) => {
|
|
197
246
|
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
const outputFile = await Util.resolveOutputFile(options.outputFile);
|
|
201
|
-
// init outputDir
|
|
202
|
-
const outputDir = path.dirname(outputFile);
|
|
203
|
-
// clean
|
|
204
|
-
if (fs.existsSync(outputDir)) {
|
|
205
|
-
fs.rmSync(outputDir, {
|
|
206
|
-
recursive: true,
|
|
207
|
-
force: true,
|
|
208
|
-
maxRetries: 10
|
|
209
|
-
});
|
|
210
|
-
}
|
|
247
|
+
const { outputFile, outputDir } = options;
|
|
211
248
|
|
|
212
|
-
|
|
213
|
-
recursive: true
|
|
214
|
-
});
|
|
215
|
-
// for attachment path handler
|
|
216
|
-
options.outputDir = outputDir;
|
|
249
|
+
const trends = await getTrends(options.trend);
|
|
217
250
|
|
|
218
251
|
const attachmentPathHandler = typeof options.attachmentPath === 'function' ? options.attachmentPath : null;
|
|
219
252
|
|
|
220
|
-
const
|
|
221
|
-
const
|
|
253
|
+
const startDates = [];
|
|
254
|
+
const dateRanges = [];
|
|
222
255
|
const metadata = {};
|
|
223
256
|
const system = [];
|
|
224
257
|
const rows = [];
|
|
225
258
|
const artifactsList = [];
|
|
226
259
|
|
|
227
|
-
for (const
|
|
260
|
+
for (const dataItem of dataList) {
|
|
228
261
|
|
|
229
|
-
|
|
262
|
+
const { data, jsonDir } = dataItem;
|
|
230
263
|
|
|
231
|
-
|
|
232
|
-
|
|
264
|
+
attachmentsHandler(data, jsonDir, outputDir, attachmentPathHandler);
|
|
265
|
+
|
|
266
|
+
startDates.push(data.date);
|
|
267
|
+
dateRanges.push({
|
|
268
|
+
start: data.date,
|
|
269
|
+
end: data.date + data.duration
|
|
270
|
+
});
|
|
233
271
|
|
|
234
272
|
// merge metadata (may collect from diff shard)
|
|
235
|
-
Object.assign(metadata,
|
|
273
|
+
Object.assign(metadata, data.metadata);
|
|
236
274
|
|
|
237
275
|
// merge system
|
|
238
|
-
system.push(
|
|
276
|
+
system.push(data.system);
|
|
239
277
|
|
|
240
278
|
// merge rows
|
|
241
279
|
rows.push({
|
|
242
280
|
// add shard level suite
|
|
243
|
-
title:
|
|
281
|
+
title: data.system.hostname,
|
|
244
282
|
type: 'suite',
|
|
245
283
|
suiteType: 'shard',
|
|
246
|
-
caseNum:
|
|
247
|
-
subs:
|
|
284
|
+
caseNum: data.summary.tests.value,
|
|
285
|
+
subs: data.rows
|
|
248
286
|
});
|
|
249
287
|
|
|
250
|
-
if (
|
|
288
|
+
if (data.artifacts) {
|
|
251
289
|
artifactsList.push({
|
|
252
|
-
jsonDir
|
|
253
|
-
artifacts:
|
|
290
|
+
jsonDir,
|
|
291
|
+
artifacts: data.artifacts
|
|
254
292
|
});
|
|
255
293
|
}
|
|
256
294
|
|
|
@@ -260,7 +298,7 @@ const mergeDataList = async (dataList, options) => {
|
|
|
260
298
|
|
|
261
299
|
// base on first one, do not change dataList (need for onData)
|
|
262
300
|
const mergedData = {
|
|
263
|
-
... dataList[0]
|
|
301
|
+
... dataList[0].data
|
|
264
302
|
};
|
|
265
303
|
|
|
266
304
|
// merge new options
|
|
@@ -272,11 +310,10 @@ const mergeDataList = async (dataList, options) => {
|
|
|
272
310
|
|
|
273
311
|
const reportName = options.name || mergedData.name;
|
|
274
312
|
|
|
275
|
-
const date = Math.min.apply(null,
|
|
313
|
+
const date = Math.min.apply(null, startDates);
|
|
276
314
|
const dateH = new Date(date).toLocaleString();
|
|
277
315
|
|
|
278
|
-
const
|
|
279
|
-
const duration = endDate - date;
|
|
316
|
+
const duration = Util.getDuration(dateRanges, options.durationStrategy);
|
|
280
317
|
const durationH = Util.TF(duration);
|
|
281
318
|
|
|
282
319
|
Object.assign(mergedData, {
|
|
@@ -315,19 +352,30 @@ module.exports = async (reportDataList, userOptions = {}) => {
|
|
|
315
352
|
|
|
316
353
|
Util.logInfo('merging report data ...');
|
|
317
354
|
|
|
318
|
-
const dataList = await initDataList(reportDataList);
|
|
319
|
-
if (!dataList) {
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
355
|
const options = {
|
|
324
356
|
... getDefaultOptions(),
|
|
325
357
|
... userOptions
|
|
326
358
|
};
|
|
327
359
|
|
|
360
|
+
// init options
|
|
361
|
+
const outputFile = Util.resolveOutputFile(options.outputFile);
|
|
362
|
+
options.outputFile = outputFile;
|
|
363
|
+
// init outputDir
|
|
364
|
+
const outputDir = path.dirname(outputFile);
|
|
365
|
+
// clean
|
|
366
|
+
Util.initDir(outputDir);
|
|
367
|
+
// for attachment path handler
|
|
368
|
+
options.outputDir = outputDir;
|
|
369
|
+
|
|
370
|
+
const dataList = await initDataList(reportDataList, options);
|
|
371
|
+
if (!dataList) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
|
|
328
375
|
const reportData = await mergeDataList(dataList, options);
|
|
329
376
|
// console.log(reportData.artifacts);
|
|
330
377
|
|
|
331
|
-
|
|
378
|
+
const rawData = dataList.map((it) => it.data);
|
|
379
|
+
return generateReport(reportData, options, rawData);
|
|
332
380
|
|
|
333
381
|
};
|