ortoni-report 2.0.4 → 2.0.5
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 +11 -0
- package/dist/ortoni-report.d.ts +27 -47
- package/dist/ortoni-report.js +23151 -268
- package/dist/ortoni-report.mjs +23146 -269
- package/dist/style/main.css +40 -1
- package/dist/utils/expressServer.js +33 -0
- package/dist/utils/utils.js +17 -1
- package/dist/utils/webSocketHelper.js +93 -0
- package/dist/views/main.hbs +168 -113
- package/dist/views/testPanel.hbs +0 -1
- package/dist/views/userInfo.hbs +10 -9
- package/package.json +3 -1
- package/readme.md +110 -67
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
exports.startReportServer = void 0;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
/**
|
|
9
|
+
* Starts an Express server to serve the HTML report and keeps it running.
|
|
10
|
+
* @param {string} reportPath - Path to the folder where the report is stored.
|
|
11
|
+
* @param {string} reportFilename - Name of the HTML report file to serve.
|
|
12
|
+
* @param {number} port - Port number to serve the report on (default is 8080).
|
|
13
|
+
*/
|
|
14
|
+
function startReportServer(reportPath, reportFilename, port = 8080) {
|
|
15
|
+
const app = (0, express_1.default)();
|
|
16
|
+
// Serve static files from the report directory
|
|
17
|
+
app.use(express_1.default.static(reportPath));
|
|
18
|
+
// Start the server and keep it running
|
|
19
|
+
const server = app.listen(port, () => {
|
|
20
|
+
const reportUrl = `http://localhost:${port}/${reportFilename}`;
|
|
21
|
+
console.log(`Report is available at ${reportUrl}`);
|
|
22
|
+
});
|
|
23
|
+
// Ensure that the process doesn't exit prematurely
|
|
24
|
+
process.on('SIGINT', () => {
|
|
25
|
+
console.log('Shutting down the server...');
|
|
26
|
+
server.close(() => {
|
|
27
|
+
console.log('Server closed');
|
|
28
|
+
process.exit(0);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
return server;
|
|
32
|
+
}
|
|
33
|
+
exports.startReportServer = startReportServer;
|
package/dist/utils/utils.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ensureHtmlExtension = exports.safeStringify = exports.formatDate = exports.normalizeFilePath = exports.msToTime = void 0;
|
|
6
|
+
exports.escapeHtml = exports.ensureHtmlExtension = exports.safeStringify = exports.formatDate = exports.normalizeFilePath = exports.msToTime = void 0;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
function msToTime(duration) {
|
|
9
9
|
const milliseconds = Math.floor(duration % 1000);
|
|
@@ -67,3 +67,19 @@ function ensureHtmlExtension(filename) {
|
|
|
67
67
|
return `${filename}.html`;
|
|
68
68
|
}
|
|
69
69
|
exports.ensureHtmlExtension = ensureHtmlExtension;
|
|
70
|
+
function escapeHtml(unsafe) {
|
|
71
|
+
if (typeof unsafe !== 'string') {
|
|
72
|
+
return String(unsafe);
|
|
73
|
+
}
|
|
74
|
+
return unsafe.replace(/[&<"']/g, function (match) {
|
|
75
|
+
const escapeMap = {
|
|
76
|
+
'&': '&',
|
|
77
|
+
'<': '<',
|
|
78
|
+
'>': '>',
|
|
79
|
+
'"': '"',
|
|
80
|
+
"'": '''
|
|
81
|
+
};
|
|
82
|
+
return escapeMap[match] || match;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
exports.escapeHtml = escapeHtml;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
const http_1 = __importDefault(require("http"));
|
|
30
|
+
const ws_1 = __importStar(require("ws"));
|
|
31
|
+
const utils_1 = require("./utils");
|
|
32
|
+
class WebSocketHelper {
|
|
33
|
+
constructor(port) {
|
|
34
|
+
this.port = port;
|
|
35
|
+
this.wss = null;
|
|
36
|
+
}
|
|
37
|
+
setupWebSocket() {
|
|
38
|
+
const server = http_1.default.createServer();
|
|
39
|
+
this.wss = new ws_1.WebSocketServer({ server });
|
|
40
|
+
this.wss.on('connection', (ws) => {
|
|
41
|
+
ws.send((0, utils_1.safeStringify)({ type: 'initial', data: 'Connected to WS service' }));
|
|
42
|
+
});
|
|
43
|
+
server.listen(this.port, () => {
|
|
44
|
+
console.log(`WebSocket server is running on http://localhost:${this.port}`);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
setupCleanup() {
|
|
48
|
+
const gracefulShutdown = () => {
|
|
49
|
+
console.log('Shutting down WebSocket server...');
|
|
50
|
+
this.closeWebSocket();
|
|
51
|
+
process.exit();
|
|
52
|
+
};
|
|
53
|
+
process.on('exit', gracefulShutdown);
|
|
54
|
+
process.on('SIGINT', () => {
|
|
55
|
+
console.log('Received SIGINT. Closing WebSocket server...');
|
|
56
|
+
gracefulShutdown();
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
broadcastUpdate(tests) {
|
|
60
|
+
if (this.wss) {
|
|
61
|
+
this.wss.clients.forEach((client) => {
|
|
62
|
+
if (client.readyState === ws_1.default.OPEN) {
|
|
63
|
+
client.send((0, utils_1.safeStringify)({ type: 'update', data: tests }));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
closeWebSocket() {
|
|
69
|
+
if (this.wss) {
|
|
70
|
+
this.wss.clients.forEach((client) => {
|
|
71
|
+
if (client.readyState === ws_1.default.OPEN) {
|
|
72
|
+
client.close(1000, 'Test run completed');
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
this.wss.close(() => {
|
|
76
|
+
console.log('WebSocket server closed');
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
testComplete() {
|
|
81
|
+
if (this.wss) {
|
|
82
|
+
this.wss.clients.forEach((client) => {
|
|
83
|
+
if (client.readyState === ws_1.default.OPEN) {
|
|
84
|
+
client.send((0, utils_1.safeStringify)({ type: 'complete', data: 'Test run completed' }));
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
this.closeWebSocket();
|
|
90
|
+
}, 1000);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.default = WebSocketHelper;
|
package/dist/views/main.hbs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en" data-theme="{{preferredTheme}}">
|
|
3
|
-
|
|
4
3
|
<head>
|
|
5
4
|
<meta charset="UTF-8">
|
|
6
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<meta name="description" content="Playwright HTML report by LetCode Koushik - V2.0.
|
|
6
|
+
<meta name="description" content="Playwright HTML report by LetCode Koushik - V2.0.5">
|
|
8
7
|
<title>{{title}}</title>
|
|
9
8
|
<link rel="icon" href="https://raw.githubusercontent.com/ortoniKC/ortoni-report/refs/heads/main/favicon.png"
|
|
10
9
|
type="image/x-icon">
|
|
@@ -15,7 +14,6 @@
|
|
|
15
14
|
<style>
|
|
16
15
|
{{{inlineCss}}}
|
|
17
16
|
</style>
|
|
18
|
-
|
|
19
17
|
<body>
|
|
20
18
|
{{> navbar }}
|
|
21
19
|
<section class="section">
|
|
@@ -26,7 +24,6 @@
|
|
|
26
24
|
{{> project}}
|
|
27
25
|
</aside>
|
|
28
26
|
<section class="column is-three-fifths">
|
|
29
|
-
{{!-- Overall summary --}}
|
|
30
27
|
<div id="summary">
|
|
31
28
|
<div class="columns is-multiline has-text-centered">
|
|
32
29
|
{{> summaryCard bg="primary" status="all" statusHeader="All Tests" statusCount=totalCount}}
|
|
@@ -40,13 +37,7 @@
|
|
|
40
37
|
{{> userInfo}}
|
|
41
38
|
</div>
|
|
42
39
|
</div>
|
|
43
|
-
|
|
44
|
-
<div id="testDetails" style="display: none;">
|
|
45
|
-
<!-- Back button should be outside the dynamic content -->
|
|
46
|
-
<button class="button content" id="back-to-summary" onclick="showSummary()">Back to
|
|
47
|
-
Summary</button>
|
|
48
|
-
<!-- Test Details will be displayed here -->
|
|
49
|
-
</div>
|
|
40
|
+
<div id="testDetails" style="display: none;"></div>
|
|
50
41
|
</section>
|
|
51
42
|
</div>
|
|
52
43
|
</main>
|
|
@@ -95,11 +86,18 @@
|
|
|
95
86
|
function showSummary() {
|
|
96
87
|
summary.style.display = 'block';
|
|
97
88
|
testDetails.style.display = 'none';
|
|
98
|
-
backButton.style.display = 'none';
|
|
99
89
|
}
|
|
100
90
|
window.showSummary = showSummary;
|
|
101
91
|
|
|
102
92
|
function displayTestDetails(test) {
|
|
93
|
+
const summary = document.getElementById('summary');
|
|
94
|
+
const testDetails = document.getElementById('testDetails');
|
|
95
|
+
summary.style.display = 'none';
|
|
96
|
+
testDetails.style.opacity = '0';
|
|
97
|
+
testDetails.style.display = 'block';
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
testDetails.style.opacity = '1';
|
|
100
|
+
}, 50);
|
|
103
101
|
let currentScreenshotIndex = 0;
|
|
104
102
|
function changeScreenshot(direction) {
|
|
105
103
|
const screenshots = test.screenshots;
|
|
@@ -125,85 +123,83 @@
|
|
|
125
123
|
}
|
|
126
124
|
});
|
|
127
125
|
}
|
|
128
|
-
const summary = document.getElementById('summary');
|
|
129
|
-
const testDetails = document.getElementById('testDetails');
|
|
130
|
-
const backButton = document.querySelector('button#back-to-summary');
|
|
131
|
-
summary.style.display = 'none';
|
|
132
|
-
testDetails.style.opacity = '0';
|
|
133
|
-
testDetails.style.display = 'block';
|
|
134
|
-
setTimeout(() => {
|
|
135
|
-
testDetails.style.opacity = '1';
|
|
136
|
-
backButton.style.opacity = '1';
|
|
137
|
-
}, 50);
|
|
138
|
-
|
|
139
126
|
let statusClass = '';
|
|
127
|
+
let statusIcon = '';
|
|
140
128
|
let statusText = test.status.toUpperCase();
|
|
129
|
+
|
|
141
130
|
if (test.status.startsWith('passed')) {
|
|
142
|
-
statusClass = '
|
|
131
|
+
statusClass = 'success';
|
|
132
|
+
statusIcon = 'check-circle';
|
|
143
133
|
} else if (test.status === 'flaky') {
|
|
144
|
-
statusClass = '
|
|
134
|
+
statusClass = 'warning';
|
|
135
|
+
statusIcon = 'exclamation-triangle';
|
|
145
136
|
} else if (test.status === 'failed') {
|
|
146
|
-
statusClass = '
|
|
137
|
+
statusClass = 'danger';
|
|
138
|
+
statusIcon = 'times-circle';
|
|
147
139
|
} else {
|
|
148
|
-
statusClass = '
|
|
140
|
+
statusClass = 'info';
|
|
141
|
+
statusIcon = 'question-circle';
|
|
149
142
|
}
|
|
150
|
-
|
|
151
143
|
testDetails.innerHTML = `
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
<
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
144
|
+
<div class="sticky-header">
|
|
145
|
+
<div class="card mb-3">
|
|
146
|
+
<button class="button is-info is-light mb-3" id="back-to-summary" onclick="showSummary()">
|
|
147
|
+
<span class="icon"><i class="fa fa-chevron-left" style="color: #63E6BE;"></i></span>
|
|
148
|
+
<span>Back to Summary</span>
|
|
149
|
+
</button>
|
|
150
|
+
<div class="card-content">
|
|
151
|
+
<div class="content has-text-centered">
|
|
152
|
+
<h1 class="title is-2">${test.title}</h1>
|
|
153
|
+
<p class="subtitle is-5" id="filepath">${test.location}</p>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
<footer class="card-footer">
|
|
157
|
+
<div class="card-footer-item">
|
|
158
|
+
<div class="columns is-mobile">
|
|
159
|
+
<div class="column is-half">
|
|
160
|
+
<div class="is-flex is-align-items-center">
|
|
161
|
+
<span class="icon status-icon has-text-${statusClass}">
|
|
162
|
+
<i class="fa fa-${statusIcon}"></i>
|
|
163
|
+
</span>
|
|
164
|
+
<span class="has-text-weight-bold is-uppercase has-text-${statusClass}">${test.status}</span>
|
|
172
165
|
</div>
|
|
173
|
-
</div>`: ""}
|
|
174
|
-
${test.testTags.length > 0 ? `
|
|
175
|
-
<div class="control mt-4">
|
|
176
|
-
<div class="tags has-addons">
|
|
177
|
-
<span class="tag is-dark">Test Tags</span>
|
|
178
|
-
<span class="tag is-info">${test.testTags.join(" ")}</span>
|
|
179
166
|
</div>
|
|
180
|
-
</div>`: ""}
|
|
181
|
-
${test.videoPath ? `
|
|
182
|
-
<div id="testVideo" class="modal">
|
|
183
|
-
<div class="modal-background"></div>
|
|
184
|
-
<div class="modal-content">
|
|
185
|
-
<figure>
|
|
186
|
-
<video controls>
|
|
187
|
-
<source src="file://${test.videoPath}" type="video/webm">
|
|
188
|
-
Your browser does not support the video tag.
|
|
189
|
-
</video>
|
|
190
|
-
</figure>
|
|
191
|
-
</div>
|
|
192
|
-
<button onclick="closeVideo()" class="modal-close is-large" aria-label="close"></button>
|
|
193
167
|
</div>
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
<div class="
|
|
198
|
-
<
|
|
199
|
-
|
|
200
|
-
|
|
168
|
+
</div>
|
|
169
|
+
${test.duration ? `
|
|
170
|
+
<div class="card-footer-item">
|
|
171
|
+
<div class="column is-half">
|
|
172
|
+
<div class="is-flex is-align-items-center">
|
|
173
|
+
<span class="icon status-icon has-text-info">
|
|
174
|
+
<i class="fa fa-clock"></i>
|
|
175
|
+
</span>
|
|
176
|
+
<span class="has-text-info has-text-weight-semibold">${test.duration}</span>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
` : ''}
|
|
181
|
+
${test.projectName ? `
|
|
182
|
+
<div class="card-footer-item">
|
|
183
|
+
<div class="is-flex is-align-items-center">
|
|
184
|
+
<span class="icon status-icon has-text-info">
|
|
185
|
+
<i class="fa fa-window-maximize" style="color: #B197FC;"></i>
|
|
186
|
+
</span>
|
|
187
|
+
<span class="" style="color: #B197FC;"> ${test.projectName}</span>
|
|
188
|
+
</div>
|
|
201
189
|
</div>
|
|
202
190
|
` : ''}
|
|
191
|
+
</footer>
|
|
203
192
|
</div>
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<div class="content-wrapper">
|
|
196
|
+
${test.status != "skipped" ?
|
|
197
|
+
`<div class="card mb-5">
|
|
198
|
+
<div class="card-content">
|
|
199
|
+
<div class="columns is-multiline">
|
|
200
|
+
${test.screenshots && test.screenshots.length > 0 ? `
|
|
201
|
+
<div class="column is-half">
|
|
202
|
+
<div id="testImage" class="modal">
|
|
207
203
|
<div class="modal-background"></div>
|
|
208
204
|
<div class="modal-content">
|
|
209
205
|
<p class="image">
|
|
@@ -213,10 +209,10 @@
|
|
|
213
209
|
<button onclick="closeModal()" class="modal-close is-large" aria-label="close"></button>
|
|
214
210
|
</div>
|
|
215
211
|
|
|
216
|
-
<figure class="image
|
|
212
|
+
<figure class="image">
|
|
217
213
|
<img id="screenshot-main-img" onclick="openModal()" src="${test.screenshots[0]}" alt="Screenshot">
|
|
218
214
|
</figure>
|
|
219
|
-
<nav class="pagination is-small is-centered ${test.screenshots.length > 1 ? '' : 'is-hidden'}" role="navigation" aria-label="pagination">
|
|
215
|
+
<nav class="mt-4 pagination is-small is-centered ${test.screenshots.length > 1 ? '' : 'is-hidden'}" role="navigation" aria-label="pagination">
|
|
220
216
|
<a class="pagination-previous" >Previous</a>
|
|
221
217
|
<a class="pagination-next" >Next</a>
|
|
222
218
|
<ul class="pagination-list">
|
|
@@ -226,55 +222,115 @@
|
|
|
226
222
|
</li>`).join('')}
|
|
227
223
|
</ul>
|
|
228
224
|
</nav>
|
|
229
|
-
|
|
225
|
+
</div>
|
|
226
|
+
` : ''}
|
|
227
|
+
${test.videoPath ? `
|
|
228
|
+
<div class="column is-half">
|
|
229
|
+
<div class="video-preview" onclick="openVideo()">
|
|
230
|
+
<video controls width="100%" height="auto" preload="metadata">
|
|
231
|
+
<source src="${test.videoPath}" type="video/webm">
|
|
232
|
+
Your browser does not support the video tag.
|
|
233
|
+
</video>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
` : ''}
|
|
237
|
+
</div>
|
|
238
|
+
${test.tracePath ? `
|
|
239
|
+
<div class="columns is-centered">
|
|
240
|
+
<div class="column is-3">
|
|
241
|
+
<a href="trace/index.html?trace=http://localhost:${test.port}/${test.tracePath}" target="_blank" class="button is-link is-fullwidth mt-3">
|
|
242
|
+
<span class="icon"><i class="fa-solid fa-tv" style="color: #FFD43B;"></i></span>
|
|
243
|
+
<span class="has-text-white pl-2">View Trace</span>
|
|
244
|
+
</a>
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
` : ''}
|
|
230
248
|
</div>
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
<
|
|
234
|
-
|
|
235
|
-
|
|
249
|
+
</div>` : ''}
|
|
250
|
+
${test.annotations.length || test.testTags.length > 0 ? `
|
|
251
|
+
<div class="card mb-5">
|
|
252
|
+
<header class="card-header">
|
|
253
|
+
<p class="card-header-title">Additional Information</p>
|
|
254
|
+
</header>
|
|
255
|
+
<div class="card-content">
|
|
256
|
+
<div class="content">
|
|
257
|
+
${test.testTags.length > 0 ? `
|
|
258
|
+
<div class="control mb-4">
|
|
259
|
+
<div class="tags is-rounded">
|
|
260
|
+
${test.testTags.map(tag => `<span class="tag is-primary is-medium">${tag}</span>`).join('')}
|
|
261
|
+
</div>
|
|
262
|
+
</div>` : ""}
|
|
263
|
+
${test.annotations
|
|
236
264
|
.filter(annotation => annotation !== null && annotation !== undefined)
|
|
237
265
|
.map(annotation => `
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
<br>
|
|
241
|
-
${annotation?.description ? `<strong class="has-text-link">Description: </strong><span>${annotation?.description}</span>` : ''}
|
|
242
|
-
</div>
|
|
266
|
+
<div class="mb-4">
|
|
267
|
+
${annotation?.type ? `<strong class="has-text-link">Type: </strong><span>${annotation.type}</span>` : ''}
|
|
243
268
|
<br>
|
|
269
|
+
${annotation?.description ? `<strong class="has-text-link">Description: </strong><span>${annotation.description}</span>` : ''}
|
|
270
|
+
</div>
|
|
244
271
|
`).join('')}
|
|
245
272
|
</div>
|
|
246
|
-
</
|
|
247
|
-
|
|
248
|
-
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
` : ''}
|
|
249
276
|
${test.steps.length > 0 ? `
|
|
250
|
-
<
|
|
251
|
-
|
|
252
|
-
<
|
|
253
|
-
</
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
277
|
+
<div class="card">
|
|
278
|
+
<header class="card-header">
|
|
279
|
+
<p class="card-header-title">Steps</p>
|
|
280
|
+
</header>
|
|
281
|
+
<div class="card-content">
|
|
282
|
+
<div class="content">
|
|
283
|
+
<span id="stepDetails" class="content"></span>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
` : ''}
|
|
257
288
|
${test.errors.length ? `
|
|
258
|
-
<
|
|
259
|
-
<
|
|
289
|
+
<div class="card mt-5">
|
|
290
|
+
<header class="card-header">
|
|
291
|
+
<p class="card-header-title">Errors</p>
|
|
292
|
+
</header>
|
|
293
|
+
<div class="card-content">
|
|
294
|
+
<div class="content">
|
|
260
295
|
<pre><code class="data-lang=js">${test.errors.join('\n')}</code></pre>
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
</div>
|
|
299
|
+
` : ''}
|
|
264
300
|
${test.logs ? `
|
|
265
|
-
<
|
|
266
|
-
<
|
|
301
|
+
<div class="card mt-5">
|
|
302
|
+
<header class="card-header">
|
|
303
|
+
<p class="card-header-title">Logs</p>
|
|
304
|
+
</header>
|
|
305
|
+
<div class="card-content">
|
|
306
|
+
<div class="content">
|
|
267
307
|
<pre>${test.logs}</pre>
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
` : ''}
|
|
312
|
+
${test.videoPath ? `
|
|
313
|
+
<div id="testVideo" class="modal">
|
|
314
|
+
<div class="modal-background"></div>
|
|
315
|
+
<div class="modal-content">
|
|
316
|
+
<div class="box">
|
|
317
|
+
<video controls style="width: 100%;">
|
|
318
|
+
<source src="${test.videoPath}" type="video/webm">
|
|
319
|
+
Your browser does not support the video tag.
|
|
320
|
+
</video>
|
|
321
|
+
</div>
|
|
322
|
+
</div>
|
|
323
|
+
<button class="modal-close is-large" aria-label="close" onclick="closeVideo()"></button>
|
|
324
|
+
</div>
|
|
325
|
+
` : ''}
|
|
326
|
+
</div>`
|
|
327
|
+
if (test.screenshots.length > 0) {
|
|
272
328
|
document.querySelector('.pagination-previous').addEventListener('click', () => changeScreenshot(-1));
|
|
273
329
|
document.querySelector('.pagination-next').addEventListener('click', () => changeScreenshot(1));
|
|
274
330
|
document.querySelectorAll('.pagination-link').forEach((link, index) => {
|
|
275
331
|
link.addEventListener('click', () => gotoScreenshot(index));
|
|
276
332
|
});
|
|
277
|
-
}
|
|
333
|
+
}
|
|
278
334
|
const stepDetailsDiv = document.getElementById('stepDetails');
|
|
279
335
|
if (stepDetailsDiv) {
|
|
280
336
|
const stepsList = attachSteps(test);
|
|
@@ -282,7 +338,6 @@
|
|
|
282
338
|
stepDetailsDiv.appendChild(stepsList);
|
|
283
339
|
}
|
|
284
340
|
}
|
|
285
|
-
|
|
286
341
|
function attachSteps(test) {
|
|
287
342
|
const stepsList = document.createElement("ul");
|
|
288
343
|
stepsList.setAttribute("id", "steps");
|
package/dist/views/testPanel.hbs
CHANGED
package/dist/views/userInfo.hbs
CHANGED
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
</p>
|
|
31
31
|
</div>
|
|
32
32
|
</div>
|
|
33
|
+
{{#if (or authorName testType)}}
|
|
33
34
|
<div class="column is-half">
|
|
34
35
|
<div class="content">
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<div class="field"></div>
|
|
36
|
+
{{#if authorName}}
|
|
37
|
+
<div class="field">
|
|
38
38
|
<label class="label" for="Tester">Tester</label>
|
|
39
39
|
<p class="is-flex is-align-items-center">
|
|
40
40
|
<span class="icon has-text-info mr-2">
|
|
@@ -44,9 +44,10 @@
|
|
|
44
44
|
</p>
|
|
45
45
|
</div>
|
|
46
46
|
{{/if}}
|
|
47
|
+
|
|
47
48
|
{{#if testType}}
|
|
48
49
|
<div class="field">
|
|
49
|
-
<label class="label" for="
|
|
50
|
+
<label class="label" for="testType">Test Type</label>
|
|
50
51
|
<p class="is-flex is-align-items-center">
|
|
51
52
|
<span class="icon has-text-primary mr-2">
|
|
52
53
|
<i class="fas fa-code-branch"></i>
|
|
@@ -57,6 +58,7 @@
|
|
|
57
58
|
{{/if}}
|
|
58
59
|
</div>
|
|
59
60
|
</div>
|
|
61
|
+
{{/if}}
|
|
60
62
|
</div>
|
|
61
63
|
<div class="columns">
|
|
62
64
|
<div class="column is-half">
|
|
@@ -91,9 +93,8 @@
|
|
|
91
93
|
labels: ['Passed', 'Failed', 'Skipped', 'Flaky'],
|
|
92
94
|
datasets: [{
|
|
93
95
|
data: [{{ passCount }}, {{ failCount }}, {{ skipCount }}, {{ flakyCount }}],
|
|
94
|
-
backgroundColor: ['#28a745', '#ff6685', '#66d1ff', '#ffb70f']
|
|
95
|
-
|
|
96
|
-
},
|
|
96
|
+
backgroundColor: ['#28a745', '#ff6685', '#66d1ff', '#ffb70f']}]
|
|
97
|
+
},
|
|
97
98
|
options: {
|
|
98
99
|
responsive: true,
|
|
99
100
|
maintainAspectRatio: false,
|
|
@@ -109,7 +110,7 @@
|
|
|
109
110
|
},
|
|
110
111
|
tooltip: {
|
|
111
112
|
callbacks: {
|
|
112
|
-
label: function(tooltipItem) {
|
|
113
|
+
label: function (tooltipItem) {
|
|
113
114
|
const total = tooltipItem.dataset.data.reduce((a, b) => a + b, 0);
|
|
114
115
|
const value = tooltipItem.raw;
|
|
115
116
|
const percentage = ((value / total) * 100).toFixed(2);
|
|
@@ -187,7 +188,7 @@
|
|
|
187
188
|
{
|
|
188
189
|
label: 'Flaky',
|
|
189
190
|
data: retryTests,
|
|
190
|
-
backgroundColor:
|
|
191
|
+
backgroundColor: '#ffb70f',
|
|
191
192
|
}
|
|
192
193
|
]
|
|
193
194
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ortoni-report",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "Playwright Report By LetCode with Koushik",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"tsc": "tsc",
|
|
@@ -32,9 +32,11 @@
|
|
|
32
32
|
"homepage": "https://github.com/ortoniKC/ortoni-report#readme",
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@playwright/test": "^1.44.1",
|
|
35
|
+
"@types/express": "^5.0.0",
|
|
35
36
|
"@types/node": "^22.0.2",
|
|
36
37
|
"@types/ws": "^8.5.12",
|
|
37
38
|
"ansi-to-html": "^0.7.2",
|
|
39
|
+
"express": "^4.21.1",
|
|
38
40
|
"handlebars": "^4.7.8",
|
|
39
41
|
"tsup": "^6.5.0",
|
|
40
42
|
"typescript": "^4.9.4",
|