odhin-reports-playwright 1.0.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.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +35 -0
  3. package/lib/generate.d.ts +56 -0
  4. package/lib/generate.js +969 -0
  5. package/lib/help.d.ts +46 -0
  6. package/lib/help.js +503 -0
  7. package/lib/html/assets/css/bootstrap.min.css +1 -0
  8. package/lib/html/assets/css/dark-theme.css +55 -0
  9. package/lib/html/assets/css/dark-theme.min.css +1 -0
  10. package/lib/html/assets/css/img-comparison-slider.css +50 -0
  11. package/lib/html/assets/css/img-comparison-slider.min.css +1 -0
  12. package/lib/html/assets/css/jquery.dataTables.min.css +1 -0
  13. package/lib/html/assets/css/light-theme.css +53 -0
  14. package/lib/html/assets/css/light-theme.min.css +1 -0
  15. package/lib/html/assets/css/prism.css +163 -0
  16. package/lib/html/assets/css/prism.min.css +1 -0
  17. package/lib/html/assets/css/style-colors.css +349 -0
  18. package/lib/html/assets/css/style-colors.min.css +1 -0
  19. package/lib/html/assets/css/style.css +586 -0
  20. package/lib/html/assets/css/style.min.css +1 -0
  21. package/lib/html/assets/js/bootstrap.min.js +1 -0
  22. package/lib/html/assets/js/chart.min.js +1 -0
  23. package/lib/html/assets/js/customTheme.js +40 -0
  24. package/lib/html/assets/js/customTheme.min.js +1 -0
  25. package/lib/html/assets/js/darkTheme.js +34 -0
  26. package/lib/html/assets/js/darkTheme.min.js +1 -0
  27. package/lib/html/assets/js/dataTables.js +4 -0
  28. package/lib/html/assets/js/dataTables.min.js +1 -0
  29. package/lib/html/assets/js/img-comparison-slider.min.js +2 -0
  30. package/lib/html/assets/js/jquery-3.5.1.min.js +1 -0
  31. package/lib/html/assets/js/jquery.dataTables.min.js +1 -0
  32. package/lib/html/assets/js/lightTheme.js +34 -0
  33. package/lib/html/assets/js/lightTheme.min.js +1 -0
  34. package/lib/html/assets/js/prism.min.js +1 -0
  35. package/lib/html/assets/js/script.js +61 -0
  36. package/lib/html/assets/js/script.min.js +1 -0
  37. package/lib/html/base.html +182 -0
  38. package/lib/html/chart.html +21 -0
  39. package/lib/html/chartFile.html +33 -0
  40. package/lib/html/chartInfo.html +5 -0
  41. package/lib/html/chartJs.html +133 -0
  42. package/lib/html/chartProject.html +33 -0
  43. package/lib/html/chartStatus.html +87 -0
  44. package/lib/html/content.html +30 -0
  45. package/lib/html/runInfo.html +47 -0
  46. package/lib/html/summary.html +20 -0
  47. package/lib/html/summaryRow.html +10 -0
  48. package/lib/html/testCase.html +12 -0
  49. package/lib/html/testCaseDetails.html +125 -0
  50. package/lib/index.d.ts +12 -0
  51. package/lib/index.js +48 -0
  52. package/lib/server.mjs +8 -0
  53. package/lib/types/execFileInfo.types.d.ts +13 -0
  54. package/lib/types/execFileInfo.types.js +2 -0
  55. package/lib/types/execInfo.types.d.ts +15 -0
  56. package/lib/types/execInfo.types.js +2 -0
  57. package/lib/types/execOptions.types.d.ts +17 -0
  58. package/lib/types/execOptions.types.js +2 -0
  59. package/lib/types/execProjectInfo.types.d.ts +13 -0
  60. package/lib/types/execProjectInfo.types.js +2 -0
  61. package/lib/types/execTestCase.types.d.ts +14 -0
  62. package/lib/types/execTestCase.types.js +2 -0
  63. package/lib/types/execTestResult.types.d.ts +43 -0
  64. package/lib/types/execTestResult.types.js +2 -0
  65. package/lib/types/onEnd.types.d.ts +12 -0
  66. package/lib/types/onEnd.types.js +2 -0
  67. package/lib/types/onProject.types.d.ts +53 -0
  68. package/lib/types/onProject.types.js +2 -0
  69. package/lib/types/onStdIO.types.d.ts +11 -0
  70. package/lib/types/onStdIO.types.js +2 -0
  71. package/lib/types/onStepBegin.types.d.ts +22 -0
  72. package/lib/types/onStepBegin.types.js +2 -0
  73. package/lib/types/onStepEnd.types.d.ts +25 -0
  74. package/lib/types/onStepEnd.types.js +2 -0
  75. package/lib/types/onTestBegin.types.d.ts +15 -0
  76. package/lib/types/onTestBegin.types.js +2 -0
  77. package/lib/types/onTestEnd.types.d.ts +37 -0
  78. package/lib/types/onTestEnd.types.js +2 -0
  79. package/lib/types/testReport.types.d.ts +6 -0
  80. package/lib/types/testReport.types.js +2 -0
  81. package/package.json +67 -0
