@testomatio/reporter 1.2.0-beta-1 → 1.2.0-beta-3

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/lib/pipe/html.js CHANGED
@@ -4,8 +4,9 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const chalk = require('chalk');
6
6
  const handlebars = require('handlebars');
7
+ const fileUrl = require('file-url');
7
8
 
8
- const { fileSystem, isSameTest } = require('../utils/utils');
9
+ const { fileSystem, isSameTest, ansiRegExp } = require('../utils/utils');
9
10
  const { HTML_REPORT } = require('../constants');
10
11
 
11
12
  class HtmlPipe {
@@ -23,6 +24,7 @@ class HtmlPipe {
23
24
 
24
25
  this.isEnabled = false;
25
26
  this.htmlOutputPath = "";
27
+ this.fullHtmlOutputPath = "";
26
28
  this.tests = [];
27
29
  this.data = {};
28
30
 
@@ -35,9 +37,6 @@ class HtmlPipe {
35
37
  }
36
38
 
37
39
  if (process.env.TESTOMATIO_HTML_FILENAME && !process.env.TESTOMATIO_HTML_FILENAME.endsWith(".html")) {
38
- console.log(
39
- chalk.blue(`The name must include the extension ".html". The default report name is used!`)
40
- );
41
40
  this.htmlReportName = HTML_REPORT.REPORT_DEFAULT_NAME;
42
41
  }
43
42
 
@@ -74,6 +73,8 @@ class HtmlPipe {
74
73
  addTest(test) {
75
74
  if (!this.isEnabled) return;
76
75
 
76
+ if (!test.steps || !test.status) return;
77
+
77
78
  const index = this.tests.findIndex(t => isSameTest(t, test));
78
79
  // update if they were already added
79
80
  if (index >= 0) {
@@ -88,6 +89,37 @@ class HtmlPipe {
88
89
  if (!this.isEnabled) return;
89
90
 
90
91
  if (this.isHtml) {
92
+
93
+ this.tests.forEach(test => {
94
+
95
+ if (!test.message || test.message.trim() === "") {
96
+ test.message = "This test has no 'message' code";
97
+ }
98
+
99
+ if (!test.suite_title || test.suite_title.trim() === "") {
100
+ test.suite_title = "Unknown suite";
101
+ }
102
+
103
+ if (!test.title || test.title.trim() === "") {
104
+ test.title = "Unknown test title";
105
+ }
106
+
107
+ if (!test.files || test.files.length === 0) {
108
+ test.files = "This test has no files";
109
+ }
110
+
111
+ if (test.steps) {
112
+ if (!test.steps || test.steps.trim() === "") {
113
+ test.steps = "This test has no 'steps' code";
114
+ }
115
+ else {
116
+ test.steps = this.#removeAnsiColorCodes(test.steps);
117
+ }
118
+ }
119
+
120
+ // TODO: u can added an additional test values to this checks in the future
121
+ });
122
+
91
123
  this.data = {
92
124
  runId: this.store.runId,
93
125
  status: runParams.status,
@@ -107,20 +139,41 @@ class HtmlPipe {
107
139
  debug('HTML tests data:', data);
108
140
 
109
141
  if (!this.htmlOutputPath && this.htmlOutputPath !== "") {
110
- console.log(chalk.yellow(`HTML export path is not set, ignoring...`));
142
+ console.log(chalk.yellow(`🚨 HTML export path is not set, ignoring...`));
111
143
  return;
112
144
  }
113
145
 
114
- console.log(chalk.yellow(`The test results will be added to the HTML report. It will take some time...`));
146
+ console.log(chalk.yellow(`⏳ The test results will be added to the HTML report. It will take some time...`));
115
147
  // generate output HTML based on the template
116
148
  const html = this.#generateHTMLReport(data);
117
149
 
150
+ if (process.env.TESTOMATIO_HTML_FILENAME && !process.env.TESTOMATIO_HTML_FILENAME.endsWith(".html")) {
151
+ console.log(
152
+ chalk.blue("HTML filename must include the extension \".html\"." +
153
+ ` The default report name "${this.htmlOutputPath}" is used!`)
154
+ );
155
+ }
156
+
118
157
  fs.writeFileSync(this.htmlOutputPath, html, 'utf-8');
158
+
159
+ // Check if the file exists
160
+ if (fs.existsSync(this.htmlOutputPath)) {
161
+ // Get the absolute path of the file
162
+ const absolutePath = path.resolve(this.htmlOutputPath);
163
+ // Convert the file path to a file URL
164
+ const fileUrlPath = fileUrl(absolutePath, {resolve: true});
165
+
166
+ debug('HTML tests data:', fileUrlPath);
167
+
168
+ console.log(chalk.green(`📊 The HTML report was successfully generated. Full filepath: ${fileUrlPath}`));
169
+ } else {
170
+ console.log(chalk.red(`🚨 Failed to generate the HTML report.`));
171
+ }
119
172
  }
120
173
 
121
174
  #generateHTMLReport(data) {
122
175
  if (!this.templateHtmlPath) {
123
- console.log(chalk.red(`HTML template not found. Report generation is impossible!`))
176
+ console.log(chalk.red(`🚨 HTML template not found. Report generation is impossible!`))
124
177
  return;
125
178
  }
126
179
 
@@ -129,7 +182,6 @@ class HtmlPipe {
129
182
  try {
130
183
  const template = handlebars.compile(templateSource);
131
184
 
132
- console.log(chalk.green(`Generated HTML report saved in file: ${this.htmlOutputPath}`));
133
185
  return template(data);
134
186
  }
135
187
  catch (e) {
@@ -142,7 +194,49 @@ class HtmlPipe {
142
194
  tests.filter(test => test.status.toLowerCase() === status.toLowerCase()).length
143
195
  );
144
196
 
145
- handlebars.registerHelper('json', (obj) => JSON.stringify(obj));
197
+ handlebars.registerHelper('json', (tests) => {
198
+ function replaceScriptTagsInArray(array) {
199
+ return array.map(obj => {
200
+ const keysToCheck = ["steps", "stack", "title", "suite_title", "message", "code"];
201
+ const newObj = {};
202
+
203
+ for (const key in obj) {
204
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
205
+ if (key === "example") {
206
+ newObj[key] = {};
207
+ for (const subKey in obj[key]) {
208
+ if (Object.prototype.hasOwnProperty.call(obj[key], subKey)) {
209
+ newObj[key][subKey] = typeof obj[key][subKey] === "string"
210
+ ? obj[key][subKey]
211
+ .replace(/<script>/g, "<$cript>")
212
+ .replace(/<\/script>/g, "</$cript>")
213
+ : obj[key][subKey];
214
+ }
215
+ }
216
+ } else if (keysToCheck.includes(key)) {
217
+ newObj[key] = typeof obj[key] === "string"
218
+ ? obj[key].replace(/<script>/g, "<$cript>").replace(/<\/script>/g, "</$cript>")
219
+ : obj[key];
220
+ } else {
221
+ newObj[key] = obj[key];
222
+ }
223
+ }
224
+ }
225
+
226
+ return newObj;
227
+ });
228
+ }
229
+
230
+ // Remove ANSI escape codes
231
+ return JSON.stringify(replaceScriptTagsInArray(tests));
232
+ });
233
+ }
234
+
235
+ #removeAnsiColorCodes(str) {
236
+ let updatedStr = str.replace(ansiRegExp(), "");
237
+ updatedStr = updatedStr.replace(/\n/g, '<br>');
238
+
239
+ return updatedStr;
146
240
  }
147
241
 
148
242
  toString() {
@@ -245,6 +245,29 @@
245
245
  font-size: 14px;
246
246
  white-space: pre-line;
247
247
  }
248
+ /* Passed TAB*/
249
+ #passedTest:not(:checked) + .btn-outline-dark {
250
+ background-color: #39BD2F;
251
+ }
252
+ #passedTest:checked + .btn-outline-dark {
253
+ background-color: #68cf61;
254
+ color: white;
255
+ }
256
+ /* Failed TAB*/
257
+ #failedTest:not(:checked) + .btn-outline-dark {
258
+ background-color: #F2230C;
259
+ }
260
+ #failedTest:checked + .btn-outline-dark {
261
+ background-color: #FA6E5E;
262
+ color: white;
263
+ }
264
+ /* Skipped TAB*/
265
+ #skippedTest:not(:checked) + .btn-outline-dark {
266
+ background-color: #F2C00C;
267
+ }
268
+ #skippedTest:checked + .btn-outline-dark {
269
+ background-color: #dfc155;
270
+ }
248
271
  </style>
249
272
  </head>
250
273
 
@@ -471,8 +494,8 @@
471
494
  }
