ortoni-report 1.1.3 → 1.1.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.
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en">
2
+ <html lang="en" data-theme="{{preferredTheme}}">
3
3
 
4
4
  <head>
5
5
  <meta charset="UTF-8">
@@ -7,54 +7,39 @@
7
7
  <meta name="description" content="Plawright HTML report by LetCode Koushik">
8
8
  <title>Playwright Test Report</title>
9
9
  <link rel="icon" href="node_modules/ortoni-report/dist/icon/32.png" type="image/x-icon">
10
- <link rel="stylesheet" href="node_modules/ortoni-report/dist/css/pico.css">
11
- <style>
12
- body {
13
- zoom: 0.9;
14
- }
15
-
16
- main.container {
17
- display: grid;
18
- grid-template-columns: 1fr 2fr;
19
- gap: 20px;
20
- }
21
-
22
- .header {
23
- display: grid;
24
- grid-template-columns: 1fr 2fr;
25
- grid-column-gap: 20px;
26
- grid-row-gap: 20px;
27
- justify-items: stretch;
28
- align-items: center;
29
- justify-content: space-evenly;
10
+ <link rel="stylesheet" href="node_modules/ortoni-report/dist/css/main.css">
11
+ </head>
12
+ <style>
13
+ #summary, #testDetails, button#back-to-summary {
14
+ transition: opacity 0.2s ease-in-out;
30
15
  }