@@ -0,0 +1,969 @@
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 fs_1 = __importDefault(require("fs"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const help_1 = __importDefault(require("./help"));
9
+ const picocolors_1 = require("picocolors");
10
+ const lodash_1 = require("lodash");
11
+ const child_process_1 = require("child_process");
12
+ const node_util_1 = __importDefault(require("node:util"));
13
+ const process_1 = require("process");
14
+ class Generate {
15
+ constructor(execOptions) {
16
+ // Const Variables
17
+ this.OUTPUT_FOLDER = "odhin-reports";
18
+ this.TITLE = "Odhin Reports";
19
+ this.TEST_FOLDER = "tests";
20
+ this.THEME = "light";
21
+ this.INDEX_FILE = "index.html";
22
+ this.execOptions = execOptions;
23
+ this.totalDuration = 0;
24
+ this.help = new help_1.default(this.execOptions);
25
+ this.testCases = [];
26
+ this.execInfo = {
27
+ projectName: "",
28
+ totalPassed: 0,
29
+ totalFailed: 0,
30
+ totalTimedOut: 0,
31
+ totalSkipped: 0,
32
+ totalInterrupted: 0,
33
+ totalTests: 0,
34
+ startTime: "",
35
+ endTime: "",
36
+ execFiles: [],
37
+ execProjects: [],
38
+ };
39
+ this.execOptions.testFolder =
40
+ this.execOptions.testFolder !== undefined
41
+ ? this.execOptions.testFolder
42
+ : this.TEST_FOLDER;
43
+ this.execOptions.title =
44
+ this.execOptions.title !== undefined
45
+ ? this.execOptions.title
46
+ : this.TITLE;
47
+ this.execOptions.testEnvironment =
48
+ this.execOptions.testEnvironment !== undefined
49
+ ? this.execOptions.testEnvironment
50
+ : "";
51
+ this.execOptions.project =
52
+ this.execOptions.project !== undefined ? this.execOptions.project : "";
53
+ this.execOptions.release =
54
+ this.execOptions.release !== undefined ? this.execOptions.release : "";
55
+ this.execOptions.embedAssets =
56
+ this.execOptions.embedAssets !== undefined
57
+ ? this.execOptions.embedAssets
58
+ : true;
59
+ this.execOptions.embedAttachments =
60
+ this.execOptions.embedAttachments !== undefined
61
+ ? this.execOptions.embedAttachments
62
+ : true;
63
+ this.execOptions.outputFolder =
64
+ this.execOptions.outputFolder !== undefined
65
+ ? this.execOptions.outputFolder
66
+ : this.OUTPUT_FOLDER;
67
+ this.execOptions.startServer =
68
+ this.execOptions.startServer !== undefined
69
+ ? this.execOptions.startServer
70
+ : true;
71
+ this.execOptions.consoleLog =
72
+ this.execOptions.consoleLog !== undefined
73
+ ? this.execOptions.consoleLog
74
+ : true;
75
+ this.execOptions.consoleError =
76
+ this.execOptions.consoleError !== undefined
77
+ ? this.execOptions.consoleError
78
+ : true;
79
+ this.execOptions.consoleTestOutput =
80
+ this.execOptions.consoleTestOutput !== undefined
81
+ ? this.execOptions.consoleTestOutput
82
+ : false;
83
+ this.execOptions.simpleConsoleLog =
84
+ this.execOptions.simpleConsoleLog !== undefined
85
+ ? this.execOptions.simpleConsoleLog
86
+ : false;
87
+ this.execOptions.initialTheme =
88
+ this.execOptions.initialTheme !== undefined
89
+ ? this.execOptions.initialTheme
90
+ : this.THEME;
91
+ this.execOptions.indexFilename =
92
+ this.execOptions.indexFilename !== undefined
93
+ ? this.execOptions.indexFilename
94
+ .replaceAll(".html", "")
95
+ .replaceAll(".htm", "")
96
+ .replaceAll(".", "_")
97
+ .replaceAll(" ", "_") + ".html"
98
+ : this.INDEX_FILE;
99
+ this.help.showError = this.execOptions.consoleError;
100
+ // Remove output folder if exists
101
+ fs_1.default.rmSync(this.execOptions.outputFolder, { recursive: true, force: true });
102
+ try {
103
+ // Load HTML Files
104
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/base.html"), "utf-8", (err, data) => {
105
+ if (err)
106
+ throw err;
107
+ this.base = data;
108
+ });
109
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/runInfo.html"), "utf-8", (err, data) => {
110
+ if (err)
111
+ throw err;
112
+ this.runInfo = data;
113
+ });
114
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/chart.html"), "utf-8", (err, data) => {
115
+ if (err)
116
+ throw err;
117
+ this.chart = data;
118
+ });
119
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/chartInfo.html"), "utf-8", (err, data) => {
120
+ if (err)
121
+ throw err;
122
+ this.chartInfo = data;
123
+ });
124
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/chartStatus.html"), "utf-8", (err, data) => {
125
+ if (err)
126
+ throw err;
127
+ this.chartStatus = data;
128
+ });
129
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/chartFile.html"), "utf-8", (err, data) => {
130
+ if (err)
131
+ throw err;
132
+ this.chartFile = data;
133
+ });
134
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/chartProject.html"), "utf-8", (err, data) => {
135
+ if (err)
136
+ throw err;
137
+ this.chartProject = data;
138
+ });
139
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/chartJs.html"), "utf-8", (err, data) => {
140
+ if (err)
141
+ throw err;
142
+ this.chartJs = data;
143
+ });
144
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/content.html"), "utf-8", (err, data) => {
145
+ if (err)
146
+ throw err;
147
+ this.content = data;
148
+ });
149
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/summary.html"), "utf-8", (err, data) => {
150
+ if (err)
151
+ throw err;
152
+ this.summary = data;
153
+ });
154
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/summaryRow.html"), "utf-8", (err, data) => {
155
+ if (err)
156
+ throw err;
157
+ this.summaryRow = data;
158
+ });
159
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/testCase.html"), "utf-8", (err, data) => {
160
+ if (err)
161
+ throw err;
162
+ this.testCaseTemplate = data;
163
+ });
164
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/testCaseDetails.html"), "utf-8", (err, data) => {
165
+ if (err)
166
+ throw err;
167
+ this.testCaseDetailsTemplate = data;
168
+ });
169
+ // Load Theme Files
170
+ if (fs_1.default.existsSync(this.execOptions.initialTheme)) {
171
+ fs_1.default.readFile(this.execOptions.initialTheme, "utf-8", (err, data) => {
172
+ if (err)
173
+ throw err;
174
+ this.cssThemeCustom = data;
175
+ });
176
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/customTheme.min.js"), "utf-8", (err, data) => {
177
+ if (err)
178
+ throw err;
179
+ this.themeJs = data;
180
+ });
181
+ }
182
+ else {
183
+ this.cssThemeCustom = "";
184
+ switch (this.execOptions.initialTheme) {
185
+ case "light":
186
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/lightTheme.min.js"), "utf-8", (err, data) => {
187
+ if (err)
188
+ throw err;
189
+ this.themeJs = data;
190
+ });
191
+ break;
192
+ case "dark":
193
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/darkTheme.min.js"), "utf-8", (err, data) => {
194
+ if (err)
195
+ throw err;
196
+ this.themeJs = data;
197
+ });
198
+ break;
199
+ default:
200
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/lightTheme.min.js"), "utf-8", (err, data) => {
201
+ if (err)
202
+ throw err;
203
+ this.themeJs = data;
204
+ });
205
+ break;
206
+ }
207
+ }
208
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/css/light-theme.min.css"), "utf-8", (err, data) => {
209
+ if (err)
210
+ throw err;
211
+ this.cssThemeLight = data;
212
+ });
213
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/css/dark-theme.min.css"), "utf-8", (err, data) => {
214
+ if (err)
215
+ throw err;
216
+ this.cssThemeDark = data;
217
+ });
218
+ // Load CSS Files
219
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/css/style-colors.min.css"), "utf-8", (err, data) => {
220
+ if (err)
221
+ throw err;
222
+ this.cssColors = data;
223
+ });
224
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/css/style.min.css"), "utf-8", (err, data) => {
225
+ if (err)
226
+ throw err;
227
+ this.css = data;
228
+ });
229
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/css/jquery.dataTables.min.css"), "utf-8", (err, data) => {
230
+ if (err)
231
+ throw err;
232
+ this.jqueryDataTablesCss = data;
233
+ });
234
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/css/bootstrap.min.css"), "utf-8", (err, data) => {
235
+ if (err)
236
+ throw err;
237
+ this.bootstrapCss = data;
238
+ });
239
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/css/prism.min.css"), "utf-8", (err, data) => {
240
+ if (err)
241
+ throw err;
242
+ this.prismCss = data;
243
+ });
244
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/css/img-comparison-slider.min.css"), "utf-8", (err, data) => {
245
+ if (err)
246
+ throw err;
247
+ this.imgComparisonSliderCss = data;
248
+ });
249
+ // Load JS Files
250
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/jquery-3.5.1.min.js"), "utf-8", (err, data) => {
251
+ if (err)
252
+ throw err;
253
+ this.jQuery = data;
254
+ });
255
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/script.min.js"), "utf-8", (err, data) => {
256
+ if (err)
257
+ throw err;
258
+ this.js = data;
259
+ });
260
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/chart.min.js"), "utf-8", (err, data) => {
261
+ if (err)
262
+ throw err;
263
+ this.chartJsLibrary = data;
264
+ });
265
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/jquery.dataTables.min.js"), "utf-8", (err, data) => {
266
+ if (err)
267
+ throw err;
268
+ this.jqueryDataTablesJs = data;
269
+ });
270
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/dataTables.min.js"), "utf-8", (err, data) => {
271
+ if (err)
272
+ throw err;
273
+ this.dataTables = data;
274
+ });
275
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/bootstrap.min.js"), "utf-8", (err, data) => {
276
+ if (err)
277
+ throw err;
278
+ this.bootstrapJs = data;
279
+ });
280
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/prism.min.js"), "utf-8", (err, data) => {
281
+ if (err)
282
+ throw err;
283
+ this.prismJs = data;
284
+ });
285
+ fs_1.default.readFile(path_1.default.resolve(__dirname, "html/assets/js/img-comparison-slider.min.js"), "utf-8", (err, data) => {
286
+ if (err)
287
+ throw err;
288
+ this.imgComparisonSliderJs = data;
289
+ });
290
+ }
291
+ catch (error) {
292
+ if (this.execOptions.consoleError === true) {
293
+ console.error(error);
294
+ }
295
+ }
296
+ if (this.execOptions.consoleLog === true) {
297
+ if (this.execOptions.simpleConsoleLog === true) {
298
+ console.log(`-------------------------------------`);
299
+ console.log(` `);
300
+ }
301
+ else {
302
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.blue)(`-------------------------------------`))}`);
303
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.blue)(` `))}`);
304
+ }
305
+ }
306
+ }
307
+ async onBegin(config, suite) {
308
+ this.execInfo.startTime = new Date().toUTCString();
309
+ config.projects.forEach((p, index) => {
310
+ this.execInfo.projectName += index > 0 ? ", " : "";
311
+ this.execInfo.projectName +=
312
+ p.name.charAt(0).toUpperCase() + p.name.slice(1);
313
+ });
314
+ if (suite.allTests().length >= 1) {
315
+ if (this.execOptions.consoleLog === true) {
316
+ let text = `Starting the run with ${suite.allTests().length} test`;
317
+ if (suite.allTests().length > 1) {
318
+ text += "s";
319
+ }
320
+ if (this.execOptions.simpleConsoleLog === true) {
321
+ console.log(`⏺ ` + text);
322
+ console.log(` `);
323
+ }
324
+ else {
325
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.yellow)(`⏺ `))}${(0, picocolors_1.bold)((0, picocolors_1.blue)(text))}`);
326
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.blue)(` `))}`);
327
+ }
328
+ }
329
+ }
330
+ else {
331
+ if (this.execOptions.consoleLog === true) {
332
+ if (this.execOptions.simpleConsoleLog === true) {
333
+ console.log(`❌ No tests found`);
334
+ console.log(` `);
335
+ console.log(`-------------------------------------`);
336
+ }
337
+ else {
338
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.red)(`❌ No tests found`))}`);
339
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.blue)(` `))}`);
340
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.blue)(`-------------------------------------`))}`);
341
+ }
342
+ }
343
+ (0, process_1.exit)(1);
344
+ }
345
+ }
346
+ async onTestEnd(testCase, result) {
347
+ this.execInfo.endTime = new Date().toUTCString();
348
+ this.testCases.push({
349
+ testCase: testCase,
350
+ result: result,
351
+ });
352
+ this.totalDuration = this.totalDuration + result.duration;
353
+ let project = "";
354
+ let tst = testCase;
355
+ if (tst.projectId !== undefined) {
356
+ project = tst.projectId;
357
+ project = project.charAt(0).toUpperCase() + project.slice(1) + " | ";
358
+ }
359
+ if (result.status === "passed" || result.retry === testCase.retries) {
360
+ // Update Files
361
+ let fileUpdate = false;
362
+ this.execInfo.execFiles.forEach((f, index) => {
363
+ if (f.filename ===
364
+ this.help.getShortFilePath(testCase.filename, this.execOptions.testFolder)) {
365
+ this.execInfo.execFiles[index].totalTests++;
366
+ this.execInfo.execFiles[index].totalDuration =
367
+ this.execInfo.execFiles[index].totalDuration + result.duration;
368
+ (this.execInfo.execFiles[index].totalPassed =
369
+ result.status == "passed"
370
+ ? this.execInfo.execFiles[index].totalPassed + 1
371
+ : this.execInfo.execFiles[index].totalPassed),
372
+ (this.execInfo.execFiles[index].totalFailed =
373
+ result.status == "failed"
374
+ ? this.execInfo.execFiles[index].totalFailed + 1
375
+ : this.execInfo.execFiles[index].totalFailed),
376
+ (this.execInfo.execFiles[index].totalTimedOut =
377
+ result.status == "timedOut"
378
+ ? this.execInfo.execFiles[index].totalTimedOut + 1
379
+ : this.execInfo.execFiles[index].totalTimedOut),
380
+ (this.execInfo.execFiles[index].totalSkipped =
381
+ result.status == "skipped"
382
+ ? this.execInfo.execFiles[index].totalSkipped + 1
383
+ : this.execInfo.execFiles[index].totalSkipped),
384
+ (this.execInfo.execFiles[index].totalInterrupted =
385
+ result.status == "interrupted"
386
+ ? this.execInfo.execFiles[index].totalInterrupted + 1
387
+ : this.execInfo.execFiles[index].totalInterrupted),
388
+ (this.execInfo.execFiles[index].endTime = new Date().toUTCString());
389
+ fileUpdate = true;
390
+ }
391
+ });
392
+ if (!fileUpdate) {
393
+ this.execInfo.execFiles.push({
394
+ filename: this.help.getShortFilePath(testCase.filename, this.execOptions.testFolder),
395
+ color: this.help.getRandomColor(),
396
+ totalPassed: result.status == "passed" ? 1 : 0,
397
+ totalFailed: result.status == "failed" ? 1 : 0,
398
+ totalTimedOut: result.status == "timedOut" ? 1 : 0,
399
+ totalSkipped: result.status == "skipped" ? 1 : 0,
400
+ totalInterrupted: result.status == "interrupted" ? 1 : 0,
401
+ totalTests: 1,
402
+ totalDuration: result.duration,
403
+ startTime: new Date(new Date().getTime() - result.duration).toUTCString(),
404
+ endTime: new Date().toUTCString(),
405
+ });
406
+ }
407
+ // Update Projects
408
+ let projectUpdate = false;
409
+ this.execInfo.execProjects.forEach((b, index) => {
410
+ if (b.project === testCase.projectId) {
411
+ this.execInfo.execProjects[index].totalTests++;
412
+ this.execInfo.execProjects[index].totalDuration =
413
+ this.execInfo.execProjects[index].totalDuration + result.duration;
414
+ (this.execInfo.execProjects[index].totalPassed =
415
+ result.status == "passed"
416
+ ? this.execInfo.execProjects[index].totalPassed + 1
417
+ : this.execInfo.execProjects[index].totalPassed),
418
+ (this.execInfo.execProjects[index].totalFailed =
419
+ result.status == "failed"
420
+ ? this.execInfo.execProjects[index].totalFailed + 1
421
+ : this.execInfo.execProjects[index].totalFailed),
422
+ (this.execInfo.execProjects[index].totalTimedOut =
423
+ result.status == "timedOut"
424
+ ? this.execInfo.execProjects[index].totalTimedOut + 1
425
+ : this.execInfo.execProjects[index].totalTimedOut),
426
+ (this.execInfo.execProjects[index].totalSkipped =
427
+ result.status == "skipped"
428
+ ? this.execInfo.execProjects[index].totalSkipped + 1
429
+ : this.execInfo.execProjects[index].totalSkipped),
430
+ (this.execInfo.execProjects[index].totalInterrupted =
431
+ result.status == "interrupted"
432
+ ? this.execInfo.execProjects[index].totalInterrupted + 1
433
+ : this.execInfo.execProjects[index].totalInterrupted),
434
+ (this.execInfo.execProjects[index].endTime =
435
+ new Date().toUTCString());
436
+ projectUpdate = true;
437
+ }
438
+ });
439
+ if (!projectUpdate && testCase.projectInfo) {
440
+ this.execInfo.execProjects.push({
441
+ project: testCase.projectId,
442
+ color: this.help.getRandomColor(),
443
+ totalPassed: result.status == "passed" ? 1 : 0,
444
+ totalFailed: result.status == "failed" ? 1 : 0,
445
+ totalTimedOut: result.status == "timedOut" ? 1 : 0,
446
+ totalSkipped: result.status == "skipped" ? 1 : 0,
447
+ totalInterrupted: result.status == "interrupted" ? 1 : 0,
448
+ totalTests: 1,
449
+ totalDuration: result.duration,
450
+ startTime: new Date(new Date().getTime() - result.duration).toUTCString(),
451
+ endTime: new Date().toUTCString(),
452
+ });
453
+ }
454
+ switch (result.status) {
455
+ case "passed":
456
+ this.execInfo.totalPassed++;
457
+ if (this.execOptions.consoleLog === true) {
458
+ if (this.execOptions.simpleConsoleLog === true) {
459
+ console.log(`✅ ${project}${testCase.title}`);
460
+ }
461
+ else {
462
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.green)(`✅ ${project}${testCase.title}`))}`);
463
+ }
464
+ }
465
+ break;
466
+ case "failed":
467
+ this.execInfo.totalFailed++;
468
+ if (this.execOptions.consoleLog === true) {
469
+ if (this.execOptions.simpleConsoleLog === true) {
470
+ console.log(`⛔ ${project}${testCase.title}`);
471
+ }
472
+ else {
473
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.red)(`⛔ ${project}${testCase.title}`))}`);
474
+ }
475
+ }
476
+ break;
477
+ case "timedOut":
478
+ this.execInfo.totalTimedOut++;
479
+ if (this.execOptions.consoleLog === true) {
480
+ if (this.execOptions.simpleConsoleLog === true) {
481
+ console.log(`⛔ ${project}${testCase.title}`);
482
+ }
483
+ else {
484
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.magenta)(`⛔ ${project}${testCase.title}`))}`);
485
+ }
486
+ }
487
+ break;
488
+ case "skipped":
489
+ this.execInfo.totalSkipped++;
490
+ if (this.execOptions.consoleLog === true) {
491
+ if (this.execOptions.simpleConsoleLog === true) {
492
+ console.log(`🚫 ${project}${testCase.title}`);
493
+ }
494
+ else {
495
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.yellow)(`🚫 ${project}${testCase.title}`))}`);
496
+ }
497
+ }
498
+ break;
499
+ case "interrupted":
500
+ this.execInfo.totalInterrupted++;
501
+ if (this.execOptions.consoleLog === true) {
502
+ if (this.execOptions.simpleConsoleLog === true) {
503
+ console.log(`🚫 ${project}${testCase.title}`);
504
+ }
505
+ else {
506
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.gray)(`🚫 ${project}${testCase.title}`))}`);
507
+ }
508
+ }
509
+ break;
510
+ }
511
+ this.execInfo.totalTests++;
512
+ }
513
+ }
514
+ async onEnd() {
515
+ // Edit Chart Status
516
+ this.chartStatus = this.chartStatus.replace("{{.ChartId}}", "chart-status");
517
+ this.chartStatus = this.chartStatus.replace("{{.TotalTests}}", this.execInfo.totalTests.toString());
518
+ this.chartStatus = this.chartStatus.replaceAll("{{.TestPassedValue}}", this.execInfo.totalPassed.toString());
519
+ this.chartStatus = this.chartStatus.replaceAll("{{.TestFailedValue}}", this.execInfo.totalFailed.toString());
520
+ this.chartStatus = this.chartStatus.replaceAll("{{.TestTimedOutValue}}", this.execInfo.totalTimedOut.toString());
521
+ this.chartStatus = this.chartStatus.replaceAll("{{.TestSkippedValue}}", this.execInfo.totalSkipped.toString());
522
+ this.chartStatus = this.chartStatus.replaceAll("{{.TestInterruptedValue}}", this.execInfo.totalInterrupted.toString());
523
+ this.chartStatus = this.chartStatus.replaceAll("{{.TestPassedPercentage}}", (0, lodash_1.round)((this.execInfo.totalPassed / this.execInfo.totalTests) * 100, 2).toString());
524
+ this.chartStatus = this.chartStatus.replaceAll("{{.TestFailedPercentage}}", (0, lodash_1.round)((this.execInfo.totalFailed / this.execInfo.totalTests) * 100, 2).toString());
525
+ this.chartStatus = this.chartStatus.replaceAll("{{.TestTimedOutPercentage}}", (0, lodash_1.round)((this.execInfo.totalTimedOut / this.execInfo.totalTests) * 100, 2).toString());
526
+ this.chartStatus = this.chartStatus.replaceAll("{{.TestSkippedPercentage}}", (0, lodash_1.round)((this.execInfo.totalSkipped / this.execInfo.totalTests) * 100, 2).toString());
527
+ this.chartStatus = this.chartStatus.replaceAll("{{.TestInterruptedPercentage}}", (0, lodash_1.round)((this.execInfo.totalInterrupted / this.execInfo.totalTests) * 100, 2).toString());
528
+ this.chartJs = this.chartJs.replaceAll("{{.PassedStatusChart}}", this.execInfo.totalPassed.toString());
529
+ this.chartJs = this.chartJs.replaceAll("{{.FailedStatusChart}}", this.execInfo.totalFailed.toString());
530
+ this.chartJs = this.chartJs.replaceAll("{{.TimedOutStatusChart}}", this.execInfo.totalTimedOut.toString());
531
+ this.chartJs = this.chartJs.replaceAll("{{.SkippedStatusChart}}", this.execInfo.totalSkipped.toString());
532
+ this.chartJs = this.chartJs.replaceAll("{{.InterruptedStatusChart}}", this.execInfo.totalInterrupted.toString());
533
+ // Edit Chart File
534
+ let chartFileDetail = this.chart;
535
+ let chartJsFileLabels = "";
536
+ let chartJsFileData = "";
537
+ let chartJsFileDataColor = "";
538
+ let chartFileRows = "";
539
+ chartFileDetail = chartFileDetail.replace("{{.ChartId}}", "chart-file");
540
+ chartFileDetail = chartFileDetail.replace("{{.TotalTests}}", this.execInfo.totalTests.toString());
541
+ chartFileDetail = chartFileDetail.replace("{{.RowSpan}}", this.execInfo.execFiles.length.toString());
542
+ this.execInfo.execFiles.forEach((file, index) => {
543
+ let chartRow = this.chartInfo;
544
+ if (index == 0) {
545
+ chartRow = chartRow.replace("{{.Label}}", file.filename);
546
+ chartRow = chartRow.replace("{{.Value}}", file.totalTests.toString());
547
+ chartRow = chartRow.replace("{{.Percentage}}", (0, lodash_1.round)((file.totalTests / this.execInfo.totalTests) * 100, 2).toString());
548
+ chartJsFileLabels +=
549
+ "'" + file.filename + " (" + file.totalTests.toString() + ")" + "'";
550
+ chartJsFileData += file.totalTests.toString();
551
+ chartJsFileDataColor += "'" + file.color + "'";
552
+ }
553
+ else {
554
+ chartRow = chartRow.replace("{{.Label}}", file.filename);
555
+ chartRow = chartRow.replace("{{.Value}}", file.totalTests.toString());
556
+ chartRow = chartRow.replace("{{.Percentage}}", (0, lodash_1.round)((file.totalTests / this.execInfo.totalTests) * 100, 2).toString());
557
+ chartJsFileLabels +=
558
+ ",'" + file.filename + " (" + file.totalTests.toString() + ")" + "'";
559
+ chartJsFileData += "," + file.totalTests.toString();
560
+ chartJsFileDataColor += ",'" + file.color + "'";
561
+ }
562
+ chartRow = chartRow.replaceAll("{{.Color}}", file.color);
563
+ chartFileRows += chartRow;
564
+ });
565
+ this.chartFile = this.chartFile.replace("{{.Chart}}", chartFileDetail);
566
+ this.chartFile = this.chartFile.replaceAll("{{.ChartFile}}", chartFileRows);
567
+ this.chartJs = this.chartJs.replaceAll("{{.FilesChartLabels}}", chartJsFileLabels);
568
+ this.chartJs = this.chartJs.replaceAll("{{.FilesChartData}}", chartJsFileData);
569
+ this.chartJs = this.chartJs.replaceAll("{{.FilesChartDataColor}}", chartJsFileDataColor);
570
+ // Edit Chart Project
571
+ let chartProjectDetail = this.chart;
572
+ let chartJsProjectLabels = "";
573
+ let chartJsProjectData = "";
574
+ let chartJsProjectDataColor = "";
575
+ let chartProjectRows = "";
576
+ chartProjectDetail = chartProjectDetail.replace("{{.ChartId}}", "chart-project");
577
+ chartProjectDetail = chartProjectDetail.replace("{{.TotalTests}}", this.execInfo.totalTests.toString());
578
+ chartProjectDetail = chartProjectDetail.replace("{{.RowSpan}}", this.execInfo.execFiles.length.toString());
579
+ this.execInfo.execProjects.forEach((project, index) => {
580
+ let chartRow = this.chartInfo;
581
+ if (index == 0) {
582
+ chartRow = chartRow.replace("{{.Label}}", project.project);
583
+ chartRow = chartRow.replace("{{.Value}}", project.totalTests.toString());
584
+ chartRow = chartRow.replace("{{.Percentage}}", (0, lodash_1.round)((project.totalTests / this.execInfo.totalTests) * 100, 2).toString());
585
+ chartJsProjectLabels +=
586
+ "'" +
587
+ project.project +
588
+ " (" +
589
+ project.totalTests.toString() +
590
+ ")" +
591
+ "'";
592
+ chartJsProjectData += project.totalTests.toString();
593
+ chartJsProjectDataColor += "'" + project.color + "'";
594
+ }
595
+ else {
596
+ chartRow = chartRow.replace("{{.Label}}", project.project);
597
+ chartRow = chartRow.replace("{{.Value}}", project.totalTests.toString());
598
+ chartRow = chartRow.replace("{{.Percentage}}", (0, lodash_1.round)((project.totalTests / this.execInfo.totalTests) * 100, 2).toString());
599
+ chartJsProjectLabels +=
600
+ ",'" +
601
+ project.project +
602
+ " (" +
603
+ project.totalTests.toString() +
604
+ ")" +
605
+ "'";
606
+ chartJsProjectData += "," + project.totalTests.toString();
607
+ chartJsProjectDataColor += ",'" + project.color + "'";
608
+ }
609
+ chartRow = chartRow.replaceAll("{{.Color}}", project.color);
610
+ chartProjectRows += chartRow;
611
+ });
612
+ this.chartProject = this.chartProject.replace("{{.Chart}}", chartProjectDetail);
613
+ this.chartProject = this.chartProject.replaceAll("{{.ChartProject}}", chartProjectRows);
614
+ this.chartJs = this.chartJs.replaceAll("{{.ProjectsChartLabels}}", chartJsProjectLabels);
615
+ this.chartJs = this.chartJs.replaceAll("{{.ProjectsChartData}}", chartJsProjectData);
616
+ this.chartJs = this.chartJs.replaceAll("{{.ProjectsChartDataColor}}", chartJsProjectDataColor);
617
+ // Edit Summary Files
618
+ let summaryFiles = this.summary;
619
+ summaryFiles = summaryFiles.replace("{{.SummaryTitleName}}", "Status by test file");
620
+ summaryFiles = summaryFiles.replace("{{.SummaryColumnName}}", "Filename");
621
+ let filesSummaryRows = "";
622
+ this.execInfo.execFiles.forEach((file) => {
623
+ let filesSummaryRow = this.summaryRow;
624
+ filesSummaryRow = filesSummaryRow.replace("{{.Name}}", file.filename);
625
+ filesSummaryRow = filesSummaryRow.replace("{{.TotalTests}}", file.totalTests.toString());
626
+ filesSummaryRow = filesSummaryRow.replace("{{.TotalExecutionTime}}", this.help.convertMsToTime(new Date(file.endTime).getTime() - new Date(file.startTime).getTime()));
627
+ filesSummaryRow = filesSummaryRow.replace("{{.PassedValue}}", file.totalPassed.toString());
628
+ filesSummaryRow = filesSummaryRow.replace("{{.PassedPercentage}}", (0, lodash_1.round)((file.totalPassed / file.totalTests) * 100, 2).toString());
629
+ filesSummaryRow = filesSummaryRow.replace("{{.FailedValue}}", file.totalFailed.toString());
630
+ filesSummaryRow = filesSummaryRow.replace("{{.FailedPercentage}}", (0, lodash_1.round)((file.totalFailed / file.totalTests) * 100, 2).toString());
631
+ filesSummaryRow = filesSummaryRow.replace("{{.TimedOutValue}}", file.totalTimedOut.toString());
632
+ filesSummaryRow = filesSummaryRow.replace("{{.TimedOutPercentage}}", (0, lodash_1.round)((file.totalTimedOut / file.totalTests) * 100, 2).toString());
633
+ filesSummaryRow = filesSummaryRow.replace("{{.SkippedValue}}", file.totalSkipped.toString());
634
+ filesSummaryRow = filesSummaryRow.replace("{{.SkippedPercentage}}", (0, lodash_1.round)((file.totalSkipped / file.totalTests) * 100, 2).toString());
635
+ filesSummaryRow = filesSummaryRow.replace("{{.InterruptedValue}}", file.totalInterrupted.toString());
636
+ filesSummaryRow = filesSummaryRow.replace("{{.InterruptedPercentage}}", (0, lodash_1.round)((file.totalInterrupted / file.totalTests) * 100, 2).toString());
637
+ filesSummaryRows += filesSummaryRow;
638
+ });
639
+ summaryFiles = summaryFiles.replace("{{.Data}}", filesSummaryRows);
640
+ // Edit Summary Projects
641
+ let summaryProjects = this.summary;
642
+ summaryProjects = summaryProjects.replace("{{.SummaryTitleName}}", "Status by project");
643
+ summaryProjects = summaryProjects.replace("{{.SummaryColumnName}}", "Project");
644
+ let projectsSummaryRows = "";
645
+ this.execInfo.execProjects.forEach((project) => {
646
+ let projectSummaryRow = this.summaryRow;
647
+ projectSummaryRow = projectSummaryRow.replace("{{.Name}}", project.project);
648
+ projectSummaryRow = projectSummaryRow.replace("{{.TotalTests}}", project.totalTests.toString());
649
+ projectSummaryRow = projectSummaryRow.replace("{{.TotalExecutionTime}}", this.help.convertMsToTime(new Date(project.endTime).getTime() -
650
+ new Date(project.startTime).getTime()));
651
+ projectSummaryRow = projectSummaryRow.replace("{{.PassedValue}}", project.totalPassed.toString());
652
+ projectSummaryRow = projectSummaryRow.replace("{{.PassedPercentage}}", (0, lodash_1.round)((project.totalPassed / project.totalTests) * 100, 2).toString());
653
+ projectSummaryRow = projectSummaryRow.replace("{{.FailedValue}}", project.totalFailed.toString());
654
+ projectSummaryRow = projectSummaryRow.replace("{{.FailedPercentage}}", (0, lodash_1.round)((project.totalFailed / project.totalTests) * 100, 2).toString());
655
+ projectSummaryRow = projectSummaryRow.replace("{{.TimedOutValue}}", project.totalTimedOut.toString());
656
+ projectSummaryRow = projectSummaryRow.replace("{{.TimedOutPercentage}}", (0, lodash_1.round)((project.totalTimedOut / project.totalTests) * 100, 2).toString());
657
+ projectSummaryRow = projectSummaryRow.replace("{{.SkippedValue}}", project.totalSkipped.toString());
658
+ projectSummaryRow = projectSummaryRow.replace("{{.SkippedPercentage}}", (0, lodash_1.round)((project.totalSkipped / project.totalTests) * 100, 2).toString());
659
+ projectSummaryRow = projectSummaryRow.replace("{{.InterruptedValue}}", project.totalInterrupted.toString());
660
+ projectSummaryRow = projectSummaryRow.replace("{{.InterruptedPercentage}}", (0, lodash_1.round)((project.totalInterrupted / project.totalTests) * 100, 2).toString());
661
+ projectsSummaryRows += projectSummaryRow;
662
+ });
663
+ summaryProjects = summaryProjects.replace("{{.Data}}", projectsSummaryRows);
664
+ // Edit RunInfo
665
+ this.runInfo = this.runInfo.replaceAll("{{.Project}}", this.execOptions.project);
666
+ this.runInfo = this.runInfo.replaceAll("{{.Release}}", this.execOptions.release);
667
+ this.runInfo = this.runInfo.replaceAll("{{.TestEnvironment}}", this.execOptions.testEnvironment);
668
+ this.runInfo = this.runInfo.replaceAll("{{.StartTime}}", this.execInfo.startTime);
669
+ this.runInfo = this.runInfo.replaceAll("{{.EndTime}}", this.execInfo.endTime);
670
+ this.runInfo = this.runInfo.replaceAll("{{.TotalExecutionTime}}", this.help.convertMsToTime(new Date(this.execInfo.endTime).getTime() -
671
+ new Date(this.execInfo.startTime).getTime()));
672
+ // Prepara test data
673
+ let testCases = "";
674
+ let testCasesDetails = "";
675
+ let showRetries = false;
676
+ for (const tc of this.testCases) {
677
+ if (tc.testCase.retries > 0) {
678
+ showRetries = true;
679
+ break;
680
+ }
681
+ }
682
+ this.testCases.forEach((testCase) => {
683
+ let testCaseId = testCase.testCase.id + "-" + testCase.result.retry;
684
+ let testCaseHtml = this.testCaseTemplate;
685
+ testCaseHtml = testCaseHtml.replaceAll("{{.ModalID}}", testCaseId);
686
+ if (showRetries === true) {
687
+ testCaseHtml = testCaseHtml.replaceAll("{{.Retry}}", '<td class="{{.TDClassesCss}}">' +
688
+ (testCase.result.retry > 0
689
+ ? testCase.result.retry.toString()
690
+ : "") +
691
+ "</td>");
692
+ }
693
+ else {
694
+ testCaseHtml = testCaseHtml.replaceAll("{{.Retry}}", "");
695
+ }
696
+ testCaseHtml = testCaseHtml.replaceAll("{{.TRClassesCss}}", "result-status-" + testCase.result.status);
697
+ testCaseHtml = testCaseHtml.replaceAll("{{.TDClassesCss}}", "result-status-" + testCase.result.status);
698
+ testCaseHtml = testCaseHtml.replaceAll("{{.Title}}", testCase.testCase.title);
699
+ testCaseHtml = testCaseHtml.replaceAll("{{.Status}}", testCase.result.status);
700
+ testCaseHtml = testCaseHtml.replaceAll("{{.File}}", this.help.getShortFilePath(testCase.testCase.filename, this.execOptions.testFolder));
701
+ testCaseHtml = testCaseHtml.replaceAll("{{.Project}}", testCase.testCase.projectId);
702
+ testCaseHtml = testCaseHtml.replaceAll("{{.Duration}}", this.help.convertMsToTime(testCase.result.duration));
703
+ testCases += testCaseHtml;
704
+ let testCaseDetailsHtml = this.testCaseDetailsTemplate;
705
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.ModalID}}", testCaseId);
706
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.ModalHeaderClassesCss}}", "label-status-" + testCase.result.status);
707
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.ModalHeaderStatus}}", testCase.result.status);
708
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.Title}}", testCase.testCase.title);
709
+ // Add run info
710
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.InfoFilename}}", this.help.getShortFilePath(testCase.testCase.filename, this.execOptions.testFolder));
711
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.InfoProject}}", testCase.testCase.projectId);
712
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.InfoStartTime}}", testCase.result.startTime.toUTCString());
713
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.InfoTotalExecutionTime}}", this.help.convertMsToTime(testCase.result.duration));
714
+ if (showRetries === true) {
715
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.InfoRetry}}", '<tr><th class="odhin-text-2">Retry</th><td class="text-secondary-emphasis fst-italic">' +
716
+ testCase.result.retry.toString() +
717
+ "</td></tr>");
718
+ }
719
+ else {
720
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.InfoRetry}}", "");
721
+ }
722
+ if (testCase.testCase.tags.length > 0) {
723
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.InfoTags}}", '<tr><th class="odhin-text-2">Tags</th><td class="text-secondary-emphasis fst-italic">' +
724
+ testCase.testCase.tags.toString() +
725
+ "</td></tr>");
726
+ }
727
+ else {
728
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.InfoTags}}", "");
729
+ }
730
+ if (testCase.testCase.annotations.length > 0) {
731
+ let annotations = '<tr><th class="odhin-text-2 info-tr-space">Annotations</th><td class="text-secondary-emphasis fst-italic info-tr-space" ></td></tr>';
732
+ testCase.testCase.annotations.forEach((annotation) => {
733
+ annotations +=
734
+ '<tr><th class="odhin-text-2">' +
735
+ annotation.type +
736
+ '</th><td class="text-secondary-emphasis fst-italic">' +
737
+ (this.help.isValidURL(annotation.description) === true
738
+ ? '<a href="' +
739
+ annotation.description +
740
+ '">' +
741
+ annotation.description +
742
+ "</a>"
743
+ : annotation.description) +
744
+ "</td></tr>";
745
+ });
746
+ annotations += "<tr><th></th><td></td></tr>";
747
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.InfoAnnotations}}", annotations);
748
+ }
749
+ else {
750
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.InfoAnnotations}}", "<tr><th></th><td></td></tr>");
751
+ }
752
+ // Add errors
753
+ let errors = "";
754
+ let errorFile = "";
755
+ if (testCase.result.status === "failed" ||
756
+ testCase.result.status === "timedOut" ||
757
+ testCase.result.status === "interrupted") {
758
+ if (testCase.result.errors !== undefined) {
759
+ testCase.result.errors.forEach((err) => {
760
+ if (err.stack !== undefined && err.stack !== "") {
761
+ errors += err.stack + "\n\n";
762
+ let lastLine = err.stack.match(/(.+)([^\s])/g) || "";
763
+ errorFile = lastLine[lastLine.length - 1].split(" at ")[1];
764
+ }
765
+ else {
766
+ errors += err.message + "\n\n";
767
+ }
768
+ });
769
+ }
770
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.ErrorsTabButton}}", this.help.printErrorsTabButton(testCaseId));
771
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.Errors}}", this.help.printErrors(errors, errorFile !== undefined
772
+ ? errorFile.length > 1
773
+ ? this.help.printErrorCode(errorFile)
774
+ : ""
775
+ : "", testCaseId));
776
+ }
777
+ else {
778
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.ErrorsTabButton}}", "");
779
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.Errors}}", "");
780
+ }
781
+ // Add steps
782
+ let steps = "";
783
+ testCase.result.steps.forEach((step, index) => {
784
+ steps += this.help.printStep(testCaseId, index, step, 10);
785
+ });
786
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.Steps}}", `<div class="row m-0 p-0"><div class="col m-0 p-0">` +
787
+ steps +
788
+ `</div></div>`);
789
+ // Add Attachments
790
+ let screenshots = "";
791
+ let screenshotsComparison = "";
792
+ let screenshotExpected;
793
+ let screenshotActual;
794
+ let screenshotDiff;
795
+ let videos = "";
796
+ let trace = "";
797
+ testCase.result.attachments.forEach(async (attachment) => {
798
+ if (attachment.contentType.startsWith("image/")) {
799
+ if (attachment.name !== "screenshot") {
800
+ if (attachment.name.includes("-expected.")) {
801
+ screenshotExpected = attachment;
802
+ }
803
+ else if (attachment.name.includes("-actual.")) {
804
+ screenshotActual = attachment;
805
+ }
806
+ else if (attachment.name.includes("-diff.")) {
807
+ screenshotDiff = attachment;
808
+ }
809
+ else {
810
+ screenshots +=
811
+ attachment.path !== undefined
812
+ ? this.help.printScreenshot(testCaseId, attachment)
813
+ : attachment.body !== undefined
814
+ ? this.help.printImage(testCaseId, attachment)
815
+ : "";
816
+ }
817
+ }
818
+ else {
819
+ screenshots +=
820
+ attachment.path !== undefined
821
+ ? this.help.printScreenshot(testCaseId, attachment)
822
+ : attachment.body !== undefined
823
+ ? this.help.printImage(testCaseId, attachment)
824
+ : "";
825
+ }
826
+ }
827
+ else if (attachment.contentType.startsWith("video/")) {
828
+ videos +=
829
+ attachment.path !== undefined
830
+ ? this.help.printVideo(testCaseId, attachment)
831
+ : "";
832
+ }
833
+ else if (attachment.contentType.startsWith("application/") &&
834
+ attachment.name === "trace") {
835
+ trace =
836
+ attachment.path !== undefined
837
+ ? this.help.printTrace(testCaseId, attachment)
838
+ : "";
839
+ }
840
+ });
841
+ if (screenshotExpected !== undefined &&
842
+ screenshotActual !== undefined &&
843
+ screenshotDiff !== undefined) {
844
+ screenshotsComparison += this.help.printScreenshotComparison(testCaseId, screenshotExpected, screenshotActual, screenshotDiff);
845
+ }
846
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.ScreenshotsTabButton}}", screenshotsComparison !== "" || screenshots !== ""
847
+ ? this.help.printScreenshotsTabButton(testCaseId)
848
+ : "");
849
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.Screenshots}}", screenshotsComparison !== "" || screenshots !== ""
850
+ ? this.help.printScreenshots(screenshotsComparison + screenshots, testCaseId)
851
+ : "");
852
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.VideosTabButton}}", videos !== "" ? this.help.printVideosTabButton(testCaseId) : "");
853
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.Videos}}", videos !== "" ? this.help.printVideos(videos, testCaseId) : "");
854
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.TraceTabButton}}", trace !== "" ? this.help.printTraceTabButton(testCaseId) : "");
855
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.Trace}}", trace);
856
+ let stdout = testCase.result.stdout.toString();
857
+ //stdout = "";
858
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.StdoutTabButton}}", stdout !== "" ? this.help.printStdoutTabButton(testCaseId) : "");
859
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.Stdout}}", stdout !== "" ? this.help.printStdout(testCaseId, stdout) : "");
860
+ let stderr = testCase.result.stderr.toString();
861
+ //stderr = "";
862
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.StderrTabButton}}", stderr !== "" ? this.help.printStderrTabButton(testCaseId) : "");
863
+ testCaseDetailsHtml = testCaseDetailsHtml.replaceAll("{{.Stderr}}", stderr !== "" ? this.help.printStderr(testCaseId, stderr) : "");
864
+ testCasesDetails += testCaseDetailsHtml;
865
+ });
866
+ this.content = this.content.replace("{{.TestCases}}", testCases);
867
+ this.content = this.content.replaceAll("{{.TestCasesDetails}}", testCasesDetails);
868
+ if (showRetries === true) {
869
+ this.content = this.content.replaceAll("{{.RetryColumn}}", "<th>Retry</th>");
870
+ }
871
+ else {
872
+ this.content = this.content.replaceAll("{{.RetryColumn}}", "");
873
+ }
874
+ // Add Information to the base HTML file
875
+ this.base = this.help.updateHtml(this.base, "{{.BootstrapCss}}", this.bootstrapCss, "css", "bootstrap.css");
876
+ this.base = this.help.updateHtml(this.base, "{{.JQueryDataTablesCss}}", this.jqueryDataTablesCss, "css", "jquery-datatable.css");
877
+ this.base = this.help.updateHtml(this.base, "{{.PrismCss}}", this.prismCss, "css", "prism.css");
878
+ this.base = this.help.updateHtml(this.base, "{{.CssThemeDark}}", this.cssThemeDark, "css", "theme.css");
879
+ this.base = this.help.updateHtml(this.base, "{{.CssThemeLight}}", this.cssThemeLight, "css", "theme.css");
880
+ this.base = this.help.updateHtml(this.base, "{{.CssThemeCustom}}", this.cssThemeCustom, "css", "theme.css");
881
+ this.base = this.help.updateHtml(this.base, "{{.CssColors}}", this.cssColors, "css", "style-colors.css");
882
+ this.base = this.help.updateHtml(this.base, "{{.Css}}", this.css, "css", "style.css");
883
+ this.base = this.help.updateHtml(this.base, "{{.ImgComparisonSliderCss}}", this.imgComparisonSliderCss, "css", "img-comparison-slider.css");
884
+ this.base = this.help.updateHtml(this.base, "{{.ImgComparisonSliderJs}}", this.imgComparisonSliderJs, "js", "img-comparison-slider.js");
885
+ this.base = this.help.updateHtml(this.base, "{{.jQuery}}", this.jQuery, "js", "jquery.js");
886
+ this.base = this.help.updateHtml(this.base, "{{.JQueryDataTablesJs}}", this.jqueryDataTablesJs, "js", "jquery-datatable.js");
887
+ this.base = this.help.updateHtml(this.base, "{{.DataTables}}", this.dataTables, "js", "datatable.js");
888
+ this.base = this.help.updateHtml(this.base, "{{.ChartJsLibrary}}", this.chartJsLibrary, "js", "chartjs-library.js");
889
+ this.base = this.help.updateHtml(this.base, "{{.ChartJs}}", this.chartJs, "js", "chartjs.js");
890
+ this.base = this.help.updateHtml(this.base, "{{.Js}}", this.js, "js", "script.js");
891
+ this.base = this.help.updateHtml(this.base, "{{.ThemeJs}}", this.themeJs, "js", "theme.js");
892
+ this.base = this.help.updateHtml(this.base, "{{.BootstrapJs}}", this.bootstrapJs, "js", "bootstrap.js");
893
+ this.base = this.help.updateHtml(this.base, "{{.PrismJs}}", this.prismJs, "js", "prism.js");
894
+ this.base = this.base.replaceAll("{{.Title}}", this.execOptions.title);
895
+ this.base = this.base.replace("{{.RunInfo}}", this.runInfo);
896
+ this.base = this.base.replace("{{.ChartStatus}}", this.chartStatus);
897
+ this.base = this.base.replace("{{.ChartFile}}", this.chartFile);
898
+ this.base = this.base.replace("{{.ChartProject}}", this.chartProject);
899
+ this.base = this.base.replace("{{.SummaryFiles}}", summaryFiles);
900
+ this.base = this.base.replace("{{.SummaryProjects}}", summaryProjects);
901
+ this.base = this.base.replace("{{.Content}}", this.content);
902
+ this.base = this.base.replaceAll("{{.Version}}", process.env.npm_package_version || "");
903
+ // Create the final HTML report file
904
+ this.help.createFile(this.execOptions.outputFolder + "/" + this.execOptions.indexFilename, this.base);
905
+ if (this.execOptions.consoleLog === true) {
906
+ if (this.execOptions.simpleConsoleLog === true) {
907
+ console.log(` `);
908
+ console.log(`-------------------------------------`);
909
+ }
910
+ else {
911
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.blue)(` `))}`);
912
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.blue)(`-------------------------------------`))}`);
913
+ }
914
+ }
915
+ if (this.execOptions.startServer === true) {
916
+ let port = await this.help.getPortFree();
917
+ const execPromise = node_util_1.default.promisify(child_process_1.exec);
918
+ try {
919
+ if (this.execOptions.consoleLog === true) {
920
+ let text = `Serving HTML report at http://localhost:${port}. Press Ctrl+C to quit.`;
921
+ if (this.execOptions.simpleConsoleLog === true) {
922
+ console.log(` `);
923
+ console.log(text);
924
+ console.log(` `);
925
+ }
926
+ else {
927
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.blue)(` `))}`);
928
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.blue)(text))}`);
929
+ console.log(`${(0, picocolors_1.bold)((0, picocolors_1.blue)(` `))}`);
930
+ }
931
+ }
932
+ const cmd = "node " +
933
+ path_1.default.resolve(__dirname, "") +
934
+ "/server.mjs " +
935
+ port +
936
+ " " +
937
+ this.execOptions.outputFolder +
938
+ " " +
939
+ this.execOptions.indexFilename;
940
+ const { stdout, stderr } = await execPromise(cmd);
941
+ if (this.execOptions.consoleLog === true) {
942
+ console.log(stdout);
943
+ }
944
+ if (this.execOptions.consoleError === true) {
945
+ console.error(stderr);
946
+ }
947
+ }
948
+ catch (error) {
949
+ if (this.execOptions.consoleError === true) {
950
+ console.error(error);
951
+ }
952
+ }
953
+ }
954
+ }
955
+ async onStdOut(chunk) {
956
+ if (this.execOptions.consoleTestOutput === true) {
957
+ console.log(chunk.toString());
958
+ }
959
+ }
960
+ async onStdErr(chunk) {
961
+ if (this.execOptions.consoleTestOutput === true) {
962
+ console.log(chunk.toString());
963
+ }
964
+ }
965
+ async updateTestCases(testCases) {
966
+ this.testCases = testCases;
967
+ }
968
+ }
969
+ exports.default = Generate;