472
495
 
473
496
  // processing and adding test data to the template
474
- function addOneTest(category,testInfo = {}){
475
- const { suite, title, steps, message, files } = testInfo;
497
+ function addOneTest(category,testData = {}){
498
+ const { suite_title, title, steps, message, files } = testData;
476
499
  // radio btn test's count
477
500
  function incrementCount(element) {
478
501
  let count = parseInt(element.textContent);
@@ -562,7 +585,7 @@
562
585
 
563
586
  const testitem__name = clone.querySelector('.testitem__name');
564
587
 
565
- const fullTestName = suite ? suite + " - " + title : title;
588
+ const fullTestName = suite_title ? suite_title + " - " + title : title;
566
589
  testitem__name.textContent = fullTestName;
567
590
 
568
591
  const body = clone.querySelector('.testitem__body');
@@ -579,11 +602,16 @@
579
602
 
580
603
  let content_files = content.querySelector('div[type="files"]').querySelector('span');
581
604
 
582
- if (files && files.length > 0) {
605
+ if (files.includes("This test has no files")) {
606
+ content_files.innerHTML = files;
607
+ }
608
+
609
+ if (!files.includes("This test has no files")) {
583
610
  const filesList = document.createElement('ul');
584
611
  content_files.innerHTML = "";
585
612
 
586
- files.forEach((file) => {
613
+ if (Array.isArray(files) && files.length > 0) {
614
+ files.forEach((file) => {
587
615
  const listItem = document.createElement('li');
588
616
  const fileLink = document.createElement('a');
589
617
  fileLink.href = file.path;
@@ -594,10 +622,9 @@
594
622
  filesList.appendChild(listItem);
595
623
  });
596
624
 
597
- content_files.appendChild(filesList);
598
- }
599
- else {
600
- content_files.innerHTML = "Files are not found for this test";
625
+ content_files.appendChild(filesList);
626
+
627
+ }
601
628
  }
602
629
 
603
630
  const testitem__top = clone.querySelector('.testitem__top');
@@ -680,40 +707,11 @@
680
707
  search();
681
708
 
682
709
  const executedTests = {{{ json tests }}};
683
-
684
- // TODO: move to HTML pipe
685
- function removeAnsiColorCodes(text) {
686
- text = text.replace(/\u001b\[[0-9;]*m/g, '');
687
- text = text.replace(/\n/g, '<br>');
688
-
689
- return text;
690
- }
691
710
 
692
711
  for (let i = 0; i < executedTests.length; i++) {
693
712
  const status = executedTests[i].status;
694
- const testInfo = {
695
- suite: executedTests[i].suite_title,
696
- title: executedTests[i].title,
697
- steps: removeAnsiColorCodes(executedTests[i].steps),
698
- message: executedTests[i].message,
699
- files: executedTests[i].files,
700
- status: status,
701
- }
702
-
703
- if (!testInfo.steps && testInfo.steps.trim() === "") {
704
- testInfo.steps = "Step code is not found for this test";
705
- }
706
-
707
- if (!testInfo.message && testInfo.message.trim() === "") {
708
- testInfo.message = "Message code is not found for this test";
709
- }
710
-
711
- if (!testInfo.suite && testInfo.suite.trim() === "") {
712
- testInfo.suite = "Unknown suite";
713
- }
714
713
 
715
- // call the addOneTest() function for each test
716
- addOneTest(status, testInfo);
714
+ addOneTest(status, executedTests[i]);
717
715
  }
718
716
  </script>
719
717
  </body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "1.2.0-beta-1",
3
+ "version": "1.2.0-beta-3",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "main": "./lib/reporter.js",
6
6
  "typings": "typings/index.d.ts",
@@ -20,6 +20,7 @@
20
20
  "debug": "^4.3.4",
21
21
  "dotenv": "^16.0.1",
22
22
  "fast-xml-parser": "^4.0.8",
23
+ "file-url": "3.0.0",
23
24
  "glob": "^10.3",
24
25
  "handlebars": "^4.7.8",
25
26
  "has-flag": "^5.0.1",