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
package/dist/report-template.hbs
DELETED
|
@@ -1,823 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en" data-theme="{{preferredTheme}}">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<meta name="description" content="Playwright HTML report by LetCode Koushik - V2.0.2">
|
|
7
|
-
<title>{{title}}</title>
|
|
8
|
-
<link rel="icon" href="node_modules/ortoni-report/dist/icon/32.png" type="image/x-icon">
|
|
9
|
-
<link rel="stylesheet" href="node_modules/ortoni-report/dist/css/main.css">
|
|
10
|
-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
11
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
12
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
13
|
-
<link href="https://fonts.googleapis.com/css2?family=Nunito+Sans:ital,opsz,wght@0,6..12,200..1000;1,6..12,200..1000&family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap" rel="stylesheet">
|
|
14
|
-
</head>
|
|
15
|
-
<style>
|
|
16
|
-
#summary, #testDetails, button#back-to-summary {
|
|
17
|
-
transition: opacity 0.2s ease-in-out;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.filter.active {
|
|
21
|
-
box-shadow: rgb(38, 57, 77) 0px 20px 30px -10px;
|
|
22
|
-
font-weight: bold;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
::-webkit-scrollbar {
|
|
26
|
-
width: 8px;
|
|
27
|
-
height: 8px;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
::-webkit-scrollbar-track {
|
|
31
|
-
background: #f1f1f1;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
::-webkit-scrollbar-thumb {
|
|
35
|
-
background: var(--bulma-primary);
|
|
36
|
-
border-radius: 4px;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
::-webkit-scrollbar-thumb:hover {
|
|
40
|
-
background: #555;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
div#testDetails {
|
|
44
|
-
position: sticky;
|
|
45
|
-
top: 0;
|
|
46
|
-
z-index: 1;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.sidebar {
|
|
50
|
-
overflow-y: auto;
|
|
51
|
-
max-height: calc(100vh - 100px);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
aside li {
|
|
55
|
-
cursor: pointer;
|
|
56
|
-
}
|
|
57
|
-
details summary {
|
|
58
|
-
cursor: pointer;
|
|
59
|
-
display: flex;
|
|
60
|
-
justify-content: space-between;
|
|
61
|
-
align-items: center;
|
|
62
|
-
}
|
|
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;
|
|
73
|
-
}
|
|
74
|
-
details[open] > summary::after {
|
|
75
|
-
transform: rotate(0deg);
|
|
76
|
-
}
|
|
77
|
-
.logoimage{
|
|
78
|
-
max-width: 100px;
|
|
79
|
-
}
|
|
80
|
-
.listselected {
|
|
81
|
-
border-image: linear-gradient(45deg, var(--bulma-primary),#FF6B6B) 1;
|
|
82
|
-
font-weight: bold;
|
|
83
|
-
}
|
|
84
|
-
.has-background-flaky {
|
|
85
|
-
background-color: #ffb70f !important;
|
|
86
|
-
}
|
|
87
|
-
.has-background-retry {
|
|
88
|
-
background-color: #69748c !important;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
</style>
|
|
92
|
-
<body>
|
|
93
|
-
<section class="section">
|
|
94
|
-
<header class="container">
|
|
95
|
-
<div class="columns is-vcentered">
|
|
96
|
-
<div class="column is-two-fifths">
|
|
97
|
-
<div class="columns is-desktop is-vcentered is-multiline">
|
|
98
|
-
{{#if logo}}
|
|
99
|
-
<div class="column-1">
|
|
100
|
-
<figure class="image logoimage">
|
|
101
|
-
<img src="{{logo}}" />
|
|
102
|
-
</figure>
|
|
103
|
-
</div>
|
|
104
|
-
{{/if}}
|
|
105
|
-
{{#if projectName}}<div class="column"><span class="title">{{projectName}}</span></div>{{/if}}
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
<div class="column">
|
|
109
|
-
<div class="control">
|
|
110
|
-
<input class="input" name="search" type="search" placeholder="Search by test title" />
|
|
111
|
-
</div>
|
|
112
|
-
<div class="control has-text-info">
|
|
113
|
-
<span id="selected-filters"></span>
|
|
114
|
-
</div>
|
|
115
|
-
</div>
|
|
116
|
-
<div class="column is-1">
|
|
117
|
-
<div class="control">
|
|
118
|
-
<button id="toggle-theme" data-theme-status="{{preferredTheme}}" class="button">Theme</button>
|
|
119
|
-
</div>
|
|
120
|
-
</div>
|
|
121
|
-
</div>
|
|
122
|
-
</header>
|
|
123
|
-
</section>
|
|
124
|
-
<section class="section">
|
|
125
|
-
<main class="container">
|
|
126
|
-
<div class="columns">
|
|
127
|
-
<aside class="column is-two-fifths">
|
|
128
|
-
<div class="columns is-mobile is-vcentered">
|
|
129
|
-
<div class="column">
|
|
130
|
-
<h2 class="title is-4">Tests</h2>
|
|
131
|
-
</div>
|
|
132
|
-
<div class="column">
|
|
133
|
-
<div id="project-filter" class="dropdown is-right is-hoverable is-pulled-right">
|
|
134
|
-
<div class="dropdown-trigger">
|
|
135
|
-
<button class="button" aria-haspopup="true" aria-controls="select-filter">
|
|
136
|
-
<span>Filters</span>
|
|
137
|
-
<span class="icon is-small">
|
|
138
|
-
<i class="fas fa-angle-down" aria-hidden="true"></i>
|
|
139
|
-
</span>
|
|
140
|
-
</button>
|
|
141
|
-
</div>
|
|
142
|
-
<div class="dropdown-menu" id="select-filter" role="menu">
|
|
143
|
-
<div class="dropdown-content">
|
|
144
|
-
{{#each projects}}
|
|
145
|
-
<div class="dropdown-item">
|
|
146
|
-
<label class="checkbox">
|
|
147
|
-
<input type="checkbox" data-filter-type="project" value="{{this}}">{{this}}
|
|
148
|
-
</label>
|
|
149
|
-
</div>
|
|
150
|
-
{{/each}}
|
|
151
|
-
<hr class="dropdown-divider" />
|
|
152
|
-
{{#each allTags}}
|
|
153
|
-
<div class="dropdown-item">
|
|
154
|
-
<label class="checkbox">
|
|
155
|
-
<input type="checkbox" data-filter-type="test-tags" value="{{this}}">{{this}}
|
|
156
|
-
</label>
|
|
157
|
-
</div>
|
|
158
|
-
{{/each}}
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
</div>
|
|
162
|
-
</div>
|
|
163
|
-
</div>
|
|
164
|
-
<div class="content sidebar">
|
|
165
|
-
{{#if showProject}}
|
|
166
|
-
{{#each groupedResults}}
|
|
167
|
-
<details class="box">
|
|
168
|
-
<summary class="is-size-5 has-icon-right">
|
|
169
|
-
<div class="icon-text">
|
|
170
|
-
<span class="icon has-text-info">
|
|
171
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/file.png" alt="file name">
|
|
172
|
-
</span>
|
|
173
|
-
<span>{{@key}}</span>
|
|
174
|
-
</div>
|
|
175
|
-
</summary>
|
|
176
|
-
<ul class="mt-4 mb-4">
|
|
177
|
-
{{#each this}}
|
|
178
|
-
<details class="mt-2 mb-2">
|
|
179
|
-
<summary class="is-size-5 is-capitalized">
|
|
180
|
-
<div class="icon-text">
|
|
181
|
-
<span class="icon has-text-info">
|
|
182
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/test.png" alt="test name">
|
|
183
|
-
</span>
|
|
184
|
-
<span>{{@key}}</span>
|
|
185
|
-
</div>
|
|
186
|
-
</summary>
|
|
187
|
-
<ul class="mt-4 mb-4">
|
|
188
|
-
{{#each this}}
|
|
189
|
-
<details class="mt-2 mb-2">
|
|
190
|
-
<summary class="is-capitalized is-size-6">{{@key}}</summary>
|
|
191
|
-
<ul class="mt-4 mb-4">
|
|
192
|
-
{{#each this}}
|
|
193
|
-
<li class="media {{#if (eq status 'skipped')}}is-hidden{{/if}}" data-suite-name="{{suite}}"
|
|
194
|
-
data-test-duration="{{duration}}" data-test-tags="{{joinWithSpace testTags}}"
|
|
195
|
-
data-project-name="{{projectName}}" data-test-id="{{index}}"
|
|
196
|
-
data-test-status="{{status}} {{retry}}">
|
|
197
|
-
<div class="icon-text">
|
|
198
|
-
{{#if isRetry}}
|
|
199
|
-
<span class="icon has-text-info">
|
|
200
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/retry.png"
|
|
201
|
-
alt="Retry"></span>
|
|
202
|
-
{{/if}}
|
|
203
|
-
{{#if (eq status "passed")}}
|
|
204
|
-
<span class="icon has-text-info">
|
|
205
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/pass.png"
|
|
206
|
-
alt="Pass"></span>
|
|
207
|
-
{{/if}}
|
|
208
|
-
{{#if (eq status "failed")}}
|
|
209
|
-
<span class="icon has-text-info">
|
|
210
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/fail.png"
|
|
211
|
-
alt="Fail"></span>
|
|
212
|
-
{{else}}
|
|
213
|
-
{{#if (eq status "skipped")}}
|
|
214
|
-
<span class="icon has-text-info">
|
|
215
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/skip.png"
|
|
216
|
-
alt="Skip"></span>
|
|
217
|
-
{{/if}}
|
|
218
|
-
{{/if}}
|
|
219
|
-
{{#if (eq status "timedOut")}}
|
|
220
|
-
<span class="icon has-text-info">
|
|
221
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/timeout.png"
|
|
222
|
-
alt="timedOut"></span>
|
|
223
|
-
{{/if}}
|
|
224
|
-
{{#if (eq status "flaky")}}
|
|
225
|
-
<span class="icon has-text-info">
|
|
226
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/flaky.png"
|
|
227
|
-
alt="flaky"></span>
|
|
228
|
-
{{/if}}
|
|
229
|
-
<span>{{title}}</span>
|
|
230
|
-
</div>
|
|
231
|
-
</li>
|
|
232
|
-
{{/each}}
|
|
233
|
-
</ul>
|
|
234
|
-
</details>
|
|
235
|
-
{{/each}}
|
|
236
|
-
</ul>
|
|
237
|
-
</details>
|
|
238
|
-
{{/each}}
|
|
239
|
-
</ul>
|
|
240
|
-
</details>
|
|
241
|
-
{{/each}}
|
|
242
|
-
{{else}}
|
|
243
|
-
{{#each groupedResults}}
|
|
244
|
-
<details class="box">
|
|
245
|
-
<summary class="is-size-5 has-icon-right">
|
|
246
|
-
<div class="icon-text">
|
|
247
|
-
<span class="icon has-text-info">
|
|
248
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/file.png" alt="file name">
|
|
249
|
-
</span>
|
|
250
|
-
<span>{{@key}}</span>
|
|
251
|
-
</div>
|
|
252
|
-
</summary>
|
|
253
|
-
<ul class="mt-4 mb-4">
|
|
254
|
-
{{#each this}}
|
|
255
|
-
<details class="mt-2 mb-2">
|
|
256
|
-
<summary class="is-size-5 is-capitalized">
|
|
257
|
-
<div class="icon-text">
|
|
258
|
-
<span class="icon has-text-info">
|
|
259
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/test.png" alt="test name">
|
|
260
|
-
</span>
|
|
261
|
-
<span>{{@key}}</span>
|
|
262
|
-
</div>
|
|
263
|
-
</summary>
|
|
264
|
-
<ul class="mt-4 mb-4">
|
|
265
|
-
{{#each this}}
|
|
266
|
-
<li class="media {{#if (eq status 'skipped')}}is-hidden{{/if}}" data-suite-name="{{suite}}"
|
|
267
|
-
data-test-duration="{{duration}}" data-test-tags="{{joinWithSpace testTags}}"
|
|
268
|
-
data-project-name="{{projectName}}" data-test-id="{{index}}"
|
|
269
|
-
data-test-status="{{status}} {{retry}}">
|
|
270
|
-
<div class="icon-text">
|
|
271
|
-
{{#if isRetry}}
|
|
272
|
-
<span class="icon has-text-info">
|
|
273
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/retry.png"
|
|
274
|
-
alt="Retry"></span>
|
|
275
|
-
{{/if}}
|
|
276
|
-
{{#if (eq status "passed")}}
|
|
277
|
-
<span class="icon has-text-info">
|
|
278
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/pass.png"
|
|
279
|
-
alt="Pass"></span>
|
|
280
|
-
{{/if}}
|
|
281
|
-
{{#if (eq status "failed")}}
|
|
282
|
-
<span class="icon has-text-info">
|
|
283
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/fail.png"
|
|
284
|
-
alt="Fail"></span>
|
|
285
|
-
{{else}}
|
|
286
|
-
{{#if (eq status "skipped")}}
|
|
287
|
-
<span class="icon has-text-info">
|
|
288
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/skip.png"
|
|
289
|
-
alt="Skip"></span>
|
|
290
|
-
{{/if}}
|
|
291
|
-
{{/if}}
|
|
292
|
-
{{#if (eq status "timedOut")}}
|
|
293
|
-
<span class="icon has-text-info">
|
|
294
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/timeout.png"
|
|
295
|
-
alt="timedOut"></span>
|
|
296
|
-
{{/if}}
|
|
297
|
-
{{#if (eq status "flaky")}}
|
|
298
|
-
<span class="icon has-text-info">
|
|
299
|
-
<img class="image is-16x16" src="node_modules/ortoni-report/dist/icon/flaky.png"
|
|
300
|
-
alt="flaky"></span>
|
|
301
|
-
{{/if}}
|
|
302
|
-
<span>{{title}}</span>
|
|
303
|
-
</div>
|
|
304
|
-
</li>
|
|
305
|
-
{{/each}}
|
|
306
|
-
</ul>
|
|
307
|
-
</details>
|
|
308
|
-
{{/each}}
|
|
309
|
-
</ul>
|
|
310
|
-
</details>
|
|
311
|
-
{{/each}}
|
|
312
|
-
{{/if}}
|
|
313
|
-
</div>
|
|
314
|
-
</aside>
|
|
315
|
-
<section class="column is-three-fifths">
|
|
316
|
-
{{!-- Overall summary --}}
|
|
317
|
-
<div id="summary">
|
|
318
|
-
<div class="columns is-multiline">
|
|
319
|
-
<div class="column is-one-third">
|
|
320
|
-
<div class="card is-clickable has-background-primary filter" data-status="all">
|
|
321
|
-
<header class="card-header has-text-centered">
|
|
322
|
-
<p class="card-header-title has-text-white">All Tests</p>
|
|
323
|
-
<button class="card-header-icon" aria-label="more options">
|
|
324
|
-
<span class="icon">
|
|
325
|
-
<img aria-hidden="true" class="image is-16x16" src="node_modules/ortoni-report/dist/icon/test.png" alt="test name">
|
|
326
|
-
</span>
|
|
327
|
-
</button>
|
|
328
|
-
</header>
|
|
329
|
-
<div class="card-content">
|
|
330
|
-
<div class="content">
|
|
331
|
-
<p class="has-text-centered has-text-white">{{totalCount}}</p>
|
|
332
|
-
</div>
|
|
333
|
-
</div>
|
|
334
|
-
</div>
|
|
335
|
-
</div>
|
|
336
|
-
<div class="column is-one-third">
|
|
337
|
-
<div class="card is-clickable has-background-success filter" data-status="passed">
|
|
338
|
-
<header class="card-header has-text-centered">
|
|
339
|
-
<p class="card-header-title has-text-white">Passed</p>
|
|
340
|
-
<button class="card-header-icon" aria-label="more options">
|
|
341
|
-
<span class="icon">
|
|
342
|
-
<img aria-hidden="true" class="image is-16x16" src="node_modules/ortoni-report/dist/icon/pass.png" alt="test name">
|
|
343
|
-
</span>
|
|
344
|
-
</button>
|
|
345
|
-
</header>
|
|
346
|
-
<div class="card-content">
|
|
347
|
-
<div class="content">
|
|
348
|
-
<p class="has-text-centered has-text-white">{{passCount}}</p>
|
|
349
|
-
</div>
|
|
350
|
-
</div>
|
|
351
|
-
</div>
|
|
352
|
-
</div>
|
|
353
|
-
<div class="column is-one-third">
|
|
354
|
-
<div class="card is-clickable has-background-danger filter" data-status="failed">
|
|
355
|
-
<header class="card-header">
|
|
356
|
-
<p class="card-header-title has-text-white has-text-centered">Failed</p>
|
|
357
|
-
<button class="card-header-icon" aria-label="more options">
|
|
358
|
-
<span class="icon">
|
|
359
|
-
<img aria-hidden="true" class="image is-16x16" src="node_modules/ortoni-report/dist/icon/fail.png" alt="test name">
|
|
360
|
-
</span>
|
|
361
|
-
</button>
|
|
362
|
-
</header>
|
|
363
|
-
<div class="card-content">
|
|
364
|
-
<div class="content">
|
|
365
|
-
<p class="has-text-centered has-text-white">{{failCount}}</p>
|
|
366
|
-
</div>
|
|
367
|
-
</div>
|
|
368
|
-
</div>
|
|
369
|
-
</div>
|
|
370
|
-
</div>
|
|
371
|
-
<div class="columns is-multiline">
|
|
372
|
-
<div class="column is-one-third">
|
|
373
|
-
<div class="card is-clickable has-background-info filter" data-status="skipped">
|
|
374
|
-
<header class="card-header has-text-centered">
|
|
375
|
-
<p class="card-header-title has-text-white">Skipped</p>
|
|
376
|
-
</header>
|
|
377
|
-
<div class="card-content">
|
|
378
|
-
<div class="content">
|
|
379
|
-
<p class="has-text-centered has-text-white">{{skipCount}}</p>
|
|
380
|
-
</div>
|
|
381
|
-
</div>
|
|
382
|
-
</div>
|
|
383
|
-
</div>
|
|
384
|
-
<div class="column is-one-third">
|
|
385
|
-
<div class="card is-clickable has-background-warning filter" data-status="flaky">
|
|
386
|
-
<header class="card-header has-text-centered">
|
|
387
|
-
<p class="card-header-title has-text-white">Flaky</p>
|
|
388
|
-
</header>
|
|
389
|
-
<div class="card-content">
|
|
390
|
-
<div class="content">
|
|
391
|
-
<p class="has-text-centered has-text-white">{{flakyCount}}</p>
|
|
392
|
-
</div>
|
|
393
|
-
</div>
|
|
394
|
-
</div>
|
|
395
|
-
</div>
|
|
396
|
-
<div class="column is-one-third">
|
|
397
|
-
<div class="card is-clickable has-background-retry filter" data-status="retry">
|
|
398
|
-
<header class="card-header has-text-centered">
|
|
399
|
-
<p class="card-header-title has-text-white">Retry</p>
|
|
400
|
-
</header>
|
|
401
|
-
<div class="card-content">
|
|
402
|
-
<div class="content">
|
|
403
|
-
<p class="has-text-centered has-text-white">{{retryCount}}</p>
|
|
404
|
-
</div>
|
|
405
|
-
</div>
|
|
406
|
-
</div>
|
|
407
|
-
</div>
|
|
408
|
-
</div>
|
|
409
|
-
{{!-- Suite details with chart --}}
|
|
410
|
-
<div class="box">
|
|
411
|
-
<header class="has-text-centered title is-4">Suite</header>
|
|
412
|
-
<div class="columns">
|
|
413
|
-
<div class="column is-half">
|
|
414
|
-
{{#if authorName}}<h4>Author: {{authorName}}</h4>{{/if}}
|
|
415
|
-
{{#if testType}}<h4>Test Type: {{testType}}</h4>{{/if}}
|
|
416
|
-
{{#if totalDuration}}<h4>Duration: {{totalDuration}}</h4>{{/if}}
|
|
417
|
-
<h4>Success Rate: {{successRate}} %</h4>
|
|
418
|
-
<h4>Last Run: {{lastRunDate}}</h4>
|
|
419
|
-
</div>
|
|
420
|
-
<div class="column is-half">
|
|
421
|
-
<div class="chart-container">
|
|
422
|
-
<canvas id="testChart"></canvas>
|
|
423
|
-
</div>
|
|
424
|
-
</div>
|
|
425
|
-
</div>
|
|
426
|
-
</div>
|
|
427
|
-
</div>
|
|
428
|
-
{{!-- Test details --}}
|
|
429
|
-
<div id="testDetails" style="display: none;">
|
|
430
|
-
<!-- Back button should be outside the dynamic content -->
|
|
431
|
-
<button class="button content" id="back-to-summary"onclick="showSummary()">Back to Summary</button>
|
|
432
|
-
<!-- Test Details will be displayed here -->
|
|
433
|
-
</div>
|
|
434
|
-
</section>
|
|
435
|
-
</div>
|
|
436
|
-
</main>
|
|
437
|
-
</section>
|
|
438
|
-
<script src="node_modules/ortoni-report/dist/utils/chart.js"></script>
|
|
439
|
-
<script>
|
|
440
|
-
function escapeHtml(unsafe) {
|
|
441
|
-
return unsafe.replace(/[&<"']/g, function (match) {
|
|
442
|
-
const escapeMap = {
|
|
443
|
-
'&': '&',
|
|
444
|
-
'<': '<',
|
|
445
|
-
'>': '>',
|
|
446
|
-
'"': '"',
|
|
447
|
-
"'": '''
|
|
448
|
-
};
|
|
449
|
-
return escapeMap[match];
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
453
|
-
const testData = {{{ json results }}};
|
|
454
|
-
const testDetails = document.getElementById('testDetails');
|
|
455
|
-
const summary = document.getElementById('summary');
|
|
456
|
-
const backButton = document.querySelector('button#back-to-summary');
|
|
457
|
-
|
|
458
|
-
const themeButton = document.getElementById("toggle-theme");
|
|
459
|
-
const preferredTheme = themeButton.getAttribute("data-theme-status");
|
|
460
|
-
const htmlElement = document.documentElement;
|
|
461
|
-
|
|
462
|
-
if (preferredTheme === 'dark') {
|
|
463
|
-
htmlElement.setAttribute('data-theme', 'dark');
|
|
464
|
-
themeButton.classList.add('is-dark');
|
|
465
|
-
themeButton.textContent = 'Dark';
|
|
466
|
-
} else if (preferredTheme === 'light') {
|
|
467
|
-
htmlElement.setAttribute('data-theme', 'light');
|
|
468
|
-
themeButton.classList.add('is-light');
|
|
469
|
-
themeButton.textContent = 'Light';
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
themeButton.addEventListener('click', () => {
|
|
473
|
-
const currentTheme = htmlElement.getAttribute('data-theme');
|
|
474
|
-
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
|
|
475
|
-
htmlElement.setAttribute('data-theme', newTheme);
|
|
476
|
-
if (newTheme === 'dark') {
|
|
477
|
-
themeButton.classList.remove('is-light');
|
|
478
|
-
themeButton.classList.add('is-dark');
|
|
479
|
-
themeButton.textContent = 'Dark';
|
|
480
|
-
} else {
|
|
481
|
-
themeButton.classList.remove('is-dark');
|
|
482
|
-
themeButton.classList.add('is-light');
|
|
483
|
-
themeButton.textContent = 'Light';
|
|
484
|
-
}
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
function showSummary() {
|
|
488
|
-
summary.style.display = 'block';
|
|
489
|
-
testDetails.style.display = 'none';
|
|
490
|
-
backButton.style.display = 'none';
|
|
491
|
-
}
|
|
492
|
-
window.showSummary = showSummary;
|
|
493
|
-
function displayTestDetails(test) {
|
|
494
|
-
const summary = document.getElementById('summary');
|
|
495
|
-
const testDetails = document.getElementById('testDetails');
|
|
496
|
-
const backButton = document.querySelector('button#back-to-summary');
|
|
497
|
-
summary.style.display = 'none';
|
|
498
|
-
testDetails.style.opacity = '0';
|
|
499
|
-
testDetails.style.display = 'block';
|
|
500
|
-
setTimeout(() => {
|
|
501
|
-
testDetails.style.opacity = '1';
|
|
502
|
-
backButton.style.opacity = '1';
|
|
503
|
-
}, 50);
|
|
504
|
-
|
|
505
|
-
let statusClass = '';
|
|
506
|
-
let statusText = test.status.toUpperCase();
|
|
507
|
-
if (test.status.startsWith('passed')) {
|
|
508
|
-
statusClass = 'tag is-success';
|
|
509
|
-
} else if (test.status === 'flaky') {
|
|
510
|
-
statusClass = 'tag is-warning';
|
|
511
|
-
} else if (test.status === 'failed') {
|
|
512
|
-
statusClass = 'tag is-danger';
|
|
513
|
-
} else {
|
|
514
|
-
statusClass = 'tag is-info';
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
testDetails.innerHTML = `
|
|
518
|
-
<button class="button content" id="back-to-summary" style="display: block" onclick="showSummary()">Back to Summary</button>
|
|
519
|
-
<div class="content has-text-centered">
|
|
520
|
-
<p class="title">${test.title}</p>
|
|
521
|
-
<p class="subtitle" id="filepath">${test.location}</p>
|
|
522
|
-
</div>
|
|
523
|
-
<div class="columns">
|
|
524
|
-
<div class="column content">
|
|
525
|
-
<h4 class="title is-4">Status</h4>
|
|
526
|
-
<p class="${statusClass}">${statusText}</p>
|
|
527
|
-
${test.duration.length > 0 ? `
|
|
528
|
-
<h4 class="title is-4">Duration</h4>
|
|
529
|
-
<p class="${statusClass}">${test.duration}</p>` : ""}
|
|
530
|
-
${test.projectName.length > 0 ? `
|
|
531
|
-
<div class="control">
|
|
532
|
-
<div class="tags has-addons">
|
|
533
|
-
<span class="tag is-dark">Project</span>
|
|
534
|
-
<span class="tag is-info is-capitalized">${test.projectName}</span>
|
|
535
|
-
</div>
|
|
536
|
-
</div>`: ""}
|
|
537
|
-
${test.testTags.length > 0 ? `
|
|
538
|
-
<div class="control mt-4">
|
|
539
|
-
<div class="tags has-addons">
|
|
540
|
-
<span class="tag is-dark">Test Tags</span>
|
|
541
|
-
<span class="tag is-info">${test.testTags.join(" ")}</span>
|
|
542
|
-
</div>
|
|
543
|
-
</div>`: ""}
|
|
544
|
-
${test.videoPath ? `
|
|
545
|
-
<div id="testVideo" class="modal">
|
|
546
|
-
<div class="modal-background"></div>
|
|
547
|
-
<div class="modal-content">
|
|
548
|
-
<figure>
|
|
549
|
-
<video controls>
|
|
550
|
-
<source src="file://${test.videoPath}" type="video/webm">
|
|
551
|
-
Your browser does not support the video tag.
|
|
552
|
-
</video>
|
|
553
|
-
</figure>
|
|
554
|
-
</div>
|
|
555
|
-
<button onclick="closeVideo()" class="modal-close is-large" aria-label="close"></button>
|
|
556
|
-
</div>
|
|
557
|
-
<button class="button mt-4" onclick="openVideo()">Attachment: Video</button>
|
|
558
|
-
`:''}
|
|
559
|
-
</div>
|
|
560
|
-
<div class="column content">
|
|
561
|
-
${test.screenshotPath ? `
|
|
562
|
-
<div id="testImage" class="modal">
|
|
563
|
-
<div class="modal-background"></div>
|
|
564
|
-
<div class="modal-content">
|
|
565
|
-
<p class="image">
|
|
566
|
-
<img src="${test.base64Image ? test.screenshotPath : `file://${test.screenshotPath}`}" alt="Screenshot">
|
|
567
|
-
</p>
|
|
568
|
-
</div>
|
|
569
|
-
<button onclick="closeModal()" class="modal-close is-large" aria-label="close"></button>
|
|
570
|
-
</div>
|
|
571
|
-
<figure class="image box">
|
|
572
|
-
<img onclick="openModal()" src="${test.base64Image ? test.screenshotPath : `file://${test.screenshotPath}`}" alt="Screenshot">
|
|
573
|
-
</figure>` : ''}
|
|
574
|
-
</div>
|
|
575
|
-
</div>
|
|
576
|
-
<div class="content">
|
|
577
|
-
${test.steps.length > 0 ? `
|
|
578
|
-
<details id="stepopen">
|
|
579
|
-
<summary><h4 class="title is-4">Steps</h4></summary>
|
|
580
|
-
<span id="stepDetails" class="content"></span>
|
|
581
|
-
</details>
|
|
582
|
-
`: ``}
|
|
583
|
-
</div class="content">
|
|
584
|
-
<div>
|
|
585
|
-
${test.errors.length ? `
|
|
586
|
-
<h4 class="title is-4">Errors</h4>
|
|
587
|
-
<div class="content">
|
|
588
|
-
<pre><code class="data-lang=js">${escapeHtml(test.errors.join('\n'))}</code></pre>
|
|
589
|
-
</div>` : ''}
|
|
590
|
-
</div>
|
|
591
|
-
<div>
|
|
592
|
-
${test.logs ? `
|
|
593
|
-
<h4 class="title is-4">Logs</h4>
|
|
594
|
-
<div class="box">
|
|
595
|
-
<pre>${escapeHtml(test.logs)}</pre>
|
|
596
|
-
</div>` : ''}
|
|
597
|
-
</div>
|
|
598
|
-
`;
|
|
599
|
-
|
|
600
|
-
const stepDetailsDiv = document.getElementById('stepDetails');
|
|
601
|
-
if(stepDetailsDiv){
|
|
602
|
-
const stepsList = attachSteps(test);
|
|
603
|
-
const detail = document.getElementById("stepopen");
|
|
604
|
-
if(test.errors.length > 0){
|
|
605
|
-
detail.setAttribute("open", "");
|
|
606
|
-
}
|
|
607
|
-
stepDetailsDiv.appendChild(stepsList);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
function attachSteps(test) {
|
|
612
|
-
const stepsList = document.createElement("ul");
|
|
613
|
-
stepsList.setAttribute("id", "steps");
|
|
614
|
-
stepsList.innerHTML = '';
|
|
615
|
-
test.steps.forEach(step => {
|
|
616
|
-
const li = document.createElement('li');
|
|
617
|
-
li.innerHTML = `<strong class="${step.snippet ? 'has-text-danger' : ''}">${step.title}</strong>`;
|
|
618
|
-
if (step.snippet) {
|
|
619
|
-
const pre = document.createElement('pre');
|
|
620
|
-
const code = document.createElement('code');
|
|
621
|
-
const locationText = step.location ? `\n\nat: ${step.location}` : '';
|
|
622
|
-
code.textContent = `${step.snippet}${locationText}`;
|
|
623
|
-
code.setAttribute('data-lang', 'js');
|
|
624
|
-
pre.appendChild(code);
|
|
625
|
-
li.appendChild(pre);
|
|
626
|
-
}
|
|
627
|
-
stepsList.appendChild(li);
|
|
628
|
-
});
|
|
629
|
-
return stepsList;
|
|
630
|
-
}
|
|
631
|
-
function openModal() {
|
|
632
|
-
let modal = document.querySelector("#testImage");
|
|
633
|
-
modal.classList.add("is-active");
|
|
634
|
-
}
|
|
635
|
-
function openVideo(){
|
|
636
|
-
let modal = document.querySelector("#testVideo");
|
|
637
|
-
modal.classList.add("is-active");
|
|
638
|
-
}
|
|
639
|
-
function closeVideo(){
|
|
640
|
-
let modal = document.querySelector("#testVideo");
|
|
641
|
-
modal.classList.remove("is-active");
|
|
642
|
-
}
|
|
643
|
-
function closeModal() {
|
|
644
|
-
let modal = document.querySelector("#testImage");
|
|
645
|
-
modal.classList.remove("is-active");
|
|
646
|
-
}
|
|
647
|
-
window.openModal = openModal;
|
|
648
|
-
window.openVideo = openVideo;
|
|
649
|
-
window.closeVideo = closeVideo;
|
|
650
|
-
window.closeModal = closeModal;
|
|
651
|
-
|
|
652
|
-
document.addEventListener('keydown', (event) => {
|
|
653
|
-
if (event.key === "Escape") {
|
|
654
|
-
closeModal();
|
|
655
|
-
}});
|
|
656
|
-
|
|
657
|
-
function attachEventListeners() {
|
|
658
|
-
const checkboxes = document.querySelectorAll('#select-filter input[type="checkbox"]');
|
|
659
|
-
checkboxes.forEach(checkbox => {
|
|
660
|
-
checkbox.addEventListener('change', applyFilters);
|
|
661
|
-
});
|
|
662
|
-
const testItems = document.querySelectorAll('[data-test-id]');
|
|
663
|
-
testItems.forEach(item => {
|
|
664
|
-
item.addEventListener('click', () => {
|
|
665
|
-
testItems.forEach(i => i.classList.remove('listselected'));
|
|
666
|
-
item.classList.add('listselected');
|
|
667
|
-
const testId = item.getAttribute('data-test-id');
|
|
668
|
-
const test = testData[testId];
|
|
669
|
-
displayTestDetails(test);
|
|
670
|
-
});
|
|
671
|
-
});
|
|
672
|
-
const filters = document.querySelectorAll('.filter');
|
|
673
|
-
filters.forEach(filter => {
|
|
674
|
-
filter.addEventListener('click', () => {
|
|
675
|
-
const status = filter.getAttribute('data-status');
|
|
676
|
-
filters.forEach(f => {
|
|
677
|
-
if (f.getAttribute('data-status')) {
|
|
678
|
-
f.classList.remove('active');
|
|
679
|
-
}
|
|
680
|
-
});
|
|
681
|
-
filter.classList.add('active');
|
|
682
|
-
applyFilters();
|
|
683
|
-
});
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
function applyFilters() {
|
|
688
|
-
const selectedCheckboxes = document.querySelectorAll('#select-filter input[type="checkbox"]:checked');
|
|
689
|
-
const activeFilter = document.querySelector('.filter.active');
|
|
690
|
-
const selectedStatus = activeFilter ? activeFilter.getAttribute('data-status') : 'all';
|
|
691
|
-
const selectedProjects = [];
|
|
692
|
-
const selectedTags = [];
|
|
693
|
-
selectedCheckboxes.forEach(checkbox => {
|
|
694
|
-
if (checkbox.getAttribute('data-filter-type') === 'project') {
|
|
695
|
-
selectedProjects.push(checkbox.value.trim());
|
|
696
|
-
} else {
|
|
697
|
-
selectedTags.push(checkbox.value.trim());
|
|
698
|
-
}
|
|
699
|
-
});
|
|
700
|
-
const detailsElements = document.querySelectorAll('.sidebar details');
|
|
701
|
-
detailsElements.forEach(details => {
|
|
702
|
-
let shouldShowDetails = false;
|
|
703
|
-
const items = details.querySelectorAll('li[data-test-id]');
|
|
704
|
-
items.forEach(item => {
|
|
705
|
-
const testTags = item.getAttribute('data-test-tags').trim().split(' ').filter(Boolean);
|
|
706
|
-
const projectName = item.getAttribute('data-project-name').trim();
|
|
707
|
-
const testStatus = item.getAttribute('data-test-status').trim();
|
|
708
|
-
const matchesProject = selectedProjects.length === 0 || selectedProjects.includes(projectName);
|
|
709
|
-
const matchesTags = selectedTags.length === 0 || selectedTags.every(tag => testTags.includes(tag));
|
|
710
|
-
const matchesStatus = (selectedStatus === 'all' && testStatus !== 'skipped') ||
|
|
711
|
-
(selectedStatus !== 'all' && (
|
|
712
|
-
testStatus.includes(selectedStatus) ||
|
|
713
|
-
(selectedStatus === 'failed' && (testStatus === 'failed' || testStatus === 'timedOut')) ||
|
|
714
|
-
(selectedStatus === 'retry' && testStatus.includes('retry')) ||
|
|
715
|
-
(selectedStatus === 'flaky' && testStatus.includes('flaky'))
|
|
716
|
-
));
|
|
717
|
-
if (matchesProject && matchesTags && matchesStatus) {
|
|
718
|
-
item.classList.remove('is-hidden');
|
|
719
|
-
shouldShowDetails = true;
|
|
720
|
-
} else {
|
|
721
|
-
item.classList.add('is-hidden');
|
|
722
|
-
}
|
|
723
|
-
});
|
|
724
|
-
details.open = shouldShowDetails;
|
|
725
|
-
details.classList.toggle('is-hidden', !shouldShowDetails);
|
|
726
|
-
});
|
|
727
|
-
updateSelectedFiltersDisplay(selectedProjects, selectedTags, selectedStatus);
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
function updateSelectedFiltersDisplay(projects, tags, status) {
|
|
731
|
-
const filtersDisplay = document.getElementById('selected-filters');
|
|
732
|
-
filtersDisplay.innerHTML = '';
|
|
733
|
-
|
|
734
|
-
if (projects.length > 0) {
|
|
735
|
-
filtersDisplay.innerHTML += `<span> Projects: ${projects.join(', ')}</span>`;
|
|
736
|
-
}
|
|
737
|
-
if (tags.length > 0) {
|
|
738
|
-
filtersDisplay.innerHTML += `<span> Tags: ${tags.join(', ')}</span>`;
|
|
739
|
-
}
|
|
740
|
-
if (status !== 'all') {
|
|
741
|
-
filtersDisplay.innerHTML += `<span> Status: ${status}</span>`;
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
if (filtersDisplay.innerHTML === '') {
|
|
745
|
-
filtersDisplay.innerHTML = '<span>All Tests</span>';
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
const searchInput = document.querySelector('input[name="search"]');
|
|
749
|
-
const detailsElements = document.querySelectorAll('details');
|
|
750
|
-
function filterTests(search){
|
|
751
|
-
const searchTerm = search.toLowerCase();
|
|
752
|
-
const testItems = document.querySelectorAll('[data-test-id]');
|
|
753
|
-
|
|
754
|
-
if (searchTerm) {
|
|
755
|
-
detailsElements.forEach(detail => {
|
|
756
|
-
detail.open = false; // Collapse all details initially
|
|
757
|
-
});
|
|
758
|
-
|
|
759
|
-
testItems.forEach(item => {
|
|
760
|
-
const testTitle = item.textContent.toLowerCase();
|
|
761
|
-
if (testTitle.includes(searchTerm)) {
|
|
762
|
-
item.style.display = 'block'; // Show matching test item
|
|
763
|
-
|
|
764
|
-
let parent = item.parentElement;
|
|
765
|
-
while (parent && parent.tagName !== 'ASIDE') {
|
|
766
|
-
if (parent.tagName === 'DETAILS') {
|
|
767
|
-
parent.open = true;
|
|
768
|
-
}
|
|
769
|
-
parent = parent.parentElement;
|
|
770
|
-
}
|
|
771
|
-
} else {
|
|
772
|
-
item.style.display = 'none';
|
|
773
|
-
}
|
|
774
|
-
});
|
|
775
|
-
} else {
|
|
776
|
-
testItems.forEach(item => {
|
|
777
|
-
item.style.display = 'block';
|
|
778
|
-
});
|
|
779
|
-
detailsElements.forEach(detail => {
|
|
780
|
-
detail.open = false;
|
|
781
|
-
});
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
function debounce(func, wait) {
|
|
785
|
-
let timeout;
|
|
786
|
-
return function(...args) {
|
|
787
|
-
clearTimeout(timeout);
|
|
788
|
-
timeout = setTimeout(() => func.apply(this, args), wait);
|
|
789
|
-
};
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
const debouncedSearch = debounce((event) => {
|
|
793
|
-
filterTests(event.target.value);
|
|
794
|
-
}, 300);
|
|
795
|
-
|
|
796
|
-
searchInput.addEventListener('input', debouncedSearch);
|
|
797
|
-
|
|
798
|
-
const ctx = document.getElementById('testChart').getContext('2d');
|
|
799
|
-
new Chart(ctx, {
|
|
800
|
-
type: 'doughnut',
|
|
801
|
-
data: {
|
|
802
|
-
labels: ['Passed', 'Failed', 'Skipped','Flaky'],
|
|
803
|
-
datasets: [{
|
|
804
|
-
data: [{{ passCount }}, {{ failCount }}, {{ skipCount }}, {{flakyCount}}],
|
|
805
|
-
backgroundColor: ['#28a745', '#ff6685', '#66d1ff', '#ffb70f']
|
|
806
|
-
}]
|
|
807
|
-
},
|
|
808
|
-
options: {
|
|
809
|
-
responsive: true,
|
|
810
|
-
maintainAspectRatio: false,
|
|
811
|
-
plugins: {
|
|
812
|
-
legend: {
|
|
813
|
-
display: false
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
});
|
|
818
|
-
|
|
819
|
-
attachEventListeners();
|
|
820
|
-
});
|
|
821
|
-
</script>
|
|
822
|
-
</body>
|
|
823
|
-
</html>
|