ortoni-report 2.0.2 → 2.0.4
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 +34 -0
- package/dist/ortoni-report.d.ts +16 -3
- package/dist/ortoni-report.js +856 -661
- package/dist/ortoni-report.mjs +856 -661
- package/dist/style/main.css +89 -0
- package/dist/views/main.hbs +480 -0
- package/dist/views/navbar.hbs +46 -0
- package/dist/views/project.hbs +132 -0
- package/dist/views/summaryCard.hbs +8 -0
- package/dist/views/testPanel.hbs +37 -0
- package/dist/views/testStatus.hbs +33 -0
- package/dist/views/userInfo.hbs +208 -0
- package/package.json +6 -14
- package/readme.md +19 -42
- package/dist/cli/cli.js +0 -49
- package/dist/css/main.css +0 -22444
- package/dist/icon/32.png +0 -0
- package/dist/icon/fail.png +0 -0
- package/dist/icon/file.png +0 -0
- package/dist/icon/flaky.png +0 -0
- package/dist/icon/pass.png +0 -0
- package/dist/icon/retry.png +0 -0
- package/dist/icon/skip.png +0 -0
- package/dist/icon/test.png +0 -0
- package/dist/icon/timeout.png +0 -0
- package/dist/report-template.hbs +0 -823
- package/dist/utils/chart.js +0 -11128
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" data-theme="{{preferredTheme}}">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<meta name="description" content="Playwright HTML report by LetCode Koushik - V2.0.4">
|
|
8
|
+
<title>{{title}}</title>
|
|
9
|
+
<link rel="icon" href="https://raw.githubusercontent.com/ortoniKC/ortoni-report/refs/heads/main/favicon.png"
|
|
10
|
+
type="image/x-icon">
|
|
11
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css"
|
|
12
|
+
integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg=="
|
|
13
|
+
crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
14
|
+
</head>
|
|
15
|
+
<style>
|
|
16
|
+
{{{inlineCss}}}
|
|
17
|
+
</style>
|
|
18
|
+
|
|
19
|
+
<body>
|
|
20
|
+
{{> navbar }}
|
|
21
|
+
<section class="section">
|
|
22
|
+
<main class="container">
|
|
23
|
+
<div class="columns">
|
|
24
|
+
<aside class="column is-two-fifths">
|
|
25
|
+
{{> testPanel}}
|
|
26
|
+
{{> project}}
|
|
27
|
+
</aside>
|
|
28
|
+
<section class="column is-three-fifths">
|
|
29
|
+
{{!-- Overall summary --}}
|
|
30
|
+
<div id="summary">
|
|
31
|
+
<div class="columns is-multiline has-text-centered">
|
|
32
|
+
{{> summaryCard bg="primary" status="all" statusHeader="All Tests" statusCount=totalCount}}
|
|
33
|
+
{{> summaryCard bg="success" status="passed" statusHeader="Passed" statusCount=passCount}}
|
|
34
|
+
{{> summaryCard bg="danger" status="failed" statusHeader="Failed" statusCount=failCount}}
|
|
35
|
+
{{> summaryCard bg="info" status="skipped" statusHeader="Skipped" statusCount=skipCount}}
|
|
36
|
+
{{> summaryCard bg="warning" status="flaky" statusHeader="Flaky" statusCount=flakyCount}}
|
|
37
|
+
{{> summaryCard bg="retry" status="retry" statusHeader="Retry" statusCount=retryCount}}
|
|
38
|
+
</div>
|
|
39
|
+
<div class="box">
|
|
40
|
+
{{> userInfo}}
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
{{!-- Test details --}}
|
|
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>
|
|
50
|
+
</section>
|
|
51
|
+
</div>
|
|
52
|
+
</main>
|
|
53
|
+
</section>
|
|
54
|
+
<script>
|
|
55
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
56
|
+
let testData = {{{ json results }}};
|
|
57
|
+
const testDetails = document.getElementById('testDetails');
|
|
58
|
+
const summary = document.getElementById('summary');
|
|
59
|
+
const backButton = document.querySelector('button#back-to-summary');
|
|
60
|
+
|
|
61
|
+
const themeButton = document.getElementById("toggle-theme");
|
|
62
|
+
const preferredTheme = themeButton.getAttribute("data-theme-status");
|
|
63
|
+
const themeIcon = document.getElementById("theme-icon");
|
|
64
|
+
const htmlElement = document.documentElement;
|
|
65
|
+
|
|
66
|
+
if (preferredTheme === 'dark') {
|
|
67
|
+
htmlElement.setAttribute('data-theme', 'dark');
|
|
68
|
+
themeIcon.classList = '';
|
|
69
|
+
themeIcon.classList.add("fa", "fa-moon");
|
|
70
|
+
} else if (preferredTheme === 'light') {
|
|
71
|
+
htmlElement.setAttribute('data-theme', 'light');
|
|
72
|
+
themeIcon.classList = '';
|
|
73
|
+
themeIcon.classList.add("fa", "fa-sun");
|
|
74
|
+
} else {
|
|
75
|
+
if (window.matchMedia('(prefers-color-scheme: light)').matches) {
|
|
76
|
+
themeIcon.classList.add("fa", "fa-sun");
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
themeIcon.classList.add("fa", "fa-moon");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
themeButton.addEventListener('click', () => {
|
|
83
|
+
const currentTheme = htmlElement.getAttribute('data-theme');
|
|
84
|
+
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
|
|
85
|
+
htmlElement.setAttribute('data-theme', newTheme);
|
|
86
|
+
if (newTheme === 'dark') {
|
|
87
|
+
themeIcon.classList = '';
|
|
88
|
+
themeIcon.classList.add("fa", "fa-moon");
|
|
89
|
+
} else {
|
|
90
|
+
themeIcon.classList = '';
|
|
91
|
+
themeIcon.classList.add("fa", "fa-sun");
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
function showSummary() {
|
|
96
|
+
summary.style.display = 'block';
|
|
97
|
+
testDetails.style.display = 'none';
|
|
98
|
+
backButton.style.display = 'none';
|
|
99
|
+
}
|
|
100
|
+
window.showSummary = showSummary;
|
|
101
|
+
|
|
102
|
+
function displayTestDetails(test) {
|
|
103
|
+
let currentScreenshotIndex = 0;
|
|
104
|
+
function changeScreenshot(direction) {
|
|
105
|
+
const screenshots = test.screenshots;
|
|
106
|
+
currentScreenshotIndex = (currentScreenshotIndex + direction + screenshots.length) % screenshots.length;
|
|
107
|
+
updateScreenshot();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function gotoScreenshot(index) {
|
|
111
|
+
currentScreenshotIndex = index;
|
|
112
|
+
updateScreenshot();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function updateScreenshot() {
|
|
116
|
+
const screenshots = test.screenshots;
|
|
117
|
+
document.getElementById('screenshot-main-img').src = screenshots[currentScreenshotIndex];
|
|
118
|
+
document.getElementById('screenshot-modal-img').src = screenshots[currentScreenshotIndex];
|
|
119
|
+
|
|
120
|
+
document.querySelectorAll('.pagination-link').forEach((link, index) => {
|
|
121
|
+
if (index === currentScreenshotIndex) {
|
|
122
|
+
link.classList.add('is-current');
|
|
123
|
+
} else {
|
|
124
|
+
link.classList.remove('is-current');
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
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
|
+
let statusClass = '';
|
|
140
|
+
let statusText = test.status.toUpperCase();
|
|
141
|
+
if (test.status.startsWith('passed')) {
|
|
142
|
+
statusClass = 'tag is-success';
|
|
143
|
+
} else if (test.status === 'flaky') {
|
|
144
|
+
statusClass = 'tag is-warning';
|
|
145
|
+
} else if (test.status === 'failed') {
|
|
146
|
+
statusClass = 'tag is-danger';
|
|
147
|
+
} else {
|
|
148
|
+
statusClass = 'tag is-info';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
testDetails.innerHTML = `
|
|
152
|
+
<button class="button is-info is-light mb-4" id="back-to-summary" style="display: block"
|
|
153
|
+
onclick="showSummary()">
|
|
154
|
+
<span class="icon"><i class="fa-solid fa-chevron-left" style="color: #63E6BE;"></i></span>
|
|
155
|
+
<span>Back to Summary</span></button>
|
|
156
|
+
<div class="content has-text-centered">
|
|
157
|
+
<p class="title">${test.title}</p>
|
|
158
|
+
<p class="subtitle" id="filepath">${test.location}</p>
|
|
159
|
+
</div>
|
|
160
|
+
<div class="columns">
|
|
161
|
+
<div class="column content">
|
|
162
|
+
<h4 class="title is-4">Status</h4>
|
|
163
|
+
<p class="${statusClass}">${statusText}</p>
|
|
164
|
+
${test.duration.length > 0 ? `
|
|
165
|
+
<h4 class="title is-4">Duration</h4>
|
|
166
|
+
<p class="${statusClass}">${test.duration}</p>` : ""}
|
|
167
|
+
${test.projectName.length > 0 ? `
|
|
168
|
+
<div class="control">
|
|
169
|
+
<div class="tags has-addons">
|
|
170
|
+
<span class="tag is-dark">Project</span>
|
|
171
|
+
<span class="tag is-info is-capitalized">${test.projectName}</span>
|
|
172
|
+
</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
|
+
</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
|
+
</div>
|
|
194
|
+
<button class="button mt-4" onclick="openVideo()">Attachment: Video</button>
|
|
195
|
+
`: ''}
|
|
196
|
+
${test.tracePath ? `
|
|
197
|
+
<div class="trace-viewer mt-4">
|
|
198
|
+
<a href="${test.tracePath}" target="_blank" class="button is-small is-link">
|
|
199
|
+
View Trace
|
|
200
|
+
</a>
|
|
201
|
+
</div>
|
|
202
|
+
` : ''}
|
|
203
|
+
</div>
|
|
204
|
+
<div class="column content">
|
|
205
|
+
${test.screenshots && test.screenshots.length > 0 ? `
|
|
206
|
+
<div id="testImage" class="modal">
|
|
207
|
+
<div class="modal-background"></div>
|
|
208
|
+
<div class="modal-content">
|
|
209
|
+
<p class="image">
|
|
210
|
+
<img id="screenshot-modal-img" src="${test.screenshots[0]}" alt="Screenshot">
|
|
211
|
+
</p>
|
|
212
|
+
</div>
|
|
213
|
+
<button onclick="closeModal()" class="modal-close is-large" aria-label="close"></button>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<figure class="image box">
|
|
217
|
+
<img id="screenshot-main-img" onclick="openModal()" src="${test.screenshots[0]}" alt="Screenshot">
|
|
218
|
+
</figure>
|
|
219
|
+
<nav class="pagination is-small is-centered ${test.screenshots.length > 1 ? '' : 'is-hidden'}" role="navigation" aria-label="pagination">
|
|
220
|
+
<a class="pagination-previous" >Previous</a>
|
|
221
|
+
<a class="pagination-next" >Next</a>
|
|
222
|
+
<ul class="pagination-list">
|
|
223
|
+
${test.screenshots.map((_, index) => `
|
|
224
|
+
<li>
|
|
225
|
+
<a class="pagination-link ${index === 0 ? 'is-current' : ''}" aria-label="Goto screenshot ${index + 1}" >${index + 1}</a>
|
|
226
|
+
</li>`).join('')}
|
|
227
|
+
</ul>
|
|
228
|
+
</nav>
|
|
229
|
+
` : ''}
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
${test.annotations && test.annotations.length ? `
|
|
233
|
+
<article class="message">
|
|
234
|
+
<div class="message-body">
|
|
235
|
+
${test.annotations
|
|
236
|
+
.filter(annotation => annotation !== null && annotation !== undefined)
|
|
237
|
+
.map(annotation => `
|
|
238
|
+
<div>
|
|
239
|
+
${annotation?.type ? `<strong class="has-text-link">Type: </strong><span>${annotation?.type}</span>` : ''}
|
|
240
|
+
<br>
|
|
241
|
+
${annotation?.description ? `<strong class="has-text-link">Description: </strong><span>${annotation?.description}</span>` : ''}
|
|
242
|
+
</div>
|
|
243
|
+
<br>
|
|
244
|
+
`).join('')}
|
|
245
|
+
</div>
|
|
246
|
+
</article>
|
|
247
|
+
` : ``}
|
|
248
|
+
<div class="content">
|
|
249
|
+
${test.steps.length > 0 ? `
|
|
250
|
+
<details id="stepopen" open>
|
|
251
|
+
<summary><h4 class="title is-4">Steps</h4></summary>
|
|
252
|
+
<span id="stepDetails" class="content"></span>
|
|
253
|
+
</details>
|
|
254
|
+
`: ``}
|
|
255
|
+
</div class="content">
|
|
256
|
+
<div>
|
|
257
|
+
${test.errors.length ? `
|
|
258
|
+
<h4 class="title is-4">Errors</h4>
|
|
259
|
+
<div class="content">
|
|
260
|
+
<pre><code class="data-lang=js">${test.errors.join('\n')}</code></pre>
|
|
261
|
+
</div>` : ''}
|
|
262
|
+
</div>
|
|
263
|
+
<div>
|
|
264
|
+
${test.logs ? `
|
|
265
|
+
<h4 class="title is-4">Logs</h4>
|
|
266
|
+
<div class="box">
|
|
267
|
+
<pre>${test.logs}</pre>
|
|
268
|
+
</div>` : ''}
|
|
269
|
+
</div>
|
|
270
|
+
`;
|
|
271
|
+
if(test.screenshots.length > 0){
|
|
272
|
+
document.querySelector('.pagination-previous').addEventListener('click', () => changeScreenshot(-1));
|
|
273
|
+
document.querySelector('.pagination-next').addEventListener('click', () => changeScreenshot(1));
|
|
274
|
+
document.querySelectorAll('.pagination-link').forEach((link, index) => {
|
|
275
|
+
link.addEventListener('click', () => gotoScreenshot(index));
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
const stepDetailsDiv = document.getElementById('stepDetails');
|
|
279
|
+
if (stepDetailsDiv) {
|
|
280
|
+
const stepsList = attachSteps(test);
|
|
281
|
+
const detail = document.getElementById("stepopen");
|
|
282
|
+
stepDetailsDiv.appendChild(stepsList);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function attachSteps(test) {
|
|
287
|
+
const stepsList = document.createElement("ul");
|
|
288
|
+
stepsList.setAttribute("id", "steps");
|
|
289
|
+
stepsList.innerHTML = '';
|
|
290
|
+
test.steps.forEach(step => {
|
|
291
|
+
const li = document.createElement('li');
|
|
292
|
+
li.innerHTML = `<strong class="${step.snippet ? 'has-text-danger' : ''}">${step.title}</strong>`;
|
|
293
|
+
if (step.snippet) {
|
|
294
|
+
const pre = document.createElement('pre');
|
|
295
|
+
const code = document.createElement('code');
|
|
296
|
+
const locationText = step.location ? `\n\nat: ${step.location}` : '';
|
|
297
|
+
code.innerHTML = `${step.snippet}${locationText}`;
|
|
298
|
+
code.setAttribute('data-lang', 'js');
|
|
299
|
+
pre.appendChild(code);
|
|
300
|
+
li.appendChild(pre);
|
|
301
|
+
}
|
|
302
|
+
stepsList.appendChild(li);
|
|
303
|
+
});
|
|
304
|
+
return stepsList;
|
|
305
|
+
}
|
|
306
|
+
function openModal() {
|
|
307
|
+
let modal = document.querySelector("#testImage");
|
|
308
|
+
modal.classList.add("is-active");
|
|
309
|
+
}
|
|
310
|
+
function openVideo() {
|
|
311
|
+
let modal = document.querySelector("#testVideo");
|
|
312
|
+
modal.classList.add("is-active");
|
|
313
|
+
}
|
|
314
|
+
function closeVideo() {
|
|
315
|
+
let modal = document.querySelector("#testVideo");
|
|
316
|
+
modal.classList.remove("is-active");
|
|
317
|
+
}
|
|
318
|
+
function closeModal() {
|
|
319
|
+
let modal = document.querySelector("#testImage");
|
|
320
|
+
modal.classList.remove("is-active");
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
window.openModal = openModal;
|
|
324
|
+
window.openVideo = openVideo;
|
|
325
|
+
window.closeVideo = closeVideo;
|
|
326
|
+
window.closeModal = closeModal;
|
|
327
|
+
|
|
328
|
+
document.addEventListener('keydown', (event) => {
|
|
329
|
+
if (event.key === "Escape") {
|
|
330
|
+
closeModal();
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
function attachEventListeners() {
|
|
335
|
+
const checkboxes = document.querySelectorAll('#select-filter input[type="checkbox"]');
|
|
336
|
+
checkboxes.forEach(checkbox => {
|
|
337
|
+
checkbox.addEventListener('change', applyFilters);
|
|
338
|
+
});
|
|
339
|
+
const testItems = document.querySelectorAll('[data-test-id]');
|
|
340
|
+
testItems.forEach(item => {
|
|
341
|
+
item.addEventListener('click', () => {
|
|
342
|
+
testItems.forEach(i => i.classList.remove('listselected'));
|
|
343
|
+
item.classList.add('listselected');
|
|
344
|
+
const testId = item.getAttribute('data-test-id');
|
|
345
|
+
const test = testData[testId];
|
|
346
|
+
displayTestDetails(test);
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
const filters = document.querySelectorAll('.filter');
|
|
350
|
+
filters.forEach(filter => {
|
|
351
|
+
filter.addEventListener('click', () => {
|
|
352
|
+
const status = filter.getAttribute('data-status');
|
|
353
|
+
filters.forEach(f => {
|
|
354
|
+
if (f.getAttribute('data-status')) {
|
|
355
|
+
f.classList.remove('active');
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
filter.classList.add('active');
|
|
359
|
+
applyFilters();
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function applyFilters() {
|
|
365
|
+
const selectedCheckboxes = document.querySelectorAll('#select-filter input[type="checkbox"]:checked');
|
|
366
|
+
const activeFilter = document.querySelector('.filter.active');
|
|
367
|
+
const selectedStatus = activeFilter ? activeFilter.getAttribute('data-status') : 'all';
|
|
368
|
+
const selectedProjects = [];
|
|
369
|
+
const selectedTags = [];
|
|
370
|
+
selectedCheckboxes.forEach(checkbox => {
|
|
371
|
+
if (checkbox.getAttribute('data-filter-type') === 'project') {
|
|
372
|
+
selectedProjects.push(checkbox.value.trim());
|
|
373
|
+
} else {
|
|
374
|
+
selectedTags.push(checkbox.value.trim());
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
const detailsElements = document.querySelectorAll('.sidebar details');
|
|
378
|
+
detailsElements.forEach(details => {
|
|
379
|
+
let shouldShowDetails = false;
|
|
380
|
+
const items = details.querySelectorAll('li[data-test-id]');
|
|
381
|
+
items.forEach(item => {
|
|
382
|
+
const testTags = item.getAttribute('data-test-tags').trim().split(' ').filter(Boolean);
|
|
383
|
+
const projectName = item.getAttribute('data-project-name').trim();
|
|
384
|
+
const testStatus = item.getAttribute('data-test-status').trim();
|
|
385
|
+
const matchesProject = selectedProjects.length === 0 || selectedProjects.includes(projectName);
|
|
386
|
+
const matchesTags = selectedTags.length === 0 || selectedTags.every(tag => testTags.includes(tag));
|
|
387
|
+
const matchesStatus = (selectedStatus === 'all' && testStatus !== 'skipped') ||
|
|
388
|
+
(selectedStatus !== 'all' && (
|
|
389
|
+
testStatus === selectedStatus ||
|
|
390
|
+
(selectedStatus === 'failed' && (testStatus === 'failed' || testStatus === 'timedOut')) ||
|
|
391
|
+
(selectedStatus === 'retry' && testStatus.includes('retry')) ||
|
|
392
|
+
(selectedStatus === 'flaky' && testStatus.includes('flaky'))
|
|
393
|
+
));
|
|
394
|
+
if (matchesProject && matchesTags && matchesStatus) {
|
|
395
|
+
item.classList.remove('is-hidden');
|
|
396
|
+
shouldShowDetails = true;
|
|
397
|
+
} else {
|
|
398
|
+
item.classList.add('is-hidden');
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
details.open = shouldShowDetails;
|
|
402
|
+
details.classList.toggle('is-hidden', !shouldShowDetails);
|
|
403
|
+
});
|
|
404
|
+
updateSelectedFiltersDisplay(selectedProjects, selectedTags, selectedStatus);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function updateSelectedFiltersDisplay(projects, tags, status) {
|
|
408
|
+
const filtersDisplay = document.getElementById('selected-filters');
|
|
409
|
+
filtersDisplay.innerHTML = '';
|
|
410
|
+
|
|
411
|
+
if (projects.length > 0) {
|
|
412
|
+
filtersDisplay.innerHTML += `<span> Projects: ${projects.join(', ')}</span>`;
|
|
413
|
+
}
|
|
414
|
+
if (tags.length > 0) {
|
|
415
|
+
filtersDisplay.innerHTML += `<span> Tags: ${tags.join(', ')}</span>`;
|
|
416
|
+
}
|
|
417
|
+
if (status !== 'all') {
|
|
418
|
+
filtersDisplay.innerHTML += `<span> Status: ${status}</span>`;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (filtersDisplay.innerHTML === '') {
|
|
422
|
+
filtersDisplay.innerHTML = '<span>All Tests</span>';
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
const searchInput = document.querySelector('input[name="search"]');
|
|
426
|
+
const detailsElements = document.querySelectorAll('details');
|
|
427
|
+
function filterTests(search) {
|
|
428
|
+
const searchTerm = search.toLowerCase();
|
|
429
|
+
const testItems = document.querySelectorAll('[data-test-id]');
|
|
430
|
+
|
|
431
|
+
if (searchTerm) {
|
|
432
|
+
detailsElements.forEach(detail => {
|
|
433
|
+
detail.open = false; // Collapse all details initially
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
testItems.forEach(item => {
|
|
437
|
+
const testTitle = item.textContent.toLowerCase();
|
|
438
|
+
if (testTitle.includes(searchTerm)) {
|
|
439
|
+
item.style.display = 'block'; // Show matching test item
|
|
440
|
+
|
|
441
|
+
let parent = item.parentElement;
|
|
442
|
+
while (parent && parent.tagName !== 'ASIDE') {
|
|
443
|
+
if (parent.tagName === 'DETAILS') {
|
|
444
|
+
parent.open = true;
|
|
445
|
+
}
|
|
446
|
+
parent = parent.parentElement;
|
|
447
|
+
}
|
|
448
|
+
} else {
|
|
449
|
+
item.style.display = 'none';
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
} else {
|
|
453
|
+
testItems.forEach(item => {
|
|
454
|
+
item.style.display = 'block';
|
|
455
|
+
});
|
|
456
|
+
detailsElements.forEach(detail => {
|
|
457
|
+
detail.open = false;
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
function debounce(func, wait) {
|
|
462
|
+
let timeout;
|
|
463
|
+
return function (...args) {
|
|
464
|
+
clearTimeout(timeout);
|
|
465
|
+
timeout = setTimeout(() => func.apply(this, args), wait);
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const debouncedSearch = debounce((event) => {
|
|
470
|
+
filterTests(event.target.value);
|
|
471
|
+
}, 300);
|
|
472
|
+
|
|
473
|
+
searchInput.addEventListener('input', debouncedSearch);
|
|
474
|
+
|
|
475
|
+
attachEventListeners();
|
|
476
|
+
});
|
|
477
|
+
</script>
|
|
478
|
+
</body>
|
|
479
|
+
|
|
480
|
+
</html>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<nav class="navbar is-primary" role="navigation" aria-label="main navigation">
|
|
2
|
+
<div class="navbar-brand">
|
|
3
|
+
<a class="navbar-item">
|
|
4
|
+
{{#if logo}}
|
|
5
|
+
<img src="{{logo}}" alt="{{projectName}}" class="logoimage">
|
|
6
|
+
{{/if}}
|
|
7
|
+
{{#if projectName}}
|
|
8
|
+
<span class="ml-2 has-text-weight-bold has-text-white">{{projectName}}</span>
|
|
9
|
+
{{/if}}
|
|
10
|
+
</a>
|
|
11
|
+
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
|
|
12
|
+
<span aria-hidden="true"></span>
|
|
13
|
+
<span aria-hidden="true"></span>
|
|
14
|
+
<span aria-hidden="true"></span>
|
|
15
|
+
</a>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="navbar-menu">
|
|
18
|
+
<div class="navbar-end">
|
|
19
|
+
<div class="navbar-item">
|
|
20
|
+
<span id="selected-filters"></span>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="navbar-item">
|
|
23
|
+
<div class="field">
|
|
24
|
+
<p class="control">
|
|
25
|
+
<input class="input" name="search" type="search" placeholder="Search by test">
|
|
26
|
+
</p>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="navbar-item">
|
|
30
|
+
<button id="toggle-theme" class="" data-theme-status="{{preferredTheme}}">
|
|
31
|
+
<span class="icon">
|
|
32
|
+
<i class="" id="theme-icon"></i>
|
|
33
|
+
</span>
|
|
34
|
+
</button>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="navbar-item">
|
|
37
|
+
<figure class="image">
|
|
38
|
+
<a href="https://github.com/ortoniKC/ortoni-report/" target="_blank">
|
|
39
|
+
<img
|
|
40
|
+
src="https://raw.githubusercontent.com/ortoniKC/ortoni-report/refs/heads/main/ortoni.png" />
|
|
41
|
+
</a>
|
|
42
|
+
</figure>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</nav>
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<div class="content sidebar">
|
|
2
|
+
{{#if showProject}}
|
|
3
|
+
{{#each groupedResults}}
|
|
4
|
+
<details class="box">
|
|
5
|
+
<summary class="is-size-5 has-icon-right">
|
|
6
|
+
<div class="icon-text">
|
|
7
|
+
<span class="icon has-text-info">
|
|
8
|
+
<svg class="image is-16x16" height="512" viewBox="0 0 32 32" width="512"
|
|
9
|
+
xmlns="http://www.w3.org/2000/svg">
|
|
10
|
+
<g data-name="Layer 2">
|
|
11
|
+
<path
|
|
12
|
+
d="M11.612 30.945a3.986 3.986 0 01-2.829-1.17l-5.209-5.208a4.006 4.006 0 010-5.657l3.955-3.954a1 1 0 011.414 1.414l-3.955 3.954a2.003 2.003 0 000 2.829l5.21 5.208a2.004 2.004 0 002.828 0l7.235-7.234a2.003 2.003 0 000-2.828l-4.63-4.63a1 1 0 011.414-1.414l4.63 4.63a4.006 4.006 0 010 5.657l-7.235 7.233a3.988 3.988 0 01-2.828 1.17z"
|
|
13
|
+
fill="#232323" />
|
|
14
|
+
<path
|
|
15
|
+
d="M15.662 20.038a.997.997 0 01-.707-.293l-4.63-4.63a4.006 4.006 0 010-5.656l7.235-7.234a4.004 4.004 0 015.657 0l5.209 5.208a4.006 4.006 0 010 5.657l-3.955 3.954a1 1 0 01-1.414-1.414l3.955-3.954a2.003 2.003 0 000-2.829l-5.21-5.208a2.002 2.002 0 00-2.828 0l-7.235 7.234a2.003 2.003 0 000 2.828l4.63 4.63a1 1 0 01-.707 1.707z"
|
|
16
|
+
fill="#7fbde7" />
|
|
17
|
+
</g>
|
|
18
|
+
</svg>
|
|
19
|
+
</span>
|
|
20
|
+
<span>{{@key}}</span>
|
|
21
|
+
</div>
|
|
22
|
+
</summary>
|
|
23
|
+
<ul class="mt-4 mb-4">
|
|
24
|
+
{{#each this}}
|
|
25
|
+
<details class="mt-2 mb-2">
|
|
26
|
+
<summary class="is-size-5 is-capitalized">
|
|
27
|
+
<div class="icon-text">
|
|
28
|
+
<span class="icon has-text-info">
|
|
29
|
+
<svg class="image is-16x16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
30
|
+
<path
|
|
31
|
+
d="M181.344 42.656v394.671C181.344 478.562 214.781 512 256 512c41.25 0 74.672-33.438 74.672-74.673V42.656H181.344z"
|
|
32
|
+
fill="#e6e9ed" />
|
|
33
|
+
<path
|
|
34
|
+
d="M352 32c0 17.672-14.312 32-32 32H192c-17.656 0-32-14.328-32-32s14.344-32 32-32h128c17.688 0 32 14.328 32 32z"
|
|
35
|
+
fill="#ccd1d9" />
|
|
36
|
+
<path
|
|
37
|
+
d="M181.344 192v245.327C181.344 478.562 214.781 512 256 512c41.25 0 74.672-33.438 74.672-74.673V192H181.344z"
|
|
38
|
+
fill="#a0d468" />
|
|
39
|
+
<g fill="#434a54">
|
|
40
|
+
<path
|
|
41
|
+
d="M245.344 266.655c0-5.89-4.781-10.655-10.672-10.655h-53.328v21.328h53.328c5.89 0 10.672-4.781 10.672-10.673zM234.672 319.999h-53.328v21.328h53.328c5.891 0 10.672-4.781 10.672-10.671s-4.782-10.657-10.672-10.657zM245.344 202.656c0-5.891-4.781-10.656-10.672-10.656h-53.328v21.328h53.328c5.89 0 10.672-4.781 10.672-10.672z" />
|
|
42
|
+
</g>
|
|
43
|
+
</svg>
|
|
44
|
+
</span>
|
|
45
|
+
<span>{{@key}}</span>
|
|
46
|
+
</div>
|
|
47
|
+
</summary>
|
|
48
|
+
<ul class="mt-4 mb-4">
|
|
49
|
+
{{#each this}}
|
|
50
|
+
<details class="mt-2 mb-2">
|
|
51
|
+
<summary class="is-capitalized is-size-6">{{@key}}</summary>
|
|
52
|
+
<ul class="mt-4 mb-4">
|
|
53
|
+
{{#each this}}
|
|
54
|
+
<li class="media {{#if (eq status 'skipped')}}is-hidden{{/if}}" data-suite-name="{{suite}}"
|
|
55
|
+
data-test-duration="{{duration}}" data-test-tags="{{joinWithSpace testTags}}"
|
|
56
|
+
data-project-name="{{projectName}}" data-test-id="{{index}}"
|
|
57
|
+
data-test-status="{{status}} {{retry}}">
|
|
58
|
+
{{> testStatus}}
|
|
59
|
+
</li>
|
|
60
|
+
{{/each}}
|
|
61
|
+
</ul>
|
|
62
|
+
</details>
|
|
63
|
+
{{/each}}
|
|
64
|
+
</ul>
|
|
65
|
+
</details>
|
|
66
|
+
{{/each}}
|
|
67
|
+
</ul>
|
|
68
|
+
</details>
|
|
69
|
+
{{/each}}
|
|
70
|
+
{{else}}
|
|
71
|
+
{{#each groupedResults}}
|
|
72
|
+
<details class="box">
|
|
73
|
+
<summary class="is-size-5 has-icon-right">
|
|
74
|
+
<div class="icon-text">
|
|
75
|
+
<span class="icon has-text-info">
|
|
76
|
+
<svg class="image is-16x16" height="512" viewBox="0 0 32 32" width="512"
|
|
77
|
+
xmlns="http://www.w3.org/2000/svg">
|
|
78
|
+
<g data-name="Layer 2">
|
|
79
|
+
<path
|
|
80
|
+
d="M11.612 30.945a3.986 3.986 0 01-2.829-1.17l-5.209-5.208a4.006 4.006 0 010-5.657l3.955-3.954a1 1 0 011.414 1.414l-3.955 3.954a2.003 2.003 0 000 2.829l5.21 5.208a2.004 2.004 0 002.828 0l7.235-7.234a2.003 2.003 0 000-2.828l-4.63-4.63a1 1 0 011.414-1.414l4.63 4.63a4.006 4.006 0 010 5.657l-7.235 7.233a3.988 3.988 0 01-2.828 1.17z"
|
|
81
|
+
fill="#232323" />
|
|
82
|
+
<path
|
|
83
|
+
d="M15.662 20.038a.997.997 0 01-.707-.293l-4.63-4.63a4.006 4.006 0 010-5.656l7.235-7.234a4.004 4.004 0 015.657 0l5.209 5.208a4.006 4.006 0 010 5.657l-3.955 3.954a1 1 0 01-1.414-1.414l3.955-3.954a2.003 2.003 0 000-2.829l-5.21-5.208a2.002 2.002 0 00-2.828 0l-7.235 7.234a2.003 2.003 0 000 2.828l4.63 4.63a1 1 0 01-.707 1.707z"
|
|
84
|
+
fill="#7fbde7" />
|
|
85
|
+
</g>
|
|
86
|
+
</svg>
|
|
87
|
+
</span>
|
|
88
|
+
<span>{{@key}}</span>
|
|
89
|
+
</div>
|
|
90
|
+
</summary>
|
|
91
|
+
<ul class="mt-4 mb-4">
|
|
92
|
+
{{#each this}}
|
|
93
|
+
<details class="mt-2 mb-2">
|
|
94
|
+
<summary class="is-size-5 is-capitalized">
|
|
95
|
+
<div class="icon-text">
|
|
96
|
+
<span class="icon has-text-info">
|
|
97
|
+
<svg class="image is-16x16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
98
|
+
<path
|
|
99
|
+
d="M181.344 42.656v394.671C181.344 478.562 214.781 512 256 512c41.25 0 74.672-33.438 74.672-74.673V42.656H181.344z"
|
|
100
|
+
fill="#e6e9ed" />
|
|
101
|
+
<path
|
|
102
|
+
d="M352 32c0 17.672-14.312 32-32 32H192c-17.656 0-32-14.328-32-32s14.344-32 32-32h128c17.688 0 32 14.328 32 32z"
|
|
103
|
+
fill="#ccd1d9" />
|
|
104
|
+
<path
|
|
105
|
+
d="M181.344 192v245.327C181.344 478.562 214.781 512 256 512c41.25 0 74.672-33.438 74.672-74.673V192H181.344z"
|
|
106
|
+
fill="#a0d468" />
|
|
107
|
+
<g fill="#434a54">
|
|
108
|
+
<path
|
|
109
|
+
d="M245.344 266.655c0-5.89-4.781-10.655-10.672-10.655h-53.328v21.328h53.328c5.89 0 10.672-4.781 10.672-10.673zM234.672 319.999h-53.328v21.328h53.328c5.891 0 10.672-4.781 10.672-10.671s-4.782-10.657-10.672-10.657zM245.344 202.656c0-5.891-4.781-10.656-10.672-10.656h-53.328v21.328h53.328c5.89 0 10.672-4.781 10.672-10.672z" />
|
|
110
|
+
</g>
|
|
111
|
+
</svg>
|
|
112
|
+
</span>
|
|
113
|
+
<span>{{@key}}</span>
|
|
114
|
+
</div>
|
|
115
|
+
</summary>
|
|
116
|
+
<ul class="mt-4 mb-4">
|
|
117
|
+
{{#each this}}
|
|
118
|
+
<li class="media {{#if (eq status 'skipped')}}is-hidden{{/if}}" data-suite-name="{{suite}}"
|
|
119
|
+
data-test-duration="{{duration}}" data-test-tags="{{joinWithSpace testTags}}"
|
|
120
|
+
data-project-name="{{projectName}}" data-test-id="{{index}}"
|
|
121
|
+
data-test-status="{{status}} {{retry}}">
|
|
122
|
+
{{> testStatus}}
|
|
123
|
+
</li>
|
|
124
|
+
{{/each}}
|
|
125
|
+
</ul>
|
|
126
|
+
</details>
|
|
127
|
+
{{/each}}
|
|
128
|
+
</ul>
|
|
129
|
+
</details>
|
|
130
|
+
{{/each}}
|
|
131
|
+
{{/if}}
|
|
132
|
+
</div>
|