ortoni-report 4.0.0 → 4.0.1-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/dist/chunk-4RZ5C7KY.mjs +744 -0
- package/dist/chunk-HOOC3MDY.mjs +632 -0
- package/dist/chunk-ISCRDMPY.mjs +693 -0
- package/dist/chunk-P72FKFLZ.mjs +692 -0
- package/dist/chunk-S45BZGXX.mjs +744 -0
- package/dist/chunk-ZG4JPYLC.mjs +692 -0
- package/dist/chunk-ZSPTPISU.mjs +692 -0
- package/dist/cli.js +911 -0
- package/dist/cli.mjs +206 -0
- package/dist/index.html +2 -2
- package/dist/ortoni-report.d.mts +8 -0
- package/dist/ortoni-report.d.ts +8 -0
- package/dist/ortoni-report.js +226 -82
- package/dist/ortoni-report.mjs +64 -576
- package/package.json +11 -4
- package/dist/chunk-A6HCKATU.mjs +0 -76
- package/dist/cli/cli.js +0 -106
- package/dist/cli/cli.mjs +0 -23
- /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.d.mts
CHANGED
|
@@ -78,6 +78,13 @@ interface OrtoniReportConfig {
|
|
|
78
78
|
* @example { "key": "value" } as string
|
|
79
79
|
*/
|
|
80
80
|
meta?: Record<string, string>;
|
|
81
|
+
/**
|
|
82
|
+
* Save the history of the reports in a SQL file to be used in future reports.
|
|
83
|
+
* The history file will be saved in the report folder.
|
|
84
|
+
* @default true
|
|
85
|
+
* @example false (to disable)
|
|
86
|
+
*/
|
|
87
|
+
saveHistory?: boolean;
|
|
81
88
|
}
|
|
82
89
|
|
|
83
90
|
declare class OrtoniReport implements Reporter {
|
|
@@ -96,6 +103,7 @@ declare class OrtoniReport implements Reporter {
|
|
|
96
103
|
private shouldGenerateReport;
|
|
97
104
|
private showConsoleLogs;
|
|
98
105
|
private skipTraceViewer;
|
|
106
|
+
private shardConfig;
|
|
99
107
|
constructor(ortoniConfig?: OrtoniReportConfig);
|
|
100
108
|
private reportsCount;
|
|
101
109
|
onBegin(config: FullConfig, _suite: Suite): Promise<void>;
|
package/dist/ortoni-report.d.ts
CHANGED
|
@@ -78,6 +78,13 @@ interface OrtoniReportConfig {
|
|
|
78
78
|
* @example { "key": "value" } as string
|
|
79
79
|
*/
|
|
80
80
|
meta?: Record<string, string>;
|
|
81
|
+
/**
|
|
82
|
+
* Save the history of the reports in a SQL file to be used in future reports.
|
|
83
|
+
* The history file will be saved in the report folder.
|
|
84
|
+
* @default true
|
|
85
|
+
* @example false (to disable)
|
|
86
|
+
*/
|
|
87
|
+
saveHistory?: boolean;
|
|
81
88
|
}
|
|
82
89
|
|
|
83
90
|
declare class OrtoniReport implements Reporter {
|
|
@@ -96,6 +103,7 @@ declare class OrtoniReport implements Reporter {
|
|
|
96
103
|
private shouldGenerateReport;
|
|
97
104
|
private showConsoleLogs;
|
|
98
105
|
private skipTraceViewer;
|
|
106
|
+
private shardConfig;
|
|
99
107
|
constructor(ortoniConfig?: OrtoniReportConfig);
|
|
100
108
|
private reportsCount;
|
|
101
109
|
onBegin(config: FullConfig, _suite: Suite): Promise<void>;
|
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,62 +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
|
-
let html = import_fs.default.readFileSync(templatePath, "utf-8");
|
|
119
|
+
async writeReportFile(filename, data) {
|
|
120
|
+
let html = await readBundledTemplate();
|
|
60
121
|
const reportJSON = JSON.stringify({
|
|
61
122
|
data
|
|
62
123
|
});
|
|
63
124
|
html = html.replace("__ORTONI_TEST_REPORTDATA__", reportJSON);
|
|
64
|
-
const outputPath =
|
|
65
|
-
|
|
125
|
+
const outputPath = import_path2.default.join(process.cwd(), this.folderPath, filename);
|
|
126
|
+
import_fs2.default.writeFileSync(outputPath, html);
|
|
127
|
+
return outputPath;
|
|
128
|
+
}
|
|
129
|
+
writeRawFile(filename, data) {
|
|
130
|
+
const outputPath = import_path2.default.join(process.cwd(), this.folderPath, filename);
|
|
131
|
+
import_fs2.default.mkdirSync(import_path2.default.dirname(outputPath), { recursive: true });
|
|
132
|
+
const content = typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
133
|
+
import_fs2.default.writeFileSync(outputPath, content, "utf-8");
|
|
66
134
|
return outputPath;
|
|
67
135
|
}
|
|
68
136
|
copyTraceViewerAssets(skip) {
|
|
69
137
|
if (skip) return;
|
|
70
|
-
const traceViewerFolder =
|
|
138
|
+
const traceViewerFolder = import_path2.default.join(
|
|
71
139
|
require.resolve("playwright-core"),
|
|
72
140
|
"..",
|
|
73
141
|
"lib",
|
|
74
142
|
"vite",
|
|
75
143
|
"traceViewer"
|
|
76
144
|
);
|
|
77
|
-
const traceViewerTargetFolder =
|
|
78
|
-
const traceViewerAssetsTargetFolder =
|
|
145
|
+
const traceViewerTargetFolder = import_path2.default.join(this.folderPath, "trace");
|
|
146
|
+
const traceViewerAssetsTargetFolder = import_path2.default.join(
|
|
79
147
|
traceViewerTargetFolder,
|
|
80
148
|
"assets"
|
|
81
149
|
);
|
|
82
|
-
|
|
83
|
-
for (const file of
|
|
150
|
+
import_fs2.default.mkdirSync(traceViewerAssetsTargetFolder, { recursive: true });
|
|
151
|
+
for (const file of import_fs2.default.readdirSync(traceViewerFolder)) {
|
|
84
152
|
if (file.endsWith(".map") || file.includes("watch") || file.includes("assets"))
|
|
85
153
|
continue;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
154
|
+
import_fs2.default.copyFileSync(
|
|
155
|
+
import_path2.default.join(traceViewerFolder, file),
|
|
156
|
+
import_path2.default.join(traceViewerTargetFolder, file)
|
|
89
157
|
);
|
|
90
158
|
}
|
|
91
|
-
const assetsFolder =
|
|
92
|
-
for (const file of
|
|
159
|
+
const assetsFolder = import_path2.default.join(traceViewerFolder, "assets");
|
|
160
|
+
for (const file of import_fs2.default.readdirSync(assetsFolder)) {
|
|
93
161
|
if (file.endsWith(".map") || file.includes("xtermModule")) continue;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
162
|
+
import_fs2.default.copyFileSync(
|
|
163
|
+
import_path2.default.join(assetsFolder, file),
|
|
164
|
+
import_path2.default.join(traceViewerAssetsTargetFolder, file)
|
|
97
165
|
);
|
|
98
166
|
}
|
|
99
167
|
}
|
|
@@ -142,13 +210,46 @@ var HTMLGenerator = class {
|
|
|
142
210
|
);
|
|
143
211
|
return data;
|
|
144
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Return safe analytics/report data.
|
|
215
|
+
* If no dbManager is provided, return empty defaults and a note explaining why.
|
|
216
|
+
*/
|
|
145
217
|
async getReportData() {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
+
}
|
|
152
253
|
}
|
|
153
254
|
async prepareReportData(filteredResults, totalDuration, results, projectSet) {
|
|
154
255
|
const totalTests = filteredResults.length;
|
|
@@ -157,10 +258,10 @@ var HTMLGenerator = class {
|
|
|
157
258
|
const failed = filteredResults.filter(
|
|
158
259
|
(r) => r.status === "failed" || r.status === "timedOut"
|
|
159
260
|
).length;
|
|
160
|
-
const successRate = ((passedTests + flakyTests) / totalTests * 100).toFixed(2);
|
|
261
|
+
const successRate = totalTests === 0 ? "0.00" : ((passedTests + flakyTests) / totalTests * 100).toFixed(2);
|
|
161
262
|
const allTags = /* @__PURE__ */ new Set();
|
|
162
263
|
results.forEach(
|
|
163
|
-
(result) => result.testTags.forEach((tag) => allTags.add(tag))
|
|
264
|
+
(result) => (result.testTags || []).forEach((tag) => allTags.add(tag))
|
|
164
265
|
);
|
|
165
266
|
const projectResults = this.calculateProjectResults(
|
|
166
267
|
filteredResults,
|
|
@@ -171,13 +272,31 @@ var HTMLGenerator = class {
|
|
|
171
272
|
const testHistories = await Promise.all(
|
|
172
273
|
results.map(async (result) => {
|
|
173
274
|
const testId = `${result.filePath}:${result.projectName}:${result.title}`;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
+
}
|
|
179
297
|
})
|
|
180
298
|
);
|
|
299
|
+
const reportData = await this.getReportData();
|
|
181
300
|
return {
|
|
182
301
|
summary: {
|
|
183
302
|
overAllResult: {
|
|
@@ -209,13 +328,11 @@ var HTMLGenerator = class {
|
|
|
209
328
|
meta: this.ortoniConfig.meta
|
|
210
329
|
},
|
|
211
330
|
preferences: {
|
|
212
|
-
theme: this.ortoniConfig.preferredTheme,
|
|
213
331
|
logo: this.ortoniConfig.logo || void 0,
|
|
214
332
|
showProject: this.ortoniConfig.showProject || false
|
|
215
333
|
},
|
|
216
334
|
analytics: {
|
|
217
|
-
reportData
|
|
218
|
-
// chartTrendData: await this.chartTrendData(),
|
|
335
|
+
reportData
|
|
219
336
|
}
|
|
220
337
|
};
|
|
221
338
|
}
|
|
@@ -253,16 +370,16 @@ var HTMLGenerator = class {
|
|
|
253
370
|
}
|
|
254
371
|
};
|
|
255
372
|
|
|
256
|
-
// src/helpers/resultProcessor
|
|
373
|
+
// src/helpers/resultProcessor.ts
|
|
257
374
|
var import_ansi_to_html = __toESM(require("ansi-to-html"));
|
|
258
|
-
var
|
|
375
|
+
var import_path5 = __toESM(require("path"));
|
|
259
376
|
|
|
260
377
|
// src/utils/attachFiles.ts
|
|
261
|
-
var
|
|
262
|
-
var
|
|
378
|
+
var import_path3 = __toESM(require("path"));
|
|
379
|
+
var import_fs4 = __toESM(require("fs"));
|
|
263
380
|
|
|
264
381
|
// src/helpers/markdownConverter.ts
|
|
265
|
-
var
|
|
382
|
+
var import_fs3 = __toESM(require("fs"));
|
|
266
383
|
|
|
267
384
|
// node_modules/marked/lib/marked.esm.js
|
|
268
385
|
function M() {
|
|
@@ -1388,27 +1505,27 @@ var Qt = b.lex;
|
|
|
1388
1505
|
|
|
1389
1506
|
// src/helpers/markdownConverter.ts
|
|
1390
1507
|
function convertMarkdownToHtml(markdownPath, htmlOutputPath) {
|
|
1391
|
-
const hasMarkdown =
|
|
1392
|
-
const markdownContent = hasMarkdown ?
|
|
1508
|
+
const hasMarkdown = import_fs3.default.existsSync(markdownPath);
|
|
1509
|
+
const markdownContent = hasMarkdown ? import_fs3.default.readFileSync(markdownPath, "utf-8") : "";
|
|
1393
1510
|
const markdownHtml = hasMarkdown ? k(markdownContent) : "";
|
|
1394
1511
|
const drawerHtml = `${markdownHtml || ""}`;
|
|
1395
|
-
|
|
1512
|
+
import_fs3.default.writeFileSync(htmlOutputPath, drawerHtml.trim(), "utf-8");
|
|
1396
1513
|
if (hasMarkdown) {
|
|
1397
|
-
|
|
1514
|
+
import_fs3.default.unlinkSync(markdownPath);
|
|
1398
1515
|
}
|
|
1399
1516
|
}
|
|
1400
1517
|
|
|
1401
1518
|
// src/utils/attachFiles.ts
|
|
1402
1519
|
function attachFiles(subFolder, result, testResult, config, steps, errors) {
|
|
1403
1520
|
const folderPath = config.folderPath || "ortoni-report";
|
|
1404
|
-
const attachmentsFolder =
|
|
1521
|
+
const attachmentsFolder = import_path3.default.join(
|
|
1405
1522
|
folderPath,
|
|
1406
1523
|
"ortoni-data",
|
|
1407
1524
|
"attachments",
|
|
1408
1525
|
subFolder
|
|
1409
1526
|
);
|
|
1410
|
-
if (!
|
|
1411
|
-
|
|
1527
|
+
if (!import_fs4.default.existsSync(attachmentsFolder)) {
|
|
1528
|
+
import_fs4.default.mkdirSync(attachmentsFolder, { recursive: true });
|
|
1412
1529
|
}
|
|
1413
1530
|
if (!result.attachments) return;
|
|
1414
1531
|
const { base64Image } = config;
|
|
@@ -1417,14 +1534,14 @@ function attachFiles(subFolder, result, testResult, config, steps, errors) {
|
|
|
1417
1534
|
result.attachments.forEach((attachment) => {
|
|
1418
1535
|
const { contentType, name, path: attachmentPath, body } = attachment;
|
|
1419
1536
|
if (!attachmentPath && !body) return;
|
|
1420
|
-
const fileName = attachmentPath ?
|
|
1421
|
-
const relativePath =
|
|
1537
|
+
const fileName = attachmentPath ? import_path3.default.basename(attachmentPath) : `${name}.${getFileExtension(contentType)}`;
|
|
1538
|
+
const relativePath = import_path3.default.join(
|
|
1422
1539
|
"ortoni-data",
|
|
1423
1540
|
"attachments",
|
|
1424
1541
|
subFolder,
|
|
1425
1542
|
fileName
|
|
1426
1543
|
);
|
|
1427
|
-
const fullPath =
|
|
1544
|
+
const fullPath = import_path3.default.join(attachmentsFolder, fileName);
|
|
1428
1545
|
if (contentType === "image/png") {
|
|
1429
1546
|
handleImage(
|
|
1430
1547
|
attachmentPath,
|
|
@@ -1467,13 +1584,13 @@ function handleImage(attachmentPath, body, base64Image, fullPath, relativePath,
|
|
|
1467
1584
|
let screenshotPath = "";
|
|
1468
1585
|
if (attachmentPath) {
|
|
1469
1586
|
try {
|
|
1470
|
-
const screenshotContent =
|
|
1587
|
+
const screenshotContent = import_fs4.default.readFileSync(
|
|
1471
1588
|
attachmentPath,
|
|
1472
1589
|
base64Image ? "base64" : void 0
|
|
1473
1590
|
);
|
|
1474
1591
|
screenshotPath = base64Image ? `data:image/png;base64,${screenshotContent}` : relativePath;
|
|
1475
1592
|
if (!base64Image) {
|
|
1476
|
-
|
|
1593
|
+
import_fs4.default.copyFileSync(attachmentPath, fullPath);
|
|
1477
1594
|
}
|
|
1478
1595
|
} catch (error) {
|
|
1479
1596
|
console.error(
|
|
@@ -1490,7 +1607,7 @@ function handleImage(attachmentPath, body, base64Image, fullPath, relativePath,
|
|
|
1490
1607
|
}
|
|
1491
1608
|
function handleAttachment(attachmentPath, fullPath, relativePath, resultKey, testResult, steps, errors) {
|
|
1492
1609
|
if (attachmentPath) {
|
|
1493
|
-
|
|
1610
|
+
import_fs4.default.copyFileSync(attachmentPath, fullPath);
|
|
1494
1611
|
if (resultKey === "videoPath") {
|
|
1495
1612
|
testResult[resultKey]?.push(relativePath);
|
|
1496
1613
|
} else if (resultKey === "tracePath") {
|
|
@@ -1516,13 +1633,13 @@ function getFileExtension(contentType) {
|
|
|
1516
1633
|
}
|
|
1517
1634
|
|
|
1518
1635
|
// src/utils/utils.ts
|
|
1519
|
-
var
|
|
1636
|
+
var import_path4 = __toESM(require("path"));
|
|
1520
1637
|
function normalizeFilePath(filePath) {
|
|
1521
|
-
const normalizedPath =
|
|
1522
|
-
return
|
|
1638
|
+
const normalizedPath = import_path4.default.normalize(filePath);
|
|
1639
|
+
return import_path4.default.basename(normalizedPath);
|
|
1523
1640
|
}
|
|
1524
1641
|
function ensureHtmlExtension(filename) {
|
|
1525
|
-
const ext =
|
|
1642
|
+
const ext = import_path4.default.extname(filename);
|
|
1526
1643
|
if (ext && ext.toLowerCase() === ".html") {
|
|
1527
1644
|
return filename;
|
|
1528
1645
|
}
|
|
@@ -1570,7 +1687,7 @@ function extractSuites(titlePath) {
|
|
|
1570
1687
|
};
|
|
1571
1688
|
}
|
|
1572
1689
|
|
|
1573
|
-
// src/helpers/resultProcessor
|
|
1690
|
+
// src/helpers/resultProcessor.ts
|
|
1574
1691
|
var TestResultProcessor = class {
|
|
1575
1692
|
constructor(projectRoot) {
|
|
1576
1693
|
this.ansiToHtml = new import_ansi_to_html.default({ fg: "var(--snippet-color)" });
|
|
@@ -1626,7 +1743,7 @@ var TestResultProcessor = class {
|
|
|
1626
1743
|
}
|
|
1627
1744
|
processSteps(steps) {
|
|
1628
1745
|
return steps.map((step) => {
|
|
1629
|
-
const stepLocation = step.location ? `${
|
|
1746
|
+
const stepLocation = step.location ? `${import_path5.default.relative(this.projectRoot, step.location.file)}:${step.location.line}:${step.location.column}` : "";
|
|
1630
1747
|
return {
|
|
1631
1748
|
snippet: this.ansiToHtml.toHtml(escapeHtml(step.error?.snippet || "")),
|
|
1632
1749
|
title: step.title,
|
|
@@ -1638,16 +1755,16 @@ var TestResultProcessor = class {
|
|
|
1638
1755
|
|
|
1639
1756
|
// src/utils/expressServer.ts
|
|
1640
1757
|
var import_express = __toESM(require("express"));
|
|
1641
|
-
var
|
|
1758
|
+
var import_path6 = __toESM(require("path"));
|
|
1642
1759
|
var import_child_process = require("child_process");
|
|
1643
1760
|
function startReportServer(reportFolder, reportFilename, port = 2004, open2) {
|
|
1644
1761
|
const app = (0, import_express.default)();
|
|
1645
|
-
app.use(import_express.default.static(reportFolder));
|
|
1762
|
+
app.use(import_express.default.static(reportFolder, { index: false }));
|
|
1646
1763
|
app.get("/", (_req, res) => {
|
|
1647
1764
|
try {
|
|
1648
|
-
res.sendFile(
|
|
1765
|
+
res.sendFile(import_path6.default.resolve(reportFolder, reportFilename));
|
|
1649
1766
|
} catch (error) {
|
|
1650
|
-
console.error("Ortoni
|
|
1767
|
+
console.error("Ortoni Report: Error sending report file:", error);
|
|
1651
1768
|
res.status(500).send("Error loading report");
|
|
1652
1769
|
}
|
|
1653
1770
|
});
|
|
@@ -1661,21 +1778,21 @@ Press Ctrl+C to stop.`
|
|
|
1661
1778
|
try {
|
|
1662
1779
|
openBrowser(`http://localhost:${port}`);
|
|
1663
1780
|
} catch (error) {
|
|
1664
|
-
console.error("Ortoni
|
|
1781
|
+
console.error("Ortoni Report: Error opening browser:", error);
|
|
1665
1782
|
}
|
|
1666
1783
|
}
|
|
1667
1784
|
});
|
|
1668
1785
|
server.on("error", (error) => {
|
|
1669
1786
|
if (error.code === "EADDRINUSE") {
|
|
1670
1787
|
console.error(
|
|
1671
|
-
`Ortoni
|
|
1788
|
+
`Ortoni Report: Port ${port} is already in use. Trying a different port...`
|
|
1672
1789
|
);
|
|
1673
1790
|
} else {
|
|
1674
|
-
console.error("Ortoni
|
|
1791
|
+
console.error("Ortoni Report: Server error:", error);
|
|
1675
1792
|
}
|
|
1676
1793
|
});
|
|
1677
1794
|
} catch (error) {
|
|
1678
|
-
console.error("Ortoni
|
|
1795
|
+
console.error("Ortoni Report: Error starting the server:", error);
|
|
1679
1796
|
}
|
|
1680
1797
|
}
|
|
1681
1798
|
function openBrowser(url) {
|
|
@@ -1693,7 +1810,7 @@ function openBrowser(url) {
|
|
|
1693
1810
|
(0, import_child_process.spawn)(command, [url]);
|
|
1694
1811
|
}
|
|
1695
1812
|
} catch (error) {
|
|
1696
|
-
console.error("Ortoni
|
|
1813
|
+
console.error("Ortoni Report: Error opening the browser:", error);
|
|
1697
1814
|
}
|
|
1698
1815
|
}
|
|
1699
1816
|
|
|
@@ -1991,7 +2108,7 @@ var DatabaseManager = class {
|
|
|
1991
2108
|
};
|
|
1992
2109
|
|
|
1993
2110
|
// src/ortoni-report.ts
|
|
1994
|
-
var
|
|
2111
|
+
var import_path7 = __toESM(require("path"));
|
|
1995
2112
|
var OrtoniReport = class {
|
|
1996
2113
|
constructor(ortoniConfig = {}) {
|
|
1997
2114
|
this.ortoniConfig = ortoniConfig;
|
|
@@ -2022,8 +2139,9 @@ var OrtoniReport = class {
|
|
|
2022
2139
|
this.testResultProcessor = new TestResultProcessor(config.rootDir);
|
|
2023
2140
|
this.fileManager.ensureReportDirectory();
|
|
2024
2141
|
await this.dbManager.initialize(
|
|
2025
|
-
|
|
2142
|
+
import_path7.default.join(this.folderPath, "ortoni-data-history.sqlite")
|
|
2026
2143
|
);
|
|
2144
|
+
this.shardConfig = config?.shard;
|
|
2027
2145
|
}
|
|
2028
2146
|
onStdOut(chunk, _test, _result) {
|
|
2029
2147
|
if (this.reportsCount == 1 && this.showConsoleLogs) {
|
|
@@ -2040,7 +2158,7 @@ var OrtoniReport = class {
|
|
|
2040
2158
|
);
|
|
2041
2159
|
this.results.push(testResult);
|
|
2042
2160
|
} catch (error) {
|
|
2043
|
-
console.error("
|
|
2161
|
+
console.error("Ortoni Report: Error processing test end:", error);
|
|
2044
2162
|
}
|
|
2045
2163
|
}
|
|
2046
2164
|
printsToStdio() {
|
|
@@ -2059,6 +2177,32 @@ var OrtoniReport = class {
|
|
|
2059
2177
|
(r) => r.status !== "skipped"
|
|
2060
2178
|
);
|
|
2061
2179
|
const totalDuration = result.duration;
|
|
2180
|
+
if (this.shardConfig && this.shardConfig.total > 1) {
|
|
2181
|
+
const shard = this.shardConfig;
|
|
2182
|
+
const shardFile = `ortoni-shard-${shard.current}-of-${shard.total}.json`;
|
|
2183
|
+
const shardData = {
|
|
2184
|
+
status: result.status,
|
|
2185
|
+
duration: totalDuration,
|
|
2186
|
+
results: this.results,
|
|
2187
|
+
projectSet: Array.from(this.projectSet),
|
|
2188
|
+
userConfig: {
|
|
2189
|
+
projectName: this.ortoniConfig.projectName,
|
|
2190
|
+
authorName: this.ortoniConfig.authorName,
|
|
2191
|
+
type: this.ortoniConfig.testType,
|
|
2192
|
+
title: this.ortoniConfig.title
|
|
2193
|
+
},
|
|
2194
|
+
userMeta: {
|
|
2195
|
+
meta: this.ortoniConfig.meta
|
|
2196
|
+
}
|
|
2197
|
+
};
|
|
2198
|
+
const shardFilePath = this.fileManager.writeRawFile(
|
|
2199
|
+
shardFile,
|
|
2200
|
+
shardData
|
|
2201
|
+
);
|
|
2202
|
+
console.info(`Ortoni Report: Shard data written to ${shardFilePath}`);
|
|
2203
|
+
this.shouldGenerateReport = false;
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2062
2206
|
const runId = await this.dbManager.saveTestRun();
|
|
2063
2207
|
if (runId !== null) {
|
|
2064
2208
|
await this.dbManager.saveTestResults(runId, this.results);
|
|
@@ -2068,21 +2212,21 @@ var OrtoniReport = class {
|
|
|
2068
2212
|
this.results,
|
|
2069
2213
|
this.projectSet
|
|
2070
2214
|
);
|
|
2071
|
-
this.outputPath = this.fileManager.writeReportFile(
|
|
2215
|
+
this.outputPath = await this.fileManager.writeReportFile(
|
|
2072
2216
|
this.outputFilename,
|
|
2073
2217
|
finalReportData
|
|
2074
2218
|
);
|
|
2075
2219
|
} else {
|
|
2076
|
-
console.error("
|
|
2220
|
+
console.error("Ortoni Report: Error saving test run to database");
|
|
2077
2221
|
}
|
|
2078
2222
|
} else {
|
|
2079
2223
|
console.error(
|
|
2080
|
-
"
|
|
2224
|
+
"Ortoni Report: Report generation skipped due to error in Playwright worker!"
|
|
2081
2225
|
);
|
|
2082
2226
|
}
|
|
2083
2227
|
} catch (error) {
|
|
2084
2228
|
this.shouldGenerateReport = false;
|
|
2085
|
-
console.error("
|
|
2229
|
+
console.error("Ortoni Report: Error generating report:", error);
|
|
2086
2230
|
}
|
|
2087
2231
|
}
|
|
2088
2232
|
async onExit() {
|
|
@@ -2090,7 +2234,7 @@ var OrtoniReport = class {
|
|
|
2090
2234
|
await this.dbManager.close();
|
|
2091
2235
|
if (this.shouldGenerateReport) {
|
|
2092
2236
|
this.fileManager.copyTraceViewerAssets(this.skipTraceViewer);
|
|
2093
|
-
console.info(`Ortoni
|
|
2237
|
+
console.info(`Ortoni Report generated at ${this.outputPath}`);
|
|
2094
2238
|
this.serverManager.startServer(
|
|
2095
2239
|
this.folderPath,
|
|
2096
2240
|
this.outputFilename,
|
|
@@ -2100,7 +2244,7 @@ var OrtoniReport = class {
|
|
|
2100
2244
|
});
|
|
2101
2245
|
}
|
|
2102
2246
|
} catch (error) {
|
|
2103
|
-
console.error("
|
|
2247
|
+
console.error("Ortoni Report: Error in onExit:", error);
|
|
2104
2248
|
}
|
|
2105
2249
|
}
|
|
2106
2250
|
};
|