monocart-reporter 1.6.26 → 1.6.28

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
@@ -748,7 +748,7 @@ const report = await attachCoverageReport(coverageList, test.info(), {
748
748
  | Code formatting | N/A | ✅ | ❌ |
749
749
 
750
750
  ### Global Coverage Report
751
- 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).
751
+ The global coverage report will not be attached to any test case, but will merge all coverages into one global report after all the tests are finished. The API is `addCoverageReport(v8list, testInfo)`, currently supported `V8` only. Here is an example for Playwright Component Testing [playwright-ct-vue](https://github.com/cenfun/playwright-ct-vue).
752
752
  ```js
753
753
  // playwright.config.js
754
754
  module.exports = {
@@ -906,104 +906,60 @@ module.exports = {
906
906
  // async hook after report data generated
907
907
  onEnd: async (reportData, capability) => {
908
908
  // console.log(reportData.summary);
909
-
910
- // send email
911
- // const sendEmail = require('./common/send-email.js');
912
- // await sendEmail(reportData, capability);
913
-
914
- // testrail integration
915
- // const testrail = require('./common/testrail.js');
916
- // await testrail(reportData, capability);
917
-
918
- // jira + zephyr scale integration
919
- // const zephyrScale = require('./common/zephyr-scale.js');
920
- // await zephyrScale(reportData, capability);
921
-
922
- // jira + xray integration
923
- // const xray = require('./common/xray.js');
924
- // await xray(reportData, capability);
925
-
926
- // slack integration with webhook
927
- // const slackWebhook = require('./common/slack-webhook.js');
928
- // await slackWebhook(reportData, capability);
929
-
930
- // slack integration with web api
931
- // const slackWebApi = require('./common/slack-web-api.js');
932
- // await slackWebApi(reportData, capability);
933
-
934
- // discord integration with webhook
935
- // const discordWebhook = require('./common/discord-webhook.js');
936
- // await discordWebhook(reportData, capability);
937
-
938
- // teams integration with webhook
939
- // const teamsWebhook = require('./common/teams-webhook.js');
940
- // await teamsWebhook(reportData, capability);
941
-
942
- // html to pdf
943
- // const toPdf = require('./common/to-pdf.js');
944
- // await toPdf(reportData, capability);
945
909
  }
946
910
  }]
947
911
  ]
948
912
  };
949
913
  ```
950
914
  ## Send Email
951
- Simply send email with [nodemailer](https://nodemailer.com), check example: [send-email.js](/tests/common/send-email.js)
915
+ Simply send email with [nodemailer](https://nodemailer.com), check example: [send-email](https://github.com/cenfun/monocart-reporter-test/tree/main/integrations/send-email)
952
916
 
953
917
  ![](/docs/email.png)
954
918
 
955
919
 
956
920
  ## Testrail Integration
957
- Send results to your Testrail with [testrail-api](https://github.com/rundef/node-testrail-api), check example: [testrail.js](/tests/common/testrail.js)
921
+ Send test results to your Testrail, check example: [testrail](https://github.com/cenfun/monocart-reporter-test/tree/main/integrations/testrail)
958
922
 
959
923
  ![](/docs/testrail.png)
960
924
 
961
925
  ## Jira + Zephyr Scale Integration
962
- Create test cycle and executions with [zephyr-scale-api](https://support.smartbear.com/zephyr-scale-cloud/api-docs/), check example: [zephyr-scale.js](/tests/common/zephyr-scale.js)
926
+ Create test cycle and executions with [zephyr-scale-api](https://support.smartbear.com/zephyr-scale-cloud/api-docs/), check example: [zephyr-scale](https://github.com/cenfun/monocart-reporter-test/tree/main/integrations/zephyr-scale)
963
927
 
964
928
  ![](/docs/zephyr.png)
965
929
 
966
930
  ## Jira + Xray Integration
967
- check example: [xray.js](/tests/common/xray.js)
968
931
  - Import test execution results with [Xray REST API](https://docs.getxray.app/display/XRAYCLOUD/REST+API)
969
932
  - Update Jira issue status with [Jira Transition API](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-transitions-post)
933
+ check example: [xray](https://github.com/cenfun/monocart-reporter-test/tree/main/integrations/xray)
970
934
 
971
935
  ![](/docs/xray.png)
972
936
 
973
-
974
937
  ## Slack Integration
975
- 1. Simply send message with [@slack/webhook](https://github.com/slackapi/node-slack-sdk), example: [slack-webhook.js](/tests/common/slack-webhook.js)
976
- 2. Recommended: Post chat message and upload image with [@slack/web-api](https://github.com/slackapi/node-slack-sdk), example: [slack-web-api.js](/tests/common/slack-web-api.js)
938
+ 1. Simply send message with [@slack/webhook](https://github.com/slackapi/node-slack-sdk), example: [slack-webhook](https://github.com/cenfun/monocart-reporter-test/tree/main/integrations/slack-webhook)
939
+ 2. Recommended: Post chat message and upload image with [@slack/web-api](https://github.com/slackapi/node-slack-sdk), example: [slack-web-api](https://github.com/cenfun/monocart-reporter-test/tree/main/integrations/slack-web-api)
977
940
 
978
941
  ![](/docs/slack.png)
979
942
 
980
943
  ## Discord Integration
981
- Using [Discord webhooks](https://discord.com/developers/docs/resources/webhook) to post messages to channels. example: [discord-webhook.js](/tests/common/discord-webhook.js)
944
+ Using [Discord webhooks](https://discord.com/developers/docs/resources/webhook) to post messages to channels. example: [discord-webhook](https://github.com/cenfun/monocart-reporter-test/tree/main/integrations/discord-webhook)
982
945
 
983
946
  ![](/docs/discord.png)
984
947
 
985
948
  ## Teams Integration
986
- Please create an [Incoming Webhooks](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook) for the channel first. example: [teams-webhook.js](/tests/common/teams-webhook.js)
949
+ Please create an [Incoming Webhooks](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook) for the channel first. example: [teams-webhook](https://github.com/cenfun/monocart-reporter-test/tree/main/integrations/teams-webhook)
987
950
 
988
951
  ![](/docs/teams.png)
989
952
 
990
953
  ## Dingtalk/Weixin/Feishu Integration
991
- - [dingtalk-webhook.js](/tests/common/dingtalk-webhook.js)
992
- - [weixin-webhook.js](/tests/common/weixin-webhook.js)
993
- - [feishu-webhook.js](/tests/common/feishu-webhook.js)
954
+ - [dingtalk-webhook](https://github.com/cenfun/monocart-reporter-test/tree/main/integrations/dingtalk-webhook)
955
+ - [weixin-webhook](https://github.com/cenfun/monocart-reporter-test/tree/main/integrations/weixin-webhook)
956
+ - [feishu-webhook](https://github.com/cenfun/monocart-reporter-test/tree/main/integrations/feishu-webhook)
994
957
 
995
- ## Dependencies and Packages
958
+ ## Dependencies
996
959
  - UI Framework [Vue 3](https://github.com/vuejs/core)
997
960
  - Lightweight UI Components [vine-ui](https://github.com/cenfun/vine-ui)
998
961
  - High Performance Grid [turbogrid](https://github.com/cenfun/turbogrid)
999
962
  - String compress/decompress [lz-utils](https://github.com/cenfun/lz-utils)
1000
- - Packages
1001
- - `packages/app` Monocart report UI
1002
- - `packages/coverage` Coverage report libs
1003
- - `packages/network` Network HAR report libs
1004
- - `packages/v8` V8 HTML report UI
1005
- - `packages/vendor` Third-party libs
1006
-
1007
963
 
1008
964
  ## Contributing
1009
965
  ```sh
@@ -16,9 +16,9 @@ const getReportName = (options, config, metadata) => {
16
16
  };
17
17
 
18
18
  const artifactsHandler = async (visitor, options) => {
19
- const artifacts = [];
20
- const { coverage, network } = visitor.artifacts;
21
- visitor.artifacts = null;
19
+ const artifacts = [].concat(visitor.artifacts);
20
+ // global artifacts
21
+ const { coverage, network } = visitor.artifactDataMap;
22
22
  if (coverage) {
23
23
  const report = await generateCoverageReport(coverage, options);
24
24
  artifacts.push(report);
@@ -1,15 +1,14 @@
1
- const fs = require('fs');
2
1
  const path = require('path');
3
2
  const EC = require('eight-colors');
4
3
  const CG = require('console-grid');
5
- const { deflateSync } = require('lz-utils');
6
4
  const { nodemailer } = require('./runtime/monocart-vendor.js');
7
5
  const Util = require('./utils/util.js');
8
6
  const emailPlugin = require('./plugins/email.js');
9
7
 
10
8
  // ===========================================================================
11
9
 
12
- const generateJson = (outputDir, filename, reportData) => {
10
+ const generateJson = (outputDir, htmlFile, reportData) => {
11
+ const filename = path.basename(htmlFile, '.html');
13
12
  let jsonPath = path.resolve(outputDir, `${filename}.json`);
14
13
  Util.writeJSONSync(jsonPath, reportData);
15
14
  jsonPath = Util.relativePath(jsonPath);
@@ -17,30 +16,22 @@ const generateJson = (outputDir, filename, reportData) => {
17
16
  return jsonPath;
18
17
  };
19
18
 
20
- const generateHtml = (outputDir, filename, reportData) => {
21
- const reportDistPath = path.resolve(__dirname, 'runtime/monocart-reporter.js');
22
- const errMsg = `Not found runtime lib: ${Util.formatPath(reportDistPath)}`;
19
+ const generateHtml = async (outputDir, htmlFile, reportData, inline) => {
23
20
 
24
- let reportJs = `console.error("${errMsg}");`;
25
- if (fs.existsSync(reportDistPath)) {
26
- reportJs = Util.readFileSync(reportDistPath);
27
- } else {
28
- EC.logRed(errMsg);
29
- }
30
-
31
- const reportDataStr = deflateSync(JSON.stringify(reportData));
32
- const content = `<script>\nwindow.reportData = '${reportDataStr}';\n${reportJs}\n</script>`;
21
+ const options = {
22
+ inline,
23
+ reportData,
24
+ jsFiles: ['monocart-common.js', 'monocart-reporter.js'],
25
+ htmlDir: outputDir,
26
+ htmlFile,
33
27
 
34
- // replace template
35
- let html = Util.getTemplate(path.resolve(__dirname, 'default/template.html'));
36
- html = Util.replace(html, {
37
- title: reportData.name,
38
- content: content
39
- });
28
+ outputDir,
29
+ reportDataFile: 'report-data.js',
30
+ assetsName: 'assets',
31
+ assetsRelative: ''
32
+ };
40
33
 
41
- let htmlPath = path.resolve(outputDir, `${filename}.html`);
42
- Util.writeFileSync(htmlPath, html);
43
- htmlPath = Util.relativePath(htmlPath);
34
+ const htmlPath = await Util.saveHtmlReport(options);
44
35
  console.log(`[MCR] html report: ${EC.cyan(htmlPath)}`);
45
36
 
46
37
  const cmd = `npx monocart show-report ${htmlPath}`;
@@ -141,7 +132,7 @@ const showTestResults = (reportData) => {
141
132
  };
142
133
 
143
134
 
144
- const generateReport = (reportData, onEnd) => {
135
+ const generateReport = async (reportData, options) => {
145
136
 
146
137
  console.log('[MCR] generating test report ...');
147
138
  showTestResults(reportData);
@@ -152,29 +143,34 @@ const generateReport = (reportData, onEnd) => {
152
143
 
153
144
  if (artifacts) {
154
145
  artifacts.forEach((report) => {
155
- console.log(`[MCR] ${report.type} report: ${EC.cyan(report.htmlPath)}`);
156
-
157
- // convert htmlPath to relative reporter
158
- report.htmlPath = Util.relativePath(report.htmlPath, outputDir);
159
-
146
+ const g = report.global ? `${EC.magenta('(global)')}` : '';
147
+ console.log(`[MCR] ${report.name}: ${EC.cyan(report.path)} ${report.title} ${g}`);
148
+ // convert path to relative reporter
149
+ report.path = Util.relativePath(report.path, outputDir);
160
150
  });
161
151
  }
162
152
 
163
153
  // console.log(reportData);
164
- const filename = path.basename(outputFile, '.html');
154
+ const htmlFile = path.basename(outputFile);
155
+
165
156
  // generate json
166
- const jsonPath = generateJson(outputDir, filename, reportData);
157
+ const jsonPath = await generateJson(outputDir, htmlFile, reportData);
158
+
167
159
  // generate html
168
- const htmlPath = generateHtml(outputDir, filename, reportData);
160
+ let inline = true;
161
+ if (typeof options.inline === 'boolean') {
162
+ inline = options.inline;
163
+ }
164
+ const htmlPath = await generateHtml(outputDir, htmlFile, reportData, inline);
169
165
 
170
166
  // onEnd callback
167
+ const onEnd = options.onEnd;
171
168
  if (typeof onEnd !== 'function') {
172
169
  return;
173
170
  }
174
171
 
175
172
  // for onEnd after saved
176
173
  Object.assign(reportData, {
177
- filename,
178
174
  htmlPath,
179
175
  jsonPath
180
176
  });
package/lib/index.js CHANGED
@@ -131,7 +131,7 @@ class Reporter {
131
131
  trends: this.trends
132
132
  });
133
133
 
134
- return generateReport(reportData, this.options.onEnd);
134
+ return generateReport(reportData, this.options);
135
135
  }
136
136
 
137
137
  }
package/lib/merge-data.js CHANGED
@@ -178,6 +178,6 @@ module.exports = async (reportDataList, userOptions = {}) => {
178
178
 
179
179
  const reportData = await mergeDataList(dataList, options);
180
180
 
181
- return generateReport(reportData, options.onEnd);
181
+ return generateReport(reportData, options);
182
182
 
183
183
  };
@@ -70,7 +70,10 @@ const attachAuditReport = async (runnerResult, testInfo, options = {}) => {
70
70
  return;
71
71
  }
72
72
 
73
+ const title = options.title || `Lighthouse Report - ${testInfo.title}`;
74
+
73
75
  options = {
76
+ title,
74
77
  outputDir: Util.resolveOutputDir(testInfo),
75
78
  outputName: `audit-${Util.shortTestId(testInfo.testId)}`,
76
79
 
@@ -86,7 +89,10 @@ const attachAuditReport = async (runnerResult, testInfo, options = {}) => {
86
89
  options.htmlDir = htmlDir;
87
90
 
88
91
  // `.lhr` is the Lighthouse Result as a JS object
89
- const report = getSummaryReport(runnerResult.lhr);
92
+ const report = {
93
+ title,
94
+ ... getSummaryReport(runnerResult.lhr)
95
+ };
90
96
 
91
97
  const htmlPath = path.resolve(htmlDir, 'index.html');
92
98
  // `.report` is the HTML report as a string
@@ -15,6 +15,10 @@ const {
15
15
  // ========================================================================================================
16
16
 
17
17
  const defaultV8Options = {
18
+
19
+ // Defaults to test title
20
+ // title: '',
21
+
18
22
  // (Boolean) Whether to convert to Istanbul report
19
23
  toIstanbul: false,
20
24
 
@@ -36,6 +40,9 @@ const defaultV8Options = {
36
40
 
37
41
  const defaultIstanbulOptions = {
38
42
 
43
+ // Defaults to test title
44
+ // title: '',
45
+
39
46
  // when toIstanbul = true
40
47
  entryFilter: null,
41
48
  unpackSourceMap: true,
@@ -129,8 +136,10 @@ const attachCoverageReport = (coverageInput, testInfo, options = {}) => {
129
136
  return;
130
137
  }
131
138
 
139
+ const title = options.title || `Coverage Report - ${testInfo.title}`;
140
+
132
141
  options = {
133
- title: `Coverage Report - ${testInfo.title}`,
142
+ title,
134
143
  outputDir: Util.resolveOutputDir(testInfo),
135
144
  outputName: `coverage-${Util.shortTestId(testInfo.testId)}`,
136
145
  ... options
@@ -276,10 +285,11 @@ const generateCoverageReport = async (dataList, reporterOptions) => {
276
285
  const report = await generateGlobalCoverageReport(dataList, options);
277
286
 
278
287
  return {
279
- type: 'coverage',
280
- name: 'Coverage',
281
- htmlPath: report.htmlPath,
282
- summary: report.summary
288
+ global: true,
289
+ name: 'coverage',
290
+ path: report.htmlPath,
291
+ summary: report.summary,
292
+ title: options.title
283
293
  };
284
294
  };
285
295
 
@@ -4,6 +4,7 @@ const EC = require('eight-colors');
4
4
 
5
5
  const istanbulReports = require('istanbul-reports');
6
6
 
7
+ const Util = require('../../../utils/util.js');
7
8
  const IstanbulSummary = require('./istanbul-summary.js');
8
9
 
9
10
  const {
@@ -74,6 +75,8 @@ const saveIstanbulReport = (coverageData, fileSources, options) => {
74
75
  const htmlReport = istanbulReports.create('html', {});
75
76
  htmlReport.execute(context);
76
77
 
78
+ const htmlPath = Util.relativePath(path.resolve(options.htmlDir, 'index.html'));
79
+
77
80
  if (options.lcov) {
78
81
  const lcovReport = istanbulReports.create('lcovonly', {});
79
82
  lcovReport.execute(context);
@@ -82,7 +85,12 @@ const saveIstanbulReport = (coverageData, fileSources, options) => {
82
85
  // add watermarks and color
83
86
  const coverageReport = new IstanbulSummary();
84
87
  coverageReport.execute(context);
85
- const report = coverageReport.getReport();
88
+ const report = {
89
+ title: options.title,
90
+ htmlPath,
91
+ watermarks: contextOptions.watermarks,
92
+ ... coverageReport.getReport()
93
+ };
86
94
 
87
95
  return report;
88
96
  };
@@ -132,12 +132,26 @@ const mergeV8List = async (v8list, options) => {
132
132
 
133
133
  // ============================================================
134
134
 
135
- const saveV8HtmlReport = async (reportData, options) => {
136
-
137
- const reportDataFile = 'coverage-data.js';
138
- const jsFiles = ['monocart-code-viewer.js', 'monocart-formatter.js', 'monocart-v8.js'];
135
+ const saveV8HtmlReport = async (reportData, _options) => {
136
+
137
+ const {
138
+ htmlDir, outputDir, inline
139
+ } = _options;
140
+
141
+ const options = {
142
+ inline,
143
+ reportData,
144
+ jsFiles: ['monocart-code-viewer.js', 'monocart-formatter.js', 'monocart-common.js', 'monocart-v8.js'],
145
+ htmlDir,
146
+ htmlFile: 'index.html',
147
+
148
+ outputDir,
149
+ reportDataFile: 'coverage-data.js',
150
+ assetsName: 'assets',
151
+ assetsRelative: '../'
152
+ };
139
153
 
140
- const htmlPath = await Util.saveAttachmentHtmlReport(reportData, options, reportDataFile, jsFiles);
154
+ const htmlPath = await Util.saveHtmlReport(options);
141
155
 
142
156
  return htmlPath;
143
157
  };
@@ -195,6 +209,7 @@ const saveV8Report = async (v8list, options) => {
195
209
  const htmlPath = await saveV8HtmlReport(htmlReport, options);
196
210
 
197
211
  const report = {
212
+ title: options.title,
198
213
  type: 'v8',
199
214
  htmlPath,
200
215
  watermarks,
@@ -95,12 +95,26 @@ const getNetworkSummary = (log) => {
95
95
  return summary;
96
96
  };
97
97
 
98
- const saveNetworkHtmlReport = async (reportData, options) => {
99
-
100
- const reportDataFile = 'network-data.js';
101
- const jsFiles = ['monocart-code-viewer.js', 'monocart-formatter.js', 'monocart-network.js'];
98
+ const saveNetworkHtmlReport = async (reportData, _options) => {
99
+
100
+ const {
101
+ htmlDir, outputDir, inline
102
+ } = _options;
103
+
104
+ const options = {
105
+ inline,
106
+ reportData,
107
+ jsFiles: ['monocart-code-viewer.js', 'monocart-formatter.js', 'monocart-common.js', 'monocart-network.js'],
108
+ htmlDir,
109
+ htmlFile: 'index.html',
110
+
111
+ outputDir,
112
+ reportDataFile: 'network-data.js',
113
+ assetsName: 'assets',
114
+ assetsRelative: '../'
115
+ };
102
116
 
103
- const htmlPath = await Util.saveAttachmentHtmlReport(reportData, options, reportDataFile, jsFiles);
117
+ const htmlPath = await Util.saveHtmlReport(options);
104
118
 
105
119
  return htmlPath;
106
120
  };
@@ -120,6 +134,7 @@ const attachNetworkReport = async (har, testInfo, options = {}) => {
120
134
  ... options
121
135
  };
122
136
 
137
+ const title = options.title || `Network Report - ${testInfo.title}`;
123
138
 
124
139
  const htmlDir = path.resolve(options.outputDir, options.outputName);
125
140
  if (!fs.existsSync(htmlDir)) {
@@ -133,7 +148,7 @@ const attachNetworkReport = async (har, testInfo, options = {}) => {
133
148
 
134
149
  // save har
135
150
  const reportData = {
136
- title: `Network Report - ${testInfo.title}`,
151
+ title,
137
152
  summary,
138
153
  ... harData
139
154
  };
@@ -141,6 +156,7 @@ const attachNetworkReport = async (har, testInfo, options = {}) => {
141
156
  const htmlPath = await saveNetworkHtmlReport(reportData, options);
142
157
 
143
158
  const report = {
159
+ title,
144
160
  ... harData.log,
145
161
  htmlPath,
146
162
  summary