@testomatio/reporter 2.0.1-beta.3 → 2.0.1-beta.5-timestamp

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.
Files changed (148) hide show
  1. package/lib/adapter/codecept.js +335 -293
  2. package/lib/adapter/cucumber/current.js +203 -195
  3. package/lib/adapter/cucumber/legacy.js +155 -130
  4. package/lib/adapter/cucumber.js +16 -5
  5. package/lib/adapter/cypress-plugin/index.js +105 -91
  6. package/lib/adapter/jasmine.js +53 -54
  7. package/lib/adapter/jest.js +99 -97
  8. package/lib/adapter/mocha.js +141 -112
  9. package/lib/adapter/playwright.js +231 -199
  10. package/lib/adapter/vitest.js +149 -150
  11. package/lib/adapter/webdriver.js +121 -144
  12. package/lib/bin/cli.js +211 -229
  13. package/lib/bin/reportXml.js +52 -51
  14. package/lib/bin/startTest.js +95 -83
  15. package/lib/bin/uploadArtifacts.js +61 -56
  16. package/lib/client.js +465 -424
  17. package/lib/config.js +23 -18
  18. package/lib/constants.js +44 -50
  19. package/lib/data-storage.js +188 -216
  20. package/lib/junit-adapter/adapter.js +20 -17
  21. package/lib/junit-adapter/csharp.js +14 -28
  22. package/lib/junit-adapter/index.js +25 -27
  23. package/lib/junit-adapter/java.js +53 -41
  24. package/lib/junit-adapter/javascript.js +27 -30
  25. package/lib/junit-adapter/python.js +37 -38
  26. package/lib/junit-adapter/ruby.js +8 -11
  27. package/lib/output.js +52 -44
  28. package/lib/pipe/bitbucket.js +230 -223
  29. package/lib/pipe/csv.js +126 -113
  30. package/lib/pipe/debug.js +99 -118
  31. package/lib/pipe/github.js +213 -218
  32. package/lib/pipe/gitlab.js +206 -183
  33. package/lib/pipe/html.js +321 -258
  34. package/lib/pipe/index.js +66 -94
  35. package/lib/pipe/testomatio.js +474 -429
  36. package/lib/reporter-functions.js +26 -28
  37. package/lib/reporter.js +29 -34
  38. package/lib/services/artifacts.js +51 -55
  39. package/lib/services/index.js +12 -14
  40. package/lib/services/key-values.js +53 -56
  41. package/lib/services/logger.js +245 -226
  42. package/lib/template/testomatio.hbs +1366 -1026
  43. package/lib/uploader.js +364 -295
  44. package/lib/utils/pipe_utils.js +85 -89
  45. package/lib/utils/utils.js +307 -398
  46. package/lib/xmlReader.js +532 -525
  47. package/package.json +21 -64
  48. package/lib/adapter/codecept.d.ts +0 -2
  49. package/lib/adapter/cucumber/current.d.ts +0 -14
  50. package/lib/adapter/cucumber/legacy.d.ts +0 -0
  51. package/lib/adapter/cucumber.d.ts +0 -2
  52. package/lib/adapter/cypress-plugin/index.d.ts +0 -2
  53. package/lib/adapter/jasmine.d.ts +0 -11
  54. package/lib/adapter/jest.d.ts +0 -13
  55. package/lib/adapter/mocha.d.ts +0 -2
  56. package/lib/adapter/nightwatch.d.ts +0 -4
  57. package/lib/adapter/nightwatch.js +0 -80
  58. package/lib/adapter/playwright.d.ts +0 -14
  59. package/lib/adapter/vitest.d.ts +0 -35
  60. package/lib/adapter/webdriver.d.ts +0 -24
  61. package/lib/bin/cli.d.ts +0 -2
  62. package/lib/bin/reportXml.d.ts +0 -2
  63. package/lib/bin/startTest.d.ts +0 -2
  64. package/lib/bin/uploadArtifacts.d.ts +0 -2
  65. package/lib/client.d.ts +0 -76
  66. package/lib/config.d.ts +0 -1
  67. package/lib/constants.d.ts +0 -25
  68. package/lib/data-storage.d.ts +0 -34
  69. package/lib/junit-adapter/adapter.d.ts +0 -9
  70. package/lib/junit-adapter/csharp.d.ts +0 -5
  71. package/lib/junit-adapter/index.d.ts +0 -3
  72. package/lib/junit-adapter/java.d.ts +0 -5
  73. package/lib/junit-adapter/javascript.d.ts +0 -4
  74. package/lib/junit-adapter/python.d.ts +0 -5
  75. package/lib/junit-adapter/ruby.d.ts +0 -4
  76. package/lib/output.d.ts +0 -11
  77. package/lib/package.json +0 -3
  78. package/lib/pipe/bitbucket.d.ts +0 -25
  79. package/lib/pipe/csv.d.ts +0 -47
  80. package/lib/pipe/debug.d.ts +0 -29
  81. package/lib/pipe/github.d.ts +0 -30
  82. package/lib/pipe/gitlab.d.ts +0 -25
  83. package/lib/pipe/html.d.ts +0 -35
  84. package/lib/pipe/index.d.ts +0 -1
  85. package/lib/pipe/testomatio.d.ts +0 -71
  86. package/lib/replay.d.ts +0 -31
  87. package/lib/replay.js +0 -237
  88. package/lib/reporter-functions.d.ts +0 -34
  89. package/lib/reporter.d.ts +0 -232
  90. package/lib/services/artifacts.d.ts +0 -33
  91. package/lib/services/index.d.ts +0 -9
  92. package/lib/services/key-values.d.ts +0 -27
  93. package/lib/services/logger.d.ts +0 -64
  94. package/lib/uploader.d.ts +0 -60
  95. package/lib/utils/pipe_utils.d.ts +0 -41
  96. package/lib/utils/utils.d.ts +0 -54
  97. package/lib/xmlReader.d.ts +0 -92
  98. package/src/adapter/codecept.js +0 -373
  99. package/src/adapter/cucumber/current.js +0 -228
  100. package/src/adapter/cucumber/legacy.js +0 -158
  101. package/src/adapter/cucumber.js +0 -4
  102. package/src/adapter/cypress-plugin/index.js +0 -110
  103. package/src/adapter/jasmine.js +0 -60
  104. package/src/adapter/jest.js +0 -107
  105. package/src/adapter/mocha.cjs +0 -2
  106. package/src/adapter/mocha.js +0 -156
  107. package/src/adapter/nightwatch.js +0 -88
  108. package/src/adapter/playwright.js +0 -254
  109. package/src/adapter/vitest.js +0 -183
  110. package/src/adapter/webdriver.js +0 -142
  111. package/src/bin/cli.js +0 -348
  112. package/src/bin/reportXml.js +0 -77
  113. package/src/bin/startTest.js +0 -124
  114. package/src/bin/uploadArtifacts.js +0 -91
  115. package/src/client.js +0 -508
  116. package/src/config.js +0 -30
  117. package/src/constants.js +0 -53
  118. package/src/data-storage.js +0 -204
  119. package/src/junit-adapter/adapter.js +0 -23
  120. package/src/junit-adapter/csharp.js +0 -28
  121. package/src/junit-adapter/index.js +0 -28
  122. package/src/junit-adapter/java.js +0 -58
  123. package/src/junit-adapter/javascript.js +0 -31
  124. package/src/junit-adapter/python.js +0 -42
  125. package/src/junit-adapter/ruby.js +0 -10
  126. package/src/output.js +0 -57
  127. package/src/pipe/bitbucket.js +0 -252
  128. package/src/pipe/csv.js +0 -140
  129. package/src/pipe/debug.js +0 -119
  130. package/src/pipe/github.js +0 -232
  131. package/src/pipe/gitlab.js +0 -247
  132. package/src/pipe/html.js +0 -373
  133. package/src/pipe/index.js +0 -71
  134. package/src/pipe/testomatio.js +0 -504
  135. package/src/replay.js +0 -245
  136. package/src/reporter-functions.js +0 -55
  137. package/src/reporter.cjs_decprecated +0 -21
  138. package/src/reporter.js +0 -33
  139. package/src/services/artifacts.js +0 -59
  140. package/src/services/index.js +0 -13
  141. package/src/services/key-values.js +0 -59
  142. package/src/services/logger.js +0 -315
  143. package/src/template/emptyData.svg +0 -23
  144. package/src/template/testomatio.hbs +0 -1081
  145. package/src/uploader.js +0 -376
  146. package/src/utils/pipe_utils.js +0 -119
  147. package/src/utils/utils.js +0 -416
  148. package/src/xmlReader.js +0 -614
