ortoni-report 1.1.2 → 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.
- package/changelog.md +37 -0
- package/dist/css/main.css +22445 -0
- package/dist/icon/flaky.png +0 -0
- package/dist/ortoni-report.d.ts +24 -6
- package/dist/ortoni-report.js +49 -37
- package/dist/ortoni-report.mjs +49 -37
- package/dist/report-template.hbs +483 -345
- package/dist/types/reporterConfig.js +2 -0
- package/dist/types/testResults.js +2 -0
- package/dist/utils/modal.js +12 -72
- package/dist/utils/utils.js +44 -0
- package/package.json +47 -49
- package/readme.md +52 -14
- package/dist/css/pico.css +0 -2802
package/dist/report-template.hbs
CHANGED
|
@@ -1,59 +1,45 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
2
|
+
<html lang="en" data-theme="{{preferredTheme}}">
|
|
3
|
+
|
|
3
4
|
<head>
|
|
4
5
|
<meta charset="UTF-8">
|
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
7
|
<meta name="description" content="Plawright HTML report by LetCode Koushik">
|
|
7
8
|
<title>Playwright Test Report</title>
|
|
8
9
|
<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/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
main.container {
|
|
16
|
-
display: grid;
|
|
17
|
-
grid-template-columns: 1fr 2fr;
|
|
18
|
-
gap: 20px;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.header {
|
|
22
|
-
display: grid;
|
|
23
|
-
grid-template-columns: 1fr 2fr;
|
|
24
|
-
grid-column-gap: 20px;
|
|
25
|
-
grid-row-gap: 20px;
|
|
26
|
-
justify-items: stretch;
|
|
27
|
-
align-items: center;
|
|
28
|
-
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;
|
|
29
15
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
background-color: var(--pico-primary-background);
|
|
16
|
+
.filter.active {
|
|
17
|
+
background-color: var(--bulma-background-active);
|
|
33
18
|
}
|
|
34
19
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
color:
|
|
20
|
+
::-webkit-scrollbar {
|
|
21
|
+
width: 0px;
|
|
22
|
+
background-color: transparent;
|
|
38
23
|
}
|
|
39
24
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
25
|
+
::-webkit-scrollbar-thumb {
|
|
26
|
+
background-color: var(--pico-secondary-background);
|
|
27
|
+
;
|
|
28
|
+
border-radius: 0px;
|
|
43
29
|
}
|
|
44
30
|
|
|
45
|
-
|
|
46
|
-
color:
|
|
31
|
+
::-webkit-scrollbar-thumb:hover {
|
|
32
|
+
background-color: var(--pico-secondary-background);
|
|
33
|
+
;
|
|
47
34
|
}
|
|
48
35
|
|
|
49
|
-
|
|
50
|
-
color: #
|
|
36
|
+
::-webkit-scrollbar-track {
|
|
37
|
+
background-color: #f1f1f1;
|
|
51
38
|
}
|
|
52
39
|
|
|
53
|
-
|
|
54
|
-
color: #
|
|
40
|
+
::-webkit-scrollbar-corner {
|
|
41
|
+
background-color: #fff;
|
|
55
42
|
}
|
|
56
|
-
|
|
57
43
|
div#testDetails {
|
|
58
44
|
position: sticky;
|
|
59
45
|
top: 0;
|
|
@@ -62,123 +48,150 @@
|
|
|
62
48
|
|
|
63
49
|
.sidebar {
|
|
64
50
|
overflow-y: auto;
|
|
65
|
-
max-height: calc(100vh - 100px);
|
|
66
|
-
border-right: 1px solid #ddd;
|
|
67
|
-
padding-right: 10px;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
pre {
|
|
71
|
-
background-color: #f8f9fa;
|
|
72
|
-
padding: 1rem;
|
|
73
|
-
border-radius: 0.5rem;
|
|
74
|
-
overflow-x: auto;
|
|
51
|
+
max-height: calc(100vh - 100px);
|
|
75
52
|
}
|
|
76
53
|
|
|
77
|
-
|
|
78
|
-
display: none;
|
|
79
|
-
margin-bottom: 1rem;
|
|
80
|
-
}
|
|
81
|
-
.clickable {
|
|
54
|
+
aside li {
|
|
82
55
|
cursor: pointer;
|
|
83
|
-
transition: background-color 0.3s;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.clickable:hover {
|
|
87
|
-
background-color: #607D8B;
|
|
88
56
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
li img{
|
|
96
|
-
max-width: 8%
|
|
97
|
-
}
|
|
98
|
-
summary img{
|
|
99
|
-
max-width: 5%
|
|
100
|
-
}
|
|
101
|
-
dialog article {
|
|
102
|
-
max-width: 768px;
|
|
103
|
-
}
|
|
104
|
-
::-webkit-scrollbar {
|
|
105
|
-
width: 0px;
|
|
106
|
-
background-color: transparent;
|
|
57
|
+
details summary {
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
display: flex;
|
|
60
|
+
justify-content: space-between;
|
|
61
|
+
align-items: center;
|
|
107
62
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
background-
|
|
111
|
-
|
|
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;
|
|
112
73
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
background-color: var(--pico-secondary-background);;
|
|
74
|
+
details[open] > summary::after {
|
|
75
|
+
transform: rotate(0deg);
|
|
116
76
|
}
|
|
117
77
|
|
|
118
|
-
|
|
119
|
-
background-color: #f1f1f1;
|
|
120
|
-
}
|
|
78
|
+
</style>
|
|
121
79
|
|
|
122
|
-
::-webkit-scrollbar-corner {
|
|
123
|
-
background-color: #fff;
|
|
124
|
-
}
|
|
125
|
-
</style>
|
|
126
|
-
</head>
|
|
127
80
|
<body>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
<div>
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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>
|
|
136
99
|
</div>
|
|
137
|
-
</
|
|
138
|
-
</
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
<div>
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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>
|
|
156
133
|
</summary>
|
|
157
134
|
<ul>
|
|
158
135
|
{{#each this}}
|
|
159
136
|
<details>
|
|
160
|
-
<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>
|
|
161
145
|
<ul>
|
|
162
146
|
{{#each this}}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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>
|
|
182
195
|
{{/each}}
|
|
183
196
|
</ul>
|
|
184
197
|
</details>
|
|
@@ -186,75 +199,117 @@
|
|
|
186
199
|
</ul>
|
|
187
200
|
</details>
|
|
188
201
|
{{/each}}
|
|
189
|
-
</ul>
|
|
190
|
-
</details>
|
|
191
|
-
{{/each}}
|
|
192
|
-
</div>
|
|
193
|
-
</aside>
|
|
194
|
-
<section>
|
|
195
|
-
{{!-- Overall summary --}}
|
|
196
|
-
<div id="summary">
|
|
197
|
-
<section class="grid">
|
|
198
|
-
<div>
|
|
199
|
-
<article class="clickable filter" data-status="all">
|
|
200
|
-
<header>All Tests</header>
|
|
201
|
-
<p>{{totalCount}}</p>
|
|
202
|
-
</article>
|
|
203
|
-
</div>
|
|
204
|
-
<div>
|
|
205
|
-
<article class="clickable filter" data-status="passed">
|
|
206
|
-
<header>Passed</header>
|
|
207
|
-
<p class="text-success">{{passCount}}</p>
|
|
208
|
-
</article>
|
|
209
202
|
</div>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
<
|
|
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>
|
|
242
258
|
</div>
|
|
243
|
-
<div class="
|
|
244
|
-
<
|
|
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>
|
|
245
300
|
</div>
|
|
246
301
|
</div>
|
|
247
|
-
</
|
|
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>
|
|
248
309
|
</section>
|
|
249
310
|
</div>
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
<!-- Back button should be outside the dynamic content -->
|
|
253
|
-
<button class="back-button" onclick="showSummary()">Back to Summary</button>
|
|
254
|
-
<!-- Test Details will be displayed here -->
|
|
255
|
-
</div>
|
|
256
|
-
</section>
|
|
257
|
-
</main>
|
|
311
|
+
</main>
|
|
312
|
+
</section>
|
|
258
313
|
<script src="node_modules/ortoni-report/dist/utils/chart.js"></script>
|
|
259
314
|
<script>
|
|
260
315
|
function escapeHtml(unsafe) {
|
|
@@ -270,189 +325,272 @@
|
|
|
270
325
|
});
|
|
271
326
|
}
|
|
272
327
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
328
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
329
|
+
const testData = {{{ json results }}};
|
|
330
|
+
const testDetails = document.getElementById('testDetails');
|
|
331
|
+
const summary = document.getElementById('summary');
|
|
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';
|
|
287
360
|
}
|
|
361
|
+
});
|
|
288
362
|
|
|
289
|
-
|
|
363
|
+
function showSummary() {
|
|
364
|
+
summary.style.display = 'block';
|
|
365
|
+
testDetails.style.display = 'none';
|
|
366
|
+
backButton.style.display = 'none';
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
window.showSummary = showSummary;
|
|
290
370
|
|
|
291
|
-
|
|
371
|
+
function displayTestDetails(test) {
|
|
372
|
+
const summary = document.getElementById('summary');
|
|
373
|
+
const testDetails = document.getElementById('testDetails');
|
|
374
|
+
const backButton = document.querySelector('button#back-to-summary');
|
|
292
375
|
summary.style.display = 'none';
|
|
376
|
+
testDetails.style.opacity = '0';
|
|
293
377
|
testDetails.style.display = 'block';
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
378
|
+
setTimeout(() => {
|
|
379
|
+
testDetails.style.opacity = '1';
|
|
380
|
+
backButton.style.opacity = '1';
|
|
381
|
+
}, 50);
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
let statusClass = '';
|
|
385
|
+
let statusText = test.status.toUpperCase();
|
|
386
|
+
if (test.status.startsWith('passed')) {
|
|
387
|
+
statusClass = 'tag is-success';
|
|
388
|
+
} else if (test.status === 'flaky') {
|
|
389
|
+
statusClass = 'tag is-warning';
|
|
390
|
+
} else if (test.status === 'failed') {
|
|
391
|
+
statusClass = 'tag is-danger';
|
|
392
|
+
} else {
|
|
393
|
+
statusClass = 'tag is-info';
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
testDetails.innerHTML = `
|
|
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">
|
|
315
414
|
</p>
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
</article>
|
|
319
|
-
</dialog>` : ''}
|
|
415
|
+
</div>
|
|
416
|
+
<button onclick="closeModal()" class="modal-close is-large" aria-label="close"></button>
|
|
320
417
|
</div>
|
|
418
|
+
<figure class="image is-16by9">
|
|
419
|
+
<img onclick="openModal()" src="data:image/png;base64, ${test.screenshotPath}" alt="Screenshot">
|
|
420
|
+
</figure>` : ''}
|
|
321
421
|
</div>
|
|
322
|
-
|
|
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>
|
|
323
432
|
${test.errors.length ? `
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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>
|
|
330
439
|
${test.logs ? `
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
440
|
+
<h4 class="title is-4">Logs</h4>
|
|
441
|
+
<div class="box">
|
|
442
|
+
<pre>${escapeHtml(test.logs)}</pre>
|
|
443
|
+
</div>` : ''}
|
|
444
|
+
</div>
|
|
445
|
+
`;
|
|
446
|
+
|
|
447
|
+
const stepDetailsDiv = document.getElementById('stepDetails');
|
|
448
|
+
if(stepDetailsDiv){
|
|
449
|
+
const stepsList = attachSteps(test);
|
|
450
|
+
const detail = document.getElementById("stepopen");
|
|
451
|
+
detail.setAttribute("open", "");
|
|
452
|
+
stepDetailsDiv.appendChild(stepsList);
|
|
337
453
|
}
|
|
454
|
+
}
|
|
338
455
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
highlightedItem = item;
|
|
351
|
-
});
|
|
352
|
-
});
|
|
456
|
+
function attachSteps(test) {
|
|
457
|
+
const stepsList = document.createElement("ul");
|
|
458
|
+
stepsList.setAttribute("id", "steps");
|
|
459
|
+
stepsList.innerHTML = '';
|
|
460
|
+
test.steps.forEach(step => {
|
|
461
|
+
const li = document.createElement('li');
|
|
462
|
+
li.innerHTML = `<strong class="${step.error ? 'has-text-danger' : ''}">${step.title}</strong>`;
|
|
463
|
+
stepsList.appendChild(li);
|
|
464
|
+
});
|
|
465
|
+
return stepsList;
|
|
466
|
+
}
|
|
353
467
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
f.classList.remove('active');
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
|
-
if (status !== 'all') {
|
|
365
|
-
filter.classList.add('active');
|
|
366
|
-
}
|
|
367
|
-
applyFilter(status);
|
|
368
|
-
});
|
|
468
|
+
function attachEventListeners() {
|
|
469
|
+
const testItems = document.querySelectorAll('[data-test-id]');
|
|
470
|
+
testItems.forEach(item => {
|
|
471
|
+
item.addEventListener('click', () => {
|
|
472
|
+
const testId = item.getAttribute('data-test-id');
|
|
473
|
+
const test = testData[testId];
|
|
474
|
+
displayTestDetails(test);
|
|
369
475
|
});
|
|
370
|
-
}
|
|
476
|
+
});
|
|
371
477
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const testStatus = item.getAttribute('data-test-status');
|
|
381
|
-
if (status === 'all' || testStatus === status || (status === 'failed' &&
|
|
382
|
-
(testStatus === 'failed' || testStatus === 'timedOut'))) {
|
|
383
|
-
item.style.display = 'block'; // Show the item
|
|
384
|
-
shouldShowDetails = true; // Set shouldShowDetails to true
|
|
385
|
-
} else {
|
|
386
|
-
item.style.display = 'none'; // Hide the item
|
|
478
|
+
// Event listeners for the filter articles
|
|
479
|
+
const filters = document.querySelectorAll('.filter');
|
|
480
|
+
filters.forEach(filter => {
|
|
481
|
+
filter.addEventListener('click', () => {
|
|
482
|
+
const status = filter.getAttribute('data-status');
|
|
483
|
+
filters.forEach(f => {
|
|
484
|
+
if (f.getAttribute('data-status')) {
|
|
485
|
+
f.classList.remove('active');
|
|
387
486
|
}
|
|
388
487
|
});
|
|
389
|
-
|
|
390
|
-
|
|
488
|
+
filter.classList.add('active');
|
|
489
|
+
applyFilters();
|
|
391
490
|
});
|
|
392
|
-
}
|
|
491
|
+
});
|
|
393
492
|
|
|
493
|
+
const projectFilter = document.getElementById('project-filter');
|
|
494
|
+
projectFilter.addEventListener('change', () => {
|
|
495
|
+
applyFilters();
|
|
496
|
+
});
|
|
497
|
+
}
|
|
394
498
|
|
|
395
|
-
|
|
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
|
+
|
|
504
|
+
const testItems = document.querySelectorAll('li[data-test-id]');
|
|
396
505
|
const detailsElements = document.querySelectorAll('details');
|
|
397
506
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
const
|
|
507
|
+
detailsElements.forEach(details => {
|
|
508
|
+
let shouldShowDetails = false;
|
|
509
|
+
const items = details.querySelectorAll('li[data-test-id]');
|
|
510
|
+
items.forEach(item => {
|
|
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;
|
|
522
|
+
} else {
|
|
523
|
+
item.classList.add('is-hidden');
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
details.open = shouldShowDetails;
|
|
527
|
+
details.classList.toggle('is-hidden', !shouldShowDetails);
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const searchInput = document.querySelector('input[name="search"]');
|
|
532
|
+
const detailsElements = document.querySelectorAll('details');
|
|
533
|
+
searchInput.addEventListener('input', () => {
|
|
534
|
+
const searchTerm = searchInput.value.toLowerCase();
|
|
535
|
+
const testItems = document.querySelectorAll('[data-test-id]');
|
|
401
536
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
537
|
+
if (searchTerm) {
|
|
538
|
+
detailsElements.forEach(detail => {
|
|
539
|
+
detail.open = false; // Collapse all details initially
|
|
540
|
+
});
|
|
406
541
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
417
|
-
parent = parent.parentElement;
|
|
542
|
+
testItems.forEach(item => {
|
|
543
|
+
const testTitle = item.textContent.toLowerCase();
|
|
544
|
+
if (testTitle.includes(searchTerm)) {
|
|
545
|
+
item.style.display = 'block'; // Show matching test item
|
|
546
|
+
|
|
547
|
+
let parent = item.parentElement;
|
|
548
|
+
while (parent && parent.tagName !== 'ASIDE') {
|
|
549
|
+
if (parent.tagName === 'DETAILS') {
|
|
550
|
+
parent.open = true;
|
|
418
551
|
}
|
|
419
|
-
|
|
420
|
-
item.style.display = 'none';
|
|
552
|
+
parent = parent.parentElement;
|
|
421
553
|
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
554
|
+
} else {
|
|
555
|
+
item.style.display = 'none';
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
} else {
|
|
559
|
+
testItems.forEach(item => {
|
|
560
|
+
item.style.display = 'block';
|
|
561
|
+
});
|
|
562
|
+
detailsElements.forEach(detail => {
|
|
563
|
+
detail.open = false;
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
});
|
|
432
567
|
|
|
433
|
-
|
|
434
|
-
|
|
568
|
+
const ctx = document.getElementById('testChart').getContext('2d');
|
|
569
|
+
new Chart(ctx, {
|
|
435
570
|
type: 'doughnut',
|
|
436
571
|
data: {
|
|
437
|
-
labels: ['Passed', 'Failed', 'Skipped'],
|
|
572
|
+
labels: ['Passed', 'Failed', 'Skipped','Flaky'],
|
|
438
573
|
datasets: [{
|
|
439
|
-
data: [{{ passCount }}, {{ failCount }}, {{ skipCount }}],
|
|
440
|
-
|
|
574
|
+
data: [{{ passCount }}, {{ failCount }}, {{ skipCount }}, {{flakyCount}}],
|
|
575
|
+
backgroundColor: ['#28a745', '#dc3545', '#d5d4a1', '#FFB704']
|
|
441
576
|
}]
|
|
442
577
|
},
|
|
443
578
|
options: {
|
|
444
|
-
|
|
445
|
-
|
|
579
|
+
responsive: true,
|
|
580
|
+
maintainAspectRatio: false,
|
|
446
581
|
plugins: {
|
|
447
582
|
legend: {
|
|
448
583
|
position: 'bottom'
|
|
449
584
|
}
|
|
450
585
|
}
|
|
451
586
|
}
|
|
452
|
-
});
|
|
453
|
-
attachEventListeners();
|
|
454
587
|
});
|
|
455
|
-
|
|
456
|
-
|
|
588
|
+
|
|
589
|
+
attachEventListeners();
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
</script>
|
|
593
|
+
<script src="node_modules/ortoni-report/dist/utils/modal.js"></script>
|
|
457
594
|
</body>
|
|
458
|
-
|
|
595
|
+
|
|
596
|
+
</html>
|