@testomatio/reporter 2.6.0 → 2.6.1
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/README.md +7 -7
- package/lib/adapter/playwright.d.ts +2 -12
- package/lib/adapter/playwright.js +15 -72
- package/lib/adapter/utils/playwright.d.ts +25 -0
- package/lib/adapter/utils/playwright.js +123 -0
- package/lib/adapter/vitest.js +2 -1
- package/lib/bin/cli.js +1 -1
- package/lib/data-storage.js +1 -0
- package/lib/pipe/html.d.ts +2 -3
- package/lib/pipe/html.js +745 -37
- package/lib/pipe/testomatio.js +12 -1
- package/lib/reporter-functions.d.ts +36 -11
- package/lib/reporter-functions.js +67 -25
- package/lib/reporter.d.ts +12 -8
- package/lib/template/testomatio-old.hbs +1421 -0
- package/lib/template/testomatio.hbs +3200 -1157
- package/lib/utils/log-formatter.js +8 -4
- package/package.json +2 -2
- package/src/adapter/playwright.js +15 -79
- package/src/adapter/utils/playwright.js +121 -0
- package/src/adapter/vitest.js +2 -1
- package/src/bin/cli.js +1 -1
- package/src/data-storage.js +1 -0
- package/src/pipe/html.js +844 -38
- package/src/pipe/testomatio.js +12 -1
- package/src/reporter-functions.js +68 -28
- package/src/template/testomatio-old.hbs +1421 -0
- package/src/template/testomatio.hbs +3200 -1157
- package/src/utils/log-formatter.js +9 -4
- package/types/types.d.ts +29 -5
- package/lib/services/labels.d.ts +0 -0
- package/lib/services/labels.js +0 -0
- package/src/services/labels.js +0 -1
|
@@ -4,22 +4,22 @@
|
|
|
4
4
|
<meta charset='UTF-8' />
|
|
5
5
|
<meta
|
|
6
6
|
name='viewport'
|
|
7
|
-
content='width=device-width,
|
|
7
|
+
content='width=device-width, initial-scale=1.0'
|
|
8
8
|
/>
|
|
9
9
|
<meta http-equiv='X-UA-Compatible' content='ie=edge' />
|
|
10
10
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
11
11
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
12
|
-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@
|
|
12
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
|
13
13
|
<link
|
|
14
|
-
href='https://cdn.jsdelivr.net/npm/bootstrap@5.0
|
|
14
|
+
href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css'
|
|
15
15
|
rel='stylesheet'
|
|
16
|
-
integrity='sha384-
|
|
16
|
+
integrity='sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM'
|
|
17
17
|
crossorigin='anonymous'
|
|
18
18
|
/>
|
|
19
19
|
<link
|
|
20
20
|
rel='stylesheet'
|
|
21
|
-
href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.
|
|
22
|
-
integrity='sha512-
|
|
21
|
+
href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css'
|
|
22
|
+
integrity='sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw=='
|
|
23
23
|
crossorigin='anonymous'
|
|
24
24
|
referrerpolicy='no-referrer'
|
|
25
25
|
/>
|
|
@@ -29,1393 +29,3436 @@
|
|
|
29
29
|
<title>Report Testomat.io</title>
|
|
30
30
|
{{/if}}
|
|
31
31
|
<style>
|
|
32
|
+
:root {
|
|
33
|
+
--primary-color: #6366f1;
|
|
34
|
+
--primary-hover: #4f46e5;
|
|
35
|
+
--success-color: #10b981;
|
|
36
|
+
--danger-color: #ef4444;
|
|
37
|
+
--warning-color: #f59e0b;
|
|
38
|
+
--info-color: #3b82f6;
|
|
39
|
+
--gray-50: #f9fafb;
|
|
40
|
+
--gray-100: #f3f4f6;
|
|
41
|
+
--gray-200: #e5e7eb;
|
|
42
|
+
--gray-300: #d1d5db;
|
|
43
|
+
--gray-400: #9ca3af;
|
|
44
|
+
--gray-500: #6b7280;
|
|
45
|
+
--gray-600: #4b5563;
|
|
46
|
+
--gray-700: #374151;
|
|
47
|
+
--gray-800: #1f2937;
|
|
48
|
+
--gray-900: #111827;
|
|
49
|
+
--border-radius: 12px;
|
|
50
|
+
--transition: all 0.2s ease;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
* {
|
|
54
|
+
box-sizing: border-box;
|
|
55
|
+
}
|
|
56
|
+
|
|
32
57
|
body {
|
|
33
|
-
padding: 0;
|
|
34
58
|
margin: 0;
|
|
35
|
-
|
|
59
|
+
padding: 0;
|
|
60
|
+
font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
61
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
62
|
+
min-height: 100vh;
|
|
63
|
+
color: var(--gray-800);
|
|
36
64
|
}
|
|
37
65
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
.main-container {
|
|
67
|
+
background: rgba(255, 255, 255, 0.98);
|
|
68
|
+
backdrop-filter: blur(20px);
|
|
69
|
+
margin: 20px auto;
|
|
70
|
+
max-width: 1400px;
|
|
71
|
+
border-radius: 20px;
|
|
72
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
73
|
+
overflow: hidden;
|
|
74
|
+
overflow-y: auto;
|
|
47
75
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
76
|
+
|
|
77
|
+
.header {
|
|
78
|
+
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-hover) 100%);
|
|
79
|
+
color: white;
|
|
80
|
+
padding: 30px;
|
|
81
|
+
display: flex;
|
|
82
|
+
justify-content: space-between;
|
|
83
|
+
align-items: center;
|
|
84
|
+
flex-wrap: wrap;
|
|
85
|
+
gap: 20px;
|
|
53
86
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
87
|
+
|
|
88
|
+
.header-title {
|
|
89
|
+
display: flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
gap: 15px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.header-title h1 {
|
|
58
95
|
margin: 0;
|
|
96
|
+
font-size: 28px;
|
|
97
|
+
font-weight: 700;
|
|
98
|
+
transition: color 0.3s ease;
|
|
59
99
|
}
|
|
60
|
-
|
|
61
|
-
|
|
100
|
+
|
|
101
|
+
.header-title h1.status-passed {
|
|
102
|
+
color: var(--success-color);
|
|
62
103
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
padding-bottom: 20px;
|
|
104
|
+
|
|
105
|
+
.header-title h1.status-failed {
|
|
106
|
+
color: var(--danger-color);
|
|
67
107
|
}
|
|
68
|
-
|
|
108
|
+
|
|
109
|
+
.header-title h1.status-skipped {
|
|
110
|
+
color: var(--warning-color);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.header-title h1.status-todo {
|
|
114
|
+
color: #8b5cf6;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.header-badge {
|
|
118
|
+
background: rgba(255, 255, 255, 0.2);
|
|
119
|
+
padding: 6px 16px;
|
|
120
|
+
border-radius: 20px;
|
|
121
|
+
font-size: 14px;
|
|
122
|
+
font-weight: 500;
|
|
123
|
+
backdrop-filter: blur(10px);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.header-actions {
|
|
69
127
|
display: flex;
|
|
70
|
-
|
|
128
|
+
gap: 15px;
|
|
71
129
|
align-items: center;
|
|
72
130
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
131
|
+
|
|
132
|
+
.run-info {
|
|
133
|
+
background: rgba(255, 255, 255, 0.15);
|
|
134
|
+
padding: 8px 16px;
|
|
135
|
+
border-radius: 8px;
|
|
136
|
+
font-size: 14px;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.btn-primary-custom {
|
|
140
|
+
background: rgba(255, 255, 255, 0.9);
|
|
141
|
+
color: var(--primary-color);
|
|
142
|
+
border: none;
|
|
143
|
+
padding: 10px 24px;
|
|
144
|
+
border-radius: 8px;
|
|
145
|
+
font-weight: 600;
|
|
146
|
+
text-decoration: none;
|
|
147
|
+
transition: var(--transition);
|
|
148
|
+
display: inline-flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
gap: 8px;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.btn-primary-custom:hover {
|
|
154
|
+
background: white;
|
|
155
|
+
transform: translateY(-1px);
|
|
156
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
157
|
+
color: var(--primary-hover);
|
|
78
158
|
}
|
|
79
|
-
|
|
80
|
-
|
|
159
|
+
|
|
160
|
+
.btn-primary-custom:disabled {
|
|
161
|
+
opacity: 0.6;
|
|
162
|
+
cursor: not-allowed;
|
|
163
|
+
transform: none;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.stats-section {
|
|
167
|
+
padding: 30px;
|
|
168
|
+
background: var(--gray-50);
|
|
169
|
+
border-bottom: 1px solid var(--gray-200);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.stats-grid {
|
|
173
|
+
display: grid;
|
|
174
|
+
grid-template-columns: 2fr 1fr;
|
|
175
|
+
gap: 30px;
|
|
176
|
+
margin-bottom: 30px;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.chart-container {
|
|
180
|
+
background: white;
|
|
181
|
+
padding: 25px;
|
|
182
|
+
border-radius: var(--border-radius);
|
|
183
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
184
|
+
min-height: 400px;
|
|
185
|
+
overflow: visible !important;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.chart-section {
|
|
189
|
+
width: 100%;
|
|
190
|
+
overflow: hidden;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
#testChart {
|
|
194
|
+
width: 100% !important;
|
|
195
|
+
max-width: 100% !important;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Google Charts tooltip stabilization */
|
|
199
|
+
#testChart > div > div[style*="position: absolute"] {
|
|
200
|
+
pointer-events: none !important;
|
|
201
|
+
will-change: transform, opacity !important;
|
|
202
|
+
backface-visibility: hidden !important;
|
|
203
|
+
transform: translateZ(0) !important;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.google-visualization-tooltip {
|
|
207
|
+
pointer-events: none !important;
|
|
208
|
+
opacity: 1 !important;
|
|
209
|
+
transition: none !important;
|
|
81
210
|
}
|
|
82
|
-
|
|
211
|
+
|
|
212
|
+
.stats-info {
|
|
213
|
+
background: white;
|
|
214
|
+
padding: 25px;
|
|
215
|
+
border-radius: var(--border-radius);
|
|
216
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
83
217
|
display: flex;
|
|
84
|
-
|
|
218
|
+
flex-direction: column;
|
|
219
|
+
justify-content: center;
|
|
220
|
+
gap: 20px;
|
|
85
221
|
}
|
|
86
|
-
|
|
222
|
+
|
|
223
|
+
.stat-card {
|
|
87
224
|
display: flex;
|
|
225
|
+
justify-content: space-between;
|
|
88
226
|
align-items: center;
|
|
89
|
-
|
|
227
|
+
padding: 12px 0;
|
|
228
|
+
border-bottom: 1px solid var(--gray-100);
|
|
90
229
|
}
|
|
91
|
-
|
|
92
|
-
|
|
230
|
+
|
|
231
|
+
.stat-card:last-child {
|
|
232
|
+
border-bottom: none;
|
|
93
233
|
}
|
|
94
|
-
|
|
95
|
-
|
|
234
|
+
|
|
235
|
+
.stat-label {
|
|
236
|
+
font-size: 13px;
|
|
237
|
+
color: var(--gray-600);
|
|
238
|
+
font-weight: 500;
|
|
239
|
+
display: flex;
|
|
240
|
+
align-items: center;
|
|
241
|
+
gap: 8px;
|
|
96
242
|
}
|
|
97
|
-
|
|
98
|
-
|
|
243
|
+
|
|
244
|
+
.stat-value {
|
|
245
|
+
font-size: 16px;
|
|
246
|
+
font-weight: 700;
|
|
247
|
+
color: var(--gray-900);
|
|
99
248
|
}
|
|
100
|
-
|
|
101
|
-
|
|
249
|
+
|
|
250
|
+
.status-badge {
|
|
251
|
+
padding: 4px 12px;
|
|
252
|
+
border-radius: 20px;
|
|
253
|
+
font-size: 12px;
|
|
102
254
|
font-weight: 600;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
border-radius: 5px;
|
|
106
|
-
padding: 5px 35px;
|
|
107
|
-
margin-right: 15px;
|
|
108
|
-
}
|
|
109
|
-
.btn {
|
|
110
|
-
box-shadow:none!important;
|
|
255
|
+
text-transform: uppercase;
|
|
256
|
+
letter-spacing: 0.5px;
|
|
111
257
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
background: #CA95FF;
|
|
116
|
-
color: #FFF!important;
|
|
117
|
-
border-radius: 5px;
|
|
118
|
-
padding: 9px 37px;
|
|
119
|
-
font-size: 15px;
|
|
258
|
+
|
|
259
|
+
.status-passed {
|
|
260
|
+
color: var(--success-color);
|
|
120
261
|
}
|
|
121
|
-
|
|
122
|
-
|
|
262
|
+
|
|
263
|
+
.status-failed {
|
|
264
|
+
color: var(--danger-color);
|
|
123
265
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
color:
|
|
266
|
+
|
|
267
|
+
.status-skipped {
|
|
268
|
+
color: var(--warning-color);
|
|
127
269
|
}
|
|
128
|
-
|
|
129
|
-
|
|
270
|
+
|
|
271
|
+
.status-running {
|
|
272
|
+
color: var(--info-color);
|
|
130
273
|
}
|
|
131
|
-
|
|
132
|
-
|
|
274
|
+
|
|
275
|
+
.controls-section {
|
|
276
|
+
padding: 30px;
|
|
277
|
+
background: white;
|
|
278
|
+
border-bottom: 1px solid var(--gray-200);
|
|
133
279
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
box-shadow: none;
|
|
139
|
-
border: 1px solid black!important;
|
|
140
|
-
background: #FFF!important;
|
|
141
|
-
border-radius: 3px;
|
|
142
|
-
}
|
|
143
|
-
.btn-all {
|
|
144
|
-
border: 1px solid #A0CAFF!important;
|
|
145
|
-
}
|
|
146
|
-
.btn-passed {
|
|
147
|
-
border: 1px solid #75B583!important;
|
|
148
|
-
}
|
|
149
|
-
.btn-failed {
|
|
150
|
-
border: 1px solid #FF6363!important;
|
|
151
|
-
}
|
|
152
|
-
.btn-skipped {
|
|
153
|
-
border: 1px solid #FFC350!important;
|
|
154
|
-
}
|
|
155
|
-
.btn-all:hover,
|
|
156
|
-
.btn-all:focus {
|
|
157
|
-
color: #A0CAFF!important;
|
|
158
|
-
background: #FFF!important;
|
|
159
|
-
border: 1px solid #A0CAFF!important;
|
|
160
|
-
font-weight: 700!important;
|
|
161
|
-
}
|
|
162
|
-
.btn-all:hover span,
|
|
163
|
-
.btn-all:focus span {
|
|
164
|
-
color: #A0CAFF!important;
|
|
165
|
-
font-weight: 700!important;
|
|
166
|
-
}
|
|
167
|
-
.allTest:checked + .btn-all span {
|
|
168
|
-
color: #A0CAFF!important;
|
|
169
|
-
}
|
|
170
|
-
.allTest:checked + .btn-all {
|
|
171
|
-
color:#A0CAFF!important;
|
|
172
|
-
background: #FFF!important;
|
|
173
|
-
border: 1px solid #A0CAFF!important;
|
|
174
|
-
font-weight: 700!important;
|
|
175
|
-
}
|
|
176
|
-
.btn-passed:hover,
|
|
177
|
-
.btn-passed:focus {
|
|
178
|
-
color: #75B583!important;
|
|
179
|
-
border: 1px solid #75B583!important;
|
|
180
|
-
background: #FFF!important;
|
|
181
|
-
font-weight: 700!important;
|
|
182
|
-
}
|
|
183
|
-
.btn-passed:hover span,
|
|
184
|
-
.btn-passed:focus span {
|
|
185
|
-
color: #75B583!important;
|
|
186
|
-
font-weight: 700!important;
|
|
187
|
-
}
|
|
188
|
-
.passedTest:checked + .btn-passed span {
|
|
189
|
-
color: #75B583!important;
|
|
190
|
-
font-weight: 700!important;
|
|
191
|
-
}
|
|
192
|
-
.passedTest:checked + .btn-passed {
|
|
193
|
-
color: #75B583!important;
|
|
194
|
-
border: 1px solid #75B583!important;
|
|
195
|
-
background: #FFF!important;
|
|
196
|
-
font-weight: 700!important;
|
|
197
|
-
}
|
|
198
|
-
.btn-failed:hover,
|
|
199
|
-
.btn-failed:focus {
|
|
200
|
-
color: #FF6363!important;
|
|
201
|
-
border: 1px solid #FF6363!important;
|
|
202
|
-
background: #FFF!important;
|
|
203
|
-
font-weight: 700!important;
|
|
204
|
-
}
|
|
205
|
-
.btn-failed:hover span,
|
|
206
|
-
.btn-failed:focus span {
|
|
207
|
-
color: #FF6363!important;
|
|
208
|
-
font-weight: 700!important;
|
|
209
|
-
}
|
|
210
|
-
.failedTest:checked + .btn-failed span {
|
|
211
|
-
color: #FF6363!important;
|
|
212
|
-
font-weight: 700!important;
|
|
213
|
-
}
|
|
214
|
-
.failedTest:checked + .btn-failed {
|
|
215
|
-
color: #FF6363!important;
|
|
216
|
-
border: 1px solid #FF6363!important;
|
|
217
|
-
background: #FFF!important;
|
|
218
|
-
font-weight: 700!important;
|
|
219
|
-
}
|
|
220
|
-
.btn-skipped:hover,
|
|
221
|
-
.btn-skipped:focus {
|
|
222
|
-
color: #FFC350!important;
|
|
223
|
-
border: 1px solid #FFC350!important;
|
|
224
|
-
background: #FFF!important;
|
|
225
|
-
font-weight: 700!important;
|
|
226
|
-
}
|
|
227
|
-
.btn-skipped:hover span,
|
|
228
|
-
.btn-skipped:focus span {
|
|
229
|
-
color: #FFC350!important;
|
|
230
|
-
font-weight: 700!important;
|
|
231
|
-
}
|
|
232
|
-
.skippedTest:checked + .btn-skipped span {
|
|
233
|
-
color: #FFC350!important;
|
|
234
|
-
font-weight: 700!important;
|
|
235
|
-
}
|
|
236
|
-
.skippedTest:checked + .btn-skipped {
|
|
237
|
-
color: #FFC350!important;
|
|
238
|
-
border: 1px solid #FFC350!important;
|
|
239
|
-
background: #FFF!important;
|
|
240
|
-
font-weight: 700!important;
|
|
241
|
-
}
|
|
242
|
-
.passed {
|
|
243
|
-
color: #75B583;
|
|
244
|
-
}
|
|
245
|
-
.failed {
|
|
246
|
-
color: #FF6363;
|
|
247
|
-
}
|
|
248
|
-
.skipped {
|
|
249
|
-
color: #FFC350;
|
|
250
|
-
}
|
|
251
|
-
.testWrapp {
|
|
252
|
-
margin-top: 45px;
|
|
253
|
-
}
|
|
254
|
-
.fa-arrow-right {
|
|
255
|
-
display: none!important;
|
|
256
|
-
}
|
|
257
|
-
.header__type:hover {
|
|
258
|
-
background: #B468FF;
|
|
259
|
-
}
|
|
260
|
-
.header__case i {
|
|
261
|
-
color: grey;
|
|
262
|
-
margin-right: 5px;
|
|
263
|
-
}
|
|
264
|
-
.title {
|
|
265
|
-
display: flex;
|
|
266
|
-
margin-bottom: 20px;
|
|
280
|
+
|
|
281
|
+
.search-container {
|
|
282
|
+
position: relative;
|
|
283
|
+
margin-bottom: 25px;
|
|
267
284
|
}
|
|
268
|
-
|
|
269
|
-
|
|
285
|
+
|
|
286
|
+
.search-input {
|
|
287
|
+
width: 100%;
|
|
288
|
+
padding: 15px 20px 15px 50px;
|
|
289
|
+
border: 2px solid var(--gray-200);
|
|
290
|
+
border-radius: var(--border-radius);
|
|
270
291
|
font-size: 15px;
|
|
271
|
-
|
|
272
|
-
|
|
292
|
+
transition: var(--transition);
|
|
293
|
+
background: var(--gray-50);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.search-input:focus {
|
|
297
|
+
outline: none;
|
|
298
|
+
border-color: var(--primary-color);
|
|
299
|
+
background: white;
|
|
300
|
+
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.search-icon {
|
|
304
|
+
position: absolute;
|
|
305
|
+
left: 20px;
|
|
306
|
+
top: 50%;
|
|
307
|
+
transform: translateY(-50%);
|
|
308
|
+
color: var(--gray-400);
|
|
309
|
+
font-size: 18px;
|
|
273
310
|
}
|
|
274
|
-
|
|
311
|
+
|
|
312
|
+
.filters-container {
|
|
275
313
|
display: flex;
|
|
314
|
+
gap: 15px;
|
|
315
|
+
flex-wrap: wrap;
|
|
316
|
+
align-items: center;
|
|
317
|
+
justify-content: space-between;
|
|
276
318
|
}
|
|
277
|
-
|
|
319
|
+
|
|
320
|
+
.filter-tabs {
|
|
278
321
|
display: flex;
|
|
279
|
-
|
|
322
|
+
gap: 8px;
|
|
323
|
+
background: var(--gray-100);
|
|
324
|
+
padding: 4px;
|
|
325
|
+
border-radius: var(--border-radius);
|
|
280
326
|
}
|
|
281
|
-
|
|
282
|
-
|
|
327
|
+
|
|
328
|
+
.filter-tab {
|
|
329
|
+
padding: 10px 20px;
|
|
330
|
+
border: none;
|
|
331
|
+
background: transparent;
|
|
332
|
+
border-radius: 8px;
|
|
333
|
+
font-weight: 500;
|
|
334
|
+
cursor: pointer;
|
|
335
|
+
transition: var(--transition);
|
|
283
336
|
display: flex;
|
|
284
|
-
|
|
337
|
+
align-items: center;
|
|
338
|
+
gap: 8px;
|
|
339
|
+
color: var(--gray-600);
|
|
340
|
+
font-size: 14px;
|
|
285
341
|
}
|
|
286
|
-
|
|
287
|
-
|
|
342
|
+
|
|
343
|
+
.filter-tab:hover {
|
|
344
|
+
background: rgba(255, 255, 255, 0.5);
|
|
288
345
|
}
|
|
289
|
-
|
|
290
|
-
|
|
346
|
+
|
|
347
|
+
.filter-tab.active {
|
|
348
|
+
background: white;
|
|
349
|
+
color: var(--primary-color);
|
|
350
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
291
351
|
}
|
|
292
|
-
|
|
293
|
-
.
|
|
294
|
-
|
|
295
|
-
|
|
352
|
+
|
|
353
|
+
.filter-tab .count {
|
|
354
|
+
background: var(--gray-200);
|
|
355
|
+
padding: 2px 8px;
|
|
356
|
+
border-radius: 12px;
|
|
357
|
+
font-size: 12px;
|
|
358
|
+
font-weight: 600;
|
|
296
359
|
}
|
|
297
|
-
|
|
298
|
-
|
|
360
|
+
|
|
361
|
+
.filter-tab.active .count {
|
|
362
|
+
background: var(--primary-color);
|
|
363
|
+
color: white;
|
|
299
364
|
}
|
|
300
|
-
|
|
365
|
+
|
|
366
|
+
.pagination-control {
|
|
301
367
|
display: flex;
|
|
302
368
|
align-items: center;
|
|
369
|
+
gap: 15px;
|
|
303
370
|
}
|
|
304
|
-
|
|
305
|
-
|
|
371
|
+
|
|
372
|
+
.pagination-select {
|
|
373
|
+
padding: 10px 15px;
|
|
374
|
+
border: 2px solid var(--gray-200);
|
|
375
|
+
border-radius: 8px;
|
|
376
|
+
background: white;
|
|
377
|
+
font-size: 14px;
|
|
378
|
+
cursor: pointer;
|
|
379
|
+
transition: var(--transition);
|
|
306
380
|
}
|
|
307
|
-
|
|
308
|
-
|
|
381
|
+
|
|
382
|
+
.pagination-select:focus {
|
|
383
|
+
outline: none;
|
|
384
|
+
border-color: var(--primary-color);
|
|
385
|
+
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
|
|
309
386
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
387
|
+
|
|
388
|
+
.tests-section {
|
|
389
|
+
padding: 30px;
|
|
390
|
+
background: white;
|
|
391
|
+
min-height: 400px;
|
|
315
392
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
393
|
+
|
|
394
|
+
.test-item {
|
|
395
|
+
background: white;
|
|
396
|
+
border: 2px solid var(--gray-200);
|
|
397
|
+
border-radius: var(--border-radius);
|
|
398
|
+
margin-bottom: 20px;
|
|
399
|
+
overflow: hidden;
|
|
400
|
+
transition: var(--transition);
|
|
319
401
|
}
|
|
320
|
-
|
|
321
|
-
|
|
402
|
+
|
|
403
|
+
.test-item:hover {
|
|
404
|
+
border-color: var(--primary-color);
|
|
405
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
322
406
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
407
|
+
|
|
408
|
+
.test-header {
|
|
409
|
+
padding: 20px;
|
|
410
|
+
background: var(--gray-50);
|
|
411
|
+
cursor: pointer;
|
|
412
|
+
display: flex;
|
|
413
|
+
justify-content: space-between;
|
|
414
|
+
align-items: center;
|
|
415
|
+
transition: var(--transition);
|
|
329
416
|
}
|
|
330
|
-
|
|
331
|
-
|
|
417
|
+
|
|
418
|
+
.test-header:hover {
|
|
419
|
+
background: var(--gray-100);
|
|
332
420
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
421
|
+
|
|
422
|
+
.test-info {
|
|
423
|
+
display: flex;
|
|
424
|
+
align-items: center;
|
|
425
|
+
gap: 15px;
|
|
426
|
+
flex: 1;
|
|
336
427
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
428
|
+
|
|
429
|
+
.test-status-icon {
|
|
430
|
+
width: 40px;
|
|
431
|
+
height: 40px;
|
|
340
432
|
border-radius: 50%;
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
433
|
+
display: flex;
|
|
434
|
+
align-items: center;
|
|
435
|
+
justify-content: center;
|
|
436
|
+
font-size: 16px;
|
|
437
|
+
font-weight: 600;
|
|
346
438
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
439
|
+
|
|
440
|
+
.test-status-icon.passed {
|
|
441
|
+
background: rgba(16, 185, 129, 0.1);
|
|
442
|
+
color: var(--success-color);
|
|
350
443
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
444
|
+
|
|
445
|
+
.test-status-icon.failed {
|
|
446
|
+
background: rgba(239, 68, 68, 0.1);
|
|
447
|
+
color: var(--danger-color);
|
|
354
448
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
color:
|
|
449
|
+
|
|
450
|
+
.test-status-icon.skipped {
|
|
451
|
+
background: rgba(245, 158, 11, 0.1);
|
|
452
|
+
color: var(--warning-color);
|
|
359
453
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
margin-bottom: 15px;
|
|
454
|
+
|
|
455
|
+
.test-details {
|
|
456
|
+
flex: 1;
|
|
364
457
|
}
|
|
365
|
-
|
|
366
|
-
|
|
458
|
+
|
|
459
|
+
.test-title {
|
|
460
|
+
font-size: 16px;
|
|
461
|
+
font-weight: 600;
|
|
462
|
+
color: var(--gray-900);
|
|
463
|
+
margin-bottom: 5px;
|
|
367
464
|
display: flex;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
cursor: pointer;
|
|
372
|
-
justify-content: space-between;
|
|
465
|
+
align-items: center;
|
|
466
|
+
gap: 8px;
|
|
467
|
+
flex-wrap: wrap;
|
|
373
468
|
}
|
|
374
|
-
|
|
375
|
-
|
|
469
|
+
|
|
470
|
+
.artifact-upload-indicator {
|
|
471
|
+
display: inline-flex;
|
|
376
472
|
align-items: center;
|
|
377
473
|
justify-content: center;
|
|
378
|
-
width:
|
|
379
|
-
|
|
474
|
+
width: 20px;
|
|
475
|
+
height: 20px;
|
|
476
|
+
color: var(--primary-color);
|
|
477
|
+
font-size: 14px;
|
|
478
|
+
flex-shrink: 0;
|
|
380
479
|
}
|
|
381
|
-
|
|
382
|
-
|
|
480
|
+
|
|
481
|
+
.artifact-upload-indicator:hover {
|
|
482
|
+
transform: scale(1.1);
|
|
483
|
+
transition: transform 0.2s ease;
|
|
383
484
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
485
|
+
|
|
486
|
+
.test-suite {
|
|
487
|
+
font-size: 14px;
|
|
488
|
+
color: var(--gray-600);
|
|
388
489
|
}
|
|
389
|
-
|
|
490
|
+
|
|
491
|
+
.test-meta {
|
|
390
492
|
display: flex;
|
|
391
|
-
|
|
392
|
-
|
|
493
|
+
align-items: center;
|
|
494
|
+
gap: 20px;
|
|
393
495
|
}
|
|
394
|
-
|
|
496
|
+
|
|
497
|
+
.test-duration {
|
|
395
498
|
display: flex;
|
|
396
|
-
|
|
397
|
-
|
|
499
|
+
align-items: center;
|
|
500
|
+
gap: 5px;
|
|
501
|
+
color: var(--gray-500);
|
|
502
|
+
font-size: 14px;
|
|
398
503
|
}
|
|
399
|
-
|
|
400
|
-
|
|
504
|
+
|
|
505
|
+
.test-badges {
|
|
506
|
+
display: flex;
|
|
507
|
+
gap: 8px;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.badge {
|
|
511
|
+
padding: 4px 10px;
|
|
512
|
+
border-radius: 12px;
|
|
513
|
+
font-size: 11px;
|
|
401
514
|
font-weight: 600;
|
|
515
|
+
text-transform: uppercase;
|
|
516
|
+
letter-spacing: 0.3px;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.badge-flaky {
|
|
520
|
+
background: rgba(245, 158, 11, 0.1);
|
|
521
|
+
color: var(--warning-color);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
.badge-retry {
|
|
525
|
+
background: rgba(59, 130, 246, 0.1);
|
|
526
|
+
color: var(--info-color);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.expand-icon {
|
|
530
|
+
color: var(--gray-400);
|
|
531
|
+
transition: var(--transition);
|
|
532
|
+
font-size: 18px;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.test-item.expanded .expand-icon {
|
|
536
|
+
transform: rotate(180deg);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.test-content {
|
|
540
|
+
display: none;
|
|
541
|
+
border-top: 1px solid var(--gray-200);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
.test-item.expanded .test-content {
|
|
545
|
+
display: block;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.test-group {
|
|
549
|
+
background: white;
|
|
550
|
+
border: 2px solid var(--gray-200);
|
|
551
|
+
border-radius: var(--border-radius);
|
|
552
|
+
margin-bottom: 20px;
|
|
553
|
+
overflow: hidden;
|
|
554
|
+
transition: var(--transition);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
.test-group:hover {
|
|
558
|
+
border-color: var(--primary-color);
|
|
559
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.test-group-header {
|
|
563
|
+
padding: 20px;
|
|
564
|
+
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-hover) 100%);
|
|
565
|
+
color: white;
|
|
402
566
|
cursor: pointer;
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
padding-top: 20px;
|
|
408
|
-
padding-bottom: 20px;
|
|
567
|
+
display: flex;
|
|
568
|
+
justify-content: space-between;
|
|
569
|
+
align-items: center;
|
|
570
|
+
transition: var(--transition);
|
|
409
571
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
font-weight: 700;
|
|
572
|
+
|
|
573
|
+
.test-group-header:hover {
|
|
574
|
+
filter: brightness(1.1);
|
|
414
575
|
}
|
|
415
|
-
|
|
576
|
+
|
|
577
|
+
.test-group-title {
|
|
416
578
|
display: flex;
|
|
417
|
-
|
|
418
|
-
|
|
579
|
+
align-items: center;
|
|
580
|
+
gap: 15px;
|
|
581
|
+
flex: 1;
|
|
419
582
|
}
|
|
420
|
-
|
|
583
|
+
|
|
584
|
+
.test-group-name {
|
|
421
585
|
font-size: 18px;
|
|
422
|
-
color: black;
|
|
423
586
|
font-weight: 700;
|
|
424
|
-
margin-bottom: 15px;
|
|
425
|
-
text-decoration: underline;
|
|
426
587
|
}
|
|
427
|
-
|
|
588
|
+
|
|
589
|
+
.test-group-count {
|
|
590
|
+
background: rgba(255, 255, 255, 0.2);
|
|
591
|
+
padding: 6px 16px;
|
|
592
|
+
border-radius: 20px;
|
|
428
593
|
font-size: 14px;
|
|
429
|
-
|
|
594
|
+
font-weight: 600;
|
|
430
595
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
596
|
+
|
|
597
|
+
.test-group-stats {
|
|
598
|
+
display: flex;
|
|
599
|
+
gap: 20px;
|
|
600
|
+
font-size: 14px;
|
|
601
|
+
margin-right: 10px;
|
|
434
602
|
}
|
|
435
|
-
|
|
436
|
-
|
|
603
|
+
|
|
604
|
+
.test-group-stat {
|
|
605
|
+
display: flex;
|
|
606
|
+
align-items: center;
|
|
607
|
+
gap: 6px;
|
|
437
608
|
}
|
|
438
|
-
|
|
439
|
-
.
|
|
440
|
-
color:
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
font-weight: 600;
|
|
444
|
-
border-radius: 3px;
|
|
609
|
+
|
|
610
|
+
.test-group-expand {
|
|
611
|
+
color: white;
|
|
612
|
+
transition: var(--transition);
|
|
613
|
+
font-size: 18px;
|
|
445
614
|
}
|
|
446
|
-
|
|
447
|
-
|
|
615
|
+
|
|
616
|
+
.test-group.expanded .test-group-expand {
|
|
617
|
+
transform: rotate(180deg);
|
|
448
618
|
}
|
|
449
|
-
|
|
450
|
-
|
|
619
|
+
|
|
620
|
+
.test-group-content {
|
|
621
|
+
display: none;
|
|
622
|
+
background: var(--gray-50);
|
|
451
623
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
624
|
+
|
|
625
|
+
.test-group.expanded .test-group-content {
|
|
626
|
+
display: block;
|
|
455
627
|
}
|
|
456
|
-
|
|
457
|
-
|
|
628
|
+
|
|
629
|
+
.test-group-content .test-item {
|
|
630
|
+
border: none;
|
|
631
|
+
border-bottom: 1px solid var(--gray-200);
|
|
632
|
+
border-radius: 0;
|
|
633
|
+
margin-bottom: 0;
|
|
458
634
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
border:
|
|
462
|
-
color: black;
|
|
635
|
+
|
|
636
|
+
.test-group-content .test-item:last-child {
|
|
637
|
+
border-bottom: none;
|
|
463
638
|
}
|
|
464
|
-
|
|
639
|
+
|
|
640
|
+
.test-tabs {
|
|
465
641
|
display: flex;
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
justify-content: center;
|
|
469
|
-
margin-bottom: 150px;
|
|
642
|
+
background: var(--gray-50);
|
|
643
|
+
border-bottom: 1px solid var(--gray-200);
|
|
470
644
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
645
|
+
|
|
646
|
+
.test-tab {
|
|
647
|
+
padding: 15px 25px;
|
|
648
|
+
background: none;
|
|
649
|
+
border: none;
|
|
650
|
+
cursor: pointer;
|
|
651
|
+
font-weight: 500;
|
|
652
|
+
color: var(--gray-600);
|
|
653
|
+
transition: var(--transition);
|
|
654
|
+
position: relative;
|
|
475
655
|
}
|
|
476
|
-
</style>
|
|
477
|
-
</head>
|
|
478
656
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
657
|
+
.test-tab:hover {
|
|
658
|
+
color: var(--primary-color);
|
|
659
|
+
background: rgba(255, 255, 255, 0.5);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.test-tab.active {
|
|
663
|
+
color: var(--primary-color);
|
|
664
|
+
background: white;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.test-tab.active::after {
|
|
668
|
+
content: '';
|
|
669
|
+
position: absolute;
|
|
670
|
+
bottom: 0;
|
|
671
|
+
left: 0;
|
|
672
|
+
right: 0;
|
|
673
|
+
height: 2px;
|
|
674
|
+
background: var(--primary-color);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
.test-tab-content {
|
|
678
|
+
padding: 25px;
|
|
679
|
+
display: none;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
.test-tab-content.active {
|
|
683
|
+
display: block;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.code-block {
|
|
687
|
+
background: var(--gray-900);
|
|
688
|
+
color: #e5e7eb;
|
|
689
|
+
padding: 20px;
|
|
690
|
+
border-radius: 8px;
|
|
691
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
692
|
+
font-size: 14px;
|
|
693
|
+
line-height: 1.5;
|
|
694
|
+
overflow-x: auto;
|
|
695
|
+
white-space: pre-wrap;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.steps-container {
|
|
699
|
+
max-height: 500px;
|
|
700
|
+
overflow-y: auto;
|
|
701
|
+
border: 1px solid var(--gray-200);
|
|
702
|
+
border-radius: 8px;
|
|
703
|
+
background: white;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
.step-item {
|
|
707
|
+
padding: 12px 16px;
|
|
708
|
+
border-bottom: 1px solid var(--gray-100);
|
|
709
|
+
display: flex;
|
|
710
|
+
align-items: flex-start;
|
|
711
|
+
gap: 12px;
|
|
712
|
+
transition: var(--transition);
|
|
713
|
+
position: relative;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
.step-item:hover {
|
|
717
|
+
background: var(--gray-50);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.step-item:last-child {
|
|
721
|
+
border-bottom: none;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.step-number {
|
|
725
|
+
flex-shrink: 0;
|
|
726
|
+
width: 28px;
|
|
727
|
+
height: 28px;
|
|
728
|
+
border-radius: 50%;
|
|
729
|
+
background: var(--primary-color);
|
|
730
|
+
color: white;
|
|
731
|
+
display: flex;
|
|
732
|
+
align-items: center;
|
|
733
|
+
justify-content: center;
|
|
734
|
+
font-size: 12px;
|
|
735
|
+
font-weight: 600;
|
|
736
|
+
margin-top: 2px;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
.step-content {
|
|
740
|
+
flex: 1;
|
|
741
|
+
min-width: 0;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
.step-text {
|
|
745
|
+
font-size: 14px;
|
|
746
|
+
color: var(--gray-700);
|
|
747
|
+
line-height: 1.5;
|
|
748
|
+
margin: 0;
|
|
749
|
+
word-break: break-word;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.step-time {
|
|
753
|
+
font-size: 12px;
|
|
754
|
+
color: var(--gray-500);
|
|
755
|
+
margin-top: 4px;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.step-status {
|
|
759
|
+
width: 8px;
|
|
760
|
+
height: 8px;
|
|
761
|
+
border-radius: 50%;
|
|
762
|
+
margin-top: 8px;
|
|
763
|
+
flex-shrink: 0;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
.step-status.passed {
|
|
767
|
+
background: var(--success-color);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
.step-status.failed {
|
|
771
|
+
background: var(--danger-color);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.step-status.skipped {
|
|
775
|
+
background: var(--warning-color);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
.step-category {
|
|
779
|
+
font-size: 11px;
|
|
780
|
+
text-transform: uppercase;
|
|
781
|
+
letter-spacing: 0.5px;
|
|
782
|
+
color: var(--gray-500);
|
|
783
|
+
font-weight: 600;
|
|
784
|
+
margin-top: 4px;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
.step-children {
|
|
788
|
+
position: relative;
|
|
789
|
+
margin-left: 48px;
|
|
790
|
+
padding-left: 0;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
.step-children::before {
|
|
794
|
+
content: '';
|
|
795
|
+
position: absolute;
|
|
796
|
+
left: 0;
|
|
797
|
+
top: 0;
|
|
798
|
+
bottom: 0;
|
|
799
|
+
width: 2px;
|
|
800
|
+
background: var(--gray-300);
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
.step-children .step-item {
|
|
804
|
+
position: relative;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
.step-children .step-item::before {
|
|
808
|
+
content: '';
|
|
809
|
+
position: absolute;
|
|
810
|
+
left: -16px;
|
|
811
|
+
top: 24px;
|
|
812
|
+
width: 16px;
|
|
813
|
+
height: 2px;
|
|
814
|
+
background: var(--gray-300);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
.step-children .step-item:last-child {
|
|
818
|
+
border-bottom: none;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
.step-level-0 {
|
|
822
|
+
padding-left: 16px;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
.step-level-1 {
|
|
826
|
+
padding-left: 8px;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
.step-level-2 {
|
|
830
|
+
padding-left: 16px;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.step-level-3 {
|
|
834
|
+
padding-left: 24px;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
.step-level-4 {
|
|
838
|
+
padding-left: 32px;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
.step-item[data-step-id] {
|
|
842
|
+
position: relative;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
.step-item.step-level-0::before {
|
|
846
|
+
display: none;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
.step-duration {
|
|
850
|
+
display: inline-flex;
|
|
851
|
+
align-items: center;
|
|
852
|
+
gap: 4px;
|
|
853
|
+
font-size: 11px;
|
|
854
|
+
color: var(--gray-500);
|
|
855
|
+
margin-left: 8px;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
.message-block {
|
|
859
|
+
background: var(--gray-50);
|
|
860
|
+
padding: 20px;
|
|
861
|
+
border-radius: 8px;
|
|
862
|
+
border-left: 4px solid var(--danger-color);
|
|
863
|
+
margin-bottom: 15px;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
.message-block.info {
|
|
867
|
+
border-left-color: var(--info-color);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
.metadata-grid {
|
|
871
|
+
display: grid;
|
|
872
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
873
|
+
gap: 15px;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
.metadata-item {
|
|
877
|
+
background: var(--gray-50);
|
|
878
|
+
padding: 15px;
|
|
879
|
+
border-radius: 8px;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
.metadata-key {
|
|
883
|
+
font-weight: 600;
|
|
884
|
+
color: var(--gray-700);
|
|
885
|
+
margin-bottom: 5px;
|
|
886
|
+
font-size: 14px;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
.metadata-value {
|
|
890
|
+
color: var(--gray-600);
|
|
891
|
+
font-size: 14px;
|
|
892
|
+
word-break: break-all;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
.attachments-grid {
|
|
896
|
+
display: grid;
|
|
897
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
898
|
+
gap: 20px;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
.attachment-item {
|
|
902
|
+
background: var(--gray-50);
|
|
903
|
+
border-radius: 8px;
|
|
904
|
+
overflow: hidden;
|
|
905
|
+
transition: var(--transition);
|
|
906
|
+
cursor: pointer;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
.attachment-item:hover {
|
|
910
|
+
transform: translateY(-2px);
|
|
911
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
.attachment-image {
|
|
915
|
+
width: 100%;
|
|
916
|
+
height: 150px;
|
|
917
|
+
object-fit: cover;
|
|
918
|
+
cursor: pointer;
|
|
919
|
+
transition: var(--transition);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
.attachment-image:hover {
|
|
923
|
+
transform: scale(1.02);
|
|
924
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
.attachment-file {
|
|
928
|
+
display: flex;
|
|
929
|
+
flex-direction: column;
|
|
930
|
+
align-items: center;
|
|
931
|
+
justify-content: center;
|
|
932
|
+
height: 150px;
|
|
933
|
+
background: white;
|
|
934
|
+
cursor: pointer;
|
|
935
|
+
transition: var(--transition);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
.attachment-file:hover {
|
|
939
|
+
transform: scale(1.02);
|
|
940
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
.attachment-preview {
|
|
944
|
+
position: relative;
|
|
945
|
+
overflow: hidden;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
.attachment-overlay {
|
|
949
|
+
position: absolute;
|
|
950
|
+
top: 0;
|
|
951
|
+
left: 0;
|
|
952
|
+
right: 0;
|
|
953
|
+
bottom: 0;
|
|
954
|
+
background: rgba(0, 0, 0, 0.7);
|
|
955
|
+
display: flex;
|
|
956
|
+
align-items: center;
|
|
957
|
+
justify-content: center;
|
|
958
|
+
opacity: 0;
|
|
959
|
+
transition: opacity 0.2s ease;
|
|
960
|
+
color: white;
|
|
961
|
+
font-size: 14px;
|
|
962
|
+
font-weight: 600;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
.attachment-item:hover .attachment-overlay {
|
|
966
|
+
opacity: 1;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
.attachment-actions {
|
|
970
|
+
display: flex;
|
|
971
|
+
gap: 8px;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
.attachment-action {
|
|
975
|
+
padding: 6px 12px;
|
|
976
|
+
background: rgba(255, 255, 255, 0.2);
|
|
977
|
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
978
|
+
border-radius: 4px;
|
|
979
|
+
color: white;
|
|
980
|
+
text-decoration: none;
|
|
981
|
+
font-size: 12px;
|
|
982
|
+
cursor: pointer;
|
|
983
|
+
transition: var(--transition);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
.attachment-action:hover {
|
|
987
|
+
background: rgba(255, 255, 255, 0.3);
|
|
988
|
+
transform: translateY(-1px);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
.attachment-icon {
|
|
992
|
+
font-size: 48px;
|
|
993
|
+
color: var(--gray-400);
|
|
994
|
+
margin-bottom: 10px;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
.attachment-name {
|
|
998
|
+
padding: 12px;
|
|
999
|
+
font-size: 14px;
|
|
1000
|
+
font-weight: 500;
|
|
1001
|
+
color: var(--gray-700);
|
|
1002
|
+
text-align: center;
|
|
1003
|
+
border-top: 1px solid var(--gray-200);
|
|
1004
|
+
display: flex;
|
|
1005
|
+
flex-direction: column;
|
|
1006
|
+
gap: 4px;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
.attachment-size {
|
|
1010
|
+
font-size: 11px;
|
|
1011
|
+
color: var(--gray-500);
|
|
1012
|
+
font-weight: 400;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
.retry-info {
|
|
1016
|
+
background: rgba(59, 130, 246, 0.05);
|
|
1017
|
+
border: 1px solid rgba(59, 130, 246, 0.2);
|
|
1018
|
+
border-radius: 8px;
|
|
1019
|
+
padding: 15px;
|
|
1020
|
+
margin-bottom: 20px;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
.retry-title {
|
|
1024
|
+
font-weight: 600;
|
|
1025
|
+
color: var(--info-color);
|
|
1026
|
+
margin-bottom: 10px;
|
|
1027
|
+
display: flex;
|
|
1028
|
+
align-items: center;
|
|
1029
|
+
gap: 8px;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
.retry-attempts {
|
|
1033
|
+
display: flex;
|
|
1034
|
+
gap: 10px;
|
|
1035
|
+
flex-wrap: wrap;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
.retry-attempt {
|
|
1039
|
+
background: white;
|
|
1040
|
+
border: 1px solid var(--gray-200);
|
|
1041
|
+
border-radius: 6px;
|
|
1042
|
+
padding: 8px 12px;
|
|
1043
|
+
font-size: 13px;
|
|
1044
|
+
display: flex;
|
|
1045
|
+
align-items: center;
|
|
1046
|
+
gap: 6px;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
.retry-attempt.failed {
|
|
1050
|
+
border-color: var(--danger-color);
|
|
1051
|
+
color: var(--danger-color);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
.retry-attempt.passed {
|
|
1055
|
+
border-color: var(--success-color);
|
|
1056
|
+
color: var(--success-color);
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
.traces-instruction {
|
|
1060
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
1061
|
+
border-radius: 12px;
|
|
1062
|
+
padding: 20px;
|
|
1063
|
+
margin-bottom: 20px;
|
|
1064
|
+
color: white;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
.instruction-header {
|
|
1068
|
+
display: flex;
|
|
1069
|
+
align-items: center;
|
|
1070
|
+
gap: 10px;
|
|
1071
|
+
font-size: 16px;
|
|
1072
|
+
font-weight: 600;
|
|
1073
|
+
margin-bottom: 15px;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
.instruction-content ol {
|
|
1077
|
+
margin: 0;
|
|
1078
|
+
padding-left: 20px;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
.instruction-content li {
|
|
1082
|
+
margin-bottom: 15px;
|
|
1083
|
+
line-height: 1.6;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
.instruction-content strong {
|
|
1087
|
+
color: #fff;
|
|
1088
|
+
font-weight: 600;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
.instruction-content code {
|
|
1092
|
+
background: rgba(0, 0, 0, 0.3);
|
|
1093
|
+
color: #fff;
|
|
1094
|
+
padding: 6px 10px;
|
|
1095
|
+
border-radius: 6px;
|
|
1096
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
1097
|
+
font-size: 13px;
|
|
1098
|
+
display: inline-block;
|
|
1099
|
+
margin: 5px 0;
|
|
1100
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
.traces-list {
|
|
1104
|
+
display: flex;
|
|
1105
|
+
flex-direction: column;
|
|
1106
|
+
gap: 12px;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
.trace-download-item {
|
|
1110
|
+
background: white;
|
|
1111
|
+
border: 1px solid var(--gray-200);
|
|
1112
|
+
border-radius: 8px;
|
|
1113
|
+
padding: 15px 20px;
|
|
1114
|
+
display: flex;
|
|
1115
|
+
justify-content: space-between;
|
|
1116
|
+
align-items: center;
|
|
1117
|
+
gap: 15px;
|
|
1118
|
+
transition: var(--transition);
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
.trace-download-item:hover {
|
|
1122
|
+
border-color: var(--primary-color);
|
|
1123
|
+
box-shadow: 0 2px 8px rgba(99, 102, 241, 0.1);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
.trace-info {
|
|
1127
|
+
display: flex;
|
|
1128
|
+
align-items: center;
|
|
1129
|
+
gap: 12px;
|
|
1130
|
+
flex: 1;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
.trace-info i {
|
|
1134
|
+
font-size: 24px;
|
|
1135
|
+
color: var(--warning-color);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
.trace-name {
|
|
1139
|
+
font-size: 14px;
|
|
1140
|
+
font-weight: 500;
|
|
1141
|
+
color: var(--gray-700);
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
.trace-download-btn {
|
|
1145
|
+
background: var(--primary-color);
|
|
1146
|
+
color: white;
|
|
1147
|
+
border: none;
|
|
1148
|
+
padding: 10px 20px;
|
|
1149
|
+
border-radius: 6px;
|
|
1150
|
+
font-size: 14px;
|
|
1151
|
+
font-weight: 600;
|
|
1152
|
+
cursor: pointer;
|
|
1153
|
+
transition: var(--transition);
|
|
1154
|
+
display: inline-flex;
|
|
1155
|
+
align-items: center;
|
|
1156
|
+
gap: 8px;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
.trace-download-btn:hover {
|
|
1160
|
+
background: var(--primary-hover);
|
|
1161
|
+
transform: translateY(-1px);
|
|
1162
|
+
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
.trace-download-btn:active {
|
|
1166
|
+
transform: translateY(0);
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
.pagination-container {
|
|
1170
|
+
padding: 30px;
|
|
1171
|
+
background: white;
|
|
1172
|
+
border-top: 1px solid var(--gray-200);
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
.pagination {
|
|
1176
|
+
display: flex;
|
|
1177
|
+
justify-content: center;
|
|
1178
|
+
align-items: center;
|
|
1179
|
+
gap: 10px;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
.pagination-btn {
|
|
1183
|
+
padding: 10px 15px;
|
|
1184
|
+
border: 2px solid var(--gray-200);
|
|
1185
|
+
background: white;
|
|
1186
|
+
border-radius: 8px;
|
|
1187
|
+
cursor: pointer;
|
|
1188
|
+
transition: var(--transition);
|
|
1189
|
+
font-weight: 500;
|
|
1190
|
+
color: var(--gray-700);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
.pagination-btn:hover:not(:disabled) {
|
|
1194
|
+
border-color: var(--primary-color);
|
|
1195
|
+
color: var(--primary-color);
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
.pagination-btn.active {
|
|
1199
|
+
background: var(--primary-color);
|
|
1200
|
+
border-color: var(--primary-color);
|
|
1201
|
+
color: white;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
.pagination-btn:disabled {
|
|
1205
|
+
opacity: 0.5;
|
|
1206
|
+
cursor: not-allowed;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
.empty-state {
|
|
1210
|
+
text-align: center;
|
|
1211
|
+
padding: 60px 20px;
|
|
1212
|
+
color: var(--gray-500);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
.empty-icon {
|
|
1216
|
+
font-size: 64px;
|
|
1217
|
+
color: var(--gray-300);
|
|
1218
|
+
margin-bottom: 20px;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
.empty-title {
|
|
1222
|
+
font-size: 20px;
|
|
1223
|
+
font-weight: 600;
|
|
1224
|
+
margin-bottom: 10px;
|
|
1225
|
+
color: var(--gray-600);
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
.empty-description {
|
|
1229
|
+
font-size: 16px;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
.loading {
|
|
1233
|
+
display: flex;
|
|
1234
|
+
justify-content: center;
|
|
1235
|
+
align-items: center;
|
|
1236
|
+
padding: 40px;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
.spinner {
|
|
1240
|
+
width: 40px;
|
|
1241
|
+
height: 40px;
|
|
1242
|
+
border: 4px solid var(--gray-200);
|
|
1243
|
+
border-top: 4px solid var(--primary-color);
|
|
1244
|
+
border-radius: 50%;
|
|
1245
|
+
animation: spin 1s linear infinite;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
.status-todo {
|
|
1249
|
+
background: rgba(139, 92, 246, 0.1);
|
|
1250
|
+
color: #8b5cf6;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
.status-pending {
|
|
1254
|
+
background: rgba(156, 163, 175, 0.15);
|
|
1255
|
+
color: var(--gray-600);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
@keyframes spin {
|
|
1259
|
+
0% { transform: rotate(0deg); }
|
|
1260
|
+
100% { transform: rotate(360deg); }
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
@media (max-width: 768px) {
|
|
1264
|
+
.main-container {
|
|
1265
|
+
margin: 5px;
|
|
1266
|
+
border-radius: 15px;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
.header {
|
|
1270
|
+
padding: 15px;
|
|
1271
|
+
flex-direction: column;
|
|
1272
|
+
align-items: flex-start;
|
|
1273
|
+
gap: 15px;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
.header-actions {
|
|
1277
|
+
width: 100%;
|
|
1278
|
+
justify-content: space-between;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
.stats-section {
|
|
1282
|
+
padding: 15px;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
.stats-grid {
|
|
1286
|
+
grid-template-columns: 1fr;
|
|
1287
|
+
gap: 15px;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
.chart-container {
|
|
1291
|
+
min-height: auto;
|
|
1292
|
+
padding: 15px;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
.stats-info {
|
|
1296
|
+
padding: 15px;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
.stat-card {
|
|
1300
|
+
padding: 10px 0;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
.stat-value {
|
|
1304
|
+
font-size: 20px;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
.stat-label {
|
|
1308
|
+
font-size: 12px;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
.chart-section {
|
|
1312
|
+
padding: 10px;
|
|
1313
|
+
width: 100%;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
#testChart {
|
|
1317
|
+
width: 100% !important;
|
|
1318
|
+
max-width: 100% !important;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
.filters-container {
|
|
1322
|
+
padding: 15px;
|
|
1323
|
+
flex-direction: column;
|
|
1324
|
+
gap: 15px;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
.filter-tabs {
|
|
1328
|
+
width: 100%;
|
|
1329
|
+
overflow-x: auto;
|
|
1330
|
+
-webkit-overflow-scrolling: touch;
|
|
1331
|
+
order: 2;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
.pagination-control {
|
|
1335
|
+
order: 1;
|
|
1336
|
+
justify-content: center;
|
|
1337
|
+
flex-direction: column;
|
|
1338
|
+
gap: 10px;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
.pagination-select {
|
|
1342
|
+
font-size: 14px;
|
|
1343
|
+
padding: 6px 10px;
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
.search-container {
|
|
1347
|
+
margin-bottom: 5px;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
.tests-section, .controls-section {
|
|
1351
|
+
padding: 10px;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
.test-item {
|
|
1355
|
+
margin-bottom: 10px;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
.test-header {
|
|
1359
|
+
padding: 12px;
|
|
1360
|
+
flex-direction: column;
|
|
1361
|
+
align-items: flex-start;
|
|
1362
|
+
gap: 10px;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
.test-meta {
|
|
1366
|
+
width: 100%;
|
|
1367
|
+
justify-content: space-between;
|
|
1368
|
+
padding: 0;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
.test-tabs {
|
|
1372
|
+
overflow-x: auto;
|
|
1373
|
+
white-space: nowrap;
|
|
1374
|
+
-webkit-overflow-scrolling: touch;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
.test-tab {
|
|
1378
|
+
padding: 8px 12px;
|
|
1379
|
+
font-size: 13px;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
.test-tab-content {
|
|
1383
|
+
padding: 12px;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
.metadata-grid,
|
|
1387
|
+
.attachments-grid {
|
|
1388
|
+
grid-template-columns: 1fr;
|
|
1389
|
+
gap: 8px;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
.metadata-item,
|
|
1393
|
+
.attachment-item {
|
|
1394
|
+
padding: 10px;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
.pagination-container {
|
|
1398
|
+
padding: 15px;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
.pagination-btn {
|
|
1402
|
+
padding: 8px 12px;
|
|
1403
|
+
font-size: 14px;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
.settings-modal-content {
|
|
1407
|
+
width: 95%;
|
|
1408
|
+
max-width: none;
|
|
1409
|
+
margin: 10px;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
.settings-meta-grid {
|
|
1413
|
+
grid-template-columns: 1fr;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
.env-var-item {
|
|
1417
|
+
grid-template-columns: 1fr;
|
|
1418
|
+
gap: 8px;
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
.env-vars-list {
|
|
1422
|
+
max-height: 250px;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
.env-var-value {
|
|
1426
|
+
padding: 4px 8px;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
@media (min-width: 769px) and (max-width: 1024px) {
|
|
1431
|
+
.stats-section {
|
|
1432
|
+
padding: 20px;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
.stats-grid {
|
|
1436
|
+
grid-template-columns: 1fr;
|
|
1437
|
+
gap: 20px;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
.chart-container {
|
|
1441
|
+
padding: 20px;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
.stats-info {
|
|
1445
|
+
padding: 20px;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
.chart-section {
|
|
1449
|
+
padding: 20px;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
#testChart {
|
|
1453
|
+
width: 100% !important;
|
|
1454
|
+
max-width: 100% !important;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
.filters-container {
|
|
1458
|
+
padding: 15px 20px;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
.tests-section {
|
|
1462
|
+
padding: 15px;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
.test-header {
|
|
1466
|
+
padding: 15px;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
.metadata-grid,
|
|
1470
|
+
.attachments-grid {
|
|
1471
|
+
grid-template-columns: repeat(2, 1fr);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
@media (max-width: 480px) {
|
|
1476
|
+
.stats-section {
|
|
1477
|
+
padding: 10px;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
.stats-grid {
|
|
1481
|
+
grid-template-columns: 1fr;
|
|
1482
|
+
gap: 10px;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
.chart-container {
|
|
1486
|
+
padding: 10px;
|
|
1487
|
+
min-height: auto;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
.stats-info {
|
|
1491
|
+
padding: 12px;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
.stat-card {
|
|
1495
|
+
padding: 8px 0;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
.stat-value {
|
|
1499
|
+
font-size: 18px;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
.stat-label {
|
|
1503
|
+
font-size: 11px;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
.chart-section {
|
|
1507
|
+
padding: 5px;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
.filter-tabs {
|
|
1511
|
+
gap: 5px;
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
.test-tab {
|
|
1515
|
+
padding: 6px 10px;
|
|
1516
|
+
font-size: 12px;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
.badge {
|
|
1520
|
+
font-size: 10px;
|
|
1521
|
+
padding: 2px 6px;
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
.text-center { text-align: center; }
|
|
1526
|
+
.mt-20 { margin-top: 20px; }
|
|
1527
|
+
.mb-20 { margin-bottom: 20px; }
|
|
1528
|
+
.hidden { display: none !important; }
|
|
1529
|
+
.fade-in {
|
|
1530
|
+
animation: fadeIn 0.3s ease-in;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
@keyframes fadeIn {
|
|
1534
|
+
from { opacity: 0; transform: translateY(10px); }
|
|
1535
|
+
to { opacity: 1; transform: translateY(0); }
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
.todo-info {
|
|
1539
|
+
text-align: center;
|
|
1540
|
+
padding: 40px 20px;
|
|
1541
|
+
color: var(--warning-color);
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
.todo-title {
|
|
1545
|
+
font-size: 18px;
|
|
1546
|
+
font-weight: 600;
|
|
1547
|
+
margin-bottom: 15px;
|
|
1548
|
+
color: var(--warning-color);
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
.todo-title i {
|
|
1552
|
+
margin-right: 8px;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
.todo-description {
|
|
1556
|
+
font-size: 14px;
|
|
1557
|
+
color: var(--gray-600);
|
|
1558
|
+
margin-bottom: 25px;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
.todo-details {
|
|
1562
|
+
background: var(--gray-50);
|
|
1563
|
+
border-radius: 8px;
|
|
1564
|
+
padding: 20px;
|
|
1565
|
+
text-align: left;
|
|
1566
|
+
border: 1px solid var(--gray-200);
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
.todo-details p {
|
|
1570
|
+
margin: 8px 0;
|
|
1571
|
+
font-size: 13px;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
.todo-details strong {
|
|
1575
|
+
color: var(--gray-700);
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
.test-status-icon.todo {
|
|
1579
|
+
background: var(--warning-color);
|
|
1580
|
+
color: white;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
.test-status-icon.todo i {
|
|
1584
|
+
color: white;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
.settings-btn {
|
|
1588
|
+
background: rgba(255, 255, 255, 0.2);
|
|
1589
|
+
border: none;
|
|
1590
|
+
padding: 10px 16px;
|
|
1591
|
+
border-radius: 8px;
|
|
1592
|
+
color: white;
|
|
1593
|
+
cursor: pointer;
|
|
1594
|
+
transition: var(--transition);
|
|
1595
|
+
font-size: 18px;
|
|
1596
|
+
display: flex;
|
|
1597
|
+
align-items: center;
|
|
1598
|
+
justify-content: center;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
.settings-btn i{
|
|
1602
|
+
transition: var(--transition);
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
.settings-btn:hover {
|
|
1606
|
+
background: rgba(255, 255, 255, 0.3);
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
.settings-btn:hover i{
|
|
1610
|
+
transform: rotate(45deg);
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
.settings-modal {
|
|
1614
|
+
display: none;
|
|
1615
|
+
position: fixed;
|
|
1616
|
+
z-index: 10000;
|
|
1617
|
+
left: 0;
|
|
1618
|
+
top: 0;
|
|
1619
|
+
width: 100%;
|
|
1620
|
+
height: 100%;
|
|
1621
|
+
background-color: rgba(0, 0, 0, 0.6);
|
|
1622
|
+
backdrop-filter: blur(4px);
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
.settings-modal.active {
|
|
1626
|
+
display: flex;
|
|
1627
|
+
align-items: center;
|
|
1628
|
+
justify-content: center;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
.settings-modal-content {
|
|
1632
|
+
background: white;
|
|
1633
|
+
border-radius: var(--border-radius);
|
|
1634
|
+
width: 90%;
|
|
1635
|
+
max-width: 600px;
|
|
1636
|
+
max-height: 80vh;
|
|
1637
|
+
overflow: hidden;
|
|
1638
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
1639
|
+
animation: modalSlideIn 0.3s ease;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
@keyframes modalSlideIn {
|
|
1643
|
+
from {
|
|
1644
|
+
opacity: 0;
|
|
1645
|
+
transform: translateY(-50px) scale(0.95);
|
|
1646
|
+
}
|
|
1647
|
+
to {
|
|
1648
|
+
opacity: 1;
|
|
1649
|
+
transform: translateY(0) scale(1);
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
.settings-modal-header {
|
|
1654
|
+
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-hover) 100%);
|
|
1655
|
+
color: white;
|
|
1656
|
+
padding: 20px 25px;
|
|
1657
|
+
display: flex;
|
|
1658
|
+
justify-content: space-between;
|
|
1659
|
+
align-items: center;
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
.settings-modal-title {
|
|
1663
|
+
font-size: 20px;
|
|
1664
|
+
font-weight: 600;
|
|
1665
|
+
display: flex;
|
|
1666
|
+
align-items: center;
|
|
1667
|
+
gap: 10px;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
.settings-modal-close {
|
|
1671
|
+
background: rgba(255, 255, 255, 0.2);
|
|
1672
|
+
border: none;
|
|
1673
|
+
color: white;
|
|
1674
|
+
font-size: 20px;
|
|
1675
|
+
width: 36px;
|
|
1676
|
+
height: 36px;
|
|
1677
|
+
border-radius: 50%;
|
|
1678
|
+
cursor: pointer;
|
|
1679
|
+
transition: var(--transition);
|
|
1680
|
+
display: flex;
|
|
1681
|
+
align-items: center;
|
|
1682
|
+
justify-content: center;
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
.settings-modal-close:hover {
|
|
1686
|
+
background: rgba(255, 255, 255, 0.3);
|
|
1687
|
+
transform: rotate(90deg);
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
.settings-modal-body {
|
|
1691
|
+
padding: 25px;
|
|
1692
|
+
overflow-y: auto;
|
|
1693
|
+
max-height: calc(80vh - 80px);
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
.settings-section {
|
|
1697
|
+
margin-bottom: 25px;
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
.settings-section:last-child {
|
|
1701
|
+
margin-bottom: 0;
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
.settings-section-title {
|
|
1705
|
+
font-size: 14px;
|
|
1706
|
+
font-weight: 600;
|
|
1707
|
+
color: var(--gray-700);
|
|
1708
|
+
text-transform: uppercase;
|
|
1709
|
+
letter-spacing: 0.5px;
|
|
1710
|
+
margin-bottom: 15px;
|
|
1711
|
+
display: flex;
|
|
1712
|
+
align-items: center;
|
|
1713
|
+
gap: 8px;
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
.settings-meta-grid {
|
|
1717
|
+
display: grid;
|
|
1718
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
1719
|
+
gap: 12px;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
.settings-meta-item {
|
|
1723
|
+
display: flex;
|
|
1724
|
+
align-items: center;
|
|
1725
|
+
gap: 10px;
|
|
1726
|
+
padding: 10px 12px;
|
|
1727
|
+
background: var(--gray-50);
|
|
1728
|
+
border-radius: 8px;
|
|
1729
|
+
border: 2px solid var(--gray-200);
|
|
1730
|
+
cursor: pointer;
|
|
1731
|
+
transition: var(--transition);
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
.settings-meta-item:hover {
|
|
1735
|
+
border-color: var(--primary-color);
|
|
1736
|
+
background: white;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
.settings-meta-item input[type="checkbox"] {
|
|
1740
|
+
width: 18px;
|
|
1741
|
+
height: 18px;
|
|
1742
|
+
cursor: pointer;
|
|
1743
|
+
accent-color: var(--primary-color);
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
.settings-meta-label {
|
|
1747
|
+
font-size: 14px;
|
|
1748
|
+
color: var(--gray-700);
|
|
1749
|
+
font-weight: 500;
|
|
1750
|
+
flex: 1;
|
|
1751
|
+
word-break: break-word;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
.settings-meta-count {
|
|
1755
|
+
font-size: 11px;
|
|
1756
|
+
color: var(--gray-500);
|
|
1757
|
+
background: var(--gray-200);
|
|
1758
|
+
padding: 2px 8px;
|
|
1759
|
+
border-radius: 12px;
|
|
1760
|
+
font-weight: 600;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
.settings-tabs-nav {
|
|
1764
|
+
display: flex;
|
|
1765
|
+
gap: 10px;
|
|
1766
|
+
margin-bottom: 20px;
|
|
1767
|
+
border-bottom: 2px solid var(--gray-200);
|
|
1768
|
+
padding-bottom: 0;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
.settings-tab {
|
|
1772
|
+
flex: 1;
|
|
1773
|
+
padding: 12px 16px;
|
|
1774
|
+
border: none;
|
|
1775
|
+
background: transparent;
|
|
1776
|
+
color: var(--gray-600);
|
|
1777
|
+
font-size: 14px;
|
|
1778
|
+
font-weight: 600;
|
|
1779
|
+
cursor: pointer;
|
|
1780
|
+
transition: var(--transition);
|
|
1781
|
+
display: flex;
|
|
1782
|
+
align-items: center;
|
|
1783
|
+
justify-content: center;
|
|
1784
|
+
gap: 8px;
|
|
1785
|
+
border-bottom: 2px solid transparent;
|
|
1786
|
+
margin-bottom: -2px;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
.settings-tab:hover {
|
|
1790
|
+
background: var(--gray-100);
|
|
1791
|
+
color: var(--gray-700);
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
.settings-tab.active {
|
|
1795
|
+
color: var(--primary-color);
|
|
1796
|
+
border-bottom-color: var(--primary-color);
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
.settings-tab-content {
|
|
1800
|
+
display: none;
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
.settings-tab-content.active {
|
|
1804
|
+
display: block;
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
.env-vars-container {
|
|
1808
|
+
display: flex;
|
|
1809
|
+
flex-direction: column;
|
|
1810
|
+
gap: 20px;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
.env-vars-group {
|
|
1814
|
+
background: var(--gray-50);
|
|
1815
|
+
border: 1px solid var(--gray-200);
|
|
1816
|
+
border-radius: 8px;
|
|
1817
|
+
overflow: hidden;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
.env-vars-group-title {
|
|
1821
|
+
background: var(--gray-100);
|
|
1822
|
+
padding: 12px 15px;
|
|
1823
|
+
font-size: 13px;
|
|
1824
|
+
font-weight: 600;
|
|
1825
|
+
color: var(--gray-700);
|
|
1826
|
+
border-bottom: 1px solid var(--gray-200);
|
|
1827
|
+
display: flex;
|
|
1828
|
+
align-items: center;
|
|
1829
|
+
justify-content: space-between;
|
|
1830
|
+
gap: 8px;
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
.env-vars-count {
|
|
1834
|
+
font-size: 11px;
|
|
1835
|
+
background: var(--primary-color);
|
|
1836
|
+
color: white;
|
|
1837
|
+
padding: 2px 8px;
|
|
1838
|
+
border-radius: 10px;
|
|
1839
|
+
font-weight: 500;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
.env-vars-list {
|
|
1843
|
+
display: flex;
|
|
1844
|
+
flex-direction: column;
|
|
1845
|
+
max-height: 400px;
|
|
1846
|
+
overflow-y: auto;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
.env-var-item {
|
|
1850
|
+
display: grid;
|
|
1851
|
+
grid-template-columns: 1fr 1fr;
|
|
1852
|
+
padding: 12px 15px;
|
|
1853
|
+
border-bottom: 1px solid var(--gray-200);
|
|
1854
|
+
gap: 15px;
|
|
1855
|
+
transition: var(--transition);
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
.env-var-item:last-child {
|
|
1859
|
+
border-bottom: none;
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
.env-var-item:hover {
|
|
1863
|
+
background: white;
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
.env-var-item.env-var-unset {
|
|
1867
|
+
background: var(--gray-100);
|
|
1868
|
+
opacity: 0.7;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
.env-var-item.env-var-unset:hover {
|
|
1872
|
+
background: var(--gray-200);
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
.env-var-info {
|
|
1876
|
+
display: flex;
|
|
1877
|
+
flex-direction: column;
|
|
1878
|
+
gap: 4px;
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
.env-var-key {
|
|
1882
|
+
font-size: 12px;
|
|
1883
|
+
font-weight: 600;
|
|
1884
|
+
color: var(--primary-color);
|
|
1885
|
+
font-family: 'Courier New', monospace;
|
|
1886
|
+
word-break: break-all;
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
.env-var-description {
|
|
1890
|
+
font-size: 11px;
|
|
1891
|
+
color: var(--gray-600);
|
|
1892
|
+
line-height: 1.3;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
.env-var-value {
|
|
1896
|
+
font-size: 12px;
|
|
1897
|
+
color: var(--gray-700);
|
|
1898
|
+
font-family: 'Courier New', monospace;
|
|
1899
|
+
word-break: break-all;
|
|
1900
|
+
padding: 6px 10px;
|
|
1901
|
+
background: white;
|
|
1902
|
+
border: 1px solid var(--gray-300);
|
|
1903
|
+
border-radius: 4px;
|
|
1904
|
+
display: flex;
|
|
1905
|
+
align-items: center;
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
.env-var-value.env-var-empty {
|
|
1909
|
+
background: var(--gray-100);
|
|
1910
|
+
color: var(--gray-500);
|
|
1911
|
+
font-style: italic;
|
|
1912
|
+
border-style: dashed;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
.env-var-value.env-var-confidential {
|
|
1916
|
+
background: var(--gray-100);
|
|
1917
|
+
color: var(--gray-600);
|
|
1918
|
+
font-style: italic;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
.settings-footer {
|
|
1922
|
+
padding: 15px 25px;
|
|
1923
|
+
background: var(--gray-50);
|
|
1924
|
+
border-top: 1px solid var(--gray-200);
|
|
1925
|
+
display: flex;
|
|
1926
|
+
justify-content: flex-end;
|
|
1927
|
+
gap: 10px;
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
.settings-btn-action {
|
|
1931
|
+
padding: 10px 20px;
|
|
1932
|
+
border: none;
|
|
1933
|
+
border-radius: 8px;
|
|
1934
|
+
font-weight: 600;
|
|
1935
|
+
cursor: pointer;
|
|
1936
|
+
transition: var(--transition);
|
|
1937
|
+
font-size: 14px;
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
.settings-btn-reset {
|
|
1941
|
+
background: transparent;
|
|
1942
|
+
color: var(--gray-500);
|
|
1943
|
+
border: 1px solid var(--gray-300);
|
|
1944
|
+
margin-right: auto;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
.settings-btn-reset:hover {
|
|
1948
|
+
background: var(--gray-100);
|
|
1949
|
+
color: var(--gray-700);
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
.settings-btn-cancel {
|
|
1953
|
+
background: var(--gray-200);
|
|
1954
|
+
color: var(--gray-700);
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
.settings-btn-cancel:hover {
|
|
1958
|
+
background: var(--gray-300);
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
.settings-btn-save {
|
|
1962
|
+
background: var(--primary-color);
|
|
1963
|
+
color: white;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
.settings-btn-save:hover {
|
|
1967
|
+
background: var(--primary-hover);
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
/* Meta item visibility control */
|
|
1971
|
+
.meta-item {
|
|
1972
|
+
transition: var(--transition);
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
.meta-item.hidden {
|
|
1976
|
+
display: none !important;
|
|
1977
|
+
}
|
|
1978
|
+
</style>
|
|
1979
|
+
</head>
|
|
514
1980
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
1981
|
+
<body>
|
|
1982
|
+
<div class='main-container'>
|
|
1983
|
+
<header class='header'>
|
|
1984
|
+
<div class='header-title'>
|
|
1985
|
+
<h1 id='mainTitle'>{{title}}</h1>
|
|
1986
|
+
<div class='header-badge'>Automated Tests</div>
|
|
1987
|
+
</div>
|
|
1988
|
+
<div class='header-actions'>
|
|
1989
|
+
{{#if runId}}
|
|
1990
|
+
<div class='run-info'>
|
|
1991
|
+
<i class='fas fa-hashtag'></i>
|
|
1992
|
+
Run #{{runId}}
|
|
519
1993
|
</div>
|
|
520
|
-
|
|
1994
|
+
{{/if}}
|
|
1995
|
+
<button class='settings-btn' onclick='openSettings()' title='Report Settings'>
|
|
1996
|
+
<i class='fas fa-cog'></i>
|
|
1997
|
+
</button>
|
|
1998
|
+
{{#if runUrl}}
|
|
1999
|
+
<a href='{{runUrl}}' target='_blank' class='btn-primary-custom'>
|
|
2000
|
+
<i class='fas fa-external-link-alt'></i>
|
|
2001
|
+
Full Report
|
|
2002
|
+
</a>
|
|
2003
|
+
{{else}}
|
|
2004
|
+
<button class='btn-primary-custom' disabled>
|
|
2005
|
+
<i class='fas fa-external-link-alt'></i>
|
|
2006
|
+
Full Report
|
|
2007
|
+
</button>
|
|
2008
|
+
{{/if}}
|
|
521
2009
|
</div>
|
|
2010
|
+
</header>
|
|
522
2011
|
|
|
523
|
-
|
|
524
|
-
<div class='
|
|
525
|
-
<div class='
|
|
526
|
-
<div
|
|
527
|
-
<div id='graff'></div>
|
|
528
|
-
</div>
|
|
2012
|
+
<section class='stats-section'>
|
|
2013
|
+
<div class='stats-grid'>
|
|
2014
|
+
<div class='chart-container'>
|
|
2015
|
+
<div id='testChart'></div>
|
|
529
2016
|
</div>
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
<
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
<div></div>
|
|
540
|
-
<p>{{status}}</p>
|
|
541
|
-
</div>
|
|
542
|
-
</div>
|
|
543
|
-
<!-- 1 -->
|
|
544
|
-
<!-- 1 -->
|
|
545
|
-
<div class='statdesc__row'>
|
|
546
|
-
<div class='statdesc__row_first'>
|
|
547
|
-
<p>Execution Duration</p>
|
|
548
|
-
</div>
|
|
549
|
-
<span>{{executionTime}}</span>
|
|
550
|
-
</div>
|
|
551
|
-
<!-- 1 -->
|
|
552
|
-
<!-- 1 -->
|
|
553
|
-
<div class='statdesc__row'>
|
|
554
|
-
<div class='statdesc__row_first'>
|
|
555
|
-
<p>Tests</p>
|
|
2017
|
+
<div class='stats-info'>
|
|
2018
|
+
<div class='stat-card'>
|
|
2019
|
+
<div class='stat-label'>
|
|
2020
|
+
<i class='fas fa-chart-line' style='font-size: 14px;'></i>
|
|
2021
|
+
Execution Status
|
|
2022
|
+
</div>
|
|
2023
|
+
<div class='stat-value'>
|
|
2024
|
+
<span class='status-badge status-{{status}}'>{{status}}</span>
|
|
2025
|
+
</div>
|
|
556
2026
|
</div>
|
|
557
|
-
<
|
|
2027
|
+
<div class='stat-card'>
|
|
2028
|
+
<div class='stat-label'>
|
|
2029
|
+
<i class='fas fa-clock' style='font-size: 14px;'></i>
|
|
2030
|
+
Duration
|
|
2031
|
+
</div>
|
|
2032
|
+
<div class='stat-value'>{{executionTime}}</div>
|
|
558
2033
|
</div>
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
2034
|
+
<div class='stat-card'>
|
|
2035
|
+
<div class='stat-label'>
|
|
2036
|
+
<i class='fas fa-list-check' style='font-size: 14px;'></i>
|
|
2037
|
+
Total Tests
|
|
2038
|
+
</div>
|
|
2039
|
+
<div class='stat-value'>{{tests.length}}</div>
|
|
564
2040
|
</div>
|
|
565
|
-
<
|
|
2041
|
+
<div class='stat-card'>
|
|
2042
|
+
<div class='stat-label'>
|
|
2043
|
+
<i class='fas fa-calendar-alt' style='font-size: 14px;'></i>
|
|
2044
|
+
Started At
|
|
2045
|
+
</div>
|
|
2046
|
+
<div class='stat-value'>{{executionDate}}</div>
|
|
566
2047
|
</div>
|
|
567
|
-
<!-- 1 -->
|
|
568
|
-
</div>
|
|
569
2048
|
</div>
|
|
570
2049
|
</div>
|
|
2050
|
+
</section>
|
|
2051
|
+
|
|
2052
|
+
<section class='controls-section'>
|
|
2053
|
+
<div class='search-container'>
|
|
2054
|
+
<i class='fas fa-search search-icon'></i>
|
|
2055
|
+
<input
|
|
2056
|
+
type='text'
|
|
2057
|
+
class='search-input'
|
|
2058
|
+
placeholder='Search tests by name or suite...'
|
|
2059
|
+
id='searchInput'
|
|
2060
|
+
/>
|
|
571
2061
|
</div>
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
2062
|
+
<div class='filters-container'>
|
|
2063
|
+
<div class='filter-tabs'>
|
|
2064
|
+
<button class='filter-tab active' data-filter='all'>
|
|
2065
|
+
<i class='fas fa-list'></i>
|
|
2066
|
+
All
|
|
2067
|
+
<span class='count' id='countAll'>{{tests.length}}</span>
|
|
2068
|
+
</button>
|
|
2069
|
+
<button class='filter-tab' data-filter='passed'>
|
|
2070
|
+
<i class='fas fa-check-circle'></i>
|
|
2071
|
+
Passed
|
|
2072
|
+
<span class='count' id='countPassed'>{{getTestsByStatus tests "passed"}}</span>
|
|
2073
|
+
</button>
|
|
2074
|
+
<button class='filter-tab' data-filter='failed'>
|
|
2075
|
+
<i class='fas fa-times-circle'></i>
|
|
2076
|
+
Failed
|
|
2077
|
+
<span class='count' id='countFailed'>{{getTestsByStatus tests "failed"}}</span>
|
|
2078
|
+
</button>
|
|
2079
|
+
<button class='filter-tab' data-filter='skipped'>
|
|
2080
|
+
<i class='fas fa-forward'></i>
|
|
2081
|
+
Skipped
|
|
2082
|
+
<span class='count' id='countSkipped'>{{getTestsByStatus tests "skipped"}}</span>
|
|
2083
|
+
</button>
|
|
2084
|
+
<button class='filter-tab' data-filter='todo'>
|
|
2085
|
+
<i class='fas fa-list-check'></i>
|
|
2086
|
+
Todo
|
|
2087
|
+
<span class='count' id='countTodo'>{{getTestsByStatus tests "todo"}}</span>
|
|
2088
|
+
</button>
|
|
2089
|
+
</div>
|
|
2090
|
+
<div class='pagination-control'>
|
|
2091
|
+
<label for='pageSizeSelect' style='font-weight: 500; color: var(--gray-600);'>Tests per page:</label>
|
|
2092
|
+
<select id='pageSizeSelect' class='pagination-select'>
|
|
2093
|
+
<option value='10'>10</option>
|
|
2094
|
+
<option value='25'>25</option>
|
|
2095
|
+
<option value='50'>50</option>
|
|
2096
|
+
<option value='100'>100</option>
|
|
2097
|
+
</select>
|
|
2098
|
+
<label for='groupingSelect' style='font-weight: 500; color: var(--gray-600); margin-left: 20px;'>Group by:</label>
|
|
2099
|
+
<select id='groupingSelect' class='pagination-select'>
|
|
2100
|
+
<option value='all'>All Tests</option>
|
|
2101
|
+
<option value='suite'>By Suite</option>
|
|
2102
|
+
<option value='file'>By File</option>
|
|
2103
|
+
</select>
|
|
2104
|
+
</div>
|
|
2105
|
+
</div>
|
|
2106
|
+
</section>
|
|
2107
|
+
|
|
2108
|
+
<section class='tests-section'>
|
|
2109
|
+
<div id='testsContainer'>
|
|
2110
|
+
{{#if tests.length}}
|
|
2111
|
+
<!-- Test items will be dynamically inserted here -->
|
|
2112
|
+
{{else}}
|
|
2113
|
+
<div class='empty-state'>
|
|
2114
|
+
<div class='empty-icon'>
|
|
2115
|
+
<i class='fas fa-inbox'></i>
|
|
580
2116
|
</div>
|
|
581
|
-
<
|
|
582
|
-
|
|
583
|
-
style='border:none;height:54px;background:#F6FAFF;font-weight:600;font-size:15px;'
|
|
584
|
-
class='form-control inputSearch'
|
|
585
|
-
aria-label='Search'
|
|
586
|
-
aria-describedby='basic-addon1'
|
|
587
|
-
/>
|
|
2117
|
+
<div class='empty-title'>No Tests Found</div>
|
|
2118
|
+
<div class='empty-description'>No tests were executed in this run.</div>
|
|
588
2119
|
</div>
|
|
2120
|
+
{{/if}}
|
|
2121
|
+
</div>
|
|
2122
|
+
</section>
|
|
2123
|
+
|
|
2124
|
+
<section class='pagination-container' id='paginationContainer'>
|
|
2125
|
+
<!-- Pagination will be dynamically inserted here -->
|
|
2126
|
+
</section>
|
|
2127
|
+
</div>
|
|
2128
|
+
|
|
2129
|
+
<div id='settingsModal' class='settings-modal'>
|
|
2130
|
+
<div class='settings-modal-content'>
|
|
2131
|
+
<div class='settings-modal-header'>
|
|
2132
|
+
<div class='settings-modal-title'>
|
|
2133
|
+
<i class='fas fa-cog'></i>
|
|
2134
|
+
Report Settings
|
|
589
2135
|
</div>
|
|
2136
|
+
<button class='settings-modal-close' onclick='closeSettings()'>
|
|
2137
|
+
<i class='fas fa-times'></i>
|
|
2138
|
+
</button>
|
|
590
2139
|
</div>
|
|
2140
|
+
<div class='settings-modal-body'>
|
|
2141
|
+
<div class='settings-tabs-nav'>
|
|
2142
|
+
<button class='settings-tab active' data-tab='metadata' onclick='switchSettingsTab(event)'>
|
|
2143
|
+
<i class='fas fa-tags'></i>
|
|
2144
|
+
Metadata
|
|
2145
|
+
</button>
|
|
2146
|
+
<button class='settings-tab' data-tab='envvars' onclick='switchSettingsTab(event)'>
|
|
2147
|
+
<i class='fas fa-code'></i>
|
|
2148
|
+
Environment Variables
|
|
2149
|
+
</button>
|
|
2150
|
+
</div>
|
|
591
2151
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
category='all'
|
|
602
|
-
checked
|
|
603
|
-
/>
|
|
604
|
-
|
|
605
|
-
<label class='btn btn-all' for='allTest' style='padding:9px;margin-right:8px;background:#A0CAFF;color:#fff;border:none;text-align:center;border-radius:3px;font-weight:600;font-size:12px;width:83px;height:37px'>All
|
|
606
|
-
<span style='color:#fff;font-weight:600;font-size:12px;' class='numTest numAll' name='numTest' lcategory='all'>0</span>
|
|
607
|
-
</label>
|
|
608
|
-
|
|
609
|
-
<input
|
|
610
|
-
type='radio'
|
|
611
|
-
class='btn-check passedTest'
|
|
612
|
-
name='groupTest'
|
|
613
|
-
id='passedTest'
|
|
614
|
-
autocomplete='off'
|
|
615
|
-
category='passed'
|
|
616
|
-
/>
|
|
617
|
-
|
|
618
|
-
<label class='btn btn-passed' for='passedTest' style='padding:9px;background:#75B583;color:#fff;border:none;text-align:center;border-radius:3px;font-weight:600;font-size:12px;width:83px;height:37px'>Passed
|
|
619
|
-
<span style='color:#fff;font-weight:600;font-size:12px;' class='numTest numPassed' name='numTest' lcategory='passed'>0</span>
|
|
620
|
-
</label>
|
|
621
|
-
|
|
622
|
-
<input
|
|
623
|
-
type='radio'
|
|
624
|
-
class='btn-check failedTest'
|
|
625
|
-
name='groupTest'
|
|
626
|
-
id='failedTest'
|
|
627
|
-
autocomplete='off'
|
|
628
|
-
category='failed'
|
|
629
|
-
/>
|
|
630
|
-
|
|
631
|
-
<label class='btn btn-failed' for='failedTest' style='padding:9px;margin-left:9px;background:#FF6363;color:#fff;border:none;text-align:center;border-radius:3px;font-weight:600;font-size:12px;width:83px;height:37px'>Failed
|
|
632
|
-
<span style='color:#fff;font-weight:600;font-size:12px;' class='numTest numFailed' name='numTest' lcategory='failed'>0</span>
|
|
633
|
-
</label>
|
|
634
|
-
|
|
635
|
-
<input
|
|
636
|
-
type='radio'
|
|
637
|
-
class='btn-check skippedTest'
|
|
638
|
-
name='groupTest'
|
|
639
|
-
id='skippedTest'
|
|
640
|
-
autocomplete='off'
|
|
641
|
-
category='skipped'
|
|
642
|
-
/>
|
|
643
|
-
|
|
644
|
-
<label class='btn btn-skipped' for='skippedTest' style='padding:9px;margin-left:9px;background:#FFC350;color:#fff;border:none;text-align:center;border-radius:3px;font-weight:600;font-size:12px;width:83px;height:37px'>Skipped
|
|
645
|
-
<span style='color:#fff;font-weight:600;font-size:12px;' class='numTest numSkipped' name='numTest' lcategory='skipped'>0</span>
|
|
646
|
-
</label>
|
|
2152
|
+
<div class='settings-tab-content active' data-tab='metadata'>
|
|
2153
|
+
<div class='settings-section'>
|
|
2154
|
+
<div class='settings-section-title'>
|
|
2155
|
+
<i class='fas fa-tags'></i>
|
|
2156
|
+
Visible Metadata Fields
|
|
2157
|
+
</div>
|
|
2158
|
+
<div id='metaFieldsList' class='settings-meta-grid'>
|
|
2159
|
+
<!-- Meta fields will be dynamically inserted here -->
|
|
2160
|
+
</div>
|
|
647
2161
|
</div>
|
|
648
2162
|
</div>
|
|
649
|
-
</div>
|
|
650
|
-
|
|
651
|
-
<div class="row level_5">
|
|
652
|
-
<div class="col-12">
|
|
653
|
-
{{#if tests.length}}
|
|
654
|
-
<!-- TOP pagination & select components -->
|
|
655
|
-
<div class="d-flex justify-content-between" style="height: 40px;margin-top:45px">
|
|
656
|
-
<nav id="pagination">
|
|
657
|
-
<ul class="pagination">
|
|
658
|
-
</ul>
|
|
659
|
-
</nav>
|
|
660
|
-
{{ selectComponent }}
|
|
661
|
-
</div>
|
|
662
|
-
<!-- Test data section -->
|
|
663
|
-
<div class="testWrapp">
|
|
664
|
-
{{#each tests}}
|
|
665
|
-
<div class="testitem d-none" name="testitem" type="dummy" category="false">
|
|
666
|
-
<div class="testitem__top">
|
|
667
|
-
<div class='d-flex'>
|
|
668
|
-
<div class="testitem__icon">
|
|
669
|
-
<i class="fa-solid fa-circle-chevron-right testitem__ico testitem__ico_right ml-2"></i>
|
|
670
|
-
<i class="fa-solid fa-circle-chevron-down d-none testitem__ico testitem__ico_down ml-2"></i>
|
|
671
|
-
</div>
|
|
672
|
-
<p class="testitem__name">Test</p>
|
|
673
|
-
</div>
|
|
674
|
-
|
|
675
|
-
<svg class='folderSvg' width="17" height="17" style='margin-right:20px;margin-top: 3px' viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
676
|
-
<path d="M16.6161 1.64526H9.84355C9.62419 1.64526 9.43226 1.64526 9.2129 1.9743L8.85645 2.46784H0.85C0.383871 2.46784 0 2.90655 0 3.37268V14.1485C0 14.6146 0.383871 15.0807 0.85 15.0807H16.15C16.6161 15.0807 17 14.6146 17 14.1485V5.81301V3.4001V1.9743C17 1.78236 16.8355 1.64526 16.6161 1.64526Z" fill="#6D6D6D"/>
|
|
677
|
-
<path d="M16.6435 12.7227C16.8629 12.5582 17 12.3114 17 12.0372V5.81301V3.4001V1.9743C17 1.78236 16.8355 1.64526 16.6161 1.64526H9.84355C9.62419 1.64526 9.43226 1.64526 9.2129 1.9743L8.85645 2.46784H0.85C0.41129 2.46784 0.0548387 2.8243 0 3.23559L16.6435 12.7227Z" fill="#565656"/>
|
|
678
|
-
<path d="M0.575806 3.56445L16.6435 12.6677C16.8629 12.5032 17 12.3112 17 12.037V5.81284V4.27736L15.9581 3.56445H0.575806Z" fill="#474646"/>
|
|
679
|
-
<path d="M15.629 3.56445H1.37097V13.9838H15.629V3.56445Z" fill="white"/>
|
|
680
|
-
<path d="M15.629 3.56445H8.77417V13.9838H15.629V3.56445Z" fill="#EFEFEF"/>
|
|
681
|
-
<path d="M17 14.5323C17 14.9984 16.6161 15.3549 16.15 15.3549H0.85C0.383871 15.3549 0 14.9984 0 14.5323L0.274194 5.84039C0.274194 5.37426 0.658064 4.93555 1.12419 4.93555H15.9032C16.3694 4.93555 16.7532 5.37426 16.7532 5.84039L17 14.5323Z" fill="#A1A1A1"/>
|
|
682
|
-
<path d="M16.8903 14.9437L0.329032 5.53882C0.274194 5.6485 0.274194 5.78559 0.274194 5.89527L0 14.5324C0 14.9985 0.383871 15.3549 0.85 15.3549H16.15C16.4516 15.3549 16.7258 15.1904 16.8903 14.9437Z" fill="#565656"/>
|
|
683
|
-
<path d="M6.77259 13.2161C6.71775 13.2161 6.63549 13.1887 6.55323 13.1613C6.41613 13.1064 6.30646 12.9693 6.30646 12.8048V7.67739C6.30646 7.54029 6.41613 7.37577 6.55323 7.32093C6.69033 7.2661 6.85484 7.2661 6.99194 7.34835L10.4742 9.92577C10.5839 10.008 10.6387 10.1177 10.6387 10.2548C10.6387 10.3919 10.5839 10.5016 10.4742 10.5838L6.99194 13.1613C6.9371 13.2161 6.85484 13.2161 6.77259 13.2161Z" fill="white"/>
|
|
684
|
-
</svg>
|
|
685
|
-
</div>
|
|
686
2163
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
<div class="testitem__case" type="steps">
|
|
701
|
-
<div class="testitem__block">
|
|
702
|
-
<span>...</span>
|
|
703
|
-
</div>
|
|
2164
|
+
<div class='settings-tab-content' data-tab='envvars'>
|
|
2165
|
+
<div class='env-vars-container'>
|
|
2166
|
+
<div class='env-vars-group'>
|
|
2167
|
+
<div class='env-vars-group-title'>
|
|
2168
|
+
TESTOMATIO Variables
|
|
2169
|
+
<span class='env-vars-count'>{{ObjectLength envVars.testomatio}} total</span>
|
|
2170
|
+
</div>
|
|
2171
|
+
<div class='env-vars-list'>
|
|
2172
|
+
{{#each envVars.testomatio}}
|
|
2173
|
+
<div class='env-var-item {{#unless this.isSet}}env-var-unset{{/unless}}'>
|
|
2174
|
+
<div class='env-var-info'>
|
|
2175
|
+
<div class='env-var-key'>{{@key}}</div>
|
|
2176
|
+
<div class='env-var-description'>{{this.description}}</div>
|
|
704
2177
|
</div>
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
2178
|
+
<div class='env-var-value {{#unless this.isSet}}env-var-empty{{/unless}} {{#if this.isSensitive}}env-var-confidential{{/if}}'>
|
|
2179
|
+
{{#if this.isSensitive}}
|
|
2180
|
+
<em>confidential</em>
|
|
2181
|
+
{{else if this.isSet}}
|
|
2182
|
+
{{this.value}}
|
|
2183
|
+
{{else}}
|
|
2184
|
+
<em>(not set)</em>
|
|
2185
|
+
{{/if}}
|
|
712
2186
|
</div>
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
2187
|
+
</div>
|
|
2188
|
+
{{/each}}
|
|
2189
|
+
</div>
|
|
2190
|
+
</div>
|
|
2191
|
+
<div class='env-vars-group'>
|
|
2192
|
+
<div class='env-vars-group-title'>
|
|
2193
|
+
S3 Variables
|
|
2194
|
+
<span class='env-vars-count'>{{ObjectLength envVars.s3}} total</span>
|
|
2195
|
+
</div>
|
|
2196
|
+
<div class='env-vars-list'>
|
|
2197
|
+
{{#each envVars.s3}}
|
|
2198
|
+
<div class='env-var-item {{#unless this.isSet}}env-var-unset{{/unless}}'>
|
|
2199
|
+
<div class='env-var-info'>
|
|
2200
|
+
<div class='env-var-key'>{{@key}}</div>
|
|
2201
|
+
<div class='env-var-description'>{{this.description}}</div>
|
|
720
2202
|
</div>
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
2203
|
+
<div class='env-var-value {{#unless this.isSet}}env-var-empty{{/unless}} {{#if this.isSensitive}}env-var-confidential{{/if}}'>
|
|
2204
|
+
{{#if this.isSensitive}}
|
|
2205
|
+
<em>confidential</em>
|
|
2206
|
+
{{else if this.isSet}}
|
|
2207
|
+
{{this.value}}
|
|
2208
|
+
{{else}}
|
|
2209
|
+
<em>(not set)</em>
|
|
2210
|
+
{{/if}}
|
|
728
2211
|
</div>
|
|
729
|
-
<!-- 4 -->
|
|
730
2212
|
</div>
|
|
731
|
-
|
|
2213
|
+
{{/each}}
|
|
732
2214
|
</div>
|
|
733
|
-
|
|
2215
|
+
</div>
|
|
734
2216
|
</div>
|
|
735
|
-
<!-- BOTTOM pagination & select components -->
|
|
736
|
-
<nav class="mt-2">
|
|
737
|
-
<ul class="pagination">
|
|
738
|
-
</ul>
|
|
739
|
-
</nav>
|
|
740
|
-
{{else}}
|
|
741
|
-
<!-- No tests found section -->
|
|
742
|
-
{{ emptyDataComponent }}
|
|
743
|
-
{{/if}}
|
|
744
2217
|
</div>
|
|
745
2218
|
</div>
|
|
2219
|
+
<div class='settings-footer'>
|
|
2220
|
+
<button class='settings-btn-action settings-btn-reset' onclick='resetToDefaults()'>
|
|
2221
|
+
Reset to Defaults
|
|
2222
|
+
</button>
|
|
2223
|
+
<button class='settings-btn-action settings-btn-cancel' onclick='closeSettings()'>
|
|
2224
|
+
Cancel
|
|
2225
|
+
</button>
|
|
2226
|
+
<button class='settings-btn-action settings-btn-save' onclick='saveSettings()'>
|
|
2227
|
+
Apply Changes
|
|
2228
|
+
</button>
|
|
2229
|
+
</div>
|
|
746
2230
|
</div>
|
|
747
|
-
</
|
|
2231
|
+
</div>
|
|
748
2232
|
|
|
749
2233
|
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
|
|
750
2234
|
<script type="text/javascript">
|
|
751
|
-
|
|
2235
|
+
let allTests = {{{ pageDispleyElements tests }}}.totalTests;
|
|
2236
|
+
let currentFilter = 'all';
|
|
2237
|
+
let currentPage = 1;
|
|
2238
|
+
let pageSize = 10;
|
|
2239
|
+
let searchTerm = '';
|
|
2240
|
+
let hasTodoTests = false;
|
|
2241
|
+
let reportTitle = '{{title}}';
|
|
2242
|
+
let groupingMode = 'all';
|
|
2243
|
+
|
|
752
2244
|
google.charts.load('current', {'packages':['corechart']});
|
|
753
|
-
google.charts.setOnLoadCallback(
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
]
|
|
776
|
-
|
|
777
|
-
|
|
2245
|
+
google.charts.setOnLoadCallback(drawTestChart);
|
|
2246
|
+
|
|
2247
|
+
function createMetadataItems(metadata) {
|
|
2248
|
+
if (!metadata || Object.keys(metadata).length === 0) return '';
|
|
2249
|
+
|
|
2250
|
+
return Object.entries(metadata).map(([key, value]) => `
|
|
2251
|
+
<div class='metadata-item meta-item' data-meta-key='${key}'>
|
|
2252
|
+
<div class='metadata-key'>${key}</div>
|
|
2253
|
+
<div class='metadata-value'>${typeof value === 'object' ? JSON.stringify(value, null, 2) : value}</div>
|
|
2254
|
+
</div>
|
|
2255
|
+
`).join('');
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
function drawTestChart() {
|
|
2259
|
+
const passedTests = {{getTestsByStatus tests "passed"}};
|
|
2260
|
+
const failedTests = {{getTestsByStatus tests "failed"}};
|
|
2261
|
+
const skippedTests = {{getTestsByStatus tests "skipped"}};
|
|
2262
|
+
const todoTests = {{getTestsByStatus tests "todo"}};
|
|
2263
|
+
|
|
2264
|
+
const rows = [
|
|
2265
|
+
['Status', 'Count'],
|
|
2266
|
+
['Passed', passedTests],
|
|
2267
|
+
['Failed', failedTests],
|
|
2268
|
+
['Skipped', skippedTests],
|
|
2269
|
+
];
|
|
2270
|
+
|
|
2271
|
+
if (todoTests > 0) rows.push(['Todo', todoTests]);
|
|
2272
|
+
|
|
2273
|
+
const data = google.visualization.arrayToDataTable(rows);
|
|
2274
|
+
|
|
2275
|
+
const screenWidth = window.innerWidth;
|
|
2276
|
+
let chartHeight = 350;
|
|
2277
|
+
let chartAreaHeight = '80%';
|
|
2278
|
+
let chartAreaWidth = '95%';
|
|
2279
|
+
let pieSliceFontSize = 12;
|
|
2280
|
+
let legendFontSize = 12;
|
|
2281
|
+
|
|
2282
|
+
if (screenWidth < 480) {
|
|
2283
|
+
chartHeight = 180;
|
|
2284
|
+
chartAreaHeight = '70%';
|
|
2285
|
+
chartAreaWidth = '90%';
|
|
2286
|
+
pieSliceFontSize = 9;
|
|
2287
|
+
legendFontSize = 9;
|
|
2288
|
+
} else if (screenWidth < 768) {
|
|
2289
|
+
chartHeight = 220;
|
|
2290
|
+
chartAreaHeight = '75%';
|
|
2291
|
+
chartAreaWidth = '92%';
|
|
2292
|
+
pieSliceFontSize = 10;
|
|
2293
|
+
legendFontSize = 10;
|
|
2294
|
+
} else if (screenWidth < 1024) {
|
|
2295
|
+
chartHeight = 260;
|
|
2296
|
+
chartAreaHeight = '75%';
|
|
2297
|
+
chartAreaWidth = '94%';
|
|
2298
|
+
pieSliceFontSize = 11;
|
|
2299
|
+
legendFontSize = 11;
|
|
2300
|
+
}
|
|
2301
|
+
|
|
778
2302
|
const options = {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
'
|
|
784
|
-
'
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
2303
|
+
title: reportTitle + ' Distribution',
|
|
2304
|
+
pieHole: 0.4,
|
|
2305
|
+
colors: todoTests > 0
|
|
2306
|
+
? ['#10b981', '#ef4444', '#f59e0b', '#8b5cf6']
|
|
2307
|
+
: ['#10b981', '#ef4444', '#f59e0b'],
|
|
2308
|
+
legend: { position: 'bottom', alignment: 'center' },
|
|
2309
|
+
height: chartHeight,
|
|
2310
|
+
width: '100%',
|
|
2311
|
+
chartArea: {
|
|
2312
|
+
left: '5%',
|
|
2313
|
+
top: 20,
|
|
2314
|
+
width: chartAreaWidth,
|
|
2315
|
+
height: chartAreaHeight
|
|
2316
|
+
},
|
|
2317
|
+
pieSliceTextStyle: {
|
|
2318
|
+
fontSize: pieSliceFontSize
|
|
2319
|
+
},
|
|
2320
|
+
legend: {
|
|
2321
|
+
position: 'bottom',
|
|
2322
|
+
alignment: 'center',
|
|
2323
|
+
textStyle: {
|
|
2324
|
+
fontSize: legendFontSize
|
|
2325
|
+
},
|
|
2326
|
+
maxLines: 1
|
|
2327
|
+
},
|
|
2328
|
+
titleTextStyle: {
|
|
2329
|
+
fontSize: screenWidth < 768 ? 14 : 16
|
|
2330
|
+
},
|
|
2331
|
+
enableInteractivity: true,
|
|
2332
|
+
sliceVisibilityThreshold: 0,
|
|
2333
|
+
tooltip: {
|
|
2334
|
+
trigger: 'hover',
|
|
2335
|
+
showColorCode: true
|
|
2336
|
+
}
|
|
2337
|
+
};
|
|
2338
|
+
|
|
2339
|
+
const chart = new google.visualization.PieChart(document.getElementById('testChart'));
|
|
2340
|
+
|
|
2341
|
+
google.visualization.events.addListener(chart, 'ready', function() {
|
|
2342
|
+
const chartContainer = document.getElementById('testChart');
|
|
2343
|
+
chartContainer.style.overflow = 'visible';
|
|
2344
|
+
});
|
|
2345
|
+
|
|
788
2346
|
chart.draw(data, options);
|
|
789
2347
|
}
|
|
790
2348
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
2349
|
+
function createTestItem(test, index) {
|
|
2350
|
+
const testItem = document.createElement('div');
|
|
2351
|
+
testItem.className = 'test-item fade-in';
|
|
2352
|
+
testItem.dataset.testId = `test-${index}`;
|
|
2353
|
+
testItem.dataset.testIndex = index;
|
|
2354
|
+
|
|
2355
|
+
if (test.traces) {
|
|
2356
|
+
if (!window.testTraces) window.testTraces = {};
|
|
2357
|
+
if (typeof test.traces === 'string') {
|
|
2358
|
+
try {
|
|
2359
|
+
window.testTraces[index] = JSON.parse(test.traces);
|
|
2360
|
+
} catch (e) {
|
|
2361
|
+
console.error('Failed to parse traces:', e);
|
|
2362
|
+
window.testTraces[index] = [];
|
|
2363
|
+
}
|
|
2364
|
+
} else {
|
|
2365
|
+
window.testTraces[index] = test.traces;
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
const statusClass = test.status.toLowerCase();
|
|
2370
|
+
const hasRetries = test.retries && test.retries.retryCount > 0;
|
|
2371
|
+
const hasTraces = test.traces && (typeof test.traces === 'string' ? test.traces.trim().length > 0 : test.traces.length > 0);
|
|
2372
|
+
const hasArtifacts = test.artifacts && test.artifacts.length > 0;
|
|
2373
|
+
const hasMetadata = test.meta && Object.keys(test.meta).length > 0;
|
|
2374
|
+
const hasStack = statusClass === 'failed' && test.stack && (typeof test.stack === 'string' ? test.stack.trim().length > 0 : true);
|
|
2375
|
+
const attemptsCount = (test.retries && Array.isArray(test.retries.attempts)) ? test.retries.attempts.length : 0;
|
|
2376
|
+
const retryCount = Math.max(0, attemptsCount - 1);
|
|
2377
|
+
const isTodo = statusClass === 'todo';
|
|
2378
|
+
const isSkippedOrTodo = statusClass === 'skipped' || statusClass === 'todo';
|
|
2379
|
+
const displayTime = isSkippedOrTodo ? '-' : formatDuration(test.run_time || 0);
|
|
2380
|
+
|
|
2381
|
+
testItem.innerHTML = `
|
|
2382
|
+
<div class='test-header' onclick='toggleTest(this)'>
|
|
2383
|
+
<div class='test-info'>
|
|
2384
|
+
<div class='test-status-icon ${statusClass}'>
|
|
2385
|
+
<i class='fas fa-${getStatusIcon(statusClass)}'></i>
|
|
2386
|
+
</div>
|
|
2387
|
+
<div class='test-details'>
|
|
2388
|
+
<div class='test-title'>
|
|
2389
|
+
${test.title || 'Untitled Test'}
|
|
2390
|
+
${test.artifactsUploaded ? `
|
|
2391
|
+
<span class='artifact-upload-indicator' title='Artifacts uploaded to storage'>
|
|
2392
|
+
<i class='fas fa-cloud-upload-alt'></i>
|
|
2393
|
+
</span>
|
|
2394
|
+
` : ''}
|
|
2395
|
+
</div>
|
|
2396
|
+
<div class='test-suite'>${test.suite_title || 'Unknown Suite'}</div>
|
|
2397
|
+
</div>
|
|
2398
|
+
</div>
|
|
2399
|
+
<div class='test-meta'>
|
|
2400
|
+
<div class='test-duration'>
|
|
2401
|
+
<i class='fas fa-clock'></i>
|
|
2402
|
+
${displayTime}
|
|
2403
|
+
</div>
|
|
2404
|
+
<div class='test-badges'>
|
|
2405
|
+
${test.flaky ? '<span class=\"badge badge-flaky\">Flaky</span>' : ''}
|
|
2406
|
+
${hasRetries ? `<span class=\"badge badge-retry\">Retries: ${test.retries.retryCount}</span>` : ''}
|
|
2407
|
+
</div>
|
|
2408
|
+
<i class='fas fa-chevron-down expand-icon'></i>
|
|
2409
|
+
</div>
|
|
2410
|
+
</div>
|
|
2411
|
+
<div class='test-content'>
|
|
2412
|
+
<div class='test-tabs'>
|
|
2413
|
+
${isTodo ? `
|
|
2414
|
+
<button class='test-tab active' onclick='showTestTab(this, \"info\")'>
|
|
2415
|
+
<i class='fas fa-info-circle'></i> Info
|
|
2416
|
+
</button>
|
|
2417
|
+
` : `
|
|
2418
|
+
<button class='test-tab active' onclick='showTestTab(this, \"steps\")'>
|
|
2419
|
+
<i class='fas fa-list-ol'></i> Steps
|
|
2420
|
+
</button>
|
|
2421
|
+
<button class='test-tab' onclick='showTestTab(this, \"message\")'>
|
|
2422
|
+
<i class='fas fa-comment-dots'></i> Message
|
|
2423
|
+
</button>
|
|
2424
|
+
${hasStack ? `<button class='test-tab' onclick='showTestTab(this, \"stack\")'>
|
|
2425
|
+
<i class='fas fa-layer-group'></i> Stack
|
|
2426
|
+
</button>` : ''}
|
|
2427
|
+
${hasRetries ? `<button class='test-tab' onclick='showTestTab(this, \"retries\")'>
|
|
2428
|
+
<i class='fas fa-redo'></i> Retries
|
|
2429
|
+
</button>` : ''}
|
|
2430
|
+
${hasArtifacts ? `<button class='test-tab' onclick='showTestTab(this, \"attachments\")'>
|
|
2431
|
+
<i class='fas fa-paperclip'></i> Attachments
|
|
2432
|
+
</button>` : ''}
|
|
2433
|
+
${hasMetadata ? `<button class='test-tab' onclick='showTestTab(this, \"metadata\")'>
|
|
2434
|
+
<i class='fas fa-tags'></i> Metadata
|
|
2435
|
+
</button>` : ''}
|
|
2436
|
+
${hasTraces ? `<button class='test-tab' onclick='showTestTab(this, \"traces\")'>
|
|
2437
|
+
<i class='fas fa-bug'></i> Traces
|
|
2438
|
+
</button>` : ''}
|
|
2439
|
+
`}
|
|
2440
|
+
</div>
|
|
2441
|
+
${isTodo ? `
|
|
2442
|
+
<div class='test-tab-content active' data-tab='info'>
|
|
2443
|
+
<div class='todo-info'>
|
|
2444
|
+
<div class='todo-title'>
|
|
2445
|
+
<i class='fas fa-list-ul'></i>
|
|
2446
|
+
TODO Test
|
|
2447
|
+
</div>
|
|
2448
|
+
<div class='todo-description'>
|
|
2449
|
+
This test is marked as TODO and needs to be implemented.
|
|
2450
|
+
</div>
|
|
2451
|
+
<div class='todo-details'>
|
|
2452
|
+
<p><strong>Test Title:</strong> ${test.title || 'Untitled TODO Test'}</p>
|
|
2453
|
+
<p><strong>Suite:</strong> ${test.suite_title || 'Unknown Suite'}</p>
|
|
2454
|
+
<p><strong>Status:</strong> Implementation required</p>
|
|
2455
|
+
</div>
|
|
2456
|
+
</div>
|
|
2457
|
+
</div>
|
|
2458
|
+
` : `
|
|
2459
|
+
<div class='test-tab-content active' data-tab='steps'>
|
|
2460
|
+
<div class='steps-container' id='steps-${index}'>
|
|
2461
|
+
${(() => {
|
|
2462
|
+
const hasStepsArray = test.stepsArray && Array.isArray(test.stepsArray) && test.stepsArray.length > 0;
|
|
2463
|
+
const hasStepsString = test.steps && typeof test.steps === 'string' && test.steps.trim().length > 0;
|
|
2464
|
+
|
|
2465
|
+
if (hasStepsArray) {
|
|
2466
|
+
return renderStepsTree(test.stepsArray);
|
|
2467
|
+
} else if (hasStepsString) {
|
|
2468
|
+
const isErrorMessage = test.steps.match(/^Error:/i);
|
|
2469
|
+
|
|
2470
|
+
if (!isErrorMessage) {
|
|
2471
|
+
return renderStepsTree(test.steps);
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
return '<div style=\'padding: 20px; color: var(--gray-500); text-align: center;\'>No steps recorded</div>';
|
|
2476
|
+
})()}
|
|
2477
|
+
</div>
|
|
2478
|
+
</div>
|
|
2479
|
+
<div class='test-tab-content' data-tab='message'>
|
|
2480
|
+
<div class='message-block ${statusClass}'>
|
|
2481
|
+
<strong>${statusClass.toUpperCase()}:</strong><br>
|
|
2482
|
+
${test.message || 'No message available'}
|
|
2483
|
+
</div>
|
|
2484
|
+
</div>
|
|
2485
|
+
${hasStack ? `<div class='test-tab-content' data-tab='stack'>
|
|
2486
|
+
<div class='code-block'>${test.stack}</div>
|
|
2487
|
+
</div>` : ''}
|
|
2488
|
+
`}
|
|
2489
|
+
${hasRetries ? `<div class='test-tab-content' data-tab='retries'>
|
|
2490
|
+
<div class='retry-info'>
|
|
2491
|
+
<div class='retry-title'>
|
|
2492
|
+
<i class='fas fa-redo'></i>
|
|
2493
|
+
Retry Information (${retryCount} retries, ${attemptsCount} attempts)
|
|
2494
|
+
</div>
|
|
2495
|
+
<div class='retry-attempts'>
|
|
2496
|
+
${createRetryAttempts(test.retries)}
|
|
2497
|
+
</div>
|
|
2498
|
+
</div>
|
|
2499
|
+
</div>` : ''}
|
|
2500
|
+
${hasArtifacts ? `<div class='test-tab-content' data-tab='attachments'>
|
|
2501
|
+
<div class='attachments-grid'>
|
|
2502
|
+
${createAttachmentItems(test.artifacts)}
|
|
2503
|
+
</div>
|
|
2504
|
+
</div>` : ''}
|
|
2505
|
+
${Object.keys(test.meta || {}).length > 0 ? `<div class='test-tab-content' data-tab='metadata'>
|
|
2506
|
+
<div class='metadata-grid' data-test-meta></div>
|
|
2507
|
+
</div>` : ''}
|
|
2508
|
+
${hasTraces ? `<div class='test-tab-content' data-tab='traces'>
|
|
2509
|
+
<div class='trace-viewer-container'></div>
|
|
2510
|
+
</div>` : ''}
|
|
2511
|
+
</div>
|
|
2512
|
+
`;
|
|
797
2513
|
|
|
798
|
-
|
|
799
|
-
addCollapseExpandListener(testitem__top);
|
|
800
|
-
initializeMenu(clone);
|
|
2514
|
+
return testItem;
|
|
801
2515
|
}
|
|
802
2516
|
|
|
803
|
-
function
|
|
804
|
-
const
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
2517
|
+
function getStatusIcon(status) {
|
|
2518
|
+
const icons = {
|
|
2519
|
+
'passed': 'check',
|
|
2520
|
+
'failed': 'times',
|
|
2521
|
+
'skipped': 'forward',
|
|
2522
|
+
'pending': 'clock',
|
|
2523
|
+
'todo': 'circle'
|
|
2524
|
+
};
|
|
2525
|
+
return icons[status] || 'question';
|
|
2526
|
+
}
|
|
808
2527
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
clone.classList.remove('d-none');
|
|
812
|
-
wrapp.append(clone);
|
|
2528
|
+
function formatDuration(milliseconds) {
|
|
2529
|
+
if (!milliseconds || milliseconds === 0 || milliseconds === null) return '0ms';
|
|
813
2530
|
|
|
814
|
-
const
|
|
815
|
-
|
|
2531
|
+
const totalSeconds = Math.floor(milliseconds / 1000);
|
|
2532
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
2533
|
+
const seconds = totalSeconds % 60;
|
|
2534
|
+
const ms = milliseconds % 1000;
|
|
816
2535
|
|
|
817
|
-
|
|
2536
|
+
if (minutes > 0) {
|
|
2537
|
+
return `${minutes}m ${seconds}s ${ms}ms`;
|
|
2538
|
+
} else if (seconds > 0) {
|
|
2539
|
+
return `${seconds}s ${ms}ms`;
|
|
2540
|
+
} else {
|
|
2541
|
+
return `${ms}ms`;
|
|
2542
|
+
}
|
|
818
2543
|
}
|
|
819
2544
|
|
|
820
|
-
function
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
2545
|
+
function parseStepsToHtml(stepsText) {
|
|
2546
|
+
if (!stepsText || stepsText === 'No steps recorded') {
|
|
2547
|
+
return `<div class="step-item">
|
|
2548
|
+
<div class="step-content">
|
|
2549
|
+
<p class="step-text">${stepsText || 'No steps recorded'}</p>
|
|
2550
|
+
</div>
|
|
2551
|
+
</div>`;
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
const raw = String(stepsText);
|
|
2555
|
+
const lines = raw
|
|
2556
|
+
.split(/<br\s*\/?>|\n/gi)
|
|
2557
|
+
.map(l => l.trim())
|
|
2558
|
+
.filter(Boolean);
|
|
2559
|
+
|
|
2560
|
+
let stepNumber = 1;
|
|
2561
|
+
let html = '';
|
|
2562
|
+
|
|
2563
|
+
lines.forEach(line => {
|
|
2564
|
+
const trimmedLine = line.trim();
|
|
2565
|
+
|
|
2566
|
+
const numberedMatch = trimmedLine.match(/^(\d+)\.\s*(.+)$/);
|
|
2567
|
+
if (numberedMatch) {
|
|
2568
|
+
const [, num, text] = numberedMatch;
|
|
2569
|
+
stepNumber = parseInt(num, 10);
|
|
2570
|
+
html += createStepHtml(text, stepNumber);
|
|
2571
|
+
stepNumber++;
|
|
2572
|
+
return;
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
const checkmarkMatch = trimmedLine.match(/^([✓✗])\s*(.+)$/);
|
|
2576
|
+
if (checkmarkMatch) {
|
|
2577
|
+
const [, symbol, text] = checkmarkMatch;
|
|
2578
|
+
const status = symbol === '✓' ? 'passed' : 'failed';
|
|
2579
|
+
html += createStepHtml(text, stepNumber, status);
|
|
2580
|
+
stepNumber++;
|
|
2581
|
+
return;
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
const arrowMatch = trimmedLine.match(/^(→|▶|▸|▹)\s*(.+)$/);
|
|
2585
|
+
if (arrowMatch) {
|
|
2586
|
+
const [, symbol, text] = arrowMatch;
|
|
2587
|
+
html += createStepHtml(text, stepNumber, null, symbol);
|
|
2588
|
+
stepNumber++;
|
|
2589
|
+
return;
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2592
|
+
const bracketMatch = trimmedLine.match(/^\[([^\]]+)\]\s*(.+)$/);
|
|
2593
|
+
if (bracketMatch) {
|
|
2594
|
+
const [, category, text] = bracketMatch;
|
|
2595
|
+
html += createStepHtml(text, stepNumber, null, category);
|
|
2596
|
+
stepNumber++;
|
|
2597
|
+
return;
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2600
|
+
const keywordMatch = trimmedLine.match(/^(When|Then|And|Given|But|When\s+I|Then\s+I|And\s+I|Given\s+I|But\s+I)\s+(.+)$/i);
|
|
2601
|
+
if (keywordMatch) {
|
|
2602
|
+
const [, keyword, text] = keywordMatch;
|
|
2603
|
+
html += createStepHtml(text, stepNumber, null, keyword);
|
|
2604
|
+
stepNumber++;
|
|
2605
|
+
return;
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
html += createStepHtml(trimmedLine, stepNumber);
|
|
2609
|
+
stepNumber++;
|
|
2610
|
+
});
|
|
2611
|
+
|
|
2612
|
+
return html || `<div class="step-item">
|
|
2613
|
+
<div class="step-content">
|
|
2614
|
+
<p class="step-text">No valid steps found</p>
|
|
2615
|
+
</div>
|
|
2616
|
+
</div>`;
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
function renderStepsTree(steps, depth = 0) {
|
|
2620
|
+
if (Array.isArray(steps) && steps.length > 0) {
|
|
2621
|
+
let html = '';
|
|
2622
|
+
let stepNumber = 1;
|
|
2623
|
+
|
|
2624
|
+
steps.forEach((step, index) => {
|
|
2625
|
+
if (!step) return;
|
|
2626
|
+
|
|
2627
|
+
const hasChildren = step.steps && Array.isArray(step.steps) && step.steps.length > 0;
|
|
2628
|
+
const stepId = `step-${depth}-${index}`;
|
|
2629
|
+
const status = step.status || 'passed';
|
|
2630
|
+
const duration = step.duration || 0;
|
|
2631
|
+
const category = step.category || '';
|
|
2632
|
+
|
|
2633
|
+
html += `
|
|
2634
|
+
<div class="step-item step-level-${depth}" data-step-id="${stepId}">
|
|
2635
|
+
<div class="step-number">${stepNumber}</div>
|
|
2636
|
+
<div class="step-content">
|
|
2637
|
+
<p class="step-text">${step.title || 'Untitled step'}</p>
|
|
2638
|
+
${category && category !== 'user' ? `<div class="step-category">${category}</div>` : ''}
|
|
2639
|
+
<div class="step-time">
|
|
2640
|
+
Step ${stepNumber}
|
|
2641
|
+
${duration > 0 ? `<span class="step-duration"><i class="fas fa-clock"></i> ${formatDuration(duration)}</span>` : ''}
|
|
2642
|
+
</div>
|
|
2643
|
+
</div>
|
|
2644
|
+
<div class="step-status ${status}"></div>
|
|
2645
|
+
</div>
|
|
2646
|
+
`;
|
|
2647
|
+
|
|
2648
|
+
if (hasChildren) {
|
|
2649
|
+
html += `
|
|
2650
|
+
<div class="step-children">
|
|
2651
|
+
${renderStepsTree(step.steps, depth + 1)}
|
|
2652
|
+
</div>
|
|
2653
|
+
`;
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
stepNumber++;
|
|
2657
|
+
});
|
|
2658
|
+
|
|
2659
|
+
return html;
|
|
2660
|
+
}
|
|
825
2661
|
|
|
826
|
-
if(
|
|
827
|
-
|
|
2662
|
+
if (typeof steps === 'string') {
|
|
2663
|
+
return parseStepsToHtml(steps);
|
|
828
2664
|
}
|
|
829
|
-
|
|
830
|
-
|
|
2665
|
+
|
|
2666
|
+
return `<div class="step-item">
|
|
2667
|
+
<div class="step-content">
|
|
2668
|
+
<p class="step-text">${steps}</p>
|
|
2669
|
+
</div>
|
|
2670
|
+
</div>`;
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2673
|
+
function createStepHtml(text, number, status = null, category = null) {
|
|
2674
|
+
const statusClass = status || 'passed';
|
|
2675
|
+
const categoryText = category && category !== 'user' ? `<div class="step-category">${category}</div>` : '';
|
|
2676
|
+
const durationIcon = status ? `<div class="step-duration"><i class="fas fa-clock"></i> auto</div>` : '';
|
|
2677
|
+
|
|
2678
|
+
return `<div class="step-item">
|
|
2679
|
+
<div class="step-number">${number}</div>
|
|
2680
|
+
<div class="step-content">
|
|
2681
|
+
<p class="step-text">${text}</p>
|
|
2682
|
+
${categoryText}
|
|
2683
|
+
<div class="step-time">Step ${number}${durationIcon}</div>
|
|
2684
|
+
</div>
|
|
2685
|
+
<div class="step-status ${statusClass}"></div>
|
|
2686
|
+
</div>`;
|
|
2687
|
+
}
|
|
2688
|
+
|
|
2689
|
+
function createRetryAttempts(retries) {
|
|
2690
|
+
const attempts = Array.isArray(retries?.attempts) ? retries.attempts : [];
|
|
2691
|
+
if (!attempts.length) return '';
|
|
2692
|
+
|
|
2693
|
+
return attempts.map((a, idx) => {
|
|
2694
|
+
const status = String(a?.status || 'unknown').toLowerCase();
|
|
2695
|
+
const isFinal = idx === attempts.length - 1;
|
|
2696
|
+
|
|
2697
|
+
const icon =
|
|
2698
|
+
status === 'passed' ? 'check' :
|
|
2699
|
+
status === 'failed' ? 'times' :
|
|
2700
|
+
status === 'skipped' ? 'forward' :
|
|
2701
|
+
'question';
|
|
2702
|
+
|
|
2703
|
+
const cls =
|
|
2704
|
+
status === 'passed' ? 'passed' :
|
|
2705
|
+
status === 'failed' ? 'failed' :
|
|
2706
|
+
status === 'skipped' ? 'skipped' :
|
|
2707
|
+
'unknown';
|
|
2708
|
+
|
|
2709
|
+
return `
|
|
2710
|
+
<div class='retry-attempt ${cls}'>
|
|
2711
|
+
<i class='fas fa-${icon}'></i>
|
|
2712
|
+
Attempt ${idx + 1}${isFinal ? ' (final)' : ''}
|
|
2713
|
+
</div>
|
|
2714
|
+
`;
|
|
2715
|
+
}).join('');
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2718
|
+
function normalizeArtifact(artifact) {
|
|
2719
|
+
if (!artifact) return { filePath: '', displayName: 'attachment' };
|
|
2720
|
+
|
|
2721
|
+
if (typeof artifact === 'string') {
|
|
2722
|
+
return { filePath: artifact, displayName: artifact };
|
|
831
2723
|
}
|
|
832
|
-
|
|
833
|
-
|
|
2724
|
+
|
|
2725
|
+
if (typeof artifact === 'object') {
|
|
2726
|
+
const filePath =
|
|
2727
|
+
(typeof artifact.path === 'string' && artifact.path) ||
|
|
2728
|
+
(typeof artifact.url === 'string' && artifact.url) ||
|
|
2729
|
+
(typeof artifact.href === 'string' && artifact.href) ||
|
|
2730
|
+
(typeof artifact.file === 'string' && artifact.file) ||
|
|
2731
|
+
'';
|
|
2732
|
+
|
|
2733
|
+
const displayName =
|
|
2734
|
+
(typeof artifact.name === 'string' && artifact.name) ||
|
|
2735
|
+
(typeof artifact.fileName === 'string' && artifact.fileName) ||
|
|
2736
|
+
filePath ||
|
|
2737
|
+
'attachment';
|
|
2738
|
+
|
|
2739
|
+
return { filePath, displayName };
|
|
834
2740
|
}
|
|
835
2741
|
|
|
836
|
-
const
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
content_message = content.querySelector('div[type="message"]').querySelector('span'),
|
|
840
|
-
content_files = content.querySelector('div[type="files"]').querySelector('span');
|
|
2742
|
+
const s = String(artifact);
|
|
2743
|
+
return { filePath: s, displayName: s };
|
|
2744
|
+
}
|
|
841
2745
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
if (files.includes("This test has no files")){
|
|
847
|
-
content_files.innerHTML = files
|
|
848
|
-
folderSvg.classList.add('d-none');
|
|
2746
|
+
function safeBasename(p) {
|
|
2747
|
+
return String(p || '')
|
|
2748
|
+
.split(/[\\/]/)
|
|
2749
|
+
.pop();
|
|
849
2750
|
}
|
|
850
|
-
|
|
851
|
-
|
|
2751
|
+
|
|
2752
|
+
function createAttachmentItems(artifacts) {
|
|
2753
|
+
if (!Array.isArray(artifacts) || artifacts.length === 0) return '';
|
|
2754
|
+
|
|
2755
|
+
return artifacts
|
|
2756
|
+
.map((artifact) => {
|
|
2757
|
+
const { filePath, displayName } = normalizeArtifact(artifact);
|
|
2758
|
+
const fileName = safeBasename(displayName || filePath) || 'attachment';
|
|
2759
|
+
|
|
2760
|
+
if (!filePath) {
|
|
2761
|
+
return `
|
|
2762
|
+
<div class='attachment-item'>
|
|
2763
|
+
<div class='attachment-file'>
|
|
2764
|
+
<i class='fas fa-file' style='font-size: 48px; color: var(--gray-400);'></i>
|
|
2765
|
+
<div style='margin-top: 10px; font-size: 14px; color: var(--gray-600);'>${fileName}</div>
|
|
2766
|
+
<div style='margin-top: 6px; font-size: 12px; color: var(--gray-500);'>inline attachment</div>
|
|
2767
|
+
</div>
|
|
2768
|
+
</div>
|
|
2769
|
+
`;
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
const isImage = /\.(jpg|jpeg|png|gif|webp)$/i.test(filePath) || /\.(jpg|jpeg|png|gif|webp)$/i.test(fileName);
|
|
2773
|
+
|
|
2774
|
+
if (isImage) {
|
|
2775
|
+
return `
|
|
2776
|
+
<div class='attachment-item' onclick='openAttachment("${filePath}")''>
|
|
2777
|
+
<img src='${filePath}' alt='${fileName}' class='attachment-image'>
|
|
2778
|
+
<div class='attachment-name'>${fileName}</div>
|
|
2779
|
+
</div>
|
|
2780
|
+
`;
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
const icon = getFileIcon(filePath);
|
|
2784
|
+
return `
|
|
2785
|
+
<div class='attachment-item' onclick='openAttachment("${filePath}")''>
|
|
2786
|
+
<div class='attachment-file'>
|
|
2787
|
+
<i class='fas fa-${icon}' style='font-size: 48px; color: var(--gray-400);'></i>
|
|
2788
|
+
<div style='margin-top: 10px; font-size: 14px; color: var(--gray-600);'>${fileName}</div>
|
|
2789
|
+
</div>
|
|
2790
|
+
</div>
|
|
2791
|
+
`;
|
|
2792
|
+
})
|
|
2793
|
+
.join('');
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2796
|
+
function getFileIcon(filePath) {
|
|
2797
|
+
if (typeof filePath !== 'string') return 'file';
|
|
2798
|
+
const ext = (filePath.split('.').pop() || '').toLowerCase();
|
|
2799
|
+
const icons = {
|
|
2800
|
+
pdf: 'file-pdf',
|
|
2801
|
+
zip: 'file-archive',
|
|
2802
|
+
rar: 'file-archive',
|
|
2803
|
+
mp4: 'file-video',
|
|
2804
|
+
avi: 'file-video',
|
|
2805
|
+
mov: 'file-video',
|
|
2806
|
+
webm: 'file-video',
|
|
2807
|
+
mp3: 'file-audio',
|
|
2808
|
+
wav: 'file-audio',
|
|
2809
|
+
txt: 'file-alt',
|
|
2810
|
+
log: 'file-alt',
|
|
2811
|
+
json: 'file-code',
|
|
2812
|
+
xml: 'file-code',
|
|
2813
|
+
csv: 'file-excel',
|
|
2814
|
+
xlsx: 'file-excel',
|
|
2815
|
+
doc: 'file-word',
|
|
2816
|
+
docx: 'file-word',
|
|
2817
|
+
};
|
|
2818
|
+
return icons[ext] || 'file';
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
function toggleTest(header) {
|
|
2822
|
+
const testItem = header.closest('.test-item');
|
|
2823
|
+
testItem.classList.toggle('expanded');
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
function showTestTab(tab, tabName) {
|
|
2827
|
+
const testContent = tab.closest('.test-content');
|
|
2828
|
+
const allTabs = testContent.querySelectorAll('.test-tab');
|
|
2829
|
+
const allContents = testContent.querySelectorAll('.test-tab-content');
|
|
2830
|
+
|
|
2831
|
+
allTabs.forEach(t => t.classList.remove('active'));
|
|
2832
|
+
allContents.forEach(c => c.classList.remove('active'));
|
|
2833
|
+
|
|
2834
|
+
tab.classList.add('active');
|
|
2835
|
+
testContent.querySelector(`[data-tab=\"${tabName}\"]`).classList.add('active');
|
|
2836
|
+
|
|
2837
|
+
if (tabName === 'traces') {
|
|
2838
|
+
const testItem = tab.closest('.test-item');
|
|
2839
|
+
const testIndex = testItem.dataset.testIndex;
|
|
2840
|
+
loadTraceForTest(testIndex);
|
|
852
2841
|
}
|
|
853
2842
|
}
|
|
854
2843
|
|
|
855
|
-
function
|
|
856
|
-
const
|
|
2844
|
+
async function loadTraceForTest(testIndex) {
|
|
2845
|
+
const testItem = document.querySelector(`.test-item[data-test-index="${testIndex}"]`);
|
|
2846
|
+
if (!testItem) return;
|
|
857
2847
|
|
|
858
|
-
|
|
859
|
-
|
|
2848
|
+
let traces = window.testTraces && window.testTraces[testIndex];
|
|
2849
|
+
if (!traces || !Array.isArray(traces) || traces.length === 0) return;
|
|
860
2850
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
2851
|
+
traces = traces.filter(t => {
|
|
2852
|
+
if (typeof t === 'string' && t.trim().length > 0) return true;
|
|
2853
|
+
if (t && t.dataUrl && typeof t.dataUrl === 'string' && t.dataUrl.trim().length > 0) return true;
|
|
2854
|
+
return false;
|
|
2855
|
+
});
|
|
2856
|
+
if (traces.length === 0) return;
|
|
865
2857
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
2858
|
+
const viewerDiv = testItem.querySelector('.trace-viewer-container');
|
|
2859
|
+
if (!viewerDiv) return;
|
|
2860
|
+
|
|
2861
|
+
if (viewerDiv.dataset.loaded === 'true') return;
|
|
2862
|
+
|
|
2863
|
+
let html = `
|
|
2864
|
+
<div class="traces-instruction">
|
|
2865
|
+
<div class="instruction-header">
|
|
2866
|
+
<i class="fas fa-info-circle"></i>
|
|
2867
|
+
<span>How to view trace files</span>
|
|
2868
|
+
</div>
|
|
2869
|
+
<div class="instruction-content">
|
|
2870
|
+
<ol>
|
|
2871
|
+
<li>Download the trace file using the button below</li>
|
|
2872
|
+
<li>Extract the .zip archive if needed</li>
|
|
2873
|
+
<li><strong>Playwright traces:</strong><br>
|
|
2874
|
+
<code>npx playwright show-trace trace.zip</code><br>
|
|
2875
|
+
Or VS Code extension: "Playwright Test for VS Code"
|
|
2876
|
+
</li>
|
|
2877
|
+
<li><strong>TestCafe traces:</strong><br>
|
|
2878
|
+
<code>testcafe show-trace trace.zip</code>
|
|
2879
|
+
</li>
|
|
2880
|
+
<li><strong>Other traces:</strong><br>
|
|
2881
|
+
Check your testing framework documentation
|
|
2882
|
+
</li>
|
|
2883
|
+
</ol>
|
|
2884
|
+
</div>
|
|
2885
|
+
</div>
|
|
2886
|
+
`;
|
|
2887
|
+
|
|
2888
|
+
html += '<div class="traces-list">';
|
|
871
2889
|
|
|
872
|
-
|
|
2890
|
+
for (let idx = 0; idx < traces.length; idx++) {
|
|
2891
|
+
const trace = traces[idx];
|
|
2892
|
+
const traceDataUrl = typeof trace === 'string' ? trace : trace.dataUrl;
|
|
2893
|
+
let traceName = 'trace.zip';
|
|
2894
|
+
|
|
2895
|
+
if (typeof trace === 'object' && trace.name) {
|
|
2896
|
+
traceName = trace.name;
|
|
2897
|
+
} else if (idx === 0) {
|
|
2898
|
+
traceName = 'test-failed-trace.zip';
|
|
2899
|
+
} else {
|
|
2900
|
+
traceName = `trace-${idx + 1}.zip`;
|
|
873
2901
|
}
|
|
874
2902
|
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
fileItemContainer.classList.add('d-flex', 'flex-column', 'align-items-center', 'mr-3');
|
|
888
|
-
|
|
889
|
-
switch (fileExtension) {
|
|
890
|
-
case 'jpg':
|
|
891
|
-
case 'jpeg':
|
|
892
|
-
case 'png':
|
|
893
|
-
case 'gif':
|
|
894
|
-
fileIcon = createImagePreview(file);
|
|
895
|
-
break;
|
|
896
|
-
case 'zip':
|
|
897
|
-
const svgZipCode =
|
|
898
|
-
`<svg width="95" height="94" viewBox="0 0 95 94" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
899
|
-
<rect x="0.5" width="94" height="94" fill="url(#pattern0)"/>
|
|
900
|
-
<defs>
|
|
901
|
-
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
|
902
|
-
<use xlink:href="#image0_212_109" transform="scale(0.01)"/>
|
|
903
|
-
</pattern>
|
|
904
|
-
<image id="image0_212_109" width="100" height="100" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IArs4c6QAABwdJREFUeAHtnEmIJFUQhntEEVTwoCAouODNDWREEFzK7ow/XrW26yAi4kFwBcGLCKLQBxEPoh4GRLyoBwWvA6LixYMXQbypILiBOuLOqKOjzuhrOseXQS6RVS8jqpocaCpfvog/vvijqqa6qypXVsZ/owOjA6MDowOjA8YOMHBkyX4+2JhMTjW2ya7ckg2jvPN8SESn27lkWGlJB3IERfHxtaurZxhaZVNqWQcSuUH0GYBzbJwyqiIHYlS2dxnJmay/mE6n5/YWXNSEpLGt5+dl4Uy5QfT1dDo9b1HZe3GljcXjXsmGwZKzZr0fwAWGSMOUko0NU2V+VclJRC/Lcwx8G0K4aP5qjgqyKUeU1tI1nLuYea88D6IfmfnSVrFF3pQNLSprA2ccyrNyj4GfQwiXLWovrVyymdZgx802TgYel/sM/MrMVzsiz1ZaNjKbyvBZXZwB2JQxIPqNmYvh6TJWkE1klM4qpeFk5odlHIj+CETXZYUZUkw2MGStebS1nAF4SMaC6M9AdOM89c1yJbxZ4Z6F+nACuI+BwyLnEIA9PcvahwvopfnFsMspZr4LRP+k/YHob2a+oyvXdT8FjseuMC3FZ+Fk5tsY+CvNjUMBcGdLKd+tFHanDSQ6C+BWOZT4dAbgAV/nG6rv9IFsD2UPA4dEr4eZ+cEGW/xOC8gd9ZSVusrM1zBwUPYbgEfTOPdjCegO1ACQg5OZA4DfpRYTPdlQ1v60hLMn0FXMxTkluoqBA1JvYYYiwXT22Efl5AxFcTmIfpGaTPTUysrKLvvukooSKtlaqMPcnER0CRP9IHWJ6LnNzc1j3JqXQG4gHYWH4JwWxcXM/J3UZuYX3IYiYTp8cdseijO+Fx/fk5f6zPzKZDI51rxhCWIOoCwoOS3WAF5V4uULk43lU86rJDmt1nm7UKjJxhQpLiGS02pt3qxszBxAWVByWq2VePnCZGP5lJdTyd0Pd4AFm5u7H+4A40CqDowDWTA/xoGMA6k6sGAr9zuoO8A4kKoD40AWzI9xIONAqg4s2Mr9DuoOMA6k6sCyDCReLCCEMAlEtzPzvfGD1QDuDiHcFEI4u9rV7Ct3P3IBSJ2utbRMxst37OS+XKMo3gdwg9Ttu5a6ffPnjs8FIHW61hJcxvcdSJkP4Amp3Wdd6pS3fXKzxJaFy9tZRct85e0hWUfmdQ6E+Q1mfo2JvpS5zHy91NeupZY2L1tcLoD4TaWmnwA8XanDvFc2UNn/70PfXQMp8+P73vLLn/Hpq9zveys5+ubPHT80wJZhRB8ldQ6sra2dJsGT/a0LGGgHEnWm0+nxAL5JNWa9OE2qEY8l5+DroQHiK6G0RvwuYF1Tacy2EZUPrNXsV2QC8HwaE4jWKgHKRaqxzaHMzBQ2JMDGxsYJDHyV1Ng/mUxOqkNPYspLfPQaCBM9VtFgvrmuTte5isZOe4Qw0SNpgwG4v8mQNC4ey4901uxXpBh4Jo0BsFoJUC5SjW0OZWamsKEA1tbWTmHgp6P6RJ/s3r37uCbso3HbV7jrO5AAvJlqrK+vn9VUq+18qhGP22IH2RsKIH5wuaLNfEtbA5XYno8QZj4//ZZUvLhZW622vRqOtvD8e0MAFEVxZvrlGCJ6T97jZSc1HJr/Q3bFpyYi+jzND0T3SH3tOtWJx9q8bHFDAATgxYqu4hIXlXjFI4SBTxn4XuYx89vyJXMfs6Ren9wssbkB1oviwq2vH/9/tdPXNaA1HK2PEBm/tS6KfQBO1NRripG6TXGDnc8NwEWxr9SM3xPXXr+qzClv5VNceb7mNn7t+Z1cV2qQ+oMZ3yScEwDAlULvpaa68rzI63zZy8xXxEdjURQnS6151jUc88j1z80JwETvJnoH+7z0TPLKXwwrzXTtV4LnWFjVaUTMBRCfMipaRG81/bGx7pJJldyaVzdd+40N9tywqtOIlQuAq39A3LqXS+10LYHSvXjcd1/Gz7ru4phVV52XC0DqdK0loIzvuy/jZ113ccyqq87LBSB1utYSUMb33Zfxs667OGbVVee5A6hJbQLd/XAHsPFZXcXdD3cAtVU2ge5+uAPY+Kyu4u6HO4DaKptAdz/cAWx8Vldx98MdQG2VTaC7H+4ANj6rq7j74Q6gtsom0N0PdwAbn9VV3P1wB1BbZRPo7oc7gI3P6irufrgDqK2yCXT3wx3Axmd1FXc/3AHUVtkEuvvhDmDjs7qKux/uAGqrbALd/XAHsPFZXcXdD3cAtVU2ge5+uAPY+Kyu4u6HO4DaKptAdz/cAWx8Vldx98MdQG2VTaC7H+4ANj6rq7j74Q6gtsom0N0PdwAbn9VV3P2QAOMalQ+KqyeZK3AcQHUA0o9cPqt1JMC4rg5IbWSuwHEA1QFIP3L5POqMDowOjA6MDowOaB34F113oQg53J+KAAAAAElFTkSuQmCC"/>
|
|
905
|
-
</defs>
|
|
906
|
-
</svg>`;
|
|
907
|
-
fileIcon = createFileIcon(file,svgZipCode);
|
|
908
|
-
break;
|
|
909
|
-
case 'mp4':
|
|
910
|
-
case 'avi':
|
|
911
|
-
case 'mov':
|
|
912
|
-
case 'webm':
|
|
913
|
-
const svgVideoCode =
|
|
914
|
-
`<svg width="95" height="95" viewBox="0 0 95 95" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
915
|
-
<g clip-path="url(#clip0_212_104)">
|
|
916
|
-
<path d="M35.75 27.4702V67.5298L65.125 47.5L35.75 27.4702ZM39.6667 34.8844L58.1729 47.5L39.6667 60.1156V34.8844ZM4.41666 12.25V82.75H90.5833V12.25H4.41666ZM86.6667 78.8333H8.33333V16.1667H86.6667V78.8333Z" fill="#474646"/>
|
|
917
|
-
</g>
|
|
918
|
-
<defs>
|
|
919
|
-
<clipPath id="clip0_212_104">
|
|
920
|
-
<rect width="94" height="94" fill="white" transform="translate(0.5 0.5)"/>
|
|
921
|
-
</clipPath>
|
|
922
|
-
</defs>
|
|
923
|
-
</svg>`;
|
|
924
|
-
fileIcon = createFileIcon(file, svgVideoCode);
|
|
925
|
-
break;
|
|
926
|
-
default:
|
|
927
|
-
const svgFileCode =
|
|
928
|
-
`<svg width="95" height="94" viewBox="0 0 95 94" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
929
|
-
<rect x="0.5" width="94" height="94" fill="url(#pattern0)"/>
|
|
930
|
-
<defs>
|
|
931
|
-
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
|
932
|
-
<use xlink:href="#image0_212_112" transform="scale(0.01)"/>
|
|
933
|
-
</pattern>
|
|
934
|
-
<image id="image0_212_112" width="100" height="100" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IArs4c6QAABtNJREFUeAHtnE2IHEUUxzeiHhQUUcQPPKjgQfxkRRQV10y9/+vZdQUhC+JBQYngQRBB9OBhQTEiigqCgh78AL0IHuLJPXgRJAcRRBYvEo0gBvE7Go0xqzW7NVQ/ume6a7vq9SwVGLrr4733r9+/M8vMdNfcXP6XCWQCmUAmkAkkJsDAxoy9PlteWDgnMaZ05WbMDHfxrBPRBekoJaw0o4ZswJgvb9+9+8KEqNKUmlVDrG4QHQRwcRpSiapIQxKVbV1G6vTa3wyHw0tbJ+xrgLew0fvzrOj0dYPou+FweHlftbfS5S/MnrcKTjhZ6qxofw/gioSS4pSSC4tTZftZpU4iekv2MXC4KIqrtl9NMYNclKKUiaUrdO5i5pdlP4h+YubrJybr86BcUF+11ui0prwoxxj4pSiKG/u6lom65GImTlYcnKSTgafkOANHmPk2RclhpeVCwrLEj5qmswBW5RwQ/cHMJr66DivIRXSYutNUTXQy82NyHoj+Koju6FRMzGRyATFrbSd3U50F8KicC6K/C6I7t1M/WawUn6xwy0JtdAJ4kIETIuYYgD0ty6afLkTPzAfDaaSYeS+I/vXXB6LjzHzPtFjVcV+wPVcVM6F4iE5mvpuBf/xYawqA+yaU0h3yxe40QyxZAHdJU+zbGYCHdMnXVN/phmyZsoeBY2KtJ5j54Roset1C5I56y/KpMvMSA0flegvgCX+e+rkUqC6oRkAXOpm5APCnzMVEz9SUTd8txaVX0KxiVzqHRLcy8LvM1xtTpLBmeNLP6lJnYczNIPpV5mSi5+bm5nalX51XUYryhnp12rVOIrqOiX6UeYnoldXV1ZPUFi8FqQmZUjiGzqEx1zLzDzI3M7+mZooUM4WL2nAsnfa3ePubvMzPzO8sLCycnHzBUkhyAQ0LSp0p2gDebSivu2lyYd1l7jaT1Jmq3e0qGmSTC2sQojJF6kzVTr5YubDkAhoWlDpTtRvK626aXFh3mWczkzoPdQE9802dh7qAbEiZQDakZzyyIdmQMoGetdQvUHUB2ZAygWxIz3hkQ7IhZQI9a6lfoOoCsiFlAtmQnvHIhuxAQwCcWwBfNX1ZBGzMfn8+Ed3k0Nhf6kD0hRsH8In9SdXvc2N1RwAXuXxtjuoXaBcC7DYXMs+ktgUE4HEx5wUHjplvKY0xPz+KsQ/gNNybZTAYXOLytTnK/G1iO5nbhYAQQ+y2GKO70bcAE9HX7hYcAE+WdDFfbRc7eiIqGzLd98FgcDaAtfGL6GAJKLA+HgPWXEYm+tCfZ+8CsWNMdMD1w5hP3fz/b935wOVhYN3NscetbTbGGpj5fBfX5ujntOdtYjuZG0NAAezz8wJ4oEqsfVbDn2fvszXGnOn/z6m7S93mFLH7qmq07fNz2vO28dueH0NAU0MAnA5jfnMaCuBj+zyga9tH0er2xsqGtLC+qSE2ZQG84RlwnIE3XZuB9+rKZkPqyFT0tzKEaOAZYP8WWFNGG+EAWK5IP+rKhtSRqehvY4j9fMFEh5wJ3vHw/Pz8KRXpsyF1UOr62xhicwB42jNicxu/zTvR60rYmPxHvZaOGAgw5FlpSEH0iEhbamZDSjgmN9oYsvWVyLfSEPs5Y1KVbMgkOmKsjSFEhAozRm9bQ2NuEKnHzWzIGMX0kzaGAHh7bIgx+/3PJQBer6uWDakjU9Hf1BD7wdB/3m+0JYYx748NAo4Mh8MzKkrkP+pVUOr6Whhyrwd/Y3EwuKwA7vf77BYZVXXy/5AqKjV9LQxZG8MnOmTTLS4unlfao4ToQFWZbEgVlZq+JobIr98BvOrSEdFHY6OADSK6xo25YzbEkWhwbGKI3GzM/5pEwgbwkiwr59iack5I278Q7HlIjm3FxBDQxBAAn3u1jy4vL5/mFrK0tHSW/abXG//ZH7fzsiGOVoPjojFXFkQr7iV/Tl1ZWTnVjdkjAJJp7ecTf479EcyfY3P647amPx567l0EOjt9qwsIJRcpTp2HuoBIYEPTqvNQFxBKLlKcOg91AZHAhqZV56EuIJRcpDh1HuoCIoENTavOQ11AKLlIceo81AVEAhuaVp2HuoBQcpHi1HmoC4gENjStOg91AaHkIsWp81AXEAlsaFp1HuoCQslFilPnoS4gEtjQtOo81AWEkosUp85DXUAksKFp1XmoCwglFylOnYe6gEhgQ9Oq81AXEEouUpw6D3UBkcCGplXnoS4glFykOHUe6gIigQ1Nq85DXUAouUhx6jzUBUQCG5pWnYcUkNubTwA7DqHGBse5wvlYNsLxCAYbGugK52M2ZPPx54a7+2hdMKEXeo7LBDKBTCATyARCCfwHp/izMKqRVXgAAAAASUVORK5CYII="/>
|
|
935
|
-
</defs>
|
|
936
|
-
</svg>`;
|
|
937
|
-
fileIcon = createFileIcon(file, svgFileCode);
|
|
2903
|
+
html += `
|
|
2904
|
+
<div class="trace-download-item">
|
|
2905
|
+
<div class="trace-info">
|
|
2906
|
+
<i class="fas fa-file-archive"></i>
|
|
2907
|
+
<span class="trace-name">${traceName}</span>
|
|
2908
|
+
</div>
|
|
2909
|
+
<button class="trace-download-btn" onclick='downloadTrace("${testIndex}", ${idx})'>
|
|
2910
|
+
<i class="fas fa-download"></i>
|
|
2911
|
+
Download Trace
|
|
2912
|
+
</button>
|
|
2913
|
+
</div>
|
|
2914
|
+
`;
|
|
938
2915
|
}
|
|
939
|
-
|
|
940
|
-
fileItemContainer.appendChild(fileIcon);
|
|
941
|
-
fileItemContainer.appendChild(fileName);
|
|
942
2916
|
|
|
943
|
-
|
|
2917
|
+
html += '</div>';
|
|
2918
|
+
viewerDiv.innerHTML = html;
|
|
2919
|
+
viewerDiv.dataset.loaded = 'true';
|
|
944
2920
|
}
|
|
945
2921
|
|
|
946
|
-
function
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
const imagePreview = document.createElement('img');
|
|
950
|
-
// component styles
|
|
951
|
-
imagePreview.src = filepath;
|
|
952
|
-
imagePreview.alt = 'Image Preview';
|
|
953
|
-
imagePreview.style.maxWidth = '200px';
|
|
954
|
-
imagePreview.style.height = '150px';
|
|
955
|
-
imagePreview.style.cursor = 'pointer';
|
|
2922
|
+
function downloadTrace(testIndex, traceIdx) {
|
|
2923
|
+
const traces = window.testTraces && window.testTraces[testIndex];
|
|
2924
|
+
if (!traces || !Array.isArray(traces) || traceIdx >= traces.length) return;
|
|
956
2925
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
2926
|
+
const trace = traces[traceIdx];
|
|
2927
|
+
const traceDataUrl = typeof trace === 'string' ? trace : trace.dataUrl;
|
|
2928
|
+
const traceName = typeof trace === 'object' && trace.name ? trace.name :
|
|
2929
|
+
(traceIdx === 0 ? 'test-failed-trace.zip' : `trace-${traceIdx + 1}.zip`);
|
|
960
2930
|
|
|
961
|
-
|
|
2931
|
+
const link = document.createElement('a');
|
|
2932
|
+
link.href = traceDataUrl;
|
|
2933
|
+
link.download = traceName;
|
|
2934
|
+
document.body.appendChild(link);
|
|
2935
|
+
link.click();
|
|
2936
|
+
document.body.removeChild(link);
|
|
962
2937
|
}
|
|
963
2938
|
|
|
964
|
-
function
|
|
965
|
-
|
|
966
|
-
const filepath = file?.path || `../${file}`;
|
|
967
|
-
const fileIcon = document.createElement('div');
|
|
968
|
-
// component styles
|
|
969
|
-
fileIcon.innerHTML = svg;
|
|
970
|
-
fileIcon.style.width = '150px';
|
|
971
|
-
fileIcon.style.height = '150px';
|
|
972
|
-
fileIcon.style.cursor = 'pointer';
|
|
973
|
-
fileIcon.style.textAlign = 'center';
|
|
2939
|
+
function openAttachment(filePath) {
|
|
2940
|
+
const url = String(filePath || '').trim();
|
|
974
2941
|
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
});
|
|
2942
|
+
const ok = /^(https?:\/\/|file:\/\/|\/|\.\/|\.\.\/)/i.test(url);
|
|
2943
|
+
if (!ok) return;
|
|
978
2944
|
|
|
979
|
-
|
|
2945
|
+
const w = window.open(url, '_blank', 'noopener,noreferrer');
|
|
2946
|
+
if (w) w.opener = null;
|
|
980
2947
|
}
|
|
981
2948
|
|
|
982
|
-
function
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
2949
|
+
function groupTestsBySuite(tests) {
|
|
2950
|
+
const groups = {};
|
|
2951
|
+
|
|
2952
|
+
tests.forEach(test => {
|
|
2953
|
+
const suite = test.suite_title || 'Unknown Suite';
|
|
2954
|
+
if (!groups[suite]) {
|
|
2955
|
+
groups[suite] = [];
|
|
2956
|
+
}
|
|
2957
|
+
groups[suite].push(test);
|
|
2958
|
+
});
|
|
2959
|
+
|
|
2960
|
+
return Object.entries(groups).map(([name, tests]) => ({
|
|
2961
|
+
name,
|
|
2962
|
+
type: 'suite',
|
|
2963
|
+
tests
|
|
2964
|
+
}));
|
|
2965
|
+
}
|
|
990
2966
|
|
|
991
|
-
|
|
2967
|
+
function groupTestsByFile(tests) {
|
|
2968
|
+
const groups = {};
|
|
992
2969
|
|
|
993
|
-
|
|
994
|
-
|
|
2970
|
+
tests.forEach(test => {
|
|
2971
|
+
const file = test.file || 'Unknown File';
|
|
2972
|
+
if (!groups[file]) {
|
|
2973
|
+
groups[file] = [];
|
|
2974
|
+
}
|
|
2975
|
+
groups[file].push(test);
|
|
995
2976
|
});
|
|
996
2977
|
|
|
997
|
-
return
|
|
2978
|
+
return Object.entries(groups).map(([name, tests]) => ({
|
|
2979
|
+
name,
|
|
2980
|
+
type: 'file',
|
|
2981
|
+
tests
|
|
2982
|
+
}));
|
|
998
2983
|
}
|
|
999
2984
|
|
|
1000
|
-
function
|
|
1001
|
-
|
|
1002
|
-
|
|
2985
|
+
function filterTests() {
|
|
2986
|
+
const filteredTests = allTests.filter(test => {
|
|
2987
|
+
const matchesFilter = currentFilter === 'all' || test.status.toLowerCase() === currentFilter;
|
|
2988
|
+
const matchesSearch = searchTerm === '' ||
|
|
2989
|
+
(test.title && test.title.toLowerCase().includes(searchTerm.toLowerCase())) ||
|
|
2990
|
+
(test.suite_title && test.suite_title.toLowerCase().includes(searchTerm.toLowerCase()));
|
|
2991
|
+
|
|
2992
|
+
return matchesFilter && matchesSearch;
|
|
1003
2993
|
});
|
|
2994
|
+
|
|
2995
|
+
return filteredTests;
|
|
1004
2996
|
}
|
|
1005
2997
|
|
|
1006
|
-
function
|
|
1007
|
-
const
|
|
1008
|
-
const
|
|
1009
|
-
const testitem__ico_right = icon.querySelector('.testitem__ico_right');
|
|
1010
|
-
const testitem__ico_down = icon.querySelector('.testitem__ico_down');
|
|
1011
|
-
const body = block.querySelector('.testitem__body');
|
|
2998
|
+
function renderTests() {
|
|
2999
|
+
const container = document.getElementById('testsContainer');
|
|
3000
|
+
const filteredTests = filterTests();
|
|
1012
3001
|
|
|
1013
|
-
if (
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
testitem__ico_right.classList.remove('d-none');
|
|
3002
|
+
if (groupingMode === 'suite') {
|
|
3003
|
+
const groups = groupTestsBySuite(filteredTests);
|
|
3004
|
+
renderGroupedTests(container, groups);
|
|
3005
|
+
return;
|
|
3006
|
+
} else if (groupingMode === 'file') {
|
|
3007
|
+
const groups = groupTestsByFile(filteredTests);
|
|
3008
|
+
renderGroupedTests(container, groups);
|
|
3009
|
+
return;
|
|
1022
3010
|
}
|
|
1023
|
-
}
|
|
1024
3011
|
|
|
1025
|
-
|
|
1026
|
-
const
|
|
1027
|
-
const
|
|
3012
|
+
const startIndex = (currentPage - 1) * pageSize;
|
|
3013
|
+
const endIndex = startIndex + pageSize;
|
|
3014
|
+
const paginatedTests = filteredTests.slice(startIndex, endIndex);
|
|
1028
3015
|
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
3016
|
+
if (paginatedTests.length === 0) {
|
|
3017
|
+
container.innerHTML = `
|
|
3018
|
+
<div class='empty-state'>
|
|
3019
|
+
<div class='empty-icon'>
|
|
3020
|
+
<i class='fas fa-search'></i>
|
|
3021
|
+
</div>
|
|
3022
|
+
<div class='empty-title'>No Tests Found</div>
|
|
3023
|
+
<div class='empty-description'>No tests match your current filter criteria.</div>
|
|
3024
|
+
</div>
|
|
3025
|
+
`;
|
|
3026
|
+
} else {
|
|
3027
|
+
container.innerHTML = '';
|
|
3028
|
+
paginatedTests.forEach((test, index) => {
|
|
3029
|
+
const testItem = createTestItem(test, startIndex + index);
|
|
3030
|
+
container.appendChild(testItem);
|
|
3031
|
+
});
|
|
1033
3032
|
}
|
|
3033
|
+
|
|
3034
|
+
renderPagination(filteredTests.length);
|
|
3035
|
+
setTimeout(populateMetadataFields, 50);
|
|
1034
3036
|
}
|
|
1035
3037
|
|
|
1036
|
-
function
|
|
1037
|
-
|
|
3038
|
+
function populateMetadataFields() {
|
|
3039
|
+
const metaGrids = document.querySelectorAll('[data-test-meta]');
|
|
3040
|
+
metaGrids.forEach(grid => {
|
|
3041
|
+
const testItem = grid.closest('.test-item');
|
|
3042
|
+
if (!testItem) return;
|
|
3043
|
+
|
|
3044
|
+
const testIndex = parseInt(testItem.getAttribute('data-test-index'));
|
|
3045
|
+
const test = allTests[testIndex];
|
|
3046
|
+
if (!test || !test.meta) return;
|
|
3047
|
+
|
|
3048
|
+
Object.entries(test.meta).forEach(([key, value]) => {
|
|
3049
|
+
const metaItem = document.createElement('div');
|
|
3050
|
+
metaItem.className = 'metadata-item meta-item';
|
|
3051
|
+
metaItem.setAttribute('data-meta-key', key);
|
|
3052
|
+
|
|
3053
|
+
const keyDiv = document.createElement('div');
|
|
3054
|
+
keyDiv.className = 'metadata-key';
|
|
3055
|
+
keyDiv.textContent = key;
|
|
3056
|
+
|
|
3057
|
+
const valueDiv = document.createElement('div');
|
|
3058
|
+
valueDiv.className = 'metadata-value';
|
|
3059
|
+
valueDiv.textContent = typeof value === 'object' ? JSON.stringify(value, null, 2) : value;
|
|
1038
3060
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
3061
|
+
metaItem.appendChild(keyDiv);
|
|
3062
|
+
metaItem.appendChild(valueDiv);
|
|
3063
|
+
grid.appendChild(metaItem);
|
|
3064
|
+
});
|
|
3065
|
+
});
|
|
3066
|
+
|
|
3067
|
+
setTimeout(applyMetaVisibility, 10);
|
|
3068
|
+
}
|
|
1042
3069
|
|
|
1043
|
-
|
|
1044
|
-
|
|
3070
|
+
function renderGroupedTests(container, groups) {
|
|
3071
|
+
if (groups.length === 0) {
|
|
3072
|
+
container.innerHTML = `
|
|
3073
|
+
<div class='empty-state'>
|
|
3074
|
+
<div class='empty-icon'>
|
|
3075
|
+
<i class='fas fa-search'></i>
|
|
3076
|
+
</div>
|
|
3077
|
+
<div class='empty-title'>No Tests Found</div>
|
|
3078
|
+
<div class='empty-description'>No tests match your current filter criteria.</div>
|
|
3079
|
+
</div>
|
|
3080
|
+
`;
|
|
3081
|
+
return;
|
|
1045
3082
|
}
|
|
1046
3083
|
|
|
1047
|
-
|
|
1048
|
-
|
|
3084
|
+
container.innerHTML = '';
|
|
3085
|
+
|
|
3086
|
+
const startIndex = (currentPage - 1) * pageSize;
|
|
3087
|
+
const endIndex = startIndex + pageSize;
|
|
3088
|
+
const paginatedGroups = groups.slice(startIndex, endIndex);
|
|
3089
|
+
|
|
3090
|
+
paginatedGroups.forEach(group => {
|
|
3091
|
+
const groupItem = createTestGroup(group);
|
|
3092
|
+
container.appendChild(groupItem);
|
|
3093
|
+
});
|
|
1049
3094
|
|
|
1050
|
-
|
|
3095
|
+
renderPagination(groups.length);
|
|
3096
|
+
setTimeout(populateMetadataFields, 50);
|
|
1051
3097
|
}
|
|
1052
3098
|
|
|
1053
|
-
function
|
|
1054
|
-
const
|
|
1055
|
-
|
|
3099
|
+
function createTestGroup(group) {
|
|
3100
|
+
const groupElement = document.createElement('div');
|
|
3101
|
+
groupElement.className = 'test-group';
|
|
1056
3102
|
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
3103
|
+
const passedCount = group.tests.filter(t => t.status.toLowerCase() === 'passed').length;
|
|
3104
|
+
const failedCount = group.tests.filter(t => t.status.toLowerCase() === 'failed').length;
|
|
3105
|
+
const skippedCount = group.tests.filter(t => t.status.toLowerCase() === 'skipped').length;
|
|
3106
|
+
const todoCount = group.tests.filter(t => t.status.toLowerCase() === 'todo').length;
|
|
3107
|
+
|
|
3108
|
+
const groupIcon = group.type === 'suite' ? 'layer-group' : 'file-code';
|
|
3109
|
+
|
|
3110
|
+
const header = document.createElement('div');
|
|
3111
|
+
header.className = 'test-group-header';
|
|
3112
|
+
header.innerHTML = `
|
|
3113
|
+
<div class='test-group-title'>
|
|
3114
|
+
<i class='fas fa-${groupIcon}'></i>
|
|
3115
|
+
<div class='test-group-name'>${group.name}</div>
|
|
3116
|
+
<div class='test-group-count'>${group.tests.length} tests</div>
|
|
3117
|
+
</div>
|
|
3118
|
+
<div class='test-group-stats'>
|
|
3119
|
+
${passedCount > 0 ? `<div class='test-group-stat' style='color: #10b981;'><i class='fas fa-check-circle'></i> ${passedCount}</div>` : ''}
|
|
3120
|
+
${failedCount > 0 ? `<div class='test-group-stat' style='color: #ef4444;'><i class='fas fa-times-circle'></i> ${failedCount}</div>` : ''}
|
|
3121
|
+
${skippedCount > 0 ? `<div class='test-group-stat' style='color: #f59e0b;'><i class='fas fa-forward'></i> ${skippedCount}</div>` : ''}
|
|
3122
|
+
${todoCount > 0 ? `<div class='test-group-stat' style='color: #8b5cf6;'><i class='fas fa-clock'></i> ${todoCount}</div>` : ''}
|
|
3123
|
+
</div>
|
|
3124
|
+
<i class='fas fa-chevron-down test-group-expand'></i>
|
|
3125
|
+
`;
|
|
3126
|
+
header.onclick = () => toggleTestGroup(header);
|
|
3127
|
+
groupElement.appendChild(header);
|
|
3128
|
+
|
|
3129
|
+
const content = document.createElement('div');
|
|
3130
|
+
content.className = 'test-group-content';
|
|
3131
|
+
|
|
3132
|
+
group.tests.forEach((test, index) => {
|
|
3133
|
+
const testItem = createTestItem(test, index);
|
|
3134
|
+
content.appendChild(testItem);
|
|
3135
|
+
});
|
|
3136
|
+
|
|
3137
|
+
groupElement.appendChild(content);
|
|
3138
|
+
|
|
3139
|
+
return groupElement;
|
|
1061
3140
|
}
|
|
1062
3141
|
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
3142
|
+
function toggleTestGroup(header) {
|
|
3143
|
+
const group = header.parentElement;
|
|
3144
|
+
group.classList.toggle('expanded');
|
|
3145
|
+
}
|
|
1066
3146
|
|
|
1067
|
-
|
|
1068
|
-
const
|
|
1069
|
-
const
|
|
3147
|
+
function renderPagination(totalItems) {
|
|
3148
|
+
const container = document.getElementById('paginationContainer');
|
|
3149
|
+
const totalPages = Math.ceil(totalItems / pageSize);
|
|
1070
3150
|
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
function search(array, testEntries) {
|
|
1076
|
-
const handleSearch = (input) => {
|
|
1077
|
-
const value = input.value.trim().toLowerCase();
|
|
1078
|
-
const select = document.querySelector('.form-select');
|
|
1079
|
-
const pagination = document.querySelectorAll('nav');
|
|
3151
|
+
if (totalPages <= 1) {
|
|
3152
|
+
container.innerHTML = '';
|
|
3153
|
+
return;
|
|
3154
|
+
}
|
|
1080
3155
|
|
|
1081
|
-
|
|
1082
|
-
select.classList.add('d-none');
|
|
1083
|
-
pagination.forEach(item => item.classList.add('d-none'));
|
|
1084
|
-
}
|
|
1085
|
-
else {
|
|
1086
|
-
select.classList.remove('d-none');
|
|
1087
|
-
pagination.forEach(item => item.classList.remove('d-none'));
|
|
3156
|
+
let paginationHTML = '<div class=\"pagination\">';
|
|
1088
3157
|
|
|
1089
|
-
|
|
3158
|
+
paginationHTML += `
|
|
3159
|
+
<button class='pagination-btn' onclick='goToPage(${currentPage - 1})'
|
|
3160
|
+
${currentPage === 1 ? 'disabled' : ''}>
|
|
3161
|
+
<i class='fas fa-chevron-left'></i>
|
|
3162
|
+
</button>
|
|
3163
|
+
`;
|
|
1090
3164
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
if (testEntries[category][paginationCount][0]) {
|
|
1095
|
-
add(testEntries[category][paginationCount][0]);
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
3165
|
+
const maxVisiblePages = 5;
|
|
3166
|
+
let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2));
|
|
3167
|
+
let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);
|
|
1098
3168
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
const existingNoDataElement = document.querySelector('.noResults');
|
|
1104
|
-
|
|
1105
|
-
if (filteredTests.length === 0) {
|
|
1106
|
-
if (!existingNoDataElement) {
|
|
1107
|
-
const testElement = document.createElement('div');
|
|
1108
|
-
testElement.classList.add('noData', 'noResults');
|
|
1109
|
-
testElement.innerHTML =
|
|
1110
|
-
`<div class='noData'>
|
|
1111
|
-
<svg width="185" height="185" viewBox="0 0 370 370" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
1112
|
-
<g clip-path="url(#clip0_215_375)">
|
|
1113
|
-
<path opacity="0.1" d="M185 369.998C287.173 369.998 370.001 287.171 370.001 184.999C370.001 82.8268 287.173 0 185 0C82.8274 0 0 82.8268 0 184.999C0 287.171 82.8274 369.998 185 369.998Z" fill="#A9C7FF"/>
|
|
1114
|
-
<path d="M104.96 129.507C105.629 128.757 106.439 128.147 107.344 127.71C108.249 127.273 109.231 127.019 110.234 126.961C111.237 126.904 112.242 127.045 113.191 127.376C114.14 127.707 115.014 128.221 115.764 128.89L140.183 150.67L129.997 162.091L105.577 140.311C104.827 139.642 104.216 138.832 103.779 137.927C103.342 137.022 103.088 136.04 103.031 135.037C102.974 134.034 103.114 133.029 103.446 132.08C103.777 131.132 104.291 130.257 104.96 129.507Z" fill="white"/>
|
|
1115
|
-
<path d="M130.056 163.157L105.074 140.874C104.25 140.139 103.579 139.249 103.099 138.255C102.619 137.261 102.34 136.182 102.277 135.079C102.214 133.977 102.368 132.873 102.732 131.831C103.096 130.788 103.661 129.828 104.396 129.004C105.131 128.18 106.021 127.508 107.015 127.028C108.009 126.548 109.088 126.269 110.191 126.206C111.293 126.143 112.397 126.298 113.439 126.661C114.482 127.025 115.443 127.59 116.267 128.325L141.251 150.608L130.056 163.157ZM110.677 127.703C110.544 127.703 110.409 127.707 110.275 127.714C108.913 127.792 107.605 128.273 106.516 129.094C105.427 129.916 104.607 131.042 104.158 132.329C103.709 133.617 103.652 135.01 103.994 136.33C104.336 137.65 105.062 138.84 106.08 139.747L129.936 161.024L139.117 150.731L115.261 129.454C114.002 128.325 112.371 127.701 110.68 127.703H110.677Z" fill="#474646"/>
|
|
1116
|
-
<path d="M240 162.09L229.814 150.669L254.234 128.89C255.748 127.539 257.737 126.845 259.763 126.961C261.789 127.076 263.686 127.992 265.037 129.507C266.388 131.021 267.082 133.01 266.966 135.036C266.85 137.062 265.935 138.96 264.42 140.31L240 162.09Z" fill="white"/>
|
|
1117
|
-
<path d="M239.942 163.157L228.749 150.608L253.733 128.325C255.397 126.841 257.583 126.079 259.809 126.206C262.035 126.333 264.12 127.34 265.604 129.004C267.088 130.668 267.851 132.853 267.723 135.079C267.596 137.306 266.59 139.39 264.926 140.874L239.942 163.157ZM230.883 150.73L240.064 161.023L263.92 139.747C264.596 139.144 265.146 138.414 265.54 137.599C265.934 136.783 266.163 135.898 266.214 134.994C266.266 134.09 266.139 133.185 265.841 132.329C265.543 131.474 265.079 130.686 264.476 130.011C263.873 129.335 263.143 128.784 262.328 128.391C261.512 127.997 260.627 127.768 259.723 127.716C258.819 127.664 257.913 127.791 257.058 128.09C256.203 128.388 255.415 128.852 254.739 129.454L230.883 150.73Z" fill="#474646"/>
|
|
1118
|
-
<path d="M250.171 176.257C255.618 200.379 263.075 215.898 259.362 224.811C257.41 229.495 253.403 233.424 246.771 233.424C236.433 233.424 236.433 221.232 226.095 221.232C215.756 221.232 215.758 233.424 205.42 233.424C195.083 233.424 195.084 221.232 184.748 221.232C174.411 221.232 174.411 233.424 164.074 233.424C153.737 233.424 153.738 221.232 143.401 221.232C133.065 221.232 133.066 233.424 122.731 233.424C116.595 233.424 113.126 229.81 110.926 225.633C105.639 215.6 117.96 193.521 122.731 174.051C128.002 152.536 127.558 125.739 128.265 109.576C129.629 78.4083 153.554 53.0876 184.755 53.0876C215.955 53.0876 238.971 78.4613 241.244 109.576C242.469 126.351 245.184 154.176 250.171 176.257Z" fill="white"/>
|
|
1119
|
-
<path d="M246.771 234.186C241.249 234.186 238.506 230.95 235.852 227.818C233.311 224.822 230.911 221.992 226.095 221.992C221.278 221.992 218.882 224.822 216.339 227.818C213.685 230.948 210.942 234.186 205.42 234.186C199.899 234.186 197.156 230.95 194.503 227.818C191.962 224.822 189.562 221.992 184.748 221.992C179.933 221.992 177.535 224.822 174.992 227.818C172.339 230.948 169.596 234.186 164.074 234.186C158.552 234.186 155.808 230.95 153.16 227.822C150.619 224.825 148.219 221.995 143.404 221.995C138.589 221.995 136.191 224.825 133.65 227.822C130.998 230.951 128.255 234.189 122.734 234.189C117.243 234.189 113.161 231.508 110.254 225.992C106.568 218.996 110.995 206.627 115.683 193.534C118.011 187.03 120.416 180.305 121.994 173.874C126.21 156.668 126.743 136.45 127.172 120.204C127.272 116.362 127.368 112.732 127.51 109.548C128.186 94.1198 134.32 79.7607 144.785 69.1146C149.986 63.7845 156.204 59.5527 163.071 56.6697C169.937 53.7867 177.313 52.3113 184.76 52.3308C192.159 52.3133 199.486 53.7933 206.298 56.6817C213.11 59.5701 219.267 63.8071 224.399 69.1377C234.622 79.6633 240.876 94.0076 242.01 109.526C243.102 124.489 245.712 153.033 250.92 176.094C252.686 183.916 254.663 190.825 256.407 196.921C260.048 209.651 262.679 218.848 260.069 225.109C258.652 228.498 255.046 234.186 246.771 234.186ZM226.095 220.47C231.617 220.47 234.361 223.705 237.014 226.837C239.556 229.834 241.956 232.664 246.771 232.664C254.162 232.664 257.391 227.561 258.658 224.519C261.062 218.751 258.489 209.769 254.935 197.338C253.188 191.222 251.203 184.292 249.428 176.428C244.198 153.268 241.58 124.639 240.484 109.635C238.161 77.833 214.203 53.8517 184.754 53.8517C154.874 53.8517 130.395 78.3441 129.024 109.612C128.885 112.782 128.789 116.406 128.686 120.241C128.278 135.699 127.72 156.869 123.465 174.234C121.871 180.742 119.45 187.505 117.109 194.046C112.538 206.815 108.22 218.877 111.594 225.28C114.212 230.248 117.853 232.662 122.725 232.662C127.54 232.662 129.938 229.832 132.48 226.836C135.132 223.706 137.875 220.468 143.396 220.468C148.916 220.468 151.661 223.704 154.313 226.836C156.854 229.832 159.253 232.662 164.068 232.662C168.884 232.662 171.284 229.832 173.824 226.836C176.478 223.706 179.221 220.468 184.742 220.468C190.263 220.468 193.007 223.704 195.659 226.836C198.2 229.832 200.599 232.662 205.415 232.662C210.23 232.662 212.63 229.832 215.171 226.836C217.83 223.708 220.573 220.47 226.095 220.47Z" fill="#474646"/>
|
|
1120
|
-
<path d="M163.527 113.221C166.986 113.221 169.789 110.418 169.789 106.96C169.789 103.501 166.986 100.698 163.527 100.698C160.069 100.698 157.266 103.501 157.266 106.96C157.266 110.418 160.069 113.221 163.527 113.221Z" fill="#474646"/>
|
|
1121
|
-
<path d="M206.465 113.221C209.923 113.221 212.726 110.418 212.726 106.96C212.726 103.501 209.923 100.698 206.465 100.698C203.006 100.698 200.203 103.501 200.203 106.96C200.203 110.418 203.006 113.221 206.465 113.221Z" fill="#474646"/>
|
|
1122
|
-
<path d="M196.211 123.859C196.573 123.859 196.93 123.938 197.256 124.093C197.583 124.247 197.871 124.473 198.1 124.752C198.329 125.032 198.492 125.36 198.578 125.71C198.665 126.061 198.672 126.427 198.599 126.781C197.256 133.059 191.677 137.005 184.998 137.005C178.319 137.005 172.74 133.061 171.397 126.781C171.324 126.427 171.331 126.061 171.418 125.71C171.504 125.359 171.668 125.032 171.896 124.752C172.125 124.472 172.413 124.247 172.74 124.093C173.067 123.938 173.424 123.858 173.785 123.859H196.211Z" fill="white"/>
|
|
1123
|
-
<path d="M184.997 137.767C177.802 137.767 172.037 133.416 170.652 126.94C170.553 126.479 170.559 126.002 170.67 125.543C170.78 125.085 170.992 124.657 171.29 124.292C171.59 123.919 171.97 123.618 172.402 123.412C172.834 123.206 173.306 123.099 173.785 123.1H196.212C196.691 123.099 197.164 123.206 197.595 123.412C198.027 123.618 198.407 123.919 198.707 124.292C199.005 124.657 199.217 125.085 199.327 125.543C199.438 126.002 199.444 126.479 199.345 126.94C197.958 133.416 192.192 137.767 184.997 137.767ZM173.784 124.621C173.532 124.621 173.284 124.677 173.057 124.786C172.83 124.894 172.631 125.052 172.473 125.248C172.318 125.437 172.208 125.659 172.151 125.897C172.093 126.135 172.09 126.382 172.141 126.622C173.371 132.377 178.537 136.243 184.996 136.243C191.455 136.243 196.621 132.377 197.852 126.622C197.903 126.382 197.899 126.135 197.842 125.897C197.784 125.659 197.674 125.437 197.519 125.248C197.361 125.052 197.162 124.894 196.935 124.786C196.708 124.677 196.46 124.621 196.209 124.621H173.784Z" fill="#474646"/>
|
|
1124
|
-
<path d="M332.184 297.095C298.385 341.408 245.033 370 185.003 370C124.973 370 71.6211 341.408 37.8223 297.095C76.4052 282.579 128.135 273.704 185.003 273.704C241.872 273.704 293.598 282.579 332.184 297.095Z" fill="#A9C7FF"/>
|
|
1125
|
-
<path d="M347.711 96.8905L252.766 96.4848C252.766 80.628 261.697 77.5062 271.192 74.931C280.687 72.3558 284.959 54.9269 301.458 53.9351C311.202 53.3491 316.312 55.8566 320.544 59.0855C320.549 59.0911 320.549 59.0967 320.555 59.0967C331.158 70.5047 340.281 83.2025 347.711 96.8905Z" fill="white"/>
|
|
1126
|
-
<path d="M76.8801 214.712L2.43035 215.033C1.15867 207.26 0.386967 199.413 0.119995 191.541C16.4277 189.231 14.7598 176.27 34.2344 177.448C48.6825 178.316 52.4355 193.581 60.7471 195.835C69.0587 198.089 76.8801 200.83 76.8801 214.712Z" fill="white"/>
|
|
1127
|
-
</g>
|
|
1128
|
-
<defs>
|
|
1129
|
-
<clipPath id="clip0_215_375">
|
|
1130
|
-
<rect width="370" height="370" fill="white"/>
|
|
1131
|
-
</clipPath>
|
|
1132
|
-
</defs>
|
|
1133
|
-
</svg>
|
|
1134
|
-
|
|
1135
|
-
<div class='noDataText'>NO SEARCH RESULTS</div>
|
|
1136
|
-
</div>`;
|
|
1137
|
-
document.querySelector('.testWrapp').appendChild(testElement);
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
else {
|
|
1141
|
-
const paginationCount = select.value;
|
|
1142
|
-
const category = select.getAttribute('status');
|
|
1143
|
-
|
|
1144
|
-
if (existingNoDataElement) {
|
|
1145
|
-
existingNoDataElement.remove();
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
if (testEntries[category][paginationCount][0]) {
|
|
1149
|
-
add(filteredTests);
|
|
1150
|
-
if (!value) {
|
|
1151
|
-
remove(filteredTests);
|
|
1152
|
-
add(testEntries[category][paginationCount][0]);
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
else {
|
|
1156
|
-
if (value) {
|
|
1157
|
-
add(filteredTests);
|
|
1158
|
-
}
|
|
1159
|
-
else {
|
|
1160
|
-
if (!existingNoDataElement) {
|
|
1161
|
-
const testElement = document.createElement('div');
|
|
1162
|
-
|
|
1163
|
-
select.classList.add('d-none');
|
|
1164
|
-
testElement.classList.add('noData', 'noResults');
|
|
1165
|
-
testElement.innerHTML = 'NO RESULTS';
|
|
1166
|
-
document.querySelector('.testWrapp').appendChild(testElement);
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
};
|
|
3169
|
+
if (endPage - startPage < maxVisiblePages - 1) {
|
|
3170
|
+
startPage = Math.max(1, endPage - maxVisiblePages + 1);
|
|
3171
|
+
}
|
|
1172
3172
|
|
|
1173
|
-
|
|
1174
|
-
|
|
3173
|
+
for (let i = startPage; i <= endPage; i++) {
|
|
3174
|
+
paginationHTML += `
|
|
3175
|
+
<button class='pagination-btn ${i === currentPage ? 'active' : ''}'
|
|
3176
|
+
onclick='goToPage(${i})'>${i}</button>
|
|
3177
|
+
`;
|
|
1175
3178
|
}
|
|
1176
3179
|
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
3180
|
+
paginationHTML += `
|
|
3181
|
+
<button class='pagination-btn' onclick='goToPage(${currentPage + 1})'
|
|
3182
|
+
${currentPage === totalPages ? 'disabled' : ''}>
|
|
3183
|
+
<i class='fas fa-chevron-right'></i>
|
|
3184
|
+
</button>
|
|
3185
|
+
`;
|
|
1182
3186
|
|
|
1183
|
-
|
|
3187
|
+
paginationHTML += '</div>';
|
|
3188
|
+
container.innerHTML = paginationHTML;
|
|
3189
|
+
}
|
|
1184
3190
|
|
|
1185
|
-
|
|
1186
|
-
|
|
3191
|
+
function goToPage(page) {
|
|
3192
|
+
const filteredTests = filterTests();
|
|
3193
|
+
const totalPages = Math.ceil(filteredTests.length / pageSize);
|
|
1187
3194
|
|
|
1188
|
-
|
|
1189
|
-
pagination.forEach(item => item.classList.add('d-none'));
|
|
3195
|
+
if (page < 1 || page > totalPages) return;
|
|
1190
3196
|
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
pagination.forEach(item => item.classList.remove('d-none'));
|
|
3197
|
+
currentPage = page;
|
|
3198
|
+
renderTests();
|
|
3199
|
+
}
|
|
1195
3200
|
|
|
1196
|
-
|
|
3201
|
+
function updateCounts() {
|
|
3202
|
+
const by = (s) => allTests.filter(t => String(t.status || '').toLowerCase() === s).length;
|
|
1197
3203
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
3204
|
+
const counts = {
|
|
3205
|
+
all: allTests.length,
|
|
3206
|
+
passed: by('passed'),
|
|
3207
|
+
failed: by('failed'),
|
|
3208
|
+
skipped: by('skipped'),
|
|
3209
|
+
todo: by('todo'),
|
|
3210
|
+
};
|
|
1201
3211
|
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
3212
|
+
document.getElementById('countAll').textContent = counts.all;
|
|
3213
|
+
document.getElementById('countPassed').textContent = counts.passed;
|
|
3214
|
+
document.getElementById('countFailed').textContent = counts.failed;
|
|
3215
|
+
document.getElementById('countSkipped').textContent = counts.skipped;
|
|
1205
3216
|
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
if (existingNoDataElement) {
|
|
1214
|
-
existingNoDataElement.remove();
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
const testElement = document.createElement('div');
|
|
1218
|
-
testElement.classList.add('noData');
|
|
1219
|
-
testElement.classList.add('noResults');
|
|
1220
|
-
testElement.innerHTML = 'NO RESULTS';
|
|
1221
|
-
searchEl.classList.add('d-none');
|
|
1222
|
-
|
|
1223
|
-
const testWrapp = document.querySelector('.testWrapp');
|
|
1224
|
-
testWrapp.appendChild(testElement);
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
3217
|
+
const todoEl = document.getElementById('countTodo');
|
|
3218
|
+
if (todoEl) todoEl.textContent = counts.todo;
|
|
3219
|
+
|
|
3220
|
+
const todoTab = document.querySelector('.filter-tab[data-filter="todo"]');
|
|
3221
|
+
if (todoTab) todoTab.style.display = counts.todo > 0 ? '' : 'none';
|
|
3222
|
+
}
|
|
1227
3223
|
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
3224
|
+
function updateTitleColor() {
|
|
3225
|
+
const by = (s) => allTests.filter(t => String(t.status || '').toLowerCase() === s).length;
|
|
3226
|
+
const failed = by('failed');
|
|
3227
|
+
const passed = by('passed');
|
|
3228
|
+
const skipped = by('skipped');
|
|
3229
|
+
const todo = by('todo');
|
|
1231
3230
|
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
3231
|
+
const mainTitle = document.getElementById('mainTitle');
|
|
3232
|
+
if (!mainTitle) return;
|
|
3233
|
+
|
|
3234
|
+
mainTitle.classList.remove('status-passed', 'status-failed', 'status-skipped', 'status-todo');
|
|
3235
|
+
|
|
3236
|
+
if (failed > 0) {
|
|
3237
|
+
mainTitle.classList.add('status-failed');
|
|
3238
|
+
} else if (passed > 0) {
|
|
3239
|
+
mainTitle.classList.add('status-passed');
|
|
3240
|
+
} else if (skipped > 0) {
|
|
3241
|
+
mainTitle.classList.add('status-skipped');
|
|
3242
|
+
} else if (todo > 0) {
|
|
3243
|
+
mainTitle.classList.add('status-todo');
|
|
1237
3244
|
}
|
|
3245
|
+
}
|
|
1238
3246
|
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
switch (attribute) {
|
|
1250
|
-
case 'all':
|
|
1251
|
-
radio.innerHTML = allEntries.length;
|
|
1252
|
-
break;
|
|
1253
|
-
case 'passed':
|
|
1254
|
-
const passedCount = allEntries.filter(test => test.status === 'passed').length;
|
|
1255
|
-
radio.innerHTML = passedCount;
|
|
1256
|
-
break;
|
|
1257
|
-
case 'failed':
|
|
1258
|
-
const failedCount = allEntries.filter(test => test.status === 'failed').length;
|
|
1259
|
-
radio.innerHTML = failedCount;
|
|
1260
|
-
break;
|
|
1261
|
-
case 'skipped':
|
|
1262
|
-
const skippedCount = allEntries.filter(test => test.status === 'skipped').length;
|
|
1263
|
-
radio.innerHTML = skippedCount;
|
|
1264
|
-
break;
|
|
1265
|
-
default: // no default action for now
|
|
1266
|
-
}
|
|
3247
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
3248
|
+
const filterTabs = document.querySelectorAll('.filter-tab');
|
|
3249
|
+
filterTabs.forEach(tab => {
|
|
3250
|
+
tab.addEventListener('click', function() {
|
|
3251
|
+
filterTabs.forEach(t => t.classList.remove('active'));
|
|
3252
|
+
this.classList.add('active');
|
|
3253
|
+
|
|
3254
|
+
currentFilter = this.dataset.filter;
|
|
3255
|
+
currentPage = 1;
|
|
3256
|
+
renderTests();
|
|
1267
3257
|
});
|
|
1268
|
-
}
|
|
3258
|
+
});
|
|
3259
|
+
|
|
3260
|
+
|
|
3261
|
+
const searchInput = document.getElementById('searchInput');
|
|
3262
|
+
searchInput.addEventListener('input', function() {
|
|
3263
|
+
searchTerm = this.value.trim();
|
|
3264
|
+
currentPage = 1;
|
|
3265
|
+
renderTests();
|
|
3266
|
+
});
|
|
1269
3267
|
|
|
1270
|
-
|
|
3268
|
+
const pageSizeSelect = document.getElementById('pageSizeSelect');
|
|
3269
|
+
pageSizeSelect.addEventListener('change', function() {
|
|
3270
|
+
pageSize = parseInt(this.value);
|
|
3271
|
+
currentPage = 1;
|
|
3272
|
+
renderTests();
|
|
3273
|
+
});
|
|
1271
3274
|
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
3275
|
+
const groupingSelect = document.getElementById('groupingSelect');
|
|
3276
|
+
groupingSelect.addEventListener('change', function() {
|
|
3277
|
+
groupingMode = this.value;
|
|
3278
|
+
currentPage = 1;
|
|
3279
|
+
renderTests();
|
|
3280
|
+
});
|
|
1276
3281
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
3282
|
+
const badge = document.querySelector('.status-badge');
|
|
3283
|
+
if (badge) {
|
|
3284
|
+
const s = badge.textContent.trim().toLowerCase();
|
|
3285
|
+
badge.classList.add(`status-${s}`);
|
|
1280
3286
|
}
|
|
1281
3287
|
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
3288
|
+
updateCounts();
|
|
3289
|
+
updateTitleColor();
|
|
3290
|
+
renderTests();
|
|
3291
|
+
});
|
|
3292
|
+
|
|
3293
|
+
window.addEventListener('resize', function() {
|
|
3294
|
+
if (document.getElementById('testChart')) {
|
|
3295
|
+
drawTestChart();
|
|
1287
3296
|
}
|
|
3297
|
+
});
|
|
3298
|
+
|
|
3299
|
+
function formatFileSize(bytes) {
|
|
3300
|
+
if (!bytes) return '';
|
|
3301
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
3302
|
+
if (bytes === 0) return '0 Bytes';
|
|
3303
|
+
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
3304
|
+
return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
|
|
3305
|
+
}
|
|
3306
|
+
|
|
3307
|
+
|
|
3308
|
+
let visibleMetaKeys = new Set();
|
|
3309
|
+
const SETTINGS_STORAGE_KEY = 'testomatio_report_settings';
|
|
3310
|
+
|
|
3311
|
+
function collectAllMetaKeys() {
|
|
3312
|
+
const metaKeys = new Map();
|
|
1288
3313
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
3314
|
+
allTests.forEach(test => {
|
|
3315
|
+
if (test.meta && typeof test.meta === 'object') {
|
|
3316
|
+
Object.keys(test.meta).forEach(key => {
|
|
3317
|
+
metaKeys.set(key, (metaKeys.get(key) || 0) + 1);
|
|
3318
|
+
});
|
|
1293
3319
|
}
|
|
3320
|
+
});
|
|
3321
|
+
|
|
3322
|
+
return metaKeys;
|
|
3323
|
+
}
|
|
3324
|
+
|
|
3325
|
+
function openSettings() {
|
|
3326
|
+
const modal = document.getElementById('settingsModal');
|
|
3327
|
+
modal.classList.add('active');
|
|
3328
|
+
|
|
3329
|
+
const savedSettings = localStorage.getItem(SETTINGS_STORAGE_KEY);
|
|
3330
|
+
if (savedSettings) {
|
|
3331
|
+
visibleMetaKeys = new Set(JSON.parse(savedSettings));
|
|
3332
|
+
} else {
|
|
3333
|
+
const metaKeys = collectAllMetaKeys();
|
|
3334
|
+
visibleMetaKeys = new Set(metaKeys.keys());
|
|
1294
3335
|
}
|
|
1295
3336
|
|
|
1296
|
-
|
|
3337
|
+
renderSettingsMetaList();
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
function closeSettings() {
|
|
3341
|
+
const modal = document.getElementById('settingsModal');
|
|
3342
|
+
modal.classList.remove('active');
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
function switchSettingsTab(event) {
|
|
3346
|
+
const clickedTab = event.currentTarget;
|
|
3347
|
+
const targetTab = clickedTab.getAttribute('data-tab');
|
|
1297
3348
|
|
|
1298
|
-
const
|
|
3349
|
+
const allTabs = document.querySelectorAll('.settings-tab');
|
|
3350
|
+
allTabs.forEach(tab => tab.classList.remove('active'));
|
|
1299
3351
|
|
|
1300
|
-
|
|
3352
|
+
const allContents = document.querySelectorAll('.settings-tab-content');
|
|
3353
|
+
allContents.forEach(content => content.classList.remove('active'));
|
|
1301
3354
|
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
3355
|
+
clickedTab.classList.add('active');
|
|
3356
|
+
|
|
3357
|
+
const targetContent = document.querySelector(`.settings-tab-content[data-tab="${targetTab}"]`);
|
|
3358
|
+
if (targetContent) {
|
|
3359
|
+
targetContent.classList.add('active');
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
1305
3362
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
3363
|
+
function resetToDefaults() {
|
|
3364
|
+
const metaKeys = collectAllMetaKeys();
|
|
3365
|
+
visibleMetaKeys = new Set(metaKeys.keys());
|
|
1309
3366
|
|
|
1310
|
-
|
|
3367
|
+
const checkboxes = document.querySelectorAll('#metaFieldsList input[type="checkbox"]');
|
|
3368
|
+
checkboxes.forEach(cb => {
|
|
3369
|
+
cb.checked = true;
|
|
1311
3370
|
});
|
|
1312
3371
|
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
const endEllipsis = document.createElement('li');
|
|
1372
|
-
|
|
1373
|
-
endEllipsis.classList.add('page-item');
|
|
1374
|
-
endEllipsis.innerHTML = '<a class="page-link" href="#pagination">...</a>';
|
|
1375
|
-
endEllipsis.addEventListener('click', () => {
|
|
1376
|
-
remove(testEntries[category][index][currentPage - 1]);
|
|
1377
|
-
currentPage = totalPages;
|
|
1378
|
-
add(testEntries[category][index][currentPage - 1]);
|
|
1379
|
-
createPagination();
|
|
1380
|
-
});
|
|
1381
|
-
|
|
1382
|
-
paginationContainer.appendChild(endEllipsis);
|
|
1383
|
-
}
|
|
1384
|
-
|
|
1385
|
-
if (currentPage > 1) {
|
|
1386
|
-
const prevButton = document.createElement('li');
|
|
1387
|
-
|
|
1388
|
-
prevButton.classList.add('page-item');
|
|
1389
|
-
prevButton.innerHTML = '<a class="page-link" href="#pagination">Previous</a>';
|
|
1390
|
-
prevButton.addEventListener('click', () => {
|
|
1391
|
-
remove(testEntries[category][index][currentPage - 1]);
|
|
1392
|
-
currentPage--;
|
|
1393
|
-
add(testEntries[category][index][currentPage - 1]);
|
|
1394
|
-
createPagination();
|
|
1395
|
-
});
|
|
1396
|
-
|
|
1397
|
-
paginationContainer.insertBefore(prevButton, paginationContainer.firstChild);
|
|
1398
|
-
}
|
|
1399
|
-
if (currentPage < totalPages) {
|
|
1400
|
-
const nextButton = document.createElement('li');
|
|
1401
|
-
|
|
1402
|
-
nextButton.classList.add('page-item');
|
|
1403
|
-
nextButton.innerHTML = '<a class="page-link" href="#pagination">Next</a>';
|
|
1404
|
-
nextButton.addEventListener('click', () => {
|
|
1405
|
-
remove(testEntries[category][index][currentPage - 1]);
|
|
1406
|
-
currentPage++;
|
|
1407
|
-
add(testEntries[category][index][currentPage - 1]);
|
|
1408
|
-
createPagination();
|
|
1409
|
-
});
|
|
1410
|
-
|
|
1411
|
-
paginationContainer.appendChild(nextButton);
|
|
1412
|
-
}
|
|
1413
|
-
});
|
|
3372
|
+
console.log('[Settings] Reset to defaults - all meta fields visible');
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3375
|
+
function renderSettingsMetaList() {
|
|
3376
|
+
const container = document.getElementById('metaFieldsList');
|
|
3377
|
+
const metaKeys = collectAllMetaKeys();
|
|
3378
|
+
|
|
3379
|
+
if (metaKeys.size === 0) {
|
|
3380
|
+
container.innerHTML = `
|
|
3381
|
+
<div style='grid-column: 1/-1; text-align: center; color: var(--gray-500); padding: 40px;'>
|
|
3382
|
+
<i class='fas fa-tag' style='font-size: 48px; margin-bottom: 15px; opacity: 0.3;'></i>
|
|
3383
|
+
<p style='margin: 0;'>No metadata fields found in tests</p>
|
|
3384
|
+
</div>
|
|
3385
|
+
`;
|
|
3386
|
+
return;
|
|
3387
|
+
}
|
|
3388
|
+
|
|
3389
|
+
const sortedKeys = Array.from(metaKeys.entries()).sort((a, b) => b[1] - a[1]);
|
|
3390
|
+
|
|
3391
|
+
container.innerHTML = sortedKeys.map(([key, count]) => `
|
|
3392
|
+
<label class='settings-meta-item'>
|
|
3393
|
+
<input
|
|
3394
|
+
type='checkbox'
|
|
3395
|
+
value='${key}'
|
|
3396
|
+
${visibleMetaKeys.has(key) ? 'checked' : ''}
|
|
3397
|
+
onchange='toggleMetaKey("${key}")'
|
|
3398
|
+
>
|
|
3399
|
+
<span class='settings-meta-label'>${key}</span>
|
|
3400
|
+
<span class='settings-meta-count'>${count}</span>
|
|
3401
|
+
</label>
|
|
3402
|
+
`).join('');
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3405
|
+
function toggleMetaKey(key) {
|
|
3406
|
+
if (visibleMetaKeys.has(key)) {
|
|
3407
|
+
visibleMetaKeys.delete(key);
|
|
3408
|
+
} else {
|
|
3409
|
+
visibleMetaKeys.add(key);
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3412
|
+
|
|
3413
|
+
function saveSettings() {
|
|
3414
|
+
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(Array.from(visibleMetaKeys)));
|
|
3415
|
+
|
|
3416
|
+
applyMetaVisibility();
|
|
3417
|
+
|
|
3418
|
+
closeSettings();
|
|
3419
|
+
}
|
|
3420
|
+
|
|
3421
|
+
function applyMetaVisibility() {
|
|
3422
|
+
const allMetaItems = document.querySelectorAll('.meta-item[data-meta-key]');
|
|
3423
|
+
|
|
3424
|
+
allMetaItems.forEach(item => {
|
|
3425
|
+
const key = item.getAttribute('data-meta-key');
|
|
3426
|
+
if (visibleMetaKeys.has(key)) {
|
|
3427
|
+
item.classList.remove('hidden');
|
|
3428
|
+
} else {
|
|
3429
|
+
item.classList.add('hidden');
|
|
1414
3430
|
}
|
|
1415
|
-
|
|
3431
|
+
});
|
|
3432
|
+
}
|
|
3433
|
+
|
|
3434
|
+
function initializeSettings() {
|
|
3435
|
+
const savedSettings = localStorage.getItem(SETTINGS_STORAGE_KEY);
|
|
3436
|
+
|
|
3437
|
+
if (savedSettings) {
|
|
3438
|
+
try {
|
|
3439
|
+
const parsed = JSON.parse(savedSettings);
|
|
3440
|
+
visibleMetaKeys = new Set(parsed);
|
|
3441
|
+
} catch (e) {
|
|
3442
|
+
console.error('[Settings] Failed to parse saved settings, using defaults', e);
|
|
3443
|
+
const metaKeys = collectAllMetaKeys();
|
|
3444
|
+
visibleMetaKeys = new Set(metaKeys.keys());
|
|
3445
|
+
}
|
|
3446
|
+
} else {
|
|
3447
|
+
const metaKeys = collectAllMetaKeys();
|
|
3448
|
+
visibleMetaKeys = new Set(metaKeys.keys());
|
|
1416
3449
|
}
|
|
1417
|
-
|
|
3450
|
+
|
|
1418
3451
|
}
|
|
3452
|
+
|
|
3453
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
3454
|
+
initializeSettings();
|
|
3455
|
+
});
|
|
3456
|
+
|
|
3457
|
+
const originalRenderTests = renderTests;
|
|
3458
|
+
renderTests = function() {
|
|
3459
|
+
originalRenderTests();
|
|
3460
|
+
setTimeout(applyMetaVisibility, 50);
|
|
3461
|
+
};
|
|
1419
3462
|
</script>
|
|
1420
3463
|
</body>
|
|
1421
3464
|
</html>
|