ortoni-report 4.0.2-beta.1 → 4.0.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/changelog.md +27 -0
- package/dist/{chunk-INS3E7E6.mjs → chunk-4RZ5C7KY.mjs} +402 -296
- package/dist/{cli/cli.js → cli.js} +405 -190
- package/dist/cli.mjs +208 -0
- package/dist/helpers/HTMLGenerator.d.ts +89 -0
- package/dist/helpers/HTMLGenerator.js +163 -0
- package/dist/helpers/databaseManager.d.ts +35 -0
- package/dist/helpers/databaseManager.js +268 -0
- package/dist/helpers/fileManager.d.ts +8 -0
- package/dist/helpers/fileManager.js +60 -0
- package/dist/helpers/markdownConverter.d.ts +1 -0
- package/dist/helpers/markdownConverter.js +14 -0
- package/dist/helpers/resultProcessor.d.ts +10 -0
- package/dist/helpers/resultProcessor.js +60 -0
- package/dist/helpers/serverManager.d.ts +6 -0
- package/dist/helpers/serverManager.js +15 -0
- package/dist/helpers/templateLoader.d.ts +15 -0
- package/dist/helpers/templateLoader.js +88 -0
- package/dist/index.html +1 -1
- package/dist/mergeData.d.ts +13 -0
- package/dist/mergeData.js +182 -0
- package/dist/ortoni-report.d.mts +8 -1
- package/dist/ortoni-report.d.ts +8 -1
- package/dist/ortoni-report.js +211 -96
- package/dist/ortoni-report.mjs +25 -22
- package/dist/{ortoni-report.d.cts → types/reporterConfig.d.ts} +8 -33
- package/dist/types/reporterConfig.js +1 -0
- package/dist/types/testResults.d.ts +31 -0
- package/dist/types/testResults.js +1 -0
- package/dist/utils/attachFiles.d.ts +4 -0
- package/dist/utils/attachFiles.js +87 -0
- package/dist/utils/expressServer.d.ts +1 -0
- package/dist/utils/expressServer.js +61 -0
- package/dist/utils/groupProjects.d.ts +3 -0
- package/dist/utils/groupProjects.js +30 -0
- package/dist/utils/utils.d.ts +15 -0
- package/dist/utils/utils.js +84 -0
- package/package.json +11 -4
- package/readme.md +60 -75
- package/dist/chunk-45EJSEX2.mjs +0 -632
- package/dist/chunk-75EAJL2U.mjs +0 -632
- package/dist/chunk-A6HCKATU.mjs +0 -76
- package/dist/chunk-FGIYOFIC.mjs +0 -632
- package/dist/chunk-FHKWBHU6.mjs +0 -633
- package/dist/chunk-GLICR3VS.mjs +0 -637
- package/dist/chunk-HFO6XSKC.mjs +0 -633
- package/dist/chunk-HOZD6YIV.mjs +0 -634
- package/dist/chunk-IJO2YIFE.mjs +0 -637
- package/dist/chunk-JEIWNUQY.mjs +0 -632
- package/dist/chunk-JPLAGYR7.mjs +0 -632
- package/dist/chunk-NM6ULN2O.mjs +0 -632
- package/dist/chunk-OZS6QIJS.mjs +0 -638
- package/dist/chunk-P57227VN.mjs +0 -633
- package/dist/chunk-QMTRYN5N.js +0 -635
- package/dist/chunk-TI33PMMQ.mjs +0 -639
- package/dist/chunk-Z5NBP5TS.mjs +0 -635
- package/dist/cli/cli.cjs +0 -678
- package/dist/cli/cli.d.cts +0 -1
- package/dist/cli/cli.mjs +0 -103
- package/dist/ortoni-report.cjs +0 -2134
- /package/dist/{cli/cli.d.mts → cli.d.mts} +0 -0
- /package/dist/{cli/cli.d.ts → cli.d.ts} +0 -0
package/dist/ortoni-report.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -38,69 +37,131 @@ __export(ortoni_report_exports, {
|
|
|
38
37
|
module.exports = __toCommonJS(ortoni_report_exports);
|
|
39
38
|
|
|
40
39
|
// src/helpers/fileManager.ts
|
|
40
|
+
var import_fs2 = __toESM(require("fs"));
|
|
41
|
+
var import_path2 = __toESM(require("path"));
|
|
42
|
+
|
|
43
|
+
// src/helpers/templateLoader.ts
|
|
41
44
|
var import_fs = __toESM(require("fs"));
|
|
42
45
|
var import_path = __toESM(require("path"));
|
|
46
|
+
var import_meta = {};
|
|
47
|
+
async function readBundledTemplate(pkgName = "ortoni-report") {
|
|
48
|
+
const packagedRel = "dist/index.html";
|
|
49
|
+
try {
|
|
50
|
+
if (typeof require === "function") {
|
|
51
|
+
const resolved = require.resolve(`${pkgName}/${packagedRel}`);
|
|
52
|
+
if (import_fs.default.existsSync(resolved)) {
|
|
53
|
+
return import_fs.default.readFileSync(resolved, "utf-8");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const moduleNS = await import("module");
|
|
60
|
+
if (moduleNS && typeof moduleNS.createRequire === "function") {
|
|
61
|
+
const createRequire = moduleNS.createRequire;
|
|
62
|
+
const req = createRequire(
|
|
63
|
+
// @ts-ignore
|
|
64
|
+
typeof __filename !== "undefined" ? __filename : import_meta.url
|
|
65
|
+
);
|
|
66
|
+
const resolved = req.resolve(`${pkgName}/${packagedRel}`);
|
|
67
|
+
if (import_fs.default.existsSync(resolved)) {
|
|
68
|
+
return import_fs.default.readFileSync(resolved, "utf-8");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const here = import_path.default.resolve(__dirname, "../dist/index.html");
|
|
75
|
+
if (import_fs.default.existsSync(here)) return import_fs.default.readFileSync(here, "utf-8");
|
|
76
|
+
} catch {
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const nm = import_path.default.join(process.cwd(), "node_modules", pkgName, packagedRel);
|
|
80
|
+
if (import_fs.default.existsSync(nm)) return import_fs.default.readFileSync(nm, "utf-8");
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const alt = import_path.default.join(process.cwd(), "dist", "index.html");
|
|
85
|
+
if (import_fs.default.existsSync(alt)) return import_fs.default.readFileSync(alt, "utf-8");
|
|
86
|
+
} catch {
|
|
87
|
+
}
|
|
88
|
+
throw new Error(
|
|
89
|
+
`ortoni-report template not found (tried:
|
|
90
|
+
- require.resolve('${pkgName}/${packagedRel}')
|
|
91
|
+
- import('module').createRequire(...).resolve('${pkgName}/${packagedRel}')
|
|
92
|
+
- relative ../dist/index.html
|
|
93
|
+
- ${import_path.default.join(
|
|
94
|
+
process.cwd(),
|
|
95
|
+
"node_modules",
|
|
96
|
+
pkgName,
|
|
97
|
+
packagedRel
|
|
98
|
+
)}
|
|
99
|
+
- ${import_path.default.join(process.cwd(), "dist", "index.html")}
|
|
100
|
+
Ensure 'dist/index.html' is present in the published package and package.json 'files' includes 'dist/'.`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/helpers/fileManager.ts
|
|
43
105
|
var FileManager = class {
|
|
44
106
|
constructor(folderPath) {
|
|
45
107
|
this.folderPath = folderPath;
|
|
46
108
|
}
|
|
47
109
|
ensureReportDirectory() {
|
|
48
|
-
const ortoniDataFolder =
|
|
49
|
-
if (!
|
|
50
|
-
|
|
110
|
+
const ortoniDataFolder = import_path2.default.join(this.folderPath, "ortoni-data");
|
|
111
|
+
if (!import_fs2.default.existsSync(this.folderPath)) {
|
|
112
|
+
import_fs2.default.mkdirSync(this.folderPath, { recursive: true });
|
|
51
113
|
} else {
|
|
52
|
-
if (
|
|
53
|
-
|
|
114
|
+
if (import_fs2.default.existsSync(ortoniDataFolder)) {
|
|
115
|
+
import_fs2.default.rmSync(ortoniDataFolder, { recursive: true, force: true });
|
|
54
116
|
}
|
|
55
117
|
}
|
|
56
118
|
}
|
|
57
|
-
writeReportFile(filename, data) {
|
|
58
|
-
|
|
59
|
-
console.log("temp path - " + templatePath);
|
|
60
|
-
let html = import_fs.default.readFileSync(templatePath, "utf-8");
|
|
119
|
+
async writeReportFile(filename, data) {
|
|
120
|
+
let html = await readBundledTemplate();
|
|
61
121
|
const reportJSON = JSON.stringify({
|
|
62
122
|
data
|
|
63
123
|
});
|
|
64
124
|
html = html.replace("__ORTONI_TEST_REPORTDATA__", reportJSON);
|
|
65
|
-
|
|
66
|
-
|
|
125
|
+
const outputPath = import_path2.default.join(process.cwd(), this.folderPath, filename);
|
|
126
|
+
import_fs2.default.writeFileSync(outputPath, html);
|
|
127
|
+
return outputPath;
|
|
67
128
|
}
|
|
68
129
|
writeRawFile(filename, data) {
|
|
69
|
-
const outputPath =
|
|
70
|
-
|
|
130
|
+
const outputPath = import_path2.default.join(process.cwd(), this.folderPath, filename);
|
|
131
|
+
import_fs2.default.mkdirSync(import_path2.default.dirname(outputPath), { recursive: true });
|
|
71
132
|
const content = typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
72
|
-
|
|
133
|
+
import_fs2.default.writeFileSync(outputPath, content, "utf-8");
|
|
73
134
|
return outputPath;
|
|
74
135
|
}
|
|
75
136
|
copyTraceViewerAssets(skip) {
|
|
76
137
|
if (skip) return;
|
|
77
|
-
const traceViewerFolder =
|
|
138
|
+
const traceViewerFolder = import_path2.default.join(
|
|
78
139
|
require.resolve("playwright-core"),
|
|
79
140
|
"..",
|
|
80
141
|
"lib",
|
|
81
142
|
"vite",
|
|
82
143
|
"traceViewer"
|
|
83
144
|
);
|
|
84
|
-
const traceViewerTargetFolder =
|
|
85
|
-
const traceViewerAssetsTargetFolder =
|
|
145
|
+
const traceViewerTargetFolder = import_path2.default.join(this.folderPath, "trace");
|
|
146
|
+
const traceViewerAssetsTargetFolder = import_path2.default.join(
|
|
86
147
|
traceViewerTargetFolder,
|
|
87
148
|
"assets"
|
|
88
149
|
);
|
|
89
|
-
|
|
90
|
-
for (const file of
|
|
150
|
+
import_fs2.default.mkdirSync(traceViewerAssetsTargetFolder, { recursive: true });
|
|
151
|
+
for (const file of import_fs2.default.readdirSync(traceViewerFolder)) {
|
|
91
152
|
if (file.endsWith(".map") || file.includes("watch") || file.includes("assets"))
|
|
92
153
|
continue;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
154
|
+
import_fs2.default.copyFileSync(
|
|
155
|
+
import_path2.default.join(traceViewerFolder, file),
|
|
156
|
+
import_path2.default.join(traceViewerTargetFolder, file)
|
|
96
157
|
);
|
|
97
158
|
}
|
|
98
|
-
const assetsFolder =
|
|
99
|
-
for (const file of
|
|
159
|
+
const assetsFolder = import_path2.default.join(traceViewerFolder, "assets");
|
|
160
|
+
for (const file of import_fs2.default.readdirSync(assetsFolder)) {
|
|
100
161
|
if (file.endsWith(".map") || file.includes("xtermModule")) continue;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
162
|
+
import_fs2.default.copyFileSync(
|
|
163
|
+
import_path2.default.join(assetsFolder, file),
|
|
164
|
+
import_path2.default.join(traceViewerAssetsTargetFolder, file)
|
|
104
165
|
);
|
|
105
166
|
}
|
|
106
167
|
}
|
|
@@ -149,13 +210,46 @@ var HTMLGenerator = class {
|
|
|
149
210
|
);
|
|
150
211
|
return data;
|
|
151
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Return safe analytics/report data.
|
|
215
|
+
* If no dbManager is provided, return empty defaults and a note explaining why.
|
|
216
|
+
*/
|
|
152
217
|
async getReportData() {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
218
|
+
if (!this.dbManager) {
|
|
219
|
+
return {
|
|
220
|
+
summary: {},
|
|
221
|
+
trends: {},
|
|
222
|
+
flakyTests: [],
|
|
223
|
+
slowTests: [],
|
|
224
|
+
note: "Test history/trends are unavailable (saveHistory disabled or DB not initialized)."
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
const [summary, trends, flakyTests, slowTests] = await Promise.all([
|
|
229
|
+
this.dbManager.getSummaryData ? this.dbManager.getSummaryData() : Promise.resolve({}),
|
|
230
|
+
this.dbManager.getTrends ? this.dbManager.getTrends() : Promise.resolve({}),
|
|
231
|
+
this.dbManager.getFlakyTests ? this.dbManager.getFlakyTests() : Promise.resolve([]),
|
|
232
|
+
this.dbManager.getSlowTests ? this.dbManager.getSlowTests() : Promise.resolve([])
|
|
233
|
+
]);
|
|
234
|
+
return {
|
|
235
|
+
summary: summary ?? {},
|
|
236
|
+
trends: trends ?? {},
|
|
237
|
+
flakyTests: flakyTests ?? [],
|
|
238
|
+
slowTests: slowTests ?? []
|
|
239
|
+
};
|
|
240
|
+
} catch (err) {
|
|
241
|
+
console.warn(
|
|
242
|
+
"HTMLGenerator: failed to read analytics from DB, continuing without history.",
|
|
243
|
+
err
|
|
244
|
+
);
|
|
245
|
+
return {
|
|
246
|
+
summary: {},
|
|
247
|
+
trends: {},
|
|
248
|
+
flakyTests: [],
|
|
249
|
+
slowTests: [],
|
|
250
|
+
note: "Test history/trends could not be loaded due to a DB error."
|
|
251
|
+
};
|
|
252
|
+
}
|
|
159
253
|
}
|
|
160
254
|
async prepareReportData(filteredResults, totalDuration, results, projectSet) {
|
|
161
255
|
const totalTests = filteredResults.length;
|
|
@@ -164,10 +258,10 @@ var HTMLGenerator = class {
|
|
|
164
258
|
const failed = filteredResults.filter(
|
|
165
259
|
(r) => r.status === "failed" || r.status === "timedOut"
|
|
166
260
|
).length;
|
|
167
|
-
const successRate = ((passedTests + flakyTests) / totalTests * 100).toFixed(2);
|
|
261
|
+
const successRate = totalTests === 0 ? "0.00" : ((passedTests + flakyTests) / totalTests * 100).toFixed(2);
|
|
168
262
|
const allTags = /* @__PURE__ */ new Set();
|
|
169
263
|
results.forEach(
|
|
170
|
-
(result) => result.testTags.forEach((tag) => allTags.add(tag))
|
|
264
|
+
(result) => (result.testTags || []).forEach((tag) => allTags.add(tag))
|
|
171
265
|
);
|
|
172
266
|
const projectResults = this.calculateProjectResults(
|
|
173
267
|
filteredResults,
|
|
@@ -178,13 +272,31 @@ var HTMLGenerator = class {
|
|
|
178
272
|
const testHistories = await Promise.all(
|
|
179
273
|
results.map(async (result) => {
|
|
180
274
|
const testId = `${result.filePath}:${result.projectName}:${result.title}`;
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
275
|
+
if (!this.dbManager || !this.dbManager.getTestHistory) {
|
|
276
|
+
return {
|
|
277
|
+
testId,
|
|
278
|
+
history: []
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
const history = await this.dbManager.getTestHistory(testId);
|
|
283
|
+
return {
|
|
284
|
+
testId,
|
|
285
|
+
history: history ?? []
|
|
286
|
+
};
|
|
287
|
+
} catch (err) {
|
|
288
|
+
console.warn(
|
|
289
|
+
`HTMLGenerator: failed to read history for ${testId}`,
|
|
290
|
+
err
|
|
291
|
+
);
|
|
292
|
+
return {
|
|
293
|
+
testId,
|
|
294
|
+
history: []
|
|
295
|
+
};
|
|
296
|
+
}
|
|
186
297
|
})
|
|
187
298
|
);
|
|
299
|
+
const reportData = await this.getReportData();
|
|
188
300
|
return {
|
|
189
301
|
summary: {
|
|
190
302
|
overAllResult: {
|
|
@@ -220,7 +332,7 @@ var HTMLGenerator = class {
|
|
|
220
332
|
showProject: this.ortoniConfig.showProject || false
|
|
221
333
|
},
|
|
222
334
|
analytics: {
|
|
223
|
-
reportData
|
|
335
|
+
reportData
|
|
224
336
|
}
|
|
225
337
|
};
|
|
226
338
|
}
|
|
@@ -258,16 +370,16 @@ var HTMLGenerator = class {
|
|
|
258
370
|
}
|
|
259
371
|
};
|
|
260
372
|
|
|
261
|
-
// src/helpers/resultProcessor
|
|
373
|
+
// src/helpers/resultProcessor.ts
|
|
262
374
|
var import_ansi_to_html = __toESM(require("ansi-to-html"));
|
|
263
|
-
var
|
|
375
|
+
var import_path5 = __toESM(require("path"));
|
|
264
376
|
|
|
265
377
|
// src/utils/attachFiles.ts
|
|
266
|
-
var
|
|
267
|
-
var
|
|
378
|
+
var import_path3 = __toESM(require("path"));
|
|
379
|
+
var import_fs4 = __toESM(require("fs"));
|
|
268
380
|
|
|
269
381
|
// src/helpers/markdownConverter.ts
|
|
270
|
-
var
|
|
382
|
+
var import_fs3 = __toESM(require("fs"));
|
|
271
383
|
|
|
272
384
|
// node_modules/marked/lib/marked.esm.js
|
|
273
385
|
function M() {
|
|
@@ -1393,27 +1505,27 @@ var Qt = b.lex;
|
|
|
1393
1505
|
|
|
1394
1506
|
// src/helpers/markdownConverter.ts
|
|
1395
1507
|
function convertMarkdownToHtml(markdownPath, htmlOutputPath) {
|
|
1396
|
-
const hasMarkdown =
|
|
1397
|
-
const markdownContent = hasMarkdown ?
|
|
1508
|
+
const hasMarkdown = import_fs3.default.existsSync(markdownPath);
|
|
1509
|
+
const markdownContent = hasMarkdown ? import_fs3.default.readFileSync(markdownPath, "utf-8") : "";
|
|
1398
1510
|
const markdownHtml = hasMarkdown ? k(markdownContent) : "";
|
|
1399
1511
|
const drawerHtml = `${markdownHtml || ""}`;
|
|
1400
|
-
|
|
1512
|
+
import_fs3.default.writeFileSync(htmlOutputPath, drawerHtml.trim(), "utf-8");
|
|
1401
1513
|
if (hasMarkdown) {
|
|
1402
|
-
|
|
1514
|
+
import_fs3.default.unlinkSync(markdownPath);
|
|
1403
1515
|
}
|
|
1404
1516
|
}
|
|
1405
1517
|
|
|
1406
1518
|
// src/utils/attachFiles.ts
|
|
1407
1519
|
function attachFiles(subFolder, result, testResult, config, steps, errors) {
|
|
1408
1520
|
const folderPath = config.folderPath || "ortoni-report";
|
|
1409
|
-
const attachmentsFolder =
|
|
1521
|
+
const attachmentsFolder = import_path3.default.join(
|
|
1410
1522
|
folderPath,
|
|
1411
1523
|
"ortoni-data",
|
|
1412
1524
|
"attachments",
|
|
1413
1525
|
subFolder
|
|
1414
1526
|
);
|
|
1415
|
-
if (!
|
|
1416
|
-
|
|
1527
|
+
if (!import_fs4.default.existsSync(attachmentsFolder)) {
|
|
1528
|
+
import_fs4.default.mkdirSync(attachmentsFolder, { recursive: true });
|
|
1417
1529
|
}
|
|
1418
1530
|
if (!result.attachments) return;
|
|
1419
1531
|
const { base64Image } = config;
|
|
@@ -1422,14 +1534,14 @@ function attachFiles(subFolder, result, testResult, config, steps, errors) {
|
|
|
1422
1534
|
result.attachments.forEach((attachment) => {
|
|
1423
1535
|
const { contentType, name, path: attachmentPath, body } = attachment;
|
|
1424
1536
|
if (!attachmentPath && !body) return;
|
|
1425
|
-
const fileName = attachmentPath ?
|
|
1426
|
-
const relativePath =
|
|
1537
|
+
const fileName = attachmentPath ? import_path3.default.basename(attachmentPath) : `${name}.${getFileExtension(contentType)}`;
|
|
1538
|
+
const relativePath = import_path3.default.join(
|
|
1427
1539
|
"ortoni-data",
|
|
1428
1540
|
"attachments",
|
|
1429
1541
|
subFolder,
|
|
1430
1542
|
fileName
|
|
1431
1543
|
);
|
|
1432
|
-
const fullPath =
|
|
1544
|
+
const fullPath = import_path3.default.join(attachmentsFolder, fileName);
|
|
1433
1545
|
if (contentType === "image/png") {
|
|
1434
1546
|
handleImage(
|
|
1435
1547
|
attachmentPath,
|
|
@@ -1472,13 +1584,13 @@ function handleImage(attachmentPath, body, base64Image, fullPath, relativePath,
|
|
|
1472
1584
|
let screenshotPath = "";
|
|
1473
1585
|
if (attachmentPath) {
|
|
1474
1586
|
try {
|
|
1475
|
-
const screenshotContent =
|
|
1587
|
+
const screenshotContent = import_fs4.default.readFileSync(
|
|
1476
1588
|
attachmentPath,
|
|
1477
1589
|
base64Image ? "base64" : void 0
|
|
1478
1590
|
);
|
|
1479
1591
|
screenshotPath = base64Image ? `data:image/png;base64,${screenshotContent}` : relativePath;
|
|
1480
1592
|
if (!base64Image) {
|
|
1481
|
-
|
|
1593
|
+
import_fs4.default.copyFileSync(attachmentPath, fullPath);
|
|
1482
1594
|
}
|
|
1483
1595
|
} catch (error) {
|
|
1484
1596
|
console.error(
|
|
@@ -1495,7 +1607,7 @@ function handleImage(attachmentPath, body, base64Image, fullPath, relativePath,
|
|
|
1495
1607
|
}
|
|
1496
1608
|
function handleAttachment(attachmentPath, fullPath, relativePath, resultKey, testResult, steps, errors) {
|
|
1497
1609
|
if (attachmentPath) {
|
|
1498
|
-
|
|
1610
|
+
import_fs4.default.copyFileSync(attachmentPath, fullPath);
|
|
1499
1611
|
if (resultKey === "videoPath") {
|
|
1500
1612
|
testResult[resultKey]?.push(relativePath);
|
|
1501
1613
|
} else if (resultKey === "tracePath") {
|
|
@@ -1521,13 +1633,13 @@ function getFileExtension(contentType) {
|
|
|
1521
1633
|
}
|
|
1522
1634
|
|
|
1523
1635
|
// src/utils/utils.ts
|
|
1524
|
-
var
|
|
1636
|
+
var import_path4 = __toESM(require("path"));
|
|
1525
1637
|
function normalizeFilePath(filePath) {
|
|
1526
|
-
const normalizedPath =
|
|
1527
|
-
return
|
|
1638
|
+
const normalizedPath = import_path4.default.normalize(filePath);
|
|
1639
|
+
return import_path4.default.basename(normalizedPath);
|
|
1528
1640
|
}
|
|
1529
1641
|
function ensureHtmlExtension(filename) {
|
|
1530
|
-
const ext =
|
|
1642
|
+
const ext = import_path4.default.extname(filename);
|
|
1531
1643
|
if (ext && ext.toLowerCase() === ".html") {
|
|
1532
1644
|
return filename;
|
|
1533
1645
|
}
|
|
@@ -1575,7 +1687,7 @@ function extractSuites(titlePath) {
|
|
|
1575
1687
|
};
|
|
1576
1688
|
}
|
|
1577
1689
|
|
|
1578
|
-
// src/helpers/resultProcessor
|
|
1690
|
+
// src/helpers/resultProcessor.ts
|
|
1579
1691
|
var TestResultProcessor = class {
|
|
1580
1692
|
constructor(projectRoot) {
|
|
1581
1693
|
this.ansiToHtml = new import_ansi_to_html.default({ fg: "var(--snippet-color)" });
|
|
@@ -1620,7 +1732,7 @@ var TestResultProcessor = class {
|
|
|
1620
1732
|
testId: `${filePath}:${projectName}:${title}`
|
|
1621
1733
|
};
|
|
1622
1734
|
attachFiles(
|
|
1623
|
-
test.id,
|
|
1735
|
+
import_path5.default.join(test.id, `retry-${result.retry}`),
|
|
1624
1736
|
result,
|
|
1625
1737
|
testResult,
|
|
1626
1738
|
ortoniConfig,
|
|
@@ -1631,7 +1743,7 @@ var TestResultProcessor = class {
|
|
|
1631
1743
|
}
|
|
1632
1744
|
processSteps(steps) {
|
|
1633
1745
|
return steps.map((step) => {
|
|
1634
|
-
const stepLocation = step.location ? `${
|
|
1746
|
+
const stepLocation = step.location ? `${import_path5.default.relative(this.projectRoot, step.location.file)}:${step.location.line}:${step.location.column}` : "";
|
|
1635
1747
|
return {
|
|
1636
1748
|
snippet: this.ansiToHtml.toHtml(escapeHtml(step.error?.snippet || "")),
|
|
1637
1749
|
title: step.title,
|
|
@@ -1643,16 +1755,16 @@ var TestResultProcessor = class {
|
|
|
1643
1755
|
|
|
1644
1756
|
// src/utils/expressServer.ts
|
|
1645
1757
|
var import_express = __toESM(require("express"));
|
|
1646
|
-
var
|
|
1758
|
+
var import_path6 = __toESM(require("path"));
|
|
1647
1759
|
var import_child_process = require("child_process");
|
|
1648
1760
|
function startReportServer(reportFolder, reportFilename, port = 2004, open2) {
|
|
1649
1761
|
const app = (0, import_express.default)();
|
|
1650
|
-
app.use(import_express.default.static(reportFolder));
|
|
1762
|
+
app.use(import_express.default.static(reportFolder, { index: false }));
|
|
1651
1763
|
app.get("/", (_req, res) => {
|
|
1652
1764
|
try {
|
|
1653
|
-
res.sendFile(
|
|
1765
|
+
res.sendFile(import_path6.default.resolve(reportFolder, reportFilename));
|
|
1654
1766
|
} catch (error) {
|
|
1655
|
-
console.error("Ortoni
|
|
1767
|
+
console.error("Ortoni Report: Error sending report file:", error);
|
|
1656
1768
|
res.status(500).send("Error loading report");
|
|
1657
1769
|
}
|
|
1658
1770
|
});
|
|
@@ -1666,21 +1778,21 @@ Press Ctrl+C to stop.`
|
|
|
1666
1778
|
try {
|
|
1667
1779
|
openBrowser(`http://localhost:${port}`);
|
|
1668
1780
|
} catch (error) {
|
|
1669
|
-
console.error("Ortoni
|
|
1781
|
+
console.error("Ortoni Report: Error opening browser:", error);
|
|
1670
1782
|
}
|
|
1671
1783
|
}
|
|
1672
1784
|
});
|
|
1673
1785
|
server.on("error", (error) => {
|
|
1674
1786
|
if (error.code === "EADDRINUSE") {
|
|
1675
1787
|
console.error(
|
|
1676
|
-
`Ortoni
|
|
1788
|
+
`Ortoni Report: Port ${port} is already in use. Trying a different port...`
|
|
1677
1789
|
);
|
|
1678
1790
|
} else {
|
|
1679
|
-
console.error("Ortoni
|
|
1791
|
+
console.error("Ortoni Report: Server error:", error);
|
|
1680
1792
|
}
|
|
1681
1793
|
});
|
|
1682
1794
|
} catch (error) {
|
|
1683
|
-
console.error("Ortoni
|
|
1795
|
+
console.error("Ortoni Report: Error starting the server:", error);
|
|
1684
1796
|
}
|
|
1685
1797
|
}
|
|
1686
1798
|
function openBrowser(url) {
|
|
@@ -1698,7 +1810,7 @@ function openBrowser(url) {
|
|
|
1698
1810
|
(0, import_child_process.spawn)(command, [url]);
|
|
1699
1811
|
}
|
|
1700
1812
|
} catch (error) {
|
|
1701
|
-
console.error("Ortoni
|
|
1813
|
+
console.error("Ortoni Report: Error opening the browser:", error);
|
|
1702
1814
|
}
|
|
1703
1815
|
}
|
|
1704
1816
|
|
|
@@ -1707,7 +1819,7 @@ var ServerManager = class {
|
|
|
1707
1819
|
constructor(ortoniConfig) {
|
|
1708
1820
|
this.ortoniConfig = ortoniConfig;
|
|
1709
1821
|
}
|
|
1710
|
-
startServer(folderPath, outputFilename, overAllStatus) {
|
|
1822
|
+
async startServer(folderPath, outputFilename, overAllStatus) {
|
|
1711
1823
|
const openOption = this.ortoniConfig.open || "never";
|
|
1712
1824
|
const hasFailures = overAllStatus === "failed";
|
|
1713
1825
|
if (openOption === "always" || openOption === "on-failure" && hasFailures) {
|
|
@@ -1717,6 +1829,8 @@ var ServerManager = class {
|
|
|
1717
1829
|
this.ortoniConfig.port,
|
|
1718
1830
|
openOption
|
|
1719
1831
|
);
|
|
1832
|
+
await new Promise((_resolve) => {
|
|
1833
|
+
});
|
|
1720
1834
|
}
|
|
1721
1835
|
}
|
|
1722
1836
|
};
|
|
@@ -1996,7 +2110,7 @@ var DatabaseManager = class {
|
|
|
1996
2110
|
};
|
|
1997
2111
|
|
|
1998
2112
|
// src/ortoni-report.ts
|
|
1999
|
-
var
|
|
2113
|
+
var import_path7 = __toESM(require("path"));
|
|
2000
2114
|
var OrtoniReport = class {
|
|
2001
2115
|
constructor(ortoniConfig = {}) {
|
|
2002
2116
|
this.ortoniConfig = ortoniConfig;
|
|
@@ -2027,9 +2141,9 @@ var OrtoniReport = class {
|
|
|
2027
2141
|
this.testResultProcessor = new TestResultProcessor(config.rootDir);
|
|
2028
2142
|
this.fileManager.ensureReportDirectory();
|
|
2029
2143
|
await this.dbManager.initialize(
|
|
2030
|
-
|
|
2144
|
+
import_path7.default.join(this.folderPath, "ortoni-data-history.sqlite")
|
|
2031
2145
|
);
|
|
2032
|
-
this.
|
|
2146
|
+
this.shardConfig = config?.shard;
|
|
2033
2147
|
}
|
|
2034
2148
|
onStdOut(chunk, _test, _result) {
|
|
2035
2149
|
if (this.reportsCount == 1 && this.showConsoleLogs) {
|
|
@@ -2046,7 +2160,7 @@ var OrtoniReport = class {
|
|
|
2046
2160
|
);
|
|
2047
2161
|
this.results.push(testResult);
|
|
2048
2162
|
} catch (error) {
|
|
2049
|
-
console.error("
|
|
2163
|
+
console.error("Ortoni Report: Error processing test end:", error);
|
|
2050
2164
|
}
|
|
2051
2165
|
}
|
|
2052
2166
|
printsToStdio() {
|
|
@@ -2065,12 +2179,12 @@ var OrtoniReport = class {
|
|
|
2065
2179
|
(r) => r.status !== "skipped"
|
|
2066
2180
|
);
|
|
2067
2181
|
const totalDuration = result.duration;
|
|
2068
|
-
if (this.
|
|
2069
|
-
const shard = this.
|
|
2182
|
+
if (this.shardConfig && this.shardConfig.total > 1) {
|
|
2183
|
+
const shard = this.shardConfig;
|
|
2070
2184
|
const shardFile = `ortoni-shard-${shard.current}-of-${shard.total}.json`;
|
|
2071
2185
|
const shardData = {
|
|
2072
|
-
status: result.status,
|
|
2073
|
-
|
|
2186
|
+
// status: result.status,
|
|
2187
|
+
totalDuration,
|
|
2074
2188
|
results: this.results,
|
|
2075
2189
|
projectSet: Array.from(this.projectSet),
|
|
2076
2190
|
userConfig: {
|
|
@@ -2083,8 +2197,11 @@ var OrtoniReport = class {
|
|
|
2083
2197
|
meta: this.ortoniConfig.meta
|
|
2084
2198
|
}
|
|
2085
2199
|
};
|
|
2086
|
-
this.fileManager.writeRawFile(
|
|
2087
|
-
|
|
2200
|
+
const shardFilePath = this.fileManager.writeRawFile(
|
|
2201
|
+
shardFile,
|
|
2202
|
+
shardData
|
|
2203
|
+
);
|
|
2204
|
+
console.info(`Ortoni Report: Shard data written to ${shardFilePath}`);
|
|
2088
2205
|
this.shouldGenerateReport = false;
|
|
2089
2206
|
return;
|
|
2090
2207
|
}
|
|
@@ -2097,21 +2214,21 @@ var OrtoniReport = class {
|
|
|
2097
2214
|
this.results,
|
|
2098
2215
|
this.projectSet
|
|
2099
2216
|
);
|
|
2100
|
-
this.outputPath = this.fileManager.writeReportFile(
|
|
2217
|
+
this.outputPath = await this.fileManager.writeReportFile(
|
|
2101
2218
|
this.outputFilename,
|
|
2102
2219
|
finalReportData
|
|
2103
2220
|
);
|
|
2104
2221
|
} else {
|
|
2105
|
-
console.error("
|
|
2222
|
+
console.error("Ortoni Report: Error saving test run to database");
|
|
2106
2223
|
}
|
|
2107
2224
|
} else {
|
|
2108
2225
|
console.error(
|
|
2109
|
-
"
|
|
2226
|
+
"Ortoni Report: Report generation skipped due to error in Playwright worker!"
|
|
2110
2227
|
);
|
|
2111
2228
|
}
|
|
2112
2229
|
} catch (error) {
|
|
2113
2230
|
this.shouldGenerateReport = false;
|
|
2114
|
-
console.error("
|
|
2231
|
+
console.error("Ortoni Report: Error generating report:", error);
|
|
2115
2232
|
}
|
|
2116
2233
|
}
|
|
2117
2234
|
async onExit() {
|
|
@@ -2119,17 +2236,15 @@ var OrtoniReport = class {
|
|
|
2119
2236
|
await this.dbManager.close();
|
|
2120
2237
|
if (this.shouldGenerateReport) {
|
|
2121
2238
|
this.fileManager.copyTraceViewerAssets(this.skipTraceViewer);
|
|
2122
|
-
console.info(`Ortoni
|
|
2123
|
-
this.serverManager.startServer(
|
|
2239
|
+
console.info(`Ortoni Report generated at ${this.outputPath}`);
|
|
2240
|
+
await this.serverManager.startServer(
|
|
2124
2241
|
this.folderPath,
|
|
2125
2242
|
this.outputFilename,
|
|
2126
2243
|
this.overAllStatus
|
|
2127
2244
|
);
|
|
2128
|
-
await new Promise((_resolve) => {
|
|
2129
|
-
});
|
|
2130
2245
|
}
|
|
2131
2246
|
} catch (error) {
|
|
2132
|
-
console.error("
|
|
2247
|
+
console.error("Ortoni Report: Error in onExit:", error);
|
|
2133
2248
|
}
|
|
2134
2249
|
}
|
|
2135
2250
|
};
|