package/lib/pipe/html.js CHANGED
@@ -1,202 +1,243 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const debug_1 = __importDefault(require("debug"));
7
- const lodash_merge_1 = __importDefault(require("lodash.merge"));
8
- const fs_1 = __importDefault(require("fs"));
9
- const path_1 = __importDefault(require("path"));
10
- const picocolors_1 = __importDefault(require("picocolors"));
11
- const handlebars_1 = __importDefault(require("handlebars"));
12
- const file_url_1 = __importDefault(require("file-url"));
13
- const utils_js_1 = require("../utils/utils.js");
14
- const constants_js_1 = require("../constants.js");
15
- const node_url_1 = require("node:url");
16
- const debug = (0, debug_1.default)('@testomatio/reporter:pipe:html');
17
- // @ts-ignore – this line will be removed in compiled code (already defined in the global scope of commonjs)
1
+ const debug = require('debug')('@testomatio/reporter:pipe:html');
2
+ const merge = require('lodash.merge');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const chalk = require('chalk');
6
+ const handlebars = require('handlebars');
7
+ const fileUrl = require('file-url');
8
+ const { fileSystem, isSameTest, ansiRegExp, formatStep } = require('../utils/utils');
9
+ const { HTML_REPORT } = require('../constants');
10
+
18
11
  class HtmlPipe {
19
- constructor(params, store = {}) {
20
- this.store = store || {};
21
- this.title = params.title || process.env.TESTOMATIO_TITLE;
22
- this.apiKey = params.apiKey || process.env.TESTOMATIO;
23
- this.isHtml = process.env.TESTOMATIO_HTML_REPORT_SAVE;
24
- debug('HTML Pipe: ', this.apiKey ? 'API KEY' : '*no api key provided*');
25
- this.isEnabled = false;
26
- this.htmlOutputPath = '';
27
- this.fullHtmlOutputPath = '';
28
- this.filenameMsg = '';
29
- this.tests = [];
30
- if (this.isHtml) {
31
- this.isEnabled = true;
32
- this.htmlReportDir = process.env.TESTOMATIO_HTML_REPORT_FOLDER || constants_js_1.HTML_REPORT.FOLDER;
33
- if (process.env.TESTOMATIO_HTML_FILENAME && process.env.TESTOMATIO_HTML_FILENAME.endsWith('.html')) {
34
- this.htmlReportName = process.env.TESTOMATIO_HTML_FILENAME;
35
- }
36
- if (process.env.TESTOMATIO_HTML_FILENAME && !process.env.TESTOMATIO_HTML_FILENAME.endsWith('.html')) {
37
- this.htmlReportName = constants_js_1.HTML_REPORT.REPORT_DEFAULT_NAME;
38
- this.filenameMsg =
39
- 'HTML filename must include the extension ".html".' +
40
- ` The default report name "${this.htmlReportDir}/${constants_js_1.HTML_REPORT.REPORT_DEFAULT_NAME}" is used!`;
41
- }
42
- if (!process.env.TESTOMATIO_HTML_FILENAME) {
43
- this.htmlReportName = constants_js_1.HTML_REPORT.REPORT_DEFAULT_NAME;
44
- }
45
- this.templateFolderPath = path_1.default.resolve(__dirname, '..', 'template');
46
- this.templateHtmlPath = path_1.default.resolve(this.templateFolderPath, constants_js_1.HTML_REPORT.TEMPLATE_NAME);
47
- this.htmlOutputPath = path_1.default.join(this.htmlReportDir, this.htmlReportName);
48
- // create a new folder for the HTML reports
49
- utils_js_1.fileSystem.createDir(this.htmlReportDir);
50
- debug(picocolors_1.default.yellow('HTML Pipe:'), `Save HTML report: ${this.isEnabled}`, `HTML report folder: ${this.htmlReportDir}, report name: ${this.htmlReportName}`);
51
- }
12
+ constructor(params, store = {}) {
13
+ this.store = store || {};
14
+ this.title = params.title || process.env.TESTOMATIO_TITLE;
15
+ this.apiKey = params.apiKey || process.env.TESTOMATIO;
16
+ this.isHtml = process.env.TESTOMATIO_HTML_REPORT_SAVE;
17
+
18
+ debug('HTML Pipe: ', this.apiKey ? 'API KEY' : '*no api key provided*');
19
+
20
+ this.isEnabled = false;
21
+ this.htmlOutputPath = '';
22
+ this.fullHtmlOutputPath = '';
23
+ this.filenameMsg = '';
24
+ this.tests = [];
25
+
26
+ if (this.isHtml) {
27
+ this.isEnabled = true;
28
+ this.htmlReportDir = process.env.TESTOMATIO_HTML_REPORT_FOLDER || HTML_REPORT.FOLDER;
29
+
30
+ if (process.env.TESTOMATIO_HTML_FILENAME && process.env.TESTOMATIO_HTML_FILENAME.endsWith('.html')) {
31
+ this.htmlReportName = process.env.TESTOMATIO_HTML_FILENAME;
32
+ }
33
+
34
+ if (process.env.TESTOMATIO_HTML_FILENAME && !process.env.TESTOMATIO_HTML_FILENAME.endsWith('.html')) {
35
+ this.htmlReportName = HTML_REPORT.REPORT_DEFAULT_NAME;
36
+ this.filenameMsg =
37
+ 'HTML filename must include the extension ".html".' +
38
+ ` The default report name "${this.htmlReportDir}/${HTML_REPORT.REPORT_DEFAULT_NAME}" is used!`;
39
+ }
40
+
41
+ if (!process.env.TESTOMATIO_HTML_FILENAME) {
42
+ this.htmlReportName = HTML_REPORT.REPORT_DEFAULT_NAME;
43
+ }
44
+
45
+ this.templateFolderPath = path.resolve(__dirname, '..', 'template');
46
+ this.templateHtmlPath = path.resolve(this.templateFolderPath, HTML_REPORT.TEMPLATE_NAME);
47
+ this.htmlOutputPath = path.join(this.htmlReportDir, this.htmlReportName);
48
+ // create a new folder for the HTML reports
49
+ fileSystem.createDir(this.htmlReportDir);
50
+
51
+ debug(
52
+ chalk.yellow('HTML Pipe:'),
53
+ `Save HTML report: ${this.isEnabled}`,
54
+ `HTML report folder: ${this.htmlReportDir}, report name: ${this.htmlReportName}`,
55
+ );
52
56
  }
53
- async createRun() {
54
- // empty
57
+ }
58
+
59
+ async createRun() {
60
+ // empty
61
+ }
62
+
63
+ async prepareRun() {}
64
+
65
+ updateRun() {
66
+ // empty
67
+ }
68
+
69
+ /**
70
+ * Add test data to the result array for saving. As a result of this function, we get a result object to save.
71
+ * @param {import('../../types').RunData} test - object which includes each test entry.
72
+ */
73
+ addTest(test) {
74
+ if (!this.isEnabled) return;
75
+
76
+ if (!test.status) return;
77
+
78
+ const index = this.tests.findIndex(t => isSameTest(t, test));
79
+ // update if they were already added
80
+ if (index >= 0) {
81
+ this.tests[index] = merge(this.tests[index], test);
82
+ return;
55
83
  }
56
- async prepareRun() { }
57
- updateRun() {
58
- // empty
84
+
85
+ this.tests.push(test);
86
+ }
87
+
88
+ async finishRun(runParams) {
89
+ if (!this.isEnabled) return;
90
+
91
+ if (this.isHtml) {
92
+ // GENERATE HTML reports based on the results data
93
+ this.buildReport({
94
+ runParams,
95
+ // TODO: this.tests=[] in case of Mocha, need retest by Vitalii
96
+ tests: this.tests,
97
+ outputPath: this.htmlOutputPath,
98
+ templatePath: this.templateHtmlPath,
99
+ warningMsg: this.filenameMsg,
100
+ });
59
101
  }
60
- /**
61
- * Add test data to the result array for saving. As a result of this function, we get a result object to save.
62
- * @param {import('../../types/types.js').RunData} test - object which includes each test entry.
63
- */
64
- addTest(test) {
65
- if (!this.isEnabled)
66
- return;
67
- if (!test.status)
68
- return;
69
- const index = this.tests.findIndex(t => (0, utils_js_1.isSameTest)(t, test));
70
- // update if they were already added
71
- if (index >= 0) {
72
- this.tests[index] = (0, lodash_merge_1.default)(this.tests[index], test);
73
- return;
74
- }
75
- this.tests.push(test);
102
+ }
103
+ /**
104
+ * Generates an HTML report based on provided test data and a template.
105
+ * @param {object} opts - Test options used to generate the HTML report:
106
+ * runParams, tests, outputPath, templatePath
107
+ * @returns {void} - This function does not return anything.
108
+ */
109
+
110
+ buildReport(opts) {
111
+ const { runParams, tests, outputPath, templatePath, warningMsg: msg } = opts;
112
+
113
+ debug('HTML tests data:', tests);
114
+
115
+ if (!outputPath) {
116
+ console.log(chalk.yellow(`🚨 HTML export path is not set, ignoring...`));
117
+ return;
76
118
  }
77
- async finishRun(runParams) {
78
- if (!this.isEnabled)
79
- return;
80
- if (this.isHtml) {
81
- // GENERATE HTML reports based on the results data
82
- this.buildReport({
83
- runParams,
84
- // TODO: this.tests=[] in case of Mocha, need retest by Vitalii
85
- tests: this.tests,
86
- outputPath: this.htmlOutputPath,
87
- templatePath: this.templateHtmlPath,
88
- warningMsg: this.filenameMsg,
89
- });
90
- }
119
+
120
+ console.log(chalk.yellow(`⏳ The test results will be added to the HTML report. It will take some time...`));
121
+
122
+ if (msg) {
123
+ console.log(chalk.blue(msg));
91
124
  }
92
- /**
93
- * Generates an HTML report based on provided test data and a template.
94
- * @param {object} opts - Test options used to generate the HTML report:
95
- * runParams, tests, outputPath, templatePath
96
- * @returns {void} - This function does not return anything.
97
- */
98
- buildReport(opts) {
99
- const { runParams, tests, outputPath, templatePath, warningMsg: msg } = opts;
100
- debug('HTML tests data:', tests);
101
- if (!outputPath) {
102
- console.log(picocolors_1.default.yellow(`🚨 HTML export path is not set, ignoring...`));
103
- return;
104
- }
105
- console.log(picocolors_1.default.yellow(`⏳ The test results will be added to the HTML report. It will take some time...`));
106
- if (msg) {
107
- console.log(picocolors_1.default.blue(msg));
108
- }
109
- tests.forEach(test => {
110
- // steps could be an array or a string
111
- test.steps = Array.isArray(test.steps)
112
- ? (test.steps = test.steps
113
- .map(step => (0, utils_js_1.formatStep)(step))
114
- .flat()
115
- .join('\n'))
116
- : test.steps;
117
- if (!test.message?.trim()) {
118
- test.message = "This test has no 'message' code";
119
- }
120
- if (!test.suite_title?.trim()) {
121
- test.suite_title = 'Unknown suite';
122
- }
123
- if (!test.title?.trim()) {
124
- test.title = 'Unknown test title';
125
- }
126
- if (!test.files?.length) {
127
- test.files = 'This test has no files';
128
- }
129
- if (!test.steps?.trim()) {
130
- test.steps = "This test has no 'steps' code";
131
- }
132
- else {
133
- test.steps = removeAnsiColorCodes(test.steps);
134
- }
135
- // TODO: future-proof: currently there is no need to display Artifacts and Metadata in HTML
136
- test.artifacts = test.artifacts || [];
137
- test.meta = test.meta || {};
138
- // TODO: u can added an additional test values to this checks in the future
139
- });
140
- const data = {
141
- runId: this.store.runId || '',
142
- status: runParams.status || 'No status info',
143
- parallel: runParams.isParallel || 'No parallel info',
144
- runUrl: this.store.runUrl || '',
145
- executionTime: testExecutionSumTime(tests),
146
- executionDate: getCurrentDateTimeFormatted(),
147
- tests,
148
- };
149
- // generate output HTML based on the template
150
- const html = this.#generateHTMLReport(data, templatePath);
151
- if (!html)
152
- return;
153
- fs_1.default.writeFileSync(outputPath, html, 'utf-8');
154
- // Check if the file exists
155
- if (fs_1.default.existsSync(outputPath)) {
156
- // Get the absolute path of the file
157
- const absolutePath = path_1.default.resolve(outputPath);
158
- // Convert the file path to a file URL
159
- const fileUrlPath = (0, file_url_1.default)(absolutePath, { resolve: true });
160
- debug('HTML tests data:', fileUrlPath);
161
- console.log(picocolors_1.default.green(`📊 The HTML report was successfully generated. Full filepath: ${fileUrlPath}`));
162
- }
163
- else {
164
- console.log(picocolors_1.default.red(`🚨 Failed to generate the HTML report.`));
165
- }
125
+
126
+ tests.forEach(test => {
127
+ // steps could be an array or a string
128
+ test.steps = Array.isArray(test.steps)
129
+ ? (test.steps = test.steps
130
+ .map(step => formatStep(step))
131
+ .flat()
132
+ .join('\n'))
133
+ : test.steps;
134
+
135
+ if (!test.message?.trim()) {
136
+ test.message = "This test has no 'message' code";
137
+ }
138
+
139
+ if (!test.suite_title?.trim()) {
140
+ test.suite_title = 'Unknown suite';
141
+ }
142
+
143
+ if (!test.title?.trim()) {
144
+ test.title = 'Unknown test title';
145
+ }
146
+
147
+ if (!test.files?.length) {
148
+ test.files = 'This test has no files';
149
+ }
150
+
151
+ if (!test.steps?.trim()) {
152
+ test.steps = "This test has no 'steps' code";
153
+ } else {
154
+ test.steps = removeAnsiColorCodes(test.steps);
155
+ }
156
+
157
+ // TODO: future-proof: currently there is no need to display Artifacts and Metadata in HTML
158
+ test.artifacts = test.artifacts || [];
159
+ test.meta = test.meta || {};
160
+ // TODO: u can added an additional test values to this checks in the future
161
+ });
162
+
163
+ const data = {
164
+ runId: this.store.runId || '',
165
+ status: runParams.status || 'No status info',
166
+ parallel: runParams.isParallel || 'No parallel info',
167
+ runUrl: this.store.runUrl || '',
168
+ executionTime: testExecutionSumTime(tests),
169
+ executionDate: getCurrentDateTimeFormatted(),
170
+ tests,
171
+ };
172
+ // generate output HTML based on the template
173
+ const html = this.#generateHTMLReport(data, templatePath);
174
+
175
+ if (!html) return;
176
+
177
+ fs.writeFileSync(outputPath, html, 'utf-8');
178
+ // Check if the file exists
179
+ if (fs.existsSync(outputPath)) {
180
+ // Get the absolute path of the file
181
+ const absolutePath = path.resolve(outputPath);
182
+ // Convert the file path to a file URL
183
+ const fileUrlPath = fileUrl(absolutePath, { resolve: true });
184
+
185
+ debug('HTML tests data:', fileUrlPath);
186
+
187
+ console.log(chalk.green(`📊 The HTML report was successfully generated. Full filepath: ${fileUrlPath}`));
188
+ } else {
189
+ console.log(chalk.red(`🚨 Failed to generate the HTML report.`));
166
190
  }
167
- /**
168
- * Generates an HTML report based on provided test data and a template path.
169
- * @param {any} data - Test data used to generate the HTML report.
170
- * @param {string} [templatePath=""] - The path to the HTML template used for generating the report.
171
- * @returns {string | void} - The generated HTML report as a string or void if templatePath is not provided.
172
- */
173
- #generateHTMLReport(data, templatePath = '') {
174
- if (!templatePath) {
175
- console.log(picocolors_1.default.red(`🚨 HTML template not found. Report generation is impossible!`));
176
- return;
177
- }
178
- const templateSource = fs_1.default.readFileSync(templatePath, 'utf8');
179
- this.#loadReportHelpers();
180
- try {
181
- const template = handlebars_1.default.compile(templateSource);
182
- return template(data);
183
- }
184
- catch (e) {
185
- console.log(picocolors_1.default.red('❌ Oops! An unknown error occurred when generating an HTML report'));
186
- console.log(picocolors_1.default.red(e));
187
- }
191
+ }
192
+
193
+ /**
194
+ * Generates an HTML report based on provided test data and a template path.
195
+ * @param {any} data - Test data used to generate the HTML report.
196
+ * @param {string} [templatePath=""] - The path to the HTML template used for generating the report.
197
+ * @returns {string | void} - The generated HTML report as a string or void if templatePath is not provided.
198
+ */
199
+ #generateHTMLReport(data, templatePath = '') {
200
+ if (!templatePath) {
201
+ console.log(chalk.red(`🚨 HTML template not found. Report generation is impossible!`));
202
+ return;
203
+ }
204
+
205
+ const templateSource = fs.readFileSync(templatePath, 'utf8');
206
+ this.#loadReportHelpers();
207
+ try {
208
+ const template = handlebars.compile(templateSource);
209
+
210
+ return template(data);
211
+ } catch (e) {
212
+ console.log(chalk.red('❌ Oops! An unknown error occurred when generating an HTML report'));
213
+ console.log(chalk.red(e));
188
214
  }
189
- #loadReportHelpers() {
190
- handlebars_1.default.registerHelper('getTestsByStatus', (tests, status) => tests.filter(test => test.status.toLowerCase() === status.toLowerCase()).length);
191
- handlebars_1.default.registerHelper('selectComponent', () => new handlebars_1.default.SafeString(`<select style="width: 70px;height: 38px;" class="form-select" aria-label="Tests counter on page">
215
+ }
216
+
217
+ #loadReportHelpers() {
218
+ handlebars.registerHelper(
219
+ 'getTestsByStatus',
220
+ (tests, status) => tests.filter(test => test.status.toLowerCase() === status.toLowerCase()).length,
221
+ );
222
+
223
+ handlebars.registerHelper(
224
+ 'selectComponent',
225
+ () =>
226
+ new handlebars.SafeString(
227
+ `<select style="width: 70px;height: 38px;" class="form-select" aria-label="Tests counter on page">
192
228
  <option value="0">10</option>
193
229
  <option value="1">25</option>
194
230
  <option value="2">50</option>
195
- </select>`));
196
- handlebars_1.default.registerHelper('emptyDataComponent', () => {
197
- const svgFilePath = path_1.default.join(__dirname, '..', 'template', 'emptyData.svg');
198
- const svgContent = fs_1.default.readFileSync(svgFilePath, 'utf8');
199
- return new handlebars_1.default.SafeString(`
231
+ </select>`,
232
+ ),
233
+ );
234
+ /* eslint-disable */
235
+ handlebars.registerHelper('emptyDataComponent', () => {
236
+ const svgFilePath = path.join(__dirname, '..', 'template', 'emptyData.svg');
237
+ const svgContent = fs.readFileSync(svgFilePath, 'utf8');
238
+
239
+ return new handlebars.SafeString(
240
+ `
200
241
  <div class="noData">
201
242
  <div class="noDataSvg">
202
243
  ${svgContent}
@@ -204,53 +245,67 @@ class HtmlPipe {
204
245
  <div class="noDataText">
205
246
  NO MATCHING TESTS
206
247
  </div>
207
- <div>`);
208
- });
209
- handlebars_1.default.registerHelper('pageDispleyElements', tests => {
210
- // We wrapp the lines to the HTML format we need
211
- const totalTests = JSON.parse(JSON.stringify(tests)
212
- .replace(/<script>/g, '&lt;script&gt;')
213
- .replace(/<\/script>/g, '&lt;/script&gt;'));
214
- const paginationOptions = {
215
- 0: 10,
216
- 1: 25,
217
- 2: 50,
218
- };
219
- const statuses = ['all', 'passed', 'failed', 'skipped'];
220
- const pageItemGroups = {
221
- all: {},
222
- passed: {},
223
- failed: {},
224
- skipped: {},
225
- totalTests,
226
- };
227
- function paginateItems(items, pageSize) {
228
- const paginatedItems = [];
229
- for (let i = 0; i < items.length; i += pageSize) {
230
- paginatedItems.push(items.slice(i, i + pageSize));
231
- }
232
- return paginatedItems;
248
+ <div>`,
249
+ );
250
+ });
251
+ /* eslint-enable */
252
+ handlebars.registerHelper('pageDispleyElements', tests => {
253
+ // We wrapp the lines to the HTML format we need
254
+ const totalTests = JSON.parse(
255
+ JSON.stringify(tests)
256
+ .replace(/<script>/g, '&lt;script&gt;')
257
+ .replace(/<\/script>/g, '&lt;/script&gt;'), // eslint-disable-line
258
+ );
259
+
260
+ const paginationOptions = {
261
+ 0: 10,
262
+ 1: 25,
263
+ 2: 50,
264
+ };
265
+ const statuses = ['all', 'passed', 'failed', 'skipped'];
266
+ const pageItemGroups = {
267
+ all: {},
268
+ passed: {},
269
+ failed: {},
270
+ skipped: {},
271
+ totalTests,
272
+ };
273
+
274
+ function paginateItems(items, pageSize) {
275
+ const paginatedItems = [];
276
+ for (let i = 0; i < items.length; i += pageSize) {
277
+ paginatedItems.push(items.slice(i, i + pageSize));
278
+ }
279
+ return paginatedItems;
280
+ }
281
+
282
+ statuses.forEach(status => {
283
+ for (const option in paginationOptions) {
284
+ // eslint-disable-next-line no-prototype-builtins
285
+ if (paginationOptions.hasOwnProperty(option)) {
286
+ const pageSize = paginationOptions[option];
287
+ let filteredItems = totalTests;
288
+
289
+ if (status !== 'all') {
290
+ filteredItems = totalTests.filter(item => item.status === status);
233
291
  }
234
- statuses.forEach(status => {
235
- for (const option in paginationOptions) {
236
- if (paginationOptions.hasOwnProperty(option)) {
237
- const pageSize = paginationOptions[option];
238
- let filteredItems = totalTests;
239
- if (status !== 'all') {
240
- filteredItems = totalTests.filter(item => item.status === status);
241
- }
242
- pageItemGroups[status][option] = paginateItems(filteredItems, pageSize);
243
- }
244
- }
245
- });
246
- pageItemGroups.totalTests = totalTests;
247
- return JSON.stringify(pageItemGroups);
248
- });
249
- }
250
- toString() {
251
- return 'HTML Reporter';
252
- }
292
+
293
+ pageItemGroups[status][option] = paginateItems(filteredItems, pageSize);
294
+ }
295
+ }
296
+ });
297
+
298
+ pageItemGroups.totalTests = totalTests;
299
+
300
+ return JSON.stringify(pageItemGroups);
301
+ });
302
+ }
303
+
304
+ toString() {
305
+ return 'HTML Reporter';
306
+ }
253
307
  }
308
+
254
309
  /**
255
310
  * Calculates the total execution time for an array of tests.
256
311
  * @param {Object[]} tests - An array of test objects.
@@ -258,50 +313,58 @@ class HtmlPipe {
258
313
  * @returns {string} - The total execution time in a formatted duration string.
259
314
  */
260
315
  function testExecutionSumTime(tests) {
261
- const totalMilliseconds = tests.reduce((sum, test) => {
262
- if (typeof test.run_time === 'number' && !Number.isNaN(test.run_time)) {
263
- return sum + test.run_time;
264
- }
265
- return sum;
266
- }, 0);
267
- return formatDuration(totalMilliseconds);
316
+ const totalMilliseconds = tests.reduce((sum, test) => {
317
+ if (typeof test.run_time === 'number' && !Number.isNaN(test.run_time)) {
318
+ return sum + test.run_time;
319
+ }
320
+ return sum;
321
+ }, 0);
322
+
323
+ return formatDuration(totalMilliseconds);
268
324
  }
325
+
269
326
  /**
270
327
  * Removes ANSI color codes and converts newline characters to HTML line breaks in a given string.
271
328
  * @param {string} str - The input string containing ANSI color codes.
272
329
  * @returns {string} - The updated string with removed ANSI color codes and replaced newline characters.
273
330
  */
274
331
  function removeAnsiColorCodes(str) {
275
- let updatedStr = str.replace((0, utils_js_1.ansiRegExp)(), '');
276
- updatedStr = updatedStr.replace(/\n/g, '<br>');
277
- return updatedStr;
332
+ let updatedStr = str.replace(ansiRegExp(), '');
333
+ updatedStr = updatedStr.replace(/\n/g, '<br>');
334
+
335
+ return updatedStr;
278
336
  }
337
+
279
338
  /**
280
339
  * Formats duration in milliseconds into a human-readable string representation.
281
340
  * @param {number} duration - The duration in milliseconds.
282
341
  * @returns {string} - The formatted duration string (e.g., "2h 30m 15s 500ms").
283
342
  */
284
343
  function formatDuration(duration) {
285
- const milliseconds = duration % 1000;
286
- duration = (duration - milliseconds) / 1000;
287
- const seconds = duration % 60;
288
- duration = (duration - seconds) / 60;
289
- const minutes = duration % 60;
290
- const hours = (duration - minutes) / 60;
291
- return `${hours}h ${minutes}m ${seconds}s ${milliseconds}ms`;
344
+ const milliseconds = duration % 1000;
345
+ duration = (duration - milliseconds) / 1000;
346
+ const seconds = duration % 60;
347
+ duration = (duration - seconds) / 60;
348
+ const minutes = duration % 60;
349
+ const hours = (duration - minutes) / 60;
350
+
351
+ return `${hours}h ${minutes}m ${seconds}s ${milliseconds}ms`;
292
352
  }
353
+
293
354
  /**
294
355
  * Retrieves the current date and time in a formatted string.
295
356
  * @returns {string} - The formatted date and time string (e.g., "(01/01/2023 12:00:00)").
296
357
  */
297
358
  function getCurrentDateTimeFormatted() {
298
- const currentDate = new Date();
299
- const day = currentDate.getDate().toString().padStart(2, '0');
300
- const month = (currentDate.getMonth() + 1).toString().padStart(2, '0');
301
- const year = currentDate.getFullYear();
302
- const hours = currentDate.getHours().toString().padStart(2, '0');
303
- const minutes = currentDate.getMinutes().toString().padStart(2, '0');
304
- const seconds = currentDate.getSeconds().toString().padStart(2, '0');
305
- return `(${day}/${month}/${year} ${hours}:${minutes}:${seconds})`;
359
+ const currentDate = new Date();
360
+ const day = currentDate.getDate().toString().padStart(2, '0');
361
+ const month = (currentDate.getMonth() + 1).toString().padStart(2, '0');
362
+ const year = currentDate.getFullYear();
363
+ const hours = currentDate.getHours().toString().padStart(2, '0');
364
+ const minutes = currentDate.getMinutes().toString().padStart(2, '0');
365
+ const seconds = currentDate.getSeconds().toString().padStart(2, '0');
366
+
367
+ return `(${day}/${month}/${year} ${hours}:${minutes}:${seconds})`;
306
368
  }
369
+
307
370
  module.exports = HtmlPipe;