31
-
32
- .highlight {
33
- color: var(--pico-primary-background);
16
+ .filter.active {
17
+ background-color: var(--bulma-background-active);
34
18
  }
35
19
 
36
- .filter.active {
37
- background-color: var(--pico-primary-hover-background);
38
- color: var(--pico-primary-hover-color);
20
+ ::-webkit-scrollbar {
21
+ width: 0px;
22
+ background-color: transparent;
39
23
  }
40
24
 
41
-
42
- .text-success {
43
- color: #28a745;
25
+ ::-webkit-scrollbar-thumb {
26
+ background-color: var(--pico-secondary-background);
27
+ ;
28
+ border-radius: 0px;
44
29
  }
45
30
 
46
- .text-failure {
47
- color: #dc3545;
31
+ ::-webkit-scrollbar-thumb:hover {
32
+ background-color: var(--pico-secondary-background);
33
+ ;
48
34
  }
49
35
 
50
- .text-skip {
51
- color: #d5d4a1;
36
+ ::-webkit-scrollbar-track {
37
+ background-color: #f1f1f1;
52
38
  }
53
39
 
54
- .text-flaky {
55
- color: #b5e35e;
40
+ ::-webkit-scrollbar-corner {
41
+ background-color: #fff;
56
42
  }
57
-
58
43
  div#testDetails {
59
44
  position: sticky;
60
45
  top: 0;
@@ -64,139 +49,149 @@
64
49
  .sidebar {
65
50
  overflow-y: auto;
66
51
  max-height: calc(100vh - 100px);
67
- /* Adjust as needed */
68
- border-right: 1px solid #ddd;
69
- padding-right: 10px;
70
- }
71
-
72
- pre {
73
- background-color: #f8f9fa;
74
- padding: 1rem;
75
- border-radius: 0.5rem;
76
- overflow-x: auto;
77
52
  }
78
53
 
79
- .back-button {
80
- display: none;
81
- margin-bottom: 1rem;
82
- }
83
-
84
- .clickable {
54
+ aside li {
85
55
  cursor: pointer;
86
- transition: background-color 0.3s;
87
- }
88
-
89
- .clickable:hover {
90
- background-color: #607D8B;
91
56
  }
92
-
93
- li[data-test-id] {
94
- overflow: hidden;
95
- text-overflow: ellipsis;
96
- white-space: nowrap;
97
- max-width: 25ch;
98
- }
99
-
100
- li img {
101
- max-width: 8%
102
- }
103
-
104
- summary img {
105
- max-width: 5%
106
- }
107
-
108
- dialog article {
109
- max-width: 768px;
110
- }
111
-
112
- ::-webkit-scrollbar {
113
- width: 0px;
114
- background-color: transparent;
115
- }
116
-
117
- ::-webkit-scrollbar-thumb {
118
- background-color: var(--pico-secondary-background);
119
- ;
120
- border-radius: 0px;
57
+ details summary {
58
+ cursor: pointer;
59
+ display: flex;
60
+ justify-content: space-between;
61
+ align-items: center;
121
62
  }
122
-
123
- ::-webkit-scrollbar-thumb:hover {
124
- background-color: var(--pico-secondary-background);
125
- ;
63
+ details summary::after {
64
+ content: '';
65
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
66
+ transform:rotate(-90deg);
67
+ background-size: 1em;
68
+ background-repeat: no-repeat;
69
+ background-position:right-center;
70
+ width: 1em;
71
+ height: 1em;
72
+ transition: transform 0.2s ease-in-out;
126
73
  }
127
-
128
- ::-webkit-scrollbar-track {
129
- background-color: #f1f1f1;
74
+ details[open] > summary::after {
75
+ transform: rotate(0deg);
130
76
  }
131
77
 
132
- ::-webkit-scrollbar-corner {
133
- background-color: #fff;
134
- }
135
- </style>
136
- </head>
78
+ </style>
137
79
 
138
80
  <body>
139
- <header class="container">
140
- <div class="header">
141
- {{!-- Custom Project Name --}}
142
- <div>
143
- {{#if projectName}}<h1>{{projectName}}</h1>{{/if}}
144
- </div>
145
- <div>
146
- <input name="search" type="search" placeholder="Search by test title" />
81
+ <!-- Header -->
82
+ <section class="section">
83
+ <header class="container">
84
+ <div class="columns is-vcentered">
85
+ <div class="column is-one-third">
86
+ {{!-- Custom Project Name --}}
87
+ {{#if projectName}}<h1 class="title">{{projectName}}</h1>{{/if}}
88
+ </div>
89
+ <div class="column">
90
+ <div class="control">
91
+ <input class="input" name="search" type="search" placeholder="Search by test title" />
92
+ </div>
93
+ </div>
94
+ <div class="column is-1">
95
+ <div class="control">
96
+ <button id="toggle-theme" data-theme-status="{{preferredTheme}}" class="button">Theme</button>
97
+ </div>
98
+ </div>
147
99
  </div>
148
- </div>
149
- </header>
150
- <main class="container">
151
- {{!-- Test Scripts --}}
152
- <aside class="sidebar">
153
- <h2>Tests</h2>
154
- <div>
155
- {{#each groupedResults}}
156
- <details>
157
- <summary>
158
- <img src="node_modules/ortoni-report/dist/icon/file.png" alt="file name">
159
- <span>{{@key}}<span>
160
- </summary>
161
- <ul>
162
- {{#each this}}
163
- <details>
164
- <summary>
165
- <img src="node_modules/ortoni-report/dist/icon/test.png" alt="test name">
166
- <span>{{@key}}<span>
100
+ </header>
101
+ </section>
102
+
103
+ <!-- Main Content -->
104
+ <section class="section">
105
+ <main class="container">
106
+ <div class="columns">
107
+ <aside class="column is-one-third sidebar">
108
+ <div class="columns">
109
+ <div class="column">
110
+ <h2 class="title is-4">Tests</h2>
111
+ </div>
112
+ <div class="column">
113
+ <div class="select is-pulled-right">
114
+ <select id="project-filter">
115
+ <option value="all">All Projects</option>
116
+ {{#each projects}}
117
+ <option value="{{this}}">{{this}}</option>
118
+ {{/each}}
119
+ </select>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ <div class="content">
124
+ {{#each groupedResults}}
125
+ <details class="box">
126
+ <summary class="is-size-5 has-icon-right">
127
+ <div class="icon-text">
128
+ <span class="icon has-text-info">
129
+ <img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/file.png" alt="file name">
130
+ </span>
131
+ <span>{{@key}}</span>
132
+ </div>
167
133
  </summary>
168
134
  <ul>
169
135
  {{#each this}}
170
136
  <details>
171
- <summary>{{@key}}</summary>
137
+ <summary class="is-size-5">
138
+ <div class="icon-text">
139
+ <span class="icon has-text-info">
140
+ <img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/test.png" alt="test name">
141
+ </span>
142
+ <span>{{@key}}</span>
143
+ </div>
144
+ </summary>
172
145
  <ul>
173
146
  {{#each this}}
174
- <li data-suite-name="{{suite}}" data-project-name="{{projectName}}"
175
- data-test-id="{{index}}" data-test-status="{{status}} {{retry}}">
176
- {{#if isRetry}}
177
- <img src="node_modules/ortoni-report/dist/icon/retry.png" alt="Retry">
178
- {{/if}}
179
- {{#if (eq status "passed")}}
180
- <img src="node_modules/ortoni-report/dist/icon/pass.png" alt="Pass">
181
- {{/if}}
182
- {{#if (eq status "failed")}}
183
- <img src="node_modules/ortoni-report/dist/icon/fail.png" alt="Fail">
184
- {{else}}
185
- {{#if (eq status "skipped")}}
186
- <img src="node_modules/ortoni-report/dist/icon/skip.png" alt="Skip">
187
- {{/if}}
188
- {{/if}}
189
- {{#if (eq status "timedOut")}}
190
- <img src="node_modules/ortoni-report/dist/icon/timeout.png" alt="timedOut">
191
- {{/if}}
192
- {{#if (eq status "flaky")}}
193
- <img src="node_modules/ortoni-report/dist/icon/flaky.png" alt="flaky">
194
- {{/if}}
195
- <span>{{title}}</span>
196
- {{#if retryCount}}
197
- <p>Retry Count: {{retryCount}}</p>
198
- {{/if}}
199
- </li>
147
+ <details>
148
+ <summary>{{@key}}</summary>
149
+ <ul>
150
+ {{#each this}}
151
+ <li class="media" data-suite-name="{{suite}}"
152
+ data-project-name="{{projectName}}" data-test-id="{{index}}"
153
+ data-test-status="{{status}} {{retry}}">
154
+ <div class="icon-text">
155
+ {{#if isRetry}}
156
+ <span class="icon has-text-info">
157
+ <img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/retry.png"
158
+ alt="Retry"></span>
159
+ {{/if}}
160
+ {{#if (eq status "passed")}}
161
+ <span class="icon has-text-info">
162
+ <img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/pass.png"
163
+ alt="Pass"></span>
164
+ {{/if}}
165
+ {{#if (eq status "failed")}}
166
+ <span class="icon has-text-info">
167
+ <img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/fail.png"
168
+ alt="Fail"></span>
169
+ {{else}}
170
+ {{#if (eq status "skipped")}}
171
+ <span class="icon has-text-info">
172
+ <img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/skip.png"
173
+ alt="Skip"></span>
174
+ {{/if}}
175
+ {{/if}}
176
+ {{#if (eq status "timedOut")}}
177
+ <span class="icon has-text-info">
178
+ <img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/timeout.png"
179
+ alt="timedOut"></span>
180
+ {{/if}}
181
+ {{#if (eq status "flaky")}}
182
+ <span class="icon has-text-info">
183
+ <img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/flaky.png"
184
+ alt="flaky"></span>
185
+ {{/if}}
186
+ <span>{{title}}</span>
187
+ {{#if retryCount}}
188
+ <p>Retry Count: {{retryCount}}</p>
189
+ {{/if}}
190
+ </div>
191
+ </li>
192
+ {{/each}}
193
+ </ul>
194
+ </details>
200
195
  {{/each}}
201
196
  </ul>
202
197
  </details>
@@ -204,81 +199,117 @@
204
199
  </ul>
205
200
  </details>
206
201
  {{/each}}
207
- </ul>
208
- </details>
209
- {{/each}}
210
- </div>
211
- </aside>
212
- <section>
213
- {{!-- Overall summary --}}
214
- <div id="summary">
215
- <section class="grid">
216
- <div>
217
- <article class="clickable filter" data-status="all">
218
- <header>All Tests</header>
219
- <p>{{totalCount}}</p>
220
- </article>
221
- </div>
222
- <div>
223
- <article class="clickable filter" data-status="passed">
224
- <header>Passed</header>
225
- <p class="text-success">{{passCount}}</p>
226
- </article>
227
- </div>
228
- <div>
229
- <article class="clickable filter" data-status="failed">
230
- <header>Failed</header>
231
- <p class="text-failure">{{failCount}}</p>
232
- </article>
233
- </div>
234
- </section>
235
- <section class="grid">
236
- <div>
237
- <article class="clickable filter" data-status="skipped">
238
- <header>Skipped</header>
239
- <p class="text-skip">{{skipCount}}</p>
240
- </article>
241
202
  </div>
242
- <div>
243
- <article class="clickable filter" data-status="flaky">
244
- <header>Flaky</header>
245
- <p class="text-flaky">{{flakyCount}}</p>
246
- </article>
247
- </div>
248
- <div>
249
- <article class="clickable filter" data-status="retry">
250
- <header>Retry</header>
251
- <p class="text-skip">{{retryCount}}</p>
252
- </article>
253
- </div>
254
- </section>
255
- {{!-- Suite details with chart --}}
256
- <section>
257
- <article>
258
- <header>Suite</header>
259
- <div class="grid">
260
- <div>
261
- {{#if authorName}}<h4>Author: {{authorName}}</h4>{{/if}}
262
- {{#if testType}}<h4>Test Type: {{testType}}</h4>{{/if}}
263
- {{#if totalDuration}}<h4>Duration: {{totalDuration}}</h4>{{/if}}
264
- <h4>Success Rate: {{successRate}} %</h4>
265
- <h4>Last Run: {{lastRunDate}}</h4>
203
+ </aside>
204
+
205
+ <section class="column">
206
+ {{!-- Overall summary --}}
207
+ <div id="summary">
208
+ <div class="columns is-multiline">
209
+ <div class="column is-one-third">
210
+ <div class="card is-clickable filter" data-status="all">
211
+ <header class="card-header has-text-centered">
212
+ <p class="card-header-title">All Tests</p>
213
+ </header>
214
+ <div class="card-content">
215
+ <div class="content">
216
+ <p class="has-text-centered has-text-primary">{{totalCount}}</p>
217
+ </div>
218
+ </div>
219
+ </div>
220
+ </div>
221
+ <div class="column is-one-third">
222
+ <div class="card is-clickable filter" data-status="passed">
223
+ <header class="card-header has-text-centered">
224
+ <p class="card-header-title">Passed</p>
225
+ </header>
226
+ <div class="card-content">
227
+ <div class="content">
228
+ <p class="has-text-centered has-text-success">{{passCount}}</p>
229
+ </div>
230
+ </div>
231
+ </div>
232
+ </div>
233
+ <div class="column is-one-third">
234
+ <div class="card is-clickable filter" data-status="failed">
235
+ <header class="card-header">
236
+ <p class="card-header-title has-text-centered">Failed</p>
237
+ </header>
238
+ <div class="card-content">
239
+ <div class="content">
240
+ <p class="has-text-centered has-text-danger">{{failCount}}</p>
241
+ </div>
242
+ </div>
243
+ </div>
244
+ </div>
245
+ </div>
246
+ <div class="columns is-multiline">
247
+ <div class="column is-one-third">
248
+ <div class="card is-clickable filter" data-status="skipped">
249
+ <header class="card-header has-text-centered">
250
+ <p class="card-header-title">Skipped</p>
251
+ </header>
252
+ <div class="card-content">
253
+ <div class="content">
254
+ <p class="has-text-centered has-text-info">{{skipCount}}</p>
255
+ </div>
256
+ </div>
257
+ </div>
266
258
  </div>
267
- <div class="chart-container">
268
- <canvas id="testChart"></canvas>
259
+ <div class="column is-one-third">
260
+ <div class="card is-clickable filter" data-status="flaky">
261
+ <header class="card-header has-text-centered">
262
+ <p class="card-header-title">Flaky</p>
263
+ </header>
264
+ <div class="card-content">
265
+ <div class="content">
266
+ <p class="has-text-centered has-text-warning">{{flakyCount}}</p>
267
+ </div>
268
+ </div>
269
+ </div>
270
+ </div>
271
+ <div class="column is-one-third">
272
+ <div class="card is-clickable filter" data-status="retry">
273
+ <header class="card-header has-text-centered">
274
+ <p class="card-header-title">Retry</p>
275
+ </header>
276
+ <div class="card-content">
277
+ <div class="content">
278
+ <p class="has-text-centered has-text-info">{{retryCount}}</p>
279
+ </div>
280
+ </div>
281
+ </div>
282
+ </div>
283
+ </div>
284
+ {{!-- Suite details with chart --}}
285
+ <div class="box">
286
+ <header class="has-text-centered title is-4">Suite</header>
287
+ <div class="columns">
288
+ <div class="column is-half">
289
+ {{#if authorName}}<h4>Author: {{authorName}}</h4>{{/if}}
290
+ {{#if testType}}<h4>Test Type: {{testType}}</h4>{{/if}}
291
+ {{#if totalDuration}}<h4>Duration: {{totalDuration}}</h4>{{/if}}
292
+ <h4>Success Rate: {{successRate}} %</h4>
293
+ <h4>Last Run: {{lastRunDate}}</h4>
294
+ </div>
295
+ <div class="column is-half">
296
+ <div class="chart-container">
297
+ <canvas id="testChart"></canvas>
298
+ </div>
299
+ </div>
269
300
  </div>
270
301
  </div>
271
- </article>
302
+ </div>
303
+ {{!-- Test details --}}
304
+ <div id="testDetails" style="display: none;">
305
+ <!-- Back button should be outside the dynamic content -->
306
+ <button class="button content" id="back-to-summary"onclick="showSummary()">Back to Summary</button>
307
+ <!-- Test Details will be displayed here -->
308
+ </div>
272
309
  </section>
273
310
  </div>
274
- {{!-- Test details --}}
275
- <div id="testDetails" style="display: none;">
276
- <!-- Back button should be outside the dynamic content -->
277
- <button class="back-button" onclick="showSummary()">Back to Summary</button>
278
- <!-- Test Details will be displayed here -->
279
- </div>
280
- </section>
281
- </main>
311
+ </main>
312
+ </section>
282
313
  <script src="node_modules/ortoni-report/dist/utils/chart.js"></script>
283
314
  <script>
284
315
  function escapeHtml(unsafe) {
@@ -294,88 +325,132 @@
294
325
  });
295
326
  }
296
327
 
297
- document.addEventListener('DOMContentLoaded', () => {
298
- const testData = {{{ json results }}};
328
+ document.addEventListener('DOMContentLoaded', () => {
329
+ const testData = {{{ json results }}};
299
330
  const testDetails = document.getElementById('testDetails');
300
331
  const summary = document.getElementById('summary');
301
- const backButton = document.querySelector('.back-button');
302
- let highlightedItem = null;
332
+ const backButton = document.querySelector('button#back-to-summary');
333
+
334
+ const themeButton = document.getElementById("toggle-theme");
335
+ const preferredTheme = themeButton.getAttribute("data-theme-status");
336
+ const htmlElement = document.documentElement;
337
+
338
+ if (preferredTheme === 'dark') {
339
+ htmlElement.setAttribute('data-theme', 'dark');
340
+ themeButton.classList.add('is-dark');
341
+ themeButton.textContent = 'Dark';
342
+ } else if (preferredTheme === 'light') {
343
+ htmlElement.setAttribute('data-theme', 'light');
344
+ themeButton.classList.add('is-light');
345
+ themeButton.textContent = 'Light';
346
+ }
347
+
348
+ themeButton.addEventListener('click', () => {
349
+ const currentTheme = htmlElement.getAttribute('data-theme');
350
+ const newTheme = currentTheme === 'light' ? 'dark' : 'light';
351
+ htmlElement.setAttribute('data-theme', newTheme);
352
+ if (newTheme === 'dark') {
353
+ themeButton.classList.remove('is-light');
354
+ themeButton.classList.add('is-dark');
355
+ themeButton.textContent = 'Dark';
356
+ } else {
357
+ themeButton.classList.remove('is-dark');
358
+ themeButton.classList.add('is-light');
359
+ themeButton.textContent = 'Light';
360
+ }
361
+ });
303
362
 
304
363
  function showSummary() {
305
364
  summary.style.display = 'block';
306
365
  testDetails.style.display = 'none';
307
366
  backButton.style.display = 'none';
308
- if (highlightedItem) {
309
- highlightedItem.classList.remove('highlight');
310
- }
311
367
  }
312
368
 
313
369
  window.showSummary = showSummary;
314
370
 
315
371
  function displayTestDetails(test) {
316
- summary.style.display = 'none';
317
- testDetails.style.display = 'block';
318
- backButton.style.display = 'block';
372
+ const summary = document.getElementById('summary');
373
+ const testDetails = document.getElementById('testDetails');
374
+ const backButton = document.querySelector('button#back-to-summary');
375
+ summary.style.display = 'none';
376
+ testDetails.style.opacity = '0';
377
+ testDetails.style.display = 'block';
378
+ setTimeout(() => {
379
+ testDetails.style.opacity = '1';
380
+ backButton.style.opacity = '1';
381
+ }, 50);
382
+
383
+
319
384
  let statusClass = '';
320
385
  let statusText = test.status.toUpperCase();
321
386
  if (test.status.startsWith('passed')) {
322
- statusClass = 'text-success';
387
+ statusClass = 'tag is-success';
323
388
  } else if (test.status === 'flaky') {
324
- statusClass = 'text-flaky';
389
+ statusClass = 'tag is-warning';
390
+ } else if (test.status === 'failed') {
391
+ statusClass = 'tag is-danger';
325
392
  } else {
326
- statusClass = 'text-failure';
327
- }
393
+ statusClass = 'tag is-info';
394
+ }
395
+
328
396
  testDetails.innerHTML = `
329
- <button class="back-button" style="display: block" onclick="showSummary()">Back to Summary</button>
330
- <h3>${test.title}</h3>
331
- <div class="grid">
332
- <div>
333
- <h4>Status</h4>
334
- <p class="${statusClass}">${statusText}</p>
335
- ${test.duration != '0s' ? `
336
- <h4>Duration</h4>
337
- <p>${test.duration}</p>` : ""}
338
- </div>
339
- <div>
340
- ${test.screenshotPath ? `
341
- <img src="${test.screenshotPath}" data-target="modal-example" onclick="toggleModal(event)" alt="Screenshot">
342
- <dialog id="modal-example">
343
- <article>
344
- <header>
345
- <button aria-label="Close" rel="prev" data-target="modal-example" onclick="toggleModal(event)"></button>
346
- <p>
347
- <strong>Screenshot</strong>
397
+ <button class="button content" id="back-to-summary" style="display: block" onclick="showSummary()">Back to Summary</button>
398
+ <h3 class="title is-3 has-text-centered">${test.title}</h3>
399
+ <div class="columns">
400
+ <div class="column content">
401
+ <h4 class="title is-4">Status</h4>
402
+ <p class="${statusClass}">${statusText}</p>
403
+ ${test.duration.length > 0 ? `
404
+ <h4 class="title is-4">Duration</h4>
405
+ <p class="${statusClass}">${test.duration}</p>` : ""}
406
+ </div>
407
+ <div class="column content">
408
+ ${test.screenshotPath ? `
409
+ <div id="modal-js-example" class="modal">
410
+ <div class="modal-background"></div>
411
+ <div class="modal-content">
412
+ <p class="image is-16by9">
413
+ <img src="data:image/png;base64, ${test.screenshotPath}" alt="Screenshot">
348
414
  </p>
349
- </header><p>
350
- <img src="${test.screenshotPath}" alt="Screenshot"></p>
351
- </article>
352
- </dialog>` : ''}
415
+ </div>
416
+ <button onclick="closeModal()" class="modal-close is-large" aria-label="close"></button>
353
417
  </div>
418
+ <figure class="image is-16by9">
419
+ <img onclick="openModal()" src="data:image/png;base64, ${test.screenshotPath}" alt="Screenshot">
420
+ </figure>` : ''}
354
421
  </div>
355
- <div class="grid">
356
- <details>
357
- <summary><h4>Steps</h4></summary>
358
- <span id="stepDetails"></span>
359
- </details>
360
- </div>
361
- <div>
422
+ </div>
423
+ <div class="content">
424
+ ${test.steps.length > 0 ? `
425
+ <details id="stepopen">
426
+ <summary><h4 class="title is-4">Steps</h4></summary>
427
+ <span id="stepDetails" class="content"></span>
428
+ </details>
429
+ `: ``}
430
+ </div class="content">
431
+ <div>
362
432
  ${test.errors.length ? `
363
- <h4>Errors</h4>
364
- <div class="grid">
365
- <pre>${escapeHtml(test.errors.join('\n'))}</pre></div>
366
- ` : ''}
367
- </div>
368
- <div>
433
+ <h4 class="title is-4">Errors</h4>
434
+ <div class="content">
435
+ <pre>${escapeHtml(test.errors.join('\n'))}</pre>
436
+ </div>` : ''}
437
+ </div>
438
+ <div>
369
439
  ${test.logs ? `
370
- <h4>Logs</h4>
371
- <div class="grid">
372
- <pre>${escapeHtml(test.logs)}</pre></div>
373
- ` : ''}
374
- </div>
375
- `;
440
+ <h4 class="title is-4">Logs</h4>
441
+ <div class="box">
442
+ <pre>${escapeHtml(test.logs)}</pre>
443
+ </div>` : ''}
444
+ </div>
445
+ `;
446
+
376
447
  const stepDetailsDiv = document.getElementById('stepDetails');
377
- const stepsList = attachSteps(test);
378
- stepDetailsDiv.appendChild(stepsList);
448
+ if(stepDetailsDiv){
449
+ const stepsList = attachSteps(test);
450
+ const detail = document.getElementById("stepopen");
451
+ detail.setAttribute("open", "");
452
+ stepDetailsDiv.appendChild(stepsList);
453
+ }
379
454
  }
380
455
 
381
456
  function attachSteps(test) {
@@ -384,7 +459,7 @@
384
459
  stepsList.innerHTML = '';
385
460
  test.steps.forEach(step => {
386
461
  const li = document.createElement('li');
387
- li.innerHTML = `<strong class=${step.error ? 'text-failure' : 'test-success'}> ${step.title}</strong>`;
462
+ li.innerHTML = `<strong class="${step.error ? 'has-text-danger' : ''}">${step.title}</strong>`;
388
463
  stepsList.appendChild(li);
389
464
  });
390
465
  return stepsList;
@@ -397,11 +472,6 @@
397
472
  const testId = item.getAttribute('data-test-id');
398
473
  const test = testData[testId];
399
474
  displayTestDetails(test);
400
- if (highlightedItem) {
401
- highlightedItem.classList.remove('highlight');
402
- }
403
- item.classList.add('highlight');
404
- highlightedItem = item;
405
475
  });
406
476
  });
407
477
 
@@ -411,19 +481,26 @@
411
481
  filter.addEventListener('click', () => {
412
482
  const status = filter.getAttribute('data-status');
413
483
  filters.forEach(f => {
414
- if (f.getAttribute('data-status') !== 'all') {
484
+ if (f.getAttribute('data-status')) {
415
485
  f.classList.remove('active');
416
486
  }
417
487
  });
418
- if (status !== 'all') {
419
- filter.classList.add('active');
420
- }
421
- applyFilter(status);
488
+ filter.classList.add('active');
489
+ applyFilters();
422
490
  });
423
491
  });
492
+
493
+ const projectFilter = document.getElementById('project-filter');
494
+ projectFilter.addEventListener('change', () => {
495
+ applyFilters();
496
+ });
424
497
  }
425
498
 
426
- function applyFilter(status) {
499
+ function applyFilters() {
500
+ const selectedProject = document.getElementById('project-filter').value;
501
+ const activeFilter = document.querySelector('.filter.active');
502
+ const selectedStatus = activeFilter ? activeFilter.getAttribute('data-status') : 'all';
503
+
427
504
  const testItems = document.querySelectorAll('li[data-test-id]');
428
505
  const detailsElements = document.querySelectorAll('details');
429
506
 
@@ -431,30 +508,28 @@
431
508
  let shouldShowDetails = false;
432
509
  const items = details.querySelectorAll('li[data-test-id]');
433
510
  items.forEach(item => {
434
- const testStatus = item.getAttribute('data-test-status');
435
- if (status === 'all' || testStatus.trim() === status ||
436
- (status === 'failed' && (testStatus.trim() === 'failed' || testStatus.trim() === 'timedOut'))) {
437
- item.style.display = 'block'; // Show the item
438
- shouldShowDetails = true; // Set shouldShowDetails to true
439
- } else if ((status === 'retry' && testStatus.includes('retry'))) {
440
- item.style.display = 'block'; // Show the item
441
- shouldShowDetails = true; // Set shouldShowDetails to true
442
- }else if ((status === 'flaky' && testStatus.includes('flaky'))) {
443
- item.style.display = 'block'; // Show the item
444
- shouldShowDetails = true; // Set shouldShowDetails to true
511
+ const projectName = item.getAttribute('data-project-name').trim();
512
+ const testStatus = item.getAttribute('data-test-status').trim();
513
+ const matchesProject = (selectedProject === 'all' || projectName === selectedProject);
514
+ const matchesStatus = (selectedStatus === 'all' || testStatus.includes(selectedStatus) ||
515
+ (selectedStatus === 'failed' && (testStatus === 'failed' || testStatus === 'timedOut')) ||
516
+ (selectedStatus === 'retry' && testStatus.includes('retry')) ||
517
+ (selectedStatus === 'flaky' && testStatus.includes('flaky')));
518
+
519
+ if (matchesProject && matchesStatus) {
520
+ item.classList.remove('is-hidden');
521
+ shouldShowDetails = true;
445
522
  } else {
446
- item.style.display = 'none'; // Hide the item
523
+ item.classList.add('is-hidden');
447
524
  }
448
525
  });
449
- details.open = shouldShowDetails; // Open the details element if it has any matching items
450
- details.style.display = shouldShowDetails ? 'block' : 'none'; // Show/hide the details element
526
+ details.open = shouldShowDetails;
527
+ details.classList.toggle('is-hidden', !shouldShowDetails);
451
528
  });
452
529
  }
453
530
 
454
-
455
531
  const searchInput = document.querySelector('input[name="search"]');
456
532
  const detailsElements = document.querySelectorAll('details');
457
-
458
533
  searchInput.addEventListener('input', () => {
459
534
  const searchTerm = searchInput.value.toLowerCase();
460
535
  const testItems = document.querySelectorAll('[data-test-id]');
@@ -497,23 +572,25 @@
497
572
  labels: ['Passed', 'Failed', 'Skipped','Flaky'],
498
573
  datasets: [{
499
574
  data: [{{ passCount }}, {{ failCount }}, {{ skipCount }}, {{flakyCount}}],
500
- backgroundColor: ['#28a745', '#dc3545', '#d5d4a1', '#b5e35e']
575
+ backgroundColor: ['#28a745', '#dc3545', '#d5d4a1', '#FFB704']
501
576
  }]
502
577
  },
503
578
  options: {
504
- responsive: true,
505
- maintainAspectRatio: false,
506
- plugins: {
507
- legend: {
508
- position: 'bottom'
579
+ responsive: true,
580
+ maintainAspectRatio: false,
581
+ plugins: {
582
+ legend: {
583
+ position: 'bottom'
584
+ }
509
585
  }
510
586
  }
511
- }
512
- });
513
- attachEventListeners();
514
587
  });
515
- </script>
516
- <script src="node_modules/ortoni-report/dist/utils/modal.js"></script>
588
+
589
+ attachEventListeners();
590
+ });
591
+
592
+ </script>
593
+ <script src="node_modules/ortoni-report/dist/utils/modal.js"></script>
517
594
  </body>
518
595
 
519
596
  </html>