@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 +103 -9
- package/lib/template/testomatio.hbs +37 -39
- package/package.json +2 -1
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(
|
|
142
|
+
console.log(chalk.yellow(`🚨 HTML export path is not set, ignoring...`));
|
|
111
143
|
return;
|
|
112
144
|
}
|
|
113
145
|
|
|
114
|
-
console.log(chalk.yellow(
|
|
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(
|
|
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', (
|
|
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,
|
|
475
|
-
const {
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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",
|