@magnit-ce/code-tests 0.0.13 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,217 +1,137 @@
1
- // src/code-tests.css?raw
2
- var code_tests_default = `:host
1
+ const style = `:host
3
2
  {
4
- /*** gray ***/
5
- --uchu-light-gray-raw: 95.57% 0.003 286.35;
6
- --uchu-light-gray: oklch(var(--uchu-light-gray-raw));
3
+ --gap: 7px;
4
+ --gap-small: 3px;
5
+ --gap-medium: 14px;
6
+ --gap-large: 24px;
7
+
8
+ --surface-success: oklch(93.96% 0.05 148.74);
9
+ --primary-success: oklch(58.83% 0.158 145.05);
10
+ --border-success: solid 1px var(--primary-success);
7
11
 
8
- --uchu-gray-raw: 84.68% 0.002 197.12;
9
- --uchu-gray: oklch(var(--uchu-gray-raw));
12
+ --surface-fail: oklch(88.98% 0.052 3.28);
13
+ --primary-fail: oklch(45.8% 0.177 17.7);
14
+ --border-fail: solid 1px var(--primary-fail);
10
15
 
11
- --uchu-dark-gray-raw: 63.12% 0.004 219.55;
12
- --uchu-dark-gray: oklch(var(--uchu-dark-gray-raw));
16
+ --surface-process: oklch(89.66% 0.046 260.67);
17
+ --primary-process: oklch(43.48% 0.17 260.2);
18
+ --border-process: solid 1px var(--primary-process);
13
19
 
14
- /*** red ***/
15
- --uchu-light-red-raw: 88.98% 0.052 3.28;
16
- --uchu-light-red: oklch(var(--uchu-light-red-raw));
17
20
 
18
- --uchu-dark-red-raw: 45.8% 0.177 17.7;
19
- --uchu-dark-red: oklch(var(--uchu-dark-red-raw));
20
21
 
21
- /*** purple ***/
22
- --uchu-light-purple-raw: 89.1% 0.046 305.24;
23
- --uchu-light-purple: oklch(var(--uchu-light-purple-raw));
24
-
25
- --uchu-dark-purple-raw: 39.46% 0.164 298.29;
26
- --uchu-dark-purple: oklch(var(--uchu-dark-purple-raw));
27
-
28
- /*** blue ***/
29
- --uchu-light-blue-raw: 89.66% 0.046 260.67;
30
- --uchu-light-blue: oklch(var(--uchu-light-blue-raw));
31
-
32
- --uchu-blue-raw: 62.39% 0.181 258.33;
33
- --uchu-blue: oklch(var(--uchu-blue-raw));
34
-
35
- --uchu-dark-blue-raw: 43.48% 0.17 260.2;
36
- --uchu-dark-blue: oklch(var(--uchu-dark-blue-raw));
37
-
38
- /*** green ***/
39
- --uchu-light-green-raw: 93.96% 0.05 148.74;
40
- --uchu-light-green: oklch(var(--uchu-light-green-raw));
41
-
42
- --uchu-green-raw: 79.33% 0.179 145.62;
43
- --uchu-green: oklch(var(--uchu-green-raw));
44
-
45
- --uchu-dark-green-raw: 58.83% 0.158 145.05;
46
- --uchu-dark-green: oklch(var(--uchu-dark-green-raw));
47
-
48
- /*** general ***/
49
- --uchu-yang-raw: 99.4% 0 0;
50
- --uchu-yang: oklch(var(--uchu-yang-raw));
51
-
52
- --uchu-yin-raw: 14.38% 0.007 256.88;
53
- --uchu-yin: oklch(var(--uchu-yin-raw));
54
-
55
- /*** code-tests vars ***/
56
-
57
- --spacer: calc(1em - 7px);
58
- --small-spacer: calc(var(--spacer) / 2);
59
-
60
- --color-success: var(--uchu-green);
61
- --color-fail: var(--uchu-red);
62
- --color-process: var(--uchu-blue);
63
-
64
- --text-surface: var(--uchu-yin);
65
- --text-result: var(--uchu-yang); /* --uchu-yang: #fdfdfd; */
66
- --text-collapse-icon: var(--uchu-dark-gray); /* --uchu-dark-gray: #878a8b; */
67
- --text-hook-summary: var(--uchu-dark-purple);
68
- --text-success: var(--uchu-dark-green); /* --uchu-dark-green: #2e943a; */
69
- --text-fail: var(--uchu-dark-red); /* --uchu-dark-red: #a30d30; */
70
- --text-process: var(--uchu-dark-blue); /* --uchu-dark-blue: #0949ac; */
71
- --text-button: var(--uchu-yang); /* --uchu-dark-blue: #0949ac; */
72
- --text-placeholder: var(--uchu-dark-gray);
73
-
74
- --surface-0: var(--uchu-light-gray);
75
- --surface-test: var(--uchu-yang);
76
22
  --surface-test-summary: var(--uchu-gray);
77
23
  --surface-hook-summary: var(--uchu-light-purple);
78
- --surface-success: var(--uchu-light-green);
79
- --surface-fail: var(--uchu-light-red);
80
- --surface-process: var(--uchu-light-blue);
81
- --surface-button: var(--uchu-blue); /* --uchu-blue: #3984f2 */
82
- --surface-button-hover: var(--uchu-light-blue);
83
- --surface-button-active: var(--uchu-dark-blue);
84
- --surface-button-cancel: var(--uchu-dark-blue);
85
-
24
+ --surface-hook-any-summary: var(--uchu-light-blue);
25
+
86
26
  --border-test: solid 1px var(--uchu-dark-gray);
87
27
  --border-hook: solid 1px var(--uchu-dark-purple);
88
- --border-success: solid 1px var(--uchu-dark-green);
89
- --border-fail: solid 1px var(--uchu-dark-red);
90
- --border-process: solid 1px var(--uchu-dark-blue);
28
+ --border-hook-any: solid 1px var(--uchu-dark-blue);
91
29
  --border-button: solid 1px var(--uchu-blue);
92
-
30
+
93
31
  --success-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="%232e943a" d="M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z"/></svg>');
94
32
  --info-icon: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2022.812714%2022.814663%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20style%3D%22fill%3Atransparent%3Bstroke%3Atransparent%3Bstroke-width%3A0.999999%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dasharray%3Anone%3Bstroke-dashoffset%3A29.2913%3Bstroke-opacity%3A1%22%20d%3D%22M%2022.295505%2C11.407332%20A%2010.889144%2C10.889144%200%200%201%2011.406424%2C22.296479%2010.889144%2C10.889144%200%200%201%200.51720881%2C11.407332%2010.889144%2C10.889144%200%200%201%2011.406424%2C0.51818382%2010.889144%2C10.889144%200%200%201%2022.295505%2C11.407332%20Z%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22m%2013.945668%2C4.3053761%20c%200.150778%2C-0.96462%20-0.30687%2C-1.43709%20-1.36997%2C-1.43709%20-1.063%2C0%20-1.668452%2C0.47247%20-1.81923%2C1.43709%20-0.150779%2C0.96462%200.306971%2C1.43708%201.369971%2C1.43708%201.004%2C0%201.66845%2C-0.47246%201.819229%2C-1.43708%20z%20M%2011.693889%2C17.829726%2013.373994%2C7.0811161%20h%20-2.9333%20L%208.7605887%2C17.829726%20Z%22%20style%3D%22font-size%3A19.6861px%3Bfont-family%3APassageway%3B-inkscape-font-specification%3APassageway%3Bfill%3A%23a30d30%3Bstroke-width%3A2.5%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dashoffset%3A29.2913%22%20aria-label%3D%22i%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');
95
33
 
96
- --font-text: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
97
-
98
- /*** styles ***/
99
34
 
100
- color-scheme: light dark;
101
35
  display: grid;
102
- gap: var(--spacer);
103
- background-color: var(--surface-0);
104
- color: var(--text-surface);
105
- padding: var(--small-spacer);
106
- font-family: var(--font-text);
36
+ gap: var(--gap);
37
+ grid-auto-rows: max-content;
38
+ font-family: sans-serif;
39
+ font-size: 12px;
107
40
  }
108
41
 
109
42
  #header
110
43
  {
111
- display: grid;
112
- grid-template-columns: 1fr auto;
44
+ flex: 1;
45
+ display: flex;
113
46
  align-items: center;
114
- gap: var(--spacer);
115
- border-bottom: solid 2px;
116
- padding: var(--spacer);
117
- margin-bottom: var(--spacer);
118
- user-select: none;
47
+ gap: var(--gap);
48
+ padding: var(--gap-small) var(--gap);
119
49
  }
120
-
121
50
  #title
122
51
  {
123
- font-weight: bold;
124
- font-size: 16px;
125
- }
126
-
127
- .hook
128
- {
129
- display: none;
130
- }
131
- :host(.has-before-hook) #before-all-details
132
- ,:host(.has-after-hook) #after-all-details
133
- {
134
- display: initial;
135
- }
136
- :host(.has-required-before-hook) #required-before-any-details
137
- ,:host(.has-required-after-hook) #required-after-any-details
138
- {
139
- display: initial;
140
- }
141
-
142
- #required-before-any-summary
143
- ,#required-after-any-summary
144
- {
145
- background: var(--surface-process);
146
- color: var(--text-process);
147
- border: solid 1px var(--text-process);
148
- grid-template-columns: auto auto 1fr;
52
+ flex: 1;
149
53
  }
150
54
 
151
55
  #tests
56
+ ,#component-content
152
57
  {
153
- margin: 0;
154
- padding: 0;
155
- list-style: none;
156
58
  display: grid;
59
+ gap: var(--gap);
157
60
  grid-auto-rows: max-content;
158
- gap: var(--spacer);
159
61
  }
160
62
 
161
- summary
63
+ #header button
162
64
  {
163
- display: grid;
164
- gap: var(--spacer);
165
- padding: var(--small-spacer) var(--spacer);
65
+ align-self: stretch;
66
+ display: inline-flex;
166
67
  align-items: center;
68
+ gap: var(--gap-small);
167
69
  }
168
- summary::before
70
+
71
+ button .reset-icon
169
72
  {
170
- content: '';
171
- width: 16px;
172
- height: 16px;
173
- background: url("data:image/svg+xml,%3Csvg%20viewBox%3D'0%200%2020%2020'%20width%3D'14px'%20height%3D'14px'%20fill%3D'none'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cg%20stroke-width%3D'0'%3E%3C%2Fg%3E%3Cg%20stroke-linecap%3D'round'%20stroke-linejoin%3D'round'%3E%3C%2Fg%3E%3Cg%3E%3Cpath%20d%3D'M8.72798%2015.795L3.72798%207.795C3.10356%206.79593%203.82183%205.5%204.99998%205.5L15%205.5C16.1781%205.5%2016.8964%206.79593%2016.272%207.795L11.272%2015.795C10.6845%2016.735%209.31549%2016.735%208.72798%2015.795Z'%20fill%3D'%23878a8b'%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fsvg%3E");
73
+ width: 1em;
74
+ height: 1em;
75
+ transform: scaleX(-1);
76
+ margin-inline: 3px;
77
+ }
78
+
79
+ /* Run button */
80
+ button .arrow-icon
81
+ {
82
+ width: .75em;
83
+ height: .75em;
174
84
  transform: rotate(-90deg);
175
- transition: transform ease-out 200ms;
85
+ margin-inline: 3px;
176
86
  }
177
- [open] > summary::before
87
+ :host(.running) .run-all-button-icon
88
+ ,:host(.fail) .run-all-button-icon
178
89
  {
179
90
  transform: rotate(0);
180
- /* background: var(--surface-test-summary); */
181
91
  }
182
92
 
183
- :host(.running) .run[data-all]
93
+ /* Dropdown Layout */
94
+ summary > .run-test-button
95
+ , #run-all-button
184
96
  {
185
- color: var(--text-surface);
186
- background-color: oklch(89.68% 0.002 197.12);
187
- border-color: oklch(63.12% 0.004 219.55);
97
+ justify-self: flex-end;
98
+ margin-left: auto;
188
99
  }
189
- :host(.running) .run[data-all]:hover
100
+
101
+ summary:not(#component-summary)
190
102
  {
191
- background-color: oklch(95.57% 0.003 286.35);
192
- border-color: oklch(63.12% 0.004 219.55);
103
+ padding: var(--gap-small) var(--gap);
193
104
  }
194
- :host(.running) .run[data-all]:active
105
+ #component-summary
195
106
  {
196
- background-color: oklch(63.12% 0.004 219.55);
197
- border-color: oklch(53.12% 0.004 219.55);
107
+ padding-block: var(--gap-small);
198
108
  }
199
- :host(.running) .run[data-all]::before
109
+
110
+
111
+ /* Dropdown Markers */
112
+ summary
200
113
  {
201
- display: none;
114
+ display: flex;
115
+ align-items: center;
116
+ gap: var(--gap);
202
117
  }
203
-
204
- #before-all-summary
205
- ,#after-all-summary
118
+ summary > .arrow-icon
206
119
  {
207
- background: var(--surface-hook-summary);
208
- color: var(--text-hook-summary);
209
- grid-template-columns: auto auto 1fr;
120
+ background: var(--arrow-icon);
121
+ transform: rotate(-90deg);
122
+ transition: transform ease-out 90ms;
123
+ width: .6em;
124
+ height: .6em;
125
+ }
126
+ details[open] > summary > .arrow-icon
127
+ {
128
+ transform: rotate(0);
210
129
  }
211
130
 
131
+ /* Result Icon */
212
132
  .result-icon
213
133
  {
214
- --background-size: 24px;
134
+ --background-size: 16px;
215
135
  width: var(--background-size);
216
136
  height: var(--background-size);
217
137
 
@@ -224,184 +144,196 @@ summary::before
224
144
  }
225
145
  .result-icon::before
226
146
  {
227
- content: '\u22EF';
147
+ content: '';
148
+ font-size: 10px;
228
149
  }
229
150
 
230
- .hook
231
- {
232
- border: var(--border-hook);
233
- }
234
-
235
- .test
236
- ,#before-all-details
237
- ,#after-all-details
238
- {
239
- border: var(--border-test);
240
- border-radius: 2px;
241
- }
242
-
243
- .test summary
244
- {
245
- background: var(--surface-test-summary);
246
- grid-template-columns: auto auto 1fr auto;
247
- }
248
-
249
- .test.running .result-icon
151
+ :host(.running) #component-summary .result-icon
152
+ ,.test.running .test-summary > .result-icon
250
153
  ,.hook.running .result-icon
154
+ ,.processing-details.running .processing-result-icon
251
155
  {
252
156
  border: var(--border-process);
253
157
  background: var(--surface-process);
254
158
  }
255
- .test.success .result-icon
159
+ :host(.success) #component-summary .result-icon
160
+ ,.test.success .test-summary > .result-icon
256
161
  ,.hook.success .result-icon
162
+ ,.processing-details.success .processing-result-icon
257
163
  {
258
164
  border: var(--border-success);
259
165
  background: var(--surface-success)
260
166
  var(--success-icon);
261
167
  background-repeat: no-repeat;
262
168
  background-position: center;
263
- background-size: var(--icon-size, 16px) var(--icon-size, 16px);
169
+ background-size: var(--icon-size, 12px) var(--icon-size, 12px);
264
170
  }
265
- .test.fail .result-icon
171
+ :host(.fail) #component-summary .result-icon
172
+ ,.test.fail .test-summary > .result-icon
266
173
  ,.hook.fail .result-icon
174
+ ,.processing-details.fail .processing-result-icon
267
175
  {
268
176
  border: var(--border-fail);
269
177
  background: var(--surface-fail)
270
178
  var(--info-icon);
179
+ background-size: var(--icon-size, 16px) var(--icon-size, 16px);
271
180
  background-repeat: no-repeat;
272
181
  background-position: center;
273
182
  transform: rotate(175deg);
274
183
  }
275
- .test:is(.success,.fail) .result-icon::before
184
+ :host(:is(.success,.fail)) #component-summary .result-icon::before
185
+ ,.test:is(.success,.fail) .test-summary > .result-icon::before
276
186
  ,.hook:is(.success,.fail) .result-icon::before
187
+ ,.processing-details:is(.success,.fail) .processing-result-icon::before
277
188
  {
278
189
  display: none;
279
190
  }
280
- .test:is(.running) .result-icon::before
191
+ :host(.running) #component-summary .result-icon::before
192
+ ,.test:is(.running) .test-summary > .result-icon::before
281
193
  ,.hook:is(.running) .result-icon::before
194
+ ,.processing-details:is(.running) .processing-result-icon::before
282
195
  {
283
196
  content: '';
284
- --color: var(--text-process);
197
+ --color: var(--primary-process, currentColor);
285
198
  --animation-timing-function: linear;
286
199
  --animation-duration: 2s;
287
- width: var(--icon-size, 18px);
288
- height: var(--icon-size, 18px);
289
- mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--icon-size, 18px) / 3), black calc(var(--icon-size, 18px) / 3));
200
+ width: var(--icon-size, 14px);
201
+ height: var(--icon-size, 14px);
202
+ mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--icon-size, 14px) / 3), black calc(var(--icon-size, 14px) / 3));
290
203
  background-image: conic-gradient(transparent, transparent 135deg, var(--color));
291
204
  border-radius: 50%;
292
205
  animation: var(--animation-timing-function) var(--animation-duration) infinite spin;
293
206
  margin: 2px;
294
207
  }
295
208
 
296
- .description
209
+ /* Smaller Result icon settings for sub-test icons */
210
+ .before-each-result-icon
211
+ ,.after-each-result-icon
212
+ ,.processing-result-icon
297
213
  {
298
- user-select: none;
214
+ --background-size: 12px;
299
215
  }
300
-
301
- .test .result
302
- ,.hook .result
216
+ .before-each-result-icon::before
217
+ ,.after-each-result-icon::before
218
+ ,.processing-result-icon::before
303
219
  {
304
- background: var(--surface-test);
305
- border: var(--border-test);
306
- border-radius: 2px;
307
- margin: var(--small-spacer);
220
+ font-size: 9px;
308
221
  }
309
-
310
- .test .result:empty::before
311
- ,.results:empty::before
222
+ .hook.success .before-each-result-icon
223
+ ,.hook.success .after-each-result-icon
224
+ ,.processing-details.success .processing-result-icon
312
225
  {
313
- content: "[Test has not been run]";
314
- font-style: italic;
315
- font-size: 11px;
316
- color: var(--text-placeholder);
226
+ --icon-size: 8px;
317
227
  }
318
- .results:empty::before
228
+ .hook.fail .before-each-result-icon
229
+ ,.hook.fail .after-each-result-icon
230
+ ,.processing-details.fail .processing-result-icon
319
231
  {
320
- content: "[Tests have not been run]";
232
+ --icon-size: 12px;
321
233
  }
322
- .before-result:empty
323
- ,.after-result:empty
234
+ .hook:is(.running) .before-each-result-icon::before
235
+ ,.hook:is(.running) .after-each-result-icon::before
236
+ ,.processing-details:is(.running) .processing-result-icon::before
237
+ {
238
+ --icon-size: 9px;
239
+ }
240
+
241
+ /* Hook Display */
242
+ .hook
324
243
  {
325
244
  display: none;
326
245
  }
246
+ :host(.has-before-all-hook) #before-all-details
247
+ ,:host(.has-after-all-hook) #after-all-details
248
+ {
249
+ display: initial;
250
+ }
251
+ :host(.has-before-each-hook) .before-each-details
252
+ ,:host(.has-after-each-hook) .after-each-details
253
+ {
254
+ display: initial;
255
+ }
256
+ :host(.has-required-before-hook) #required-before-any-details
257
+ ,:host(.has-required-after-hook) #required-after-any-details
258
+ {
259
+ display: initial;
260
+ }
327
261
 
328
- .test .result
329
- ,.results
330
- ,.before-result
331
- ,.after-result
262
+ /* Test Display */
263
+ code-test .results
332
264
  {
333
- padding: var(--small-spacer) var(--spacer);
265
+ display: grid;
266
+ gap: var(--gap-small);
267
+ padding-inline-start: 1em;
334
268
  }
335
269
 
336
- pre
270
+ code-test .results details .result
271
+ ,.hook > .results
337
272
  {
338
- margin: var(--small-spacer);
273
+ margin-inline-start: 1em;
339
274
  }
340
275
 
341
- .run
276
+ .result.message:empty
342
277
  {
343
- width: auto;
344
- min-width: auto;
345
- max-width: auto;
346
- appearance: none;
347
- display: inline-flex;
348
- justify-content: center;
349
- align-items: center;
350
- padding: 3px 10px 3px 7px;
351
- font-size: 11px;
352
- gap: var(--small-spacer);
353
- border: var(--border-button);
354
- background: var(--surface-button);
355
- border-radius: 4px;
356
- text-shadow: 1px 1px rgb(0 0 0 / .2);
357
- color: var(--text-button);
278
+ padding: .5em 1em;
358
279
  }
359
- .run:hover
280
+ .result.message:empty::before
360
281
  {
361
- background: oklch(68.39% 0.181 258.33);
282
+ content: '[ this function has not been run ]';
283
+ font-family: monospace;
284
+ font-size: 12px;
285
+ font-style: italic;
362
286
  }
363
- .run:active
287
+
288
+ /* Ordered Display */
289
+ #tests
364
290
  {
365
- background: oklch(50.39% 0.181 258.33);
291
+ counter-reset: tests;
366
292
  }
367
- .run::before
293
+ code-test
368
294
  {
369
- content: '';
370
- display: block;
371
- width: 16px;
372
- height: 16px;
373
- transform: rotate(-90deg);
374
- background:
375
- url("data:image/svg+xml,%3Csvg%20viewBox%3D'0%200%2020%2020'%20width%3D'16px'%20height%3D'16px'%20fill%3D'none'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cg%20stroke-width%3D'0'%3E%3C%2Fg%3E%3Cg%20stroke-linecap%3D'round'%20stroke-linejoin%3D'round'%3E%3C%2Fg%3E%3Cg%3E%3Cpath%20d%3D'M8.72798%2015.795L3.72798%207.795C3.10356%206.79593%203.82183%205.5%204.99998%205.5L15%205.5C16.1781%205.5%2016.8964%206.79593%2016.272%207.795L11.272%2015.795C10.6845%2016.735%209.31549%2016.735%208.72798%2015.795Z'%20fill%3D'%23fdfdfd'%3E%3C%2Fpath%3E%3C%2Fg%3E%3C%2Fsvg%3E");
295
+ counter-increment: tests;
296
+ }
297
+ code-test > details > summary > .description
298
+ {
299
+ flex: 1;
300
+ }
301
+ :host(:not([ordered="false"])) code-test > details > summary > .description::before
302
+ {
303
+ content: counter(tests) ". ";
376
304
  }
377
305
 
306
+ /* Hook Name */
307
+ .hook-name,.processing-description
308
+ {
309
+ border-radius: 3px;
310
+ border: solid 1px;
311
+ /* background: rgb(0 0 0 / .2); */
312
+ font-family: monospace;
313
+ text-transform: uppercase;
314
+ font-size: 11px;
315
+ padding: 3px 7px;
316
+ }
378
317
 
379
- @media (prefers-color-scheme: dark)
318
+ #footer
319
+ {
320
+ display: flex;
321
+ justify-content: flex-end;
322
+ }
323
+ #group-results
380
324
  {
381
- :host
382
- {
383
- --text-surface: var(--uchu-yang);
384
- --text-result: var(--uchu-yang);
325
+ display: flex;
326
+ gap: var(--gap);
327
+ padding: var(--gap);
328
+ }
385
329
 
386
- --surface-0: var(--uchu-yin);
387
- --surface-test: oklch(25.11% 0.006 258.36);
388
- --surface-test-summary: oklch(35.02% 0.005 236.66);
389
- }
390
- :host(.running) .run[data-all]
391
- {
392
- background-color: oklch(35.02% 0.005 236.66);
393
- border-color: oklch(35.02% 0.005 236.66);
394
- }
395
- :host(.running) .run[data-all]:hover
396
- {
397
- background-color: oklch(63.12% 0.004 219.55);
398
- border-color:oklch(63.12% 0.004 219.55);
399
- }
400
- :host(.running) .run[data-all]:active
401
- {
402
- background-color: oklch(25.11% 0.006 258.36);
403
- border-color: oklch(25.11% 0.006 258.36);
404
- }
330
+ #passed-total-percent::before
331
+ {
332
+ content: '(';
333
+ }
334
+ #passed-total-percent::after
335
+ {
336
+ content: ')';
405
337
  }
406
338
 
407
339
  @keyframes spin
@@ -409,856 +341,1090 @@ pre
409
341
  from { transform: rotate(0deg); }
410
342
  to { transform: rotate(360deg); }
411
343
  }`;
412
-
413
- // src/code-tests.html?raw
414
- var code_tests_default2 = '<slot name="header">\n <header id="header">\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="play-button">\n <button type="button" class="run" data-all>\n <slot name="play-button-label">\n <span id="play-button-label" class="button-label label icon">Run Tests</span>\n </slot>\n </button>\n </slot>\n <slot name="details"></slot>\n </header>\n</slot>\n<details id="required-before-any-details" class="hook">\n <summary id="required-before-any-summary">\n <span id="required-before-any-result-icon" class="result-icon"></span>\n <span id="required-before-any-description" class="description">Results from Required Before Any Hook</span>\n </summary>\n <div id="required-before-any-results" class="results"></div>\n</details>\n<details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description">Results from Before All Hook</span>\n </summary>\n <div id="before-all-results" class="results"></div>\n</details>\n<ul id="tests"></ul>\n<details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description">Results from After All Hook</span>\n </summary>\n <div id="after-all-results" class="results"></div>\n</details>\n<details id="required-after-any-details" class="hook">\n <summary id="required-after-any-summary">\n <span id="required-after-any-result-icon" class="result-icon"></span>\n <span id="required-after-any-description" class="description">Results from Required After Any Hook</span>\n </summary>\n <div id="required-after-any-results" class="results"></div>\n</details>\n\n<template id="prompt-template">\n <div class="prompt" part="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>';
415
-
416
- // src/api.ts
417
- var TestPromise = class extends Promise {
418
- async toBeDefined(valueName) {
419
- const target = await this;
420
- if (target == void 0) {
421
- throw new Error(`${valueName != null ? valueName : "Value"} is undefined`);
422
- }
423
- }
424
- async toBe(value, exact = false) {
425
- const target = await this;
426
- const result = exact == true ? target === value : target == value;
427
- if (result == false) {
428
- throw new Error(` Value is not equal.
429
- Expected: ${value}
430
- Result: ${target}`);
431
- }
432
- }
433
- async toContainText(value) {
434
- const target = await this;
435
- }
436
- async toHaveAttribute(value) {
437
- const target = await this;
438
- if (!(target instanceof HTMLElement)) {
439
- throw new Error("Unable to check for attribute on non-HTMLElement target");
440
- }
441
- if (target.getAttribute(value)) {
442
- throw new Error("Taret does not have attribute");
443
- }
444
- }
344
+ const html = '<details id="component-details" class="details">\n <summary id="component-summary" class="summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <slot name="header">\n <header id="header">\n <span id="component-result-icon" class="result-icon"></span>\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="reload-button">\n <button type="button" id="reload-button" title="Reload">\n <slot name="reload-button-content">\n <slot name="reload-button-icon"><svg class="icon reset-icon reload-button-icon"><use href="#icon-definition_reset"></use></svg></slot>\n <slot name="reload-button-label"><span class="reload-button-label button-label label icon">Reload</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="run-all-button">\n <button type="button" id="run-all-button" title="Run All Tests">\n <slot name="run-all-button-content">\n <slot name="run-all-button-icon"><svg class="icon arrow-icon run-button-icon run-all-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-all-button-label"><span class="run-all-button-label run-button-label button-label label icon">Run Tests</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="header-details"></slot>\n </header>\n </slot>\n </summary>\n <div id="component-content" class="content">\n <details id="required-before-any-details" class="hook">\n <summary id="required-before-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-before-any-result-icon" class="result-icon"></span>\n <span id="required-before-any-description" class="description hook-name">Required Before Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-before-any-results" class="result message"></div>\n </div>\n </details>\n <details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description hook-name">Before All Hook</span>\n </summary>\n <div class="results">\n <div id="before-all-results" class="result message"></div>\n </div>\n </details>\n <div id="tests"></div>\n <details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description hook-name">After All Hook</span>\n </summary>\n <div class="results">\n <div id="after-all-results" class="result message"></div>\n </div>\n </details>\n <details id="required-after-any-details" class="hook">\n <summary id="required-after-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-after-any-result-icon" class="result-icon"></span>\n <span id="required-after-any-description" class="description hook-name">Required After Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-after-any-results" class="result message"></div>\n </div>\n </details>\n </div>\n \n <slot name="footer">\n <foooter id="footer">\n <span id="group-results">\n <span id="duration">\n <span id="duration-label">Duration</span>\n <span id="duration-value"></span>\n <span id="duration-unit">ms</span>\n </span>\n <span id="results-progress">\n <progress id="results-progress-value"></progress>\n </span>\n <span id="passed-total-pair">\n <span id="total-tests-passed-value"></span>\n <span id="passed-total-delimiter">of</span>\n <span id="total-tests-count-value"></span>\n <span id="total-tests-passed-label">Passed</span>\n </span>\n <span id="passed-total-percent">\n <span id="passed-total-percent-value"></span>\n <span id="passed-total-percent-label">%</span>\n </span>\n </span>\n </foooter>\n </slot>\n</details>\n<template id="prompt-template">\n <div class="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>\n<div id="icon-definitions" style="display: none;">\n <svg id="icon-definition_arrow" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path d="m3.26,6.81l-2.93,-4.69c-0.37,-0.58 0.05,-1.34 0.74,-1.34l5.87,0c0.69,0 1.11,0.76 0.74,1.34l-2.93,4.69c-0.35,0.55 -1.14,0.55 -1.49,0z" fill="var(--fill-color, currentcolor)" />\n </svg>\n <svg id="icon-definition_reset" class="icon reset" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M 5.484375 0.43359375 A 1.5224222 1.5224222 0 0 0 4.2558594 1.2011719 L 0.99804688 6.9453125 A 1.5224222 1.5224222 0 0 0 2.5488281 9.2011719 L 9.34375 8.171875 A 1.5224222 1.5224222 0 0 0 10.332031 5.7539062 L 9.4746094 4.6113281 C 11.949333 3.8016718 14.718209 4.258351 16.822266 5.9570312 C 19.510764 8.1275534 20.456787 11.785479 19.160156 14.988281 C 17.863527 18.191083 14.6405 20.15873 11.199219 19.847656 C 7.7579362 19.536584 4.9376009 17.022073 4.2363281 13.638672 A 1.5 1.5 0 0 0 2.4628906 12.474609 A 1.5 1.5 0 0 0 1.2988281 14.248047 C 2.2656928 18.912838 6.1831413 22.407052 10.927734 22.835938 C 15.672328 23.264824 20.153706 20.531029 21.941406 16.115234 C 23.729107 11.699441 22.413741 6.6156073 18.707031 3.6230469 C 16.853677 2.1267667 14.61485 1.3255701 12.347656 1.2324219 C 10.738216 1.1662975 9.1150542 1.4598646 7.6035156 2.1132812 L 6.7988281 1.0390625 A 1.5224222 1.5224222 0 0 0 5.484375 0.43359375 z " />\n </svg>\n <svg id="icon-definition_cancel" class="icon cancel" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M -7.063234 9.5244002 C -5.8135728 7.6769245 -5.0820528 5.453265 -5.0820528 3.0633809 C -5.0820529 -3.3096433 -10.278145 -8.5098163 -16.65117 -8.5098163 C -23.024193 -8.5098163 -28.22385 -3.3110105 -28.22385 3.0620137 C -28.22385 9.4350379 -23.025043 14.634694 -16.65202 14.634694 C -12.668879 14.634694 -9.1460028 12.603526 -7.063234 9.5244002 z M -9.5406311 7.8637601 C -11.076991 10.143147 -13.683157 11.63463 -16.652974 11.63463 C -19.960499 11.63463 -22.814085 9.782061 -24.244824 7.0543029 L -24.236684 7.0527515 L -8.1332524 3.983715 L -8.1305391 3.9831979 C -8.2815631 5.4121635 -8.7798709 6.7350751 -9.5406311 7.8637601 z M -9.0610781 -0.92890828 L -9.069218 -0.92735695 L -25.17265 2.1416796 L -25.175363 2.1421967 C -24.719122 -2.1725739 -21.093311 -5.5092358 -16.652928 -5.5092358 C -13.345403 -5.5092358 -10.491243 -3.6566663 -9.0610781 -0.92890828 z "\n transform="rotate(-124.20981)" />\n </svg>\n</div>';
345
+ const CodeTestEvent = {
346
+ BeforeAll: "beforeall",
347
+ AfterAll: "afterall",
348
+ BeforeTest: "beforetest",
349
+ AfterTest: "aftertest",
350
+ BeforeHook: "beforehook",
351
+ AfterHook: "afterhook",
352
+ Cancel: "cancel",
353
+ Context: "context",
354
+ Reset: "reset"
445
355
  };
446
- var CodeTests = class _CodeTests {
447
- static timeoutMS = 500;
448
- static #expectInterval;
449
- static #expectPromise;
450
- static expect(value) {
451
- const promise = new TestPromise(async (resolve, reject) => {
452
- if (value instanceof Promise) {
453
- const result = await value;
454
- resolve(result);
455
- return;
456
- }
457
- resolve(value);
458
- });
459
- return promise;
356
+ const COMPONENT_TAG_NAME$1 = "code-test";
357
+ class CodeTestElement extends HTMLElement {
358
+ state = {
359
+ testId: "",
360
+ description: "none",
361
+ isDisabled: false,
362
+ testState: void 0,
363
+ beforeEachState: void 0,
364
+ afterEachState: void 0
365
+ };
366
+ setState(state) {
367
+ this.state = state;
368
+ this.#render();
460
369
  }
461
- static expectSync(value) {
462
- const promise = new TestPromise(async (resolve, reject) => {
463
- if (value instanceof Promise) {
464
- const result = await value;
465
- resolve(result);
466
- return;
467
- }
468
- resolve(value);
370
+ setStateProperties(state) {
371
+ this.setState({
372
+ ...this.state,
373
+ ...state
469
374
  });
470
- return promise;
471
375
  }
472
- static expectBefore(value) {
473
- const promise = new TestPromise(async (resolve, reject) => {
474
- if (value instanceof Promise) {
475
- const result = await value;
476
- resolve(result);
477
- return;
376
+ setTestStateProperties(key, state) {
377
+ if (this.state[key] == null) {
378
+ return;
379
+ }
380
+ this.setState({
381
+ ...this.state,
382
+ [key]: {
383
+ ...this.state[key],
384
+ ...state
478
385
  }
479
- resolve(value);
480
386
  });
481
- return promise;
482
387
  }
483
- static async prompt(host, parent, message, options) {
484
- return new Promise((resolve, reject) => {
485
- const template = host.findElement("prompt-template");
486
- const promptElement = _CodeTests.createElementFromTemplate(template);
487
- promptElement.querySelector(".label").textContent = message;
488
- const clickHandler = (event) => {
489
- const composedPath = event.composedPath();
490
- const acceptButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("accept"));
491
- if (acceptButton != null) {
492
- const result = options?.onAccept?.() ?? true;
493
- promptElement.removeEventListener("click", clickHandler);
494
- resolve(result);
495
- return;
496
- }
497
- const rejectButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("reject"));
498
- if (rejectButton != null) {
499
- const result = options?.onReject?.() ?? false;
500
- promptElement.removeEventListener("click", clickHandler);
501
- resolve(result);
502
- return;
503
- }
504
- };
505
- promptElement.addEventListener("click", clickHandler);
506
- if (options?.acceptLabel != null) {
507
- promptElement.querySelector(".accept").textContent = options.acceptLabel;
508
- }
509
- if (options?.rejectLabel != null) {
510
- promptElement.querySelector(".reject").textContent = options.rejectLabel;
511
- }
512
- const details = parent instanceof HTMLDetailsElement ? parent : parent.querySelector(".test-details");
513
- if (details != null) {
514
- details.open = true;
515
- }
516
- parent.querySelector(".result")?.append(promptElement);
517
- });
388
+ findElement(query) {
389
+ return this.querySelector(query);
518
390
  }
519
- static createElementFromTemplate(target, parent) {
520
- const templateNode = target instanceof HTMLTemplateElement ? target : document.querySelector(target);
521
- if (templateNode == null) {
522
- throw new Error(`Unable to find template element from selector: ${target}`);
523
- }
524
- const firstChild = templateNode.content.cloneNode(true).querySelector("*");
525
- if (firstChild == null) {
526
- throw new Error(`Unable to find first child of template element`);
527
- }
528
- parent?.append(firstChild);
529
- return firstChild;
391
+ findElements(query) {
392
+ return Array.from(this.querySelectorAll(query));
530
393
  }
531
- };
532
- function expect(value) {
533
- return CodeTests.expect(value);
534
- }
535
- function prompt(host, parent, message, options) {
536
- return CodeTests.prompt(host, parent, message, options);
537
- }
538
-
539
- // node_modules/.pnpm/ce-part-utils@0.0.0/node_modules/ce-part-utils/dist/ce-part-utils.js
540
- var DEFAULT_ELEMENT_SELECTOR = ":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";
541
- function assignClassAndIdToPart(shadowRoot) {
542
- const identifiedElements = [...shadowRoot.querySelectorAll(`${DEFAULT_ELEMENT_SELECTOR}[id]`)];
543
- for (let i = 0; i < identifiedElements.length; i++) {
544
- identifiedElements[i].part.add(identifiedElements[i].id);
394
+ isRunning() {
395
+ return this.state.testState?.isRunning == true || this.state.beforeEachState?.isRunning == true || this.state.afterEachState?.isRunning == true;
545
396
  }
546
- const classedElements = [...shadowRoot.querySelectorAll(`${DEFAULT_ELEMENT_SELECTOR}[class]`)];
547
- for (let i = 0; i < classedElements.length; i++) {
548
- classedElements[i].part.add(...classedElements[i].classList);
397
+ hasRun() {
398
+ return this.state.testState?.hasRun == true || this.state.beforeEachState?.hasRun == true || this.state.afterEachState?.hasRun == true;
549
399
  }
550
- }
551
-
552
- // src/code-tests.ts
553
- var HookType = /* @__PURE__ */ ((HookType2) => {
554
- HookType2["BeforeAll"] = "beforeall";
555
- HookType2["AfterAll"] = "afterall";
556
- HookType2["BeforeEach"] = "beforeeach";
557
- HookType2["AfterEach"] = "aftereach";
558
- HookType2["RequiredBeforeAny"] = "requiredbeforeany";
559
- HookType2["RequiredAfterAny"] = "requiredafterany";
560
- return HookType2;
561
- })(HookType || {});
562
- var CodeTestEventType = /* @__PURE__ */ ((CodeTestEventType2) => {
563
- CodeTestEventType2["BeforeAll"] = "beforeall";
564
- CodeTestEventType2["AfterAll"] = "afterall";
565
- CodeTestEventType2["BeforeTest"] = "beforetest";
566
- CodeTestEventType2["AfterTest"] = "aftertest";
567
- CodeTestEventType2["Cancel"] = "cancel";
568
- return CodeTestEventType2;
569
- })(CodeTestEventType || {});
570
- var NOTESTDEFINED = Symbol("No Test Defined");
571
- var COMPONENT_STYLESHEET = new CSSStyleSheet();
572
- COMPONENT_STYLESHEET.replaceSync(code_tests_default);
573
- var COMPONENT_TAG_NAME = "code-tests";
574
- var CodeTestsElement = class extends HTMLElement {
575
- componentParts = /* @__PURE__ */ new Map();
576
- getElement(id) {
577
- if (this.componentParts.get(id) == null) {
578
- const part = this.findElement(id);
579
- if (part != null) {
580
- this.componentParts.set(id, part);
400
+ resultCategory() {
401
+ const testCategory = this.state.testState?.resultCategory ?? "none";
402
+ const beforeEachCategory = this.state.beforeEachState?.resultCategory ?? "none";
403
+ const afterEachCategory = this.state.afterEachState?.resultCategory ?? "none";
404
+ if (testCategory == "none" && beforeEachCategory == "none" && afterEachCategory == "none") {
405
+ return "none";
406
+ }
407
+ if (this.state.beforeEachState == null && this.state.afterEachState == null) {
408
+ return testCategory;
409
+ } else if (this.state.beforeEachState != null && this.state.afterEachState == null) {
410
+ if (testCategory == "fail" || beforeEachCategory == "fail") {
411
+ return "fail";
412
+ }
413
+ if (testCategory == "success" && beforeEachCategory == "success") {
414
+ return "success";
415
+ }
416
+ return "none";
417
+ } else if (this.state.beforeEachState == null && this.state.afterEachState != null) {
418
+ if (testCategory == "fail" || afterEachCategory == "fail") {
419
+ return "fail";
420
+ }
421
+ if (testCategory == "success" && afterEachCategory == "success") {
422
+ return "success";
581
423
  }
424
+ return "none";
425
+ } else if (this.state.beforeEachState != null && this.state.afterEachState != null) {
426
+ if (testCategory == "fail" || beforeEachCategory == "fail" || afterEachCategory == "fail") {
427
+ return "fail";
428
+ }
429
+ if (testCategory == "success" && beforeEachCategory == "success" && afterEachCategory == "success") {
430
+ return "success";
431
+ }
432
+ return "none";
582
433
  }
583
- return this.componentParts.get(id);
584
- }
585
- findElement(id) {
586
- return this.shadowRoot.getElementById(id);
587
- }
588
- #hooks = {};
589
- #continueRunningTests = true;
590
- constructor() {
591
- super();
592
- this.attachShadow({ mode: "open" });
593
- this.shadowRoot.innerHTML = code_tests_default2;
594
- this.shadowRoot.adoptedStyleSheets.push(COMPONENT_STYLESHEET);
595
- this.#boundClickHandler = this.#onClick.bind(this);
596
434
  }
597
435
  connectedCallback() {
598
- assignClassAndIdToPart(this.shadowRoot);
599
- this.addEventListener("click", this.#boundClickHandler);
600
- if (this.getAttribute("auto") == "false") {
601
- return;
436
+ this.#render();
437
+ }
438
+ #render() {
439
+ const resultMessage = this.state.testState == null ? "" : typeof this.state.testState.resultContent == "boolean" ? this.state.testState.resultContent == true ? `<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed</pre></code>` : `<code class="code" part="code"><pre class="pre error-message" part="pre error-message">Failed</pre></code>` : typeof this.state.testState.resultContent == "number" ? `<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed: ${this.state.testState.resultContent.toString()}</pre></code>` : typeof this.state.testState.resultContent == "string" ? this.state.testState.resultContent : "";
440
+ this.innerHTML = `<details class="test-details" part="test-details" ${this.isRunning() == true || this.hasRun() == true ? " open" : ""}>
441
+ <summary class="test-summary" part="test-summary">
442
+ <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>
443
+ <div class="result-icon test-result-icon${this.state.testState?.resultCategory != "none" ? ` ${this.state.testState?.resultCategory}` : ""}" part="result-icon"></div>
444
+ <span class="test-description description">${this.state.description}</span>
445
+ ${this.state.testState?.duration != null && this.state.testState.duration > 0 ? `<span class="test-duration duration">
446
+ <span class="test-duration-value">${this.state.testState.duration > 10 ? this.state.testState.duration.toFixed(0) : this.state.testState.duration.toFixed(2)}</span>
447
+ <span class="test-duration-unit">ms</span>
448
+ </span>` : ""}
449
+ <button type="button" class="run-test-button" part="run-test-button" title="Run Test"${this.state.isDisabled == true ? " disabled" : ""}>
450
+ <slot name="run-button-content">
451
+ <slot name="run-button-icon"><svg class="icon arrow-icon run-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>
452
+ <slot name="run-button-label"><span class="run-button-label button-label label icon">Run Test</span></slot>
453
+ </slot>
454
+ </button>
455
+ </summary>
456
+ <div class="results" part="results">
457
+ ${this.state.beforeEachState == null ? "" : `<details class="before-each-details hook${this.state.beforeEachState.resultCategory == "none" ? "" : ` ${this.state.beforeEachState.resultCategory}`}${this.state.beforeEachState.isRunning == true ? " running" : ""}" part="before-each-details hook">
458
+ <summary class="before-each-summary" part="before-each-summary">
459
+ <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>
460
+ <div class="before-each-result-icon result-icon${this.state.beforeEachState.resultCategory != "none" ? ` ${this.state.beforeEachState.resultCategory}` : ""}" part="before-each-result-icon"></div>
461
+ <span class="before-each-description description hook-name">Before Each Hook</span>
462
+ </summary>
463
+ <div class="before-each-result result message" part="before-each-result result message">${typeof this.state.beforeEachState.resultContent != "string" ? "" : this.state.beforeEachState.resultContent}</div>
464
+ </details>`}
465
+ ${this.state.testState == null ? "" : this.state.beforeEachState == null && this.state.afterEachState == null ? `<div class="test-result result message" part="test-result result message">${resultMessage}</div>` : `<details class="processing-details${this.state.testState.resultCategory == "none" ? "" : ` ${this.state.testState.resultCategory}`}${this.state.testState.isRunning == true ? " running" : ""}" part="processing-details"${this.state.testState.hasRun == true ? " open" : ""}>
466
+ <summary class="processing-summary" part="processing-summary">
467
+ <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>
468
+ <div class="processing-result-icon result-icon${this.state.testState.resultCategory != "none" ? ` ${this.state.testState.resultCategory}` : ""}" part="processing-result-icon result-icon"></div>
469
+ <span class="processing-description description">Test</span>
470
+ </summary>
471
+ <div class="test-result result message" part="test-result result message">${resultMessage}</div>
472
+ </details>`}
473
+ ${this.state.afterEachState == null ? "" : `<details class="after-each-details hook${this.state.afterEachState.resultCategory == "none" ? "" : ` ${this.state.afterEachState.resultCategory}`}${this.state.afterEachState.isRunning == true ? " running" : ""}" part="after-each-detail hooks">
474
+ <summary class="after-each-summary" part="after-each-summary">
475
+ <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>
476
+ <div class="after-each-result-icon result-icon${this.state.afterEachState.resultCategory != "none" ? ` ${this.state.afterEachState.resultCategory}` : ""}" part="before-each-result-icon"></div>
477
+ <span class="after-each-description description hook-name">After Each Hook</span>
478
+ </summary>
479
+ <div class="after-each-result result message" part="after-each-result result message">${typeof this.state.afterEachState.resultContent != "string" ? "" : this.state.afterEachState.resultContent}</div>
480
+ </details>`}
481
+ </div>
482
+ </details>`;
483
+ this.dataset.testId = this.state.testId;
484
+ this.classList.add("test");
485
+ this.part.add("test");
486
+ this.toggleAttribute("success", this.resultCategory() == "success");
487
+ this.classList.toggle("success", this.resultCategory() == "success");
488
+ this.part.toggle("success", this.resultCategory() == "success");
489
+ this.classList.toggle("fail", this.resultCategory() == "fail");
490
+ this.part.toggle("fail", this.resultCategory() == "fail");
491
+ this.classList.toggle("running", this.isRunning());
492
+ this.part.toggle("running", this.isRunning());
493
+ if (this.state.beforeEachState?.resultContent instanceof HTMLElement) {
494
+ this.querySelector(".before-each-result").append(this.state.beforeEachState.resultContent);
602
495
  }
603
- const testsPath = this.#getCurrentTestsPath();
604
- if (testsPath == null) {
605
- return;
496
+ if (this.state.testState?.resultContent instanceof HTMLElement) {
497
+ this.querySelector(".test-result").append(this.state.testState.resultContent);
498
+ }
499
+ if (this.state.afterEachState?.resultContent instanceof HTMLElement) {
500
+ this.querySelector(".after-each-result").append(this.state.afterEachState.resultContent);
606
501
  }
607
- this.loadTests(testsPath);
608
502
  }
609
- disconnectedCallback() {
610
- this.removeEventListener("click", this.#boundClickHandler);
503
+ enable() {
504
+ this.state.isDisabled = false;
505
+ this.findElement(".run-test-button").toggleAttribute("disabled", false);
611
506
  }
612
- #boundClickHandler;
613
- #onClick(event) {
614
- const runButton = event.composedPath().find((item) => item instanceof HTMLButtonElement && item.classList.contains("run"));
615
- if (runButton == null) {
507
+ disable() {
508
+ this.state.isDisabled = true;
509
+ this.findElement(".run-test-button").toggleAttribute("disabled", true);
510
+ }
511
+ async runTest(contextManager, testContext) {
512
+ if (this.state.testState?.test == null) {
616
513
  return;
617
514
  }
618
- const parentListItem = runButton.closest("li");
619
- if (parentListItem == null) {
620
- const isRunAll = runButton.hasAttribute("data-all");
621
- if (isRunAll == true) {
622
- if (this.classList.contains("running")) {
623
- if (this.classList.contains("canceled")) {
624
- return;
625
- }
626
- this.cancel();
627
- } else {
628
- this.runTests();
629
- }
515
+ this.reset();
516
+ let testResult;
517
+ let stateProperties = {};
518
+ let duration = 0;
519
+ try {
520
+ if (contextManager.shouldContinueRunningTests == false) {
521
+ throw new Error("Tests have been disabled from continuing to run.");
630
522
  }
631
- return;
523
+ const allowTest = this.dispatchEvent(new CustomEvent(CodeTestEvent.BeforeTest, { bubbles: true, cancelable: true, composed: true, detail: { testElement: this } }));
524
+ if (allowTest == false) {
525
+ throw new Error("Test has been prevented.");
526
+ }
527
+ if (testContext.codeTestsElement.state.isCanceled == true) {
528
+ throw new Error("Testing has been canceled.");
529
+ }
530
+ this.setTestStateProperties("testState", { isRunning: true });
531
+ contextManager.codeTestsElement.setState(contextManager.codeTestsElement.state);
532
+ const startTime = performance?.now() ?? Date.now();
533
+ testResult = await this.state.testState.test(testContext);
534
+ const endTime = performance?.now() ?? Date.now();
535
+ duration = endTime - startTime;
536
+ this.setTestStateProperties("testState", { isRunning: false, hasRun: true });
537
+ contextManager.codeTestsElement.setState(contextManager.codeTestsElement.state);
538
+ const testParsedResult = contextManager.parseTestResult(testResult, true);
539
+ stateProperties = {
540
+ testState: {
541
+ test: this.state.testState.test,
542
+ resultContent: testParsedResult.result,
543
+ resultCategory: testParsedResult.resultCategory,
544
+ hasRun: this.state.testState.hasRun,
545
+ isRunning: false,
546
+ duration
547
+ }
548
+ };
549
+ } catch (error) {
550
+ const errorParsedResult = contextManager.parseTestResult(testResult, false, error);
551
+ stateProperties = {
552
+ testState: {
553
+ test: this.state.testState.test,
554
+ resultContent: errorParsedResult.result,
555
+ resultCategory: errorParsedResult.resultCategory,
556
+ hasRun: this.state.testState.hasRun,
557
+ isRunning: false,
558
+ duration
559
+ }
560
+ };
561
+ console.error(error);
562
+ contextManager.shouldContinueRunningTests = false;
563
+ } finally {
564
+ this.setStateProperties({ ...stateProperties });
565
+ contextManager.codeTestsElement.setState(contextManager.codeTestsElement.state);
566
+ this.dispatchEvent(new CustomEvent(CodeTestEvent.AfterTest, { bubbles: true, cancelable: true, composed: true, detail: { testElement: this } }));
632
567
  }
633
- const testId = parentListItem.dataset.testId;
634
- if (testId == null) {
568
+ }
569
+ reset() {
570
+ const testState = this.state.testState != null ? {
571
+ resultCategory: "none",
572
+ resultContent: "",
573
+ test: this.state.testState.test,
574
+ hasRun: this.state.testState.hasRun,
575
+ isRunning: this.state.testState.isRunning,
576
+ duration: 0
577
+ } : void 0;
578
+ if (testState == void 0) {
635
579
  return;
636
580
  }
637
- const test = this.#tests.get(testId);
638
- if (test == null) {
639
- return;
581
+ this.setTestStateProperties("testState", testState);
582
+ }
583
+ getMessageElement() {
584
+ return this.findElement(".test-result");
585
+ }
586
+ static observedAttributes = ["open"];
587
+ attributeChangedCallback(attributeName, _oldValue, newValue) {
588
+ if (attributeName == "open") {
589
+ this.findElement(".test-details").toggleAttribute("open", newValue != void 0);
640
590
  }
641
- this.isCanceled = false;
642
- this.classList.remove("canceled");
643
- this.part.remove("canceled");
644
- this.#runTest(testId, test);
645
591
  }
646
- #getCurrentTestsPath() {
647
- return this.getAttribute("src") ?? this.getAttribute("test") ?? this.getAttribute("tests") ?? this.getAttribute("run") ?? this.getAttribute("path");
592
+ }
593
+ if (customElements.get(COMPONENT_TAG_NAME$1) == null) {
594
+ customElements.define(COMPONENT_TAG_NAME$1, CodeTestElement);
595
+ }
596
+ const NOTESTDEFINED = /* @__PURE__ */ Symbol("No Test Defined");
597
+ class ContextManager {
598
+ codeTestsElement;
599
+ // testContext?: TestContext;
600
+ constructor(parent) {
601
+ this.codeTestsElement = parent;
648
602
  }
649
- async loadTests(testsPath) {
650
- const path = testsPath ?? this.#getCurrentTestsPath();
603
+ //#region Loading
604
+ async loadTests(path) {
651
605
  if (path == null) {
652
606
  return;
653
607
  }
654
608
  try {
655
- this.getElement("tests").innerHTML = "";
656
- this.#tests.clear();
657
- this.classList.remove("has-before-hook");
658
- this.classList.remove("has-after-hook");
659
- const lastSlashIndexInCurrentPath = window.location.href.lastIndexOf("/");
660
- const currentPathHasExtension = window.location.href.substring(lastSlashIndexInCurrentPath).indexOf(".") != -1;
661
- const currentPath = currentPathHasExtension == true ? window.location.href.substring(0, lastSlashIndexInCurrentPath + 1) : window.location.href;
662
- const moduleDirectory = currentPath + path.substring(0, path.lastIndexOf("/") + 1);
663
- const modulePath = currentPath + path;
664
- let moduleContent = await (await fetch(modulePath)).text();
665
- moduleContent = moduleContent.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g, `'${moduleDirectory}$1'`);
666
- const moduleFile = new File([moduleContent], path.substring(path.lastIndexOf("/")), { type: "text/javascript" });
667
- const moduleURL = URL.createObjectURL(moduleFile);
668
- const module = await import(moduleURL);
669
- const tests = module.tests ?? module.default;
670
- if (tests == void 0) {
671
- throw new Error(`Unable to find tests definition in file at path: ${path}`);
672
- }
673
- const beforeAll = tests["beforeall" /* BeforeAll */];
674
- if (beforeAll != null) {
675
- this.#hooks["beforeall" /* BeforeAll */] = beforeAll;
676
- delete tests["beforeall" /* BeforeAll */];
677
- this.classList.add("has-before-hook");
678
- }
679
- const afterAll = tests["afterall" /* AfterAll */];
680
- if (afterAll != null) {
681
- this.#hooks["afterall" /* AfterAll */] = afterAll;
682
- delete tests["afterall" /* AfterAll */];
683
- this.classList.add("has-after-hook");
684
- }
685
- const beforeEach = tests["beforeeach" /* BeforeEach */];
686
- if (beforeEach != null) {
687
- this.#hooks["beforeeach" /* BeforeEach */] = beforeEach;
688
- delete tests["beforeeach" /* BeforeEach */];
689
- }
690
- const afterEach = tests["aftereach" /* AfterEach */];
691
- if (afterEach != null) {
692
- this.#hooks["aftereach" /* AfterEach */] = afterEach;
693
- delete tests["aftereach" /* AfterEach */];
694
- }
695
- const requiredBeforeAny = tests["requiredbeforeany" /* RequiredBeforeAny */];
696
- if (requiredBeforeAny != null) {
697
- this.#hooks["requiredbeforeany" /* RequiredBeforeAny */] = requiredBeforeAny;
698
- delete tests["requiredbeforeany" /* RequiredBeforeAny */];
699
- this.classList.add("has-required-before-hook");
700
- this.part.add("has-required-before-hook");
701
- }
702
- const requiredAfterAny = tests["requiredafterany" /* RequiredAfterAny */];
703
- if (requiredAfterAny != null) {
704
- this.#hooks["requiredafterany" /* RequiredAfterAny */] = requiredAfterAny;
705
- delete tests["requiredafterany" /* RequiredAfterAny */];
706
- this.classList.add("has-required-after-hook");
707
- this.part.add("has-required-after-hook");
708
- }
609
+ const { tests, hooks } = await this.#loadTests(path);
610
+ const beforeAll = hooks[Hook.BeforeAll];
611
+ const afterAll = hooks[Hook.AfterAll];
612
+ const beforeEach = hooks[Hook.BeforeEach];
613
+ const afterEach = hooks[Hook.AfterEach];
614
+ const requiredBeforeAny = hooks[Hook.RequiredBeforeAny];
615
+ const requiredAfterAny = hooks[Hook.RequiredAfterAny];
616
+ const beforeAllState = beforeAll == null ? void 0 : { resultCategory: "none", resultContent: "", test: beforeAll, hasRun: false, isRunning: false, duration: 0 };
617
+ const afterAllState = afterAll == null ? void 0 : { resultCategory: "none", resultContent: "", test: afterAll, hasRun: false, isRunning: false, duration: 0 };
618
+ const beforeEachState = beforeEach == null ? void 0 : { resultCategory: "none", resultContent: "", test: beforeEach, hasRun: false, isRunning: false, duration: 0 };
619
+ const afterEachState = afterEach == null ? void 0 : { resultCategory: "none", resultContent: "", test: afterEach, hasRun: false, isRunning: false, duration: 0 };
620
+ const requiredBeforeAnyState = requiredBeforeAny == null ? void 0 : { resultCategory: "none", resultContent: "", test: requiredBeforeAny, hasRun: false, isRunning: false, duration: 0 };
621
+ const requiredAfterAnyState = requiredAfterAny == null ? void 0 : { resultCategory: "none", resultContent: "", test: requiredAfterAny, hasRun: false, isRunning: false, duration: 0 };
622
+ this.codeTestsElement.state.beforeEachState = beforeEachState;
623
+ this.codeTestsElement.state.afterEachState = afterEachState;
709
624
  for (const [description, test] of Object.entries(tests)) {
710
625
  this.#addTest(description, test);
711
626
  }
627
+ this.codeTestsElement.setStateProperties({
628
+ beforeAllState,
629
+ afterAllState,
630
+ beforeEachState,
631
+ afterEachState,
632
+ requiredBeforeAnyState,
633
+ requiredAfterAnyState,
634
+ resetHook: hooks.reset,
635
+ contextHook: hooks.context
636
+ });
712
637
  } catch (error) {
713
- this.#addProcessError("An error occurred while loading the tasks:", error);
638
+ console.error(error);
714
639
  }
715
640
  }
716
- isCanceled = false;
717
- cancel() {
718
- this.isCanceled = true;
719
- this.classList.add("canceled");
720
- this.part.add("canceled");
721
- this.dispatchEvent(new CustomEvent("cancel" /* Cancel */, { bubbles: true, composed: true }));
641
+ async #loadTests(path) {
642
+ const module = await this.#loadModule(path);
643
+ const tests = module.tests ?? module.default;
644
+ if (tests == void 0) {
645
+ throw new Error(`Unable to find tests definition in file at path: ${path}`);
646
+ }
647
+ const hooks = {};
648
+ const beforeAll = tests[Hook.BeforeAll];
649
+ if (beforeAll != null) {
650
+ hooks[Hook.BeforeAll] = beforeAll;
651
+ delete tests[Hook.BeforeAll];
652
+ }
653
+ const afterAll = tests[Hook.AfterAll];
654
+ if (afterAll != null) {
655
+ hooks[Hook.AfterAll] = afterAll;
656
+ delete tests[Hook.AfterAll];
657
+ }
658
+ const beforeEach = tests[Hook.BeforeEach];
659
+ if (beforeEach != null) {
660
+ hooks[Hook.BeforeEach] = beforeEach;
661
+ delete tests[Hook.BeforeEach];
662
+ }
663
+ const afterEach = tests[Hook.AfterEach];
664
+ if (afterEach != null) {
665
+ hooks[Hook.AfterEach] = afterEach;
666
+ delete tests[Hook.AfterEach];
667
+ }
668
+ const requiredBeforeAny = tests[Hook.RequiredBeforeAny];
669
+ if (requiredBeforeAny != null) {
670
+ hooks[Hook.RequiredBeforeAny] = requiredBeforeAny;
671
+ delete tests[Hook.RequiredBeforeAny];
672
+ }
673
+ const requiredAfterAny = tests[Hook.RequiredAfterAny];
674
+ if (requiredAfterAny != null) {
675
+ hooks[Hook.RequiredAfterAny] = requiredAfterAny;
676
+ delete tests[Hook.RequiredAfterAny];
677
+ }
678
+ const resetHook = tests[Hook.Reset];
679
+ if (resetHook != null) {
680
+ hooks[Hook.Reset] = resetHook;
681
+ delete tests[Hook.Reset];
682
+ }
683
+ const contextHook = tests[Hook.Context];
684
+ if (contextHook != null) {
685
+ hooks[Hook.Context] = contextHook;
686
+ delete tests[Hook.Context];
687
+ }
688
+ return { tests, hooks };
722
689
  }
723
- async runTests() {
724
- this.dispatchEvent(new CustomEvent("beforeall" /* BeforeAll */, { bubbles: true, composed: true }));
725
- this.#continueRunningTests = true;
726
- this.classList.add("running");
727
- this.isCanceled = false;
728
- this.classList.remove("canceled");
729
- this.part.remove("canceled");
730
- this.toggleAttribute("success", false);
731
- const playButtonLabel = this.findElement("play-button-label");
732
- if (playButtonLabel != null) {
733
- playButtonLabel.textContent = "Cancel";
734
- }
735
- this.#clearTestStatuses();
736
- const inOrder = this.hasAttribute("in-order");
737
- const requiredBeforeHook = this.#hooks["requiredbeforeany" /* RequiredBeforeAny */];
738
- if (requiredBeforeHook != null) {
739
- let hookResult;
740
- try {
741
- const requiredBeforeAnyHookElement = this.getElement(`required-before-any-details`);
742
- requiredBeforeAnyHookElement.classList.add("running");
743
- requiredBeforeAnyHookElement.part.add("running");
744
- if (this.isCanceled == true) {
745
- throw new Error("Test has been cancelled");
746
- }
747
- hookResult = await requiredBeforeHook(this, requiredBeforeAnyHookElement);
748
- this.#handleHookResult(hookResult, true, "before", true);
749
- requiredBeforeAnyHookElement.part.remove("running");
750
- requiredBeforeAnyHookElement.classList.remove("running");
751
- } catch (error) {
752
- this.#handleHookResult(hookResult, false, "before", true, error);
753
- console.error(error);
754
- this.#continueRunningTests = false;
755
- this.classList.remove("running");
756
- this.part.remove("running");
757
- if (playButtonLabel != null) {
758
- playButtonLabel.textContent = "Run Tests";
759
- }
760
- this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
761
- return;
690
+ async #loadModule(path) {
691
+ const lastSlashIndexInCurrentPath = window.location.href.lastIndexOf("/");
692
+ const currentPathHasExtension = window.location.href.substring(lastSlashIndexInCurrentPath).indexOf(".") != -1;
693
+ const currentPath = currentPathHasExtension == true ? window.location.href.substring(0, lastSlashIndexInCurrentPath + 1) : window.location.href;
694
+ const moduleDirectory = currentPath + path.substring(0, path.lastIndexOf("/") + 1);
695
+ const modulePath = currentPath + path;
696
+ let moduleContent = await (await fetch(modulePath)).text();
697
+ moduleContent = moduleContent.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g, `'${moduleDirectory}$1'`);
698
+ const moduleFile = new File([moduleContent], path.substring(path.lastIndexOf("/")), { type: "text/javascript" });
699
+ const moduleURL = URL.createObjectURL(moduleFile);
700
+ const module = await import(
701
+ /* @vite-ignore */
702
+ moduleURL
703
+ );
704
+ return module;
705
+ }
706
+ #addTest(description, test) {
707
+ const testId = generateId();
708
+ const testElement = new CodeTestElement();
709
+ testElement.setStateProperties({
710
+ testId,
711
+ description,
712
+ testState: { test, resultCategory: "none", resultContent: "", isRunning: false, hasRun: false, duration: 0 },
713
+ beforeEachState: this.codeTestsElement.state.beforeEachState == null ? void 0 : {
714
+ isRunning: this.codeTestsElement.state.beforeEachState.isRunning,
715
+ hasRun: this.codeTestsElement.state.beforeEachState.hasRun,
716
+ resultCategory: this.codeTestsElement.state.beforeEachState.resultCategory,
717
+ resultContent: this.codeTestsElement.state.beforeEachState.resultContent,
718
+ duration: 0
719
+ },
720
+ afterEachState: this.codeTestsElement.state.afterEachState == null ? void 0 : {
721
+ isRunning: this.codeTestsElement.state.afterEachState.isRunning,
722
+ hasRun: this.codeTestsElement.state.afterEachState.hasRun,
723
+ resultCategory: this.codeTestsElement.state.afterEachState.resultCategory,
724
+ resultContent: this.codeTestsElement.state.afterEachState.resultContent,
725
+ duration: 0
762
726
  }
727
+ });
728
+ this.codeTestsElement.findElement("#tests").append(testElement);
729
+ return testId;
730
+ }
731
+ //#endregion Loading
732
+ //#region Running
733
+ shouldContinueRunningTests = true;
734
+ async runTests(tests) {
735
+ const allowTests = this.codeTestsElement.dispatchEvent(new CustomEvent(CodeTestEvent.BeforeAll, { bubbles: true, composed: true, cancelable: true }));
736
+ if (allowTests == false) {
737
+ throw new Error("Tests have been prevented.");
763
738
  }
764
- const beforeHook = this.#hooks["beforeall" /* BeforeAll */];
765
- if (beforeHook != null) {
766
- let hookResult;
767
- try {
768
- const beforeAllHookElement = this.getElement(`before-all-details`);
769
- beforeAllHookElement.classList.add("running");
770
- beforeAllHookElement.part.add("running");
771
- if (this.isCanceled == true) {
772
- throw new Error("Test has been cancelled");
773
- }
774
- hookResult = await beforeHook(this, beforeAllHookElement);
775
- this.#handleHookResult(hookResult, true, "before", false);
776
- beforeAllHookElement.part.remove("running");
777
- beforeAllHookElement.classList.remove("running");
778
- } catch (error) {
779
- this.#handleHookResult(hookResult, false, "before", false, error);
780
- console.error(error);
781
- this.#continueRunningTests = false;
782
- this.classList.remove("running");
783
- this.part.remove("running");
784
- if (playButtonLabel != null) {
785
- playButtonLabel.textContent = "Run Tests";
786
- }
787
- this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
788
- return;
789
- }
739
+ await this.codeTestsElement.reset();
740
+ for (let i = 0; i < tests.length; i++) {
741
+ tests[i].disable();
742
+ }
743
+ const context = await this.createTestContext();
744
+ await this.runHook("requiredBeforeAnyState", void 0, context);
745
+ if (this.shouldContinueRunningTests == false) {
746
+ await this.#endTests(tests, context);
747
+ return;
748
+ }
749
+ await this.runHook("beforeAllState", void 0, context);
750
+ if (this.shouldContinueRunningTests == false) {
751
+ await this.#endTests(tests, context);
752
+ return;
790
753
  }
754
+ const inOrder = this.codeTestsElement.getAttribute("ordered") != "false";
791
755
  if (inOrder == false) {
792
- const promises = [];
793
- for (const [id, test] of this.#tests) {
794
- promises.push(this.#runTest(id, test));
795
- }
756
+ const promises = tests.map((item) => this.runTest(item, true, context));
796
757
  await Promise.all(promises);
797
758
  } else {
798
- for (const [id, test] of this.#tests) {
799
- if (this.#continueRunningTests == false) {
759
+ for (let i = 0; i < tests.length; i++) {
760
+ const test = tests[i];
761
+ if (this.shouldContinueRunningTests == false) {
800
762
  break;
801
763
  }
802
- await this.#runTest(id, test, false);
764
+ await this.runTest(test, true, context);
803
765
  }
804
766
  }
805
- if (this.#continueRunningTests == false) {
806
- this.classList.remove("running");
807
- this.part.remove("running");
808
- if (playButtonLabel != null) {
809
- playButtonLabel.textContent = "Run Tests";
810
- }
811
- this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
767
+ if (this.shouldContinueRunningTests == false) {
768
+ await this.#endTests(tests, context);
812
769
  return;
813
770
  }
814
- const afterHook = this.#hooks["afterall" /* AfterAll */];
815
- if (afterHook != null) {
816
- let hookResult;
817
- try {
818
- const afterAllHookElement = this.getElement(`after-all-details`);
819
- afterAllHookElement.classList.add("running");
820
- afterAllHookElement.part.add("running");
821
- if (this.isCanceled == true) {
822
- throw new Error("Test has been cancelled");
823
- }
824
- hookResult = await afterHook(this, afterAllHookElement);
825
- this.#handleHookResult(hookResult, true, "after", false);
826
- afterAllHookElement.part.remove("running");
827
- afterAllHookElement.classList.remove("running");
828
- } catch (error) {
829
- this.#handleHookResult(hookResult, false, "after", false, error);
830
- console.error(error);
831
- const requiredAfterHook2 = this.#hooks["requiredafterany" /* RequiredAfterAny */];
832
- if (requiredAfterHook2 != null) {
833
- let hookResult2;
834
- try {
835
- const requiredAfterAnyHookElement = this.getElement(`required-after-any-details`);
836
- requiredAfterAnyHookElement.classList.add("running");
837
- requiredAfterAnyHookElement.part.add("running");
838
- if (this.isCanceled == true) {
839
- throw new Error("Test has been cancelled");
840
- }
841
- hookResult2 = await requiredAfterHook2(this, requiredAfterAnyHookElement);
842
- this.#handleHookResult(hookResult2, true, "after", true);
843
- requiredAfterAnyHookElement.part.remove("running");
844
- requiredAfterAnyHookElement.classList.remove("running");
845
- } catch (error2) {
846
- this.#handleHookResult(hookResult2, false, "after", true, error2);
847
- console.error(error2);
848
- }
849
- }
850
- this.#continueRunningTests = false;
851
- this.classList.remove("running");
852
- this.part.remove("running");
853
- if (playButtonLabel != null) {
854
- playButtonLabel.textContent = "Run Tests";
855
- }
856
- this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
857
- return;
858
- }
771
+ await this.runHook("afterAllState", void 0, context);
772
+ await this.#endTests(tests, context);
773
+ }
774
+ async #endTests(tests, context) {
775
+ await this.runHook("requiredAfterAnyState", void 0, context);
776
+ for (let i = 0; i < tests.length; i++) {
777
+ tests[i].enable();
859
778
  }
860
- const requiredAfterHook = this.#hooks["requiredafterany" /* RequiredAfterAny */];
861
- if (requiredAfterHook != null) {
862
- let hookResult;
863
- try {
864
- const requiredAfterAnyHookElement = this.getElement(`required-after-any-details`);
865
- requiredAfterAnyHookElement.classList.add("running");
866
- requiredAfterAnyHookElement.part.add("running");
867
- if (this.isCanceled == true) {
868
- throw new Error("Test has been cancelled");
869
- }
870
- hookResult = await requiredAfterHook(this, requiredAfterAnyHookElement);
871
- this.#handleHookResult(hookResult, true, "after", true);
872
- requiredAfterAnyHookElement.part.remove("running");
873
- requiredAfterAnyHookElement.classList.remove("running");
874
- } catch (error) {
875
- this.#handleHookResult(hookResult, false, "after", true, error);
876
- console.error(error);
877
- this.#continueRunningTests = false;
878
- }
779
+ this.codeTestsElement.dispatchEvent(new CustomEvent(CodeTestEvent.AfterAll, { bubbles: true, composed: true }));
780
+ }
781
+ async runTest(test, inLoop, testContext) {
782
+ if (test == null) {
783
+ return;
879
784
  }
880
- const failedTests = this.shadowRoot.querySelectorAll('[success="false"]');
881
- this.setAttribute("success", failedTests.length == 0 ? "true" : "false");
882
- this.classList.remove("running");
883
- this.part.remove("running");
884
- if (playButtonLabel != null) {
885
- playButtonLabel.textContent = "Run Tests";
785
+ if (inLoop == false) {
786
+ const tests = this.codeTestsElement.findElements("code-test");
787
+ for (let i = 0; i < tests.length; i++) {
788
+ tests[i].disable();
789
+ }
886
790
  }
887
- this.dispatchEvent(new CustomEvent("afterall" /* AfterAll */, { bubbles: true, composed: true }));
888
- }
889
- #clearTestStatuses() {
890
- for (const [testId, test] of this.#tests) {
891
- const testElement = this.getElement("tests").querySelector(`[data-test-id="${testId}"]`);
892
- if (testElement == null) {
893
- this.#addProcessError(`Unable to find test element for test: ${testId}`);
791
+ testContext = testContext ?? await this.createTestContext(test);
792
+ if (inLoop == false) {
793
+ await this.runHook("requiredBeforeAnyState", void 0, testContext);
794
+ if (this.shouldContinueRunningTests == false) {
795
+ await this.#endTest(testContext, inLoop);
894
796
  return;
895
797
  }
896
- testElement.toggleAttribute("success", false);
897
- testElement.classList.remove("success", "fail");
898
- testElement.part.remove("success", "fail");
899
- }
900
- const beforeAllHookElement = this.getElement(`before-all-details`);
901
- beforeAllHookElement.toggleAttribute("success", false);
902
- beforeAllHookElement.classList.remove("success", "fail");
903
- beforeAllHookElement.part.remove("success", "fail");
904
- const afterAllHookElement = this.getElement(`after-all-details`);
905
- afterAllHookElement.toggleAttribute("success", false);
906
- afterAllHookElement.classList.remove("success", "fail");
907
- afterAllHookElement.part.remove("success", "fail");
798
+ }
799
+ await this.runHook("beforeEachState", test, testContext);
800
+ if (this.shouldContinueRunningTests == false) {
801
+ await this.#endTest(testContext, inLoop);
802
+ return;
803
+ }
804
+ await test.runTest(this, testContext);
805
+ if (this.shouldContinueRunningTests == false) {
806
+ await this.#endTest(testContext, inLoop);
807
+ return;
808
+ }
809
+ await this.runHook("afterEachState", test, testContext);
810
+ await this.#endTest(testContext, inLoop);
908
811
  }
909
- async #runTest(testId, test, handleRequiredTests = true) {
910
- const testElement = this.getElement("tests").querySelector(`[data-test-id="${testId}"]`);
911
- if (testElement == null) {
912
- this.#addProcessError(`Unable to find test element for test: ${testId}`);
812
+ async #endTest(context, inLoop) {
813
+ if (inLoop == true) {
913
814
  return;
914
815
  }
915
- testElement.toggleAttribute("success", false);
916
- testElement.classList.add("running");
917
- testElement.part.add("running");
918
- testElement.classList.remove("success", "fail");
919
- testElement.part.remove("success", "fail");
920
- const iconElement = testElement.querySelector(".result-icon");
921
- iconElement?.classList.remove("success", "fail");
922
- iconElement?.part.remove("success", "fail");
923
- iconElement?.classList.add("running");
924
- iconElement?.part.add("running");
925
- const errorMessageElement = testElement.querySelector(".error-message");
926
- if (errorMessageElement != null) {
927
- errorMessageElement.textContent = "";
928
- }
929
- const detailsElement = testElement.querySelector("details");
930
- if (detailsElement != null) {
931
- detailsElement.open = false;
932
- }
933
- let beforeResult = NOTESTDEFINED;
934
- let testResult;
935
- let afterResult = NOTESTDEFINED;
936
- let testType;
816
+ await this.runHook("requiredAfterAnyState", void 0, context);
817
+ const tests = this.codeTestsElement.findElements("code-test");
818
+ for (let i = 0; i < tests.length; i++) {
819
+ tests[i].enable();
820
+ }
821
+ }
822
+ async runHook(testStateName, test, testContext) {
823
+ const testState = this.codeTestsElement.state[testStateName];
824
+ if (testState == null) {
825
+ return NOTESTDEFINED;
826
+ }
827
+ if (this.codeTestsElement.state.isCanceled == true) {
828
+ return { success: false, value: "Testing has been canceled." };
829
+ }
830
+ let hookResult;
937
831
  try {
938
- const allowTest = this.dispatchEvent(new CustomEvent("beforetest" /* BeforeTest */, { bubbles: true, cancelable: true, composed: true, detail: { testElement } }));
939
- if (handleRequiredTests == true) {
940
- const requiredBeforeHook = this.#hooks["requiredbeforeany" /* RequiredBeforeAny */];
941
- if (requiredBeforeHook != null) {
942
- let hookResult;
943
- try {
944
- const requiredBeforeAnyHookElement = this.getElement(`required-before-any-details`);
945
- requiredBeforeAnyHookElement.classList.add("running");
946
- requiredBeforeAnyHookElement.part.add("running");
947
- if (this.isCanceled == true) {
948
- throw new Error("Test has been cancelled");
949
- }
950
- hookResult = await requiredBeforeHook(this, requiredBeforeAnyHookElement);
951
- this.#handleHookResult(hookResult, true, "before", true);
952
- requiredBeforeAnyHookElement.part.remove("running");
953
- requiredBeforeAnyHookElement.classList.remove("running");
954
- } catch (error) {
955
- this.#handleHookResult(hookResult, true, "before", true, error);
956
- console.error(error);
957
- this.#continueRunningTests = false;
958
- return;
959
- }
960
- }
961
- }
962
- if (this.#continueRunningTests == false) {
832
+ if (this.shouldContinueRunningTests == false && (testStateName != "requiredAfterAnyState" || this.codeTestsElement.getAttribute("required-after") == "error")) {
963
833
  throw new Error("Tests have been disabled from continuing to run.");
964
834
  }
965
- if (allowTest == false || this.isCanceled == true) {
966
- throw new Error("Test has been cancelled");
967
- }
968
- const beforeHook = this.#hooks["beforeeach" /* BeforeEach */];
969
- if (beforeHook != null) {
970
- beforeResult = await beforeHook(this, testElement);
971
- }
972
- if (this.isCanceled == true) {
973
- throw new Error("Test has been cancelled");
974
- }
975
- testResult = await test(this, testElement);
976
- if (this.isCanceled == true) {
977
- throw new Error("Test has been cancelled");
978
- }
979
- const afterHook = this.#hooks["aftereach" /* AfterEach */];
980
- if (afterHook != null) {
981
- afterResult = await afterHook(this, testElement);
982
- }
983
- if (handleRequiredTests == true) {
984
- const requiredAfterHook = this.#hooks["requiredafterany" /* RequiredAfterAny */];
985
- if (requiredAfterHook != null) {
986
- let hookResult;
987
- try {
988
- const requiredBeforeAnyHookElement = this.getElement(`required-before-any-details`);
989
- requiredBeforeAnyHookElement.classList.add("running");
990
- requiredBeforeAnyHookElement.part.add("running");
991
- if (this.isCanceled == true) {
992
- throw new Error("Test has been cancelled");
993
- }
994
- hookResult = await requiredAfterHook(this, requiredBeforeAnyHookElement);
995
- this.#handleHookResult(hookResult, true, "after", true);
996
- requiredBeforeAnyHookElement.part.remove("running");
997
- requiredBeforeAnyHookElement.classList.remove("running");
998
- } catch (error) {
999
- this.#handleHookResult(hookResult, true, "after", true, error);
1000
- console.error(error);
1001
- this.#continueRunningTests = false;
1002
- return;
1003
- }
1004
- }
835
+ if (test != null) {
836
+ test.setTestStateProperties(testStateName, { isRunning: true });
1005
837
  }
1006
- testType = "before";
1007
- if (beforeResult != NOTESTDEFINED) {
1008
- this.#handleTestResult(testElement, beforeResult, true, void 0, testType);
838
+ this.codeTestsElement.setTestStateProperties(testStateName, { isRunning: true });
839
+ hookResult = await testState.test(testContext);
840
+ if (test != null) {
841
+ test.setTestStateProperties(testStateName, { isRunning: false, hasRun: true });
1009
842
  }
1010
- testType = void 0;
1011
- this.#handleTestResult(testElement, testResult, true, void 0, testType);
1012
- testType = "after";
1013
- if (afterResult != NOTESTDEFINED) {
1014
- this.#handleTestResult(testElement, afterResult, true, void 0, testType);
843
+ this.codeTestsElement.setTestStateProperties(testStateName, { isRunning: false, hasRun: true });
844
+ const hookParsedResult = this.parseTestResult(hookResult, true, void 0);
845
+ if (test != null) {
846
+ test.setTestStateProperties(testStateName, {
847
+ resultCategory: hookParsedResult.resultCategory,
848
+ resultContent: hookParsedResult.result
849
+ });
1015
850
  }
851
+ this.codeTestsElement.setTestStateProperties(testStateName, {
852
+ resultCategory: hookParsedResult.resultCategory,
853
+ resultContent: hookParsedResult.result
854
+ });
1016
855
  } catch (error) {
1017
- this.#handleTestResult(testElement, testResult, false, error, testType);
1018
856
  console.error(error);
1019
- this.#continueRunningTests = false;
857
+ this.shouldContinueRunningTests = false;
858
+ hookResult = { success: false, value: `Failed: ${error.message}` };
859
+ const errorParsedResult = this.parseTestResult(hookResult, false, error);
860
+ if (test != null) {
861
+ test.setTestStateProperties(
862
+ testStateName,
863
+ {
864
+ isRunning: false,
865
+ hasRun: true,
866
+ resultContent: errorParsedResult.result,
867
+ resultCategory: errorParsedResult.resultCategory
868
+ }
869
+ );
870
+ }
871
+ this.codeTestsElement.setTestStateProperties(testStateName, {
872
+ isRunning: false,
873
+ hasRun: true,
874
+ resultCategory: errorParsedResult.resultCategory,
875
+ resultContent: errorParsedResult.result
876
+ });
1020
877
  } finally {
1021
- testElement?.classList.remove("running");
1022
- testElement?.part.remove("running");
1023
- iconElement?.classList.remove("running");
1024
- iconElement?.part.remove("running");
1025
- this.dispatchEvent(new CustomEvent("aftertest" /* AfterTest */, { bubbles: true, cancelable: true, composed: true, detail: { testElement } }));
878
+ this.codeTestsElement.dispatchEvent(new CustomEvent(CodeTestEvent.AfterHook, { bubbles: true, composed: true, detail: hookResult }));
879
+ return hookResult;
1026
880
  }
1027
881
  }
1028
- #handleTestResult(testElement, result, finishedTest, error, beforeOrAfter) {
1029
- if (result instanceof HTMLElement) {
1030
- this.#setTestResult(testElement, result, finishedTest, beforeOrAfter);
1031
- } else if (result == void 0) {
1032
- const trueMessage = beforeOrAfter == void 0 ? "Passed" : "Hook Ran Successfully";
1033
- const defaultResult = this.#createDefaultResult(finishedTest == true ? `${trueMessage}` : `Failed${error != null ? `:
1034
- ${error.message}` : ""}`, finishedTest, beforeOrAfter);
1035
- this.#setTestResult(testElement, defaultResult, finishedTest, beforeOrAfter);
1036
- } else if (typeof result == "string") {
1037
- const defaultResult = this.#createDefaultResult(`${result}${error == null ? "" : `:
1038
- ${error.message}`}`, finishedTest, beforeOrAfter);
1039
- this.#setTestResult(testElement, defaultResult, finishedTest, beforeOrAfter);
882
+ //#endregion Running
883
+ //#region Utils
884
+ parseTestResult(result, finishedTest, error) {
885
+ if (result == NOTESTDEFINED) {
886
+ return { result: "", resultCategory: "none" };
887
+ }
888
+ if (result == void 0) {
889
+ const message = finishedTest == true ? "Passed" : `Failed${error != null ? `:
890
+ ${error.message}` : ""}`;
891
+ const className = finishedTest == true ? "success-message" : "error-message";
892
+ return {
893
+ result: `<code class="code" part="code">
894
+ <pre class="pre ${className}" part="pre ${className}">${message}</pre>
895
+ </code>`,
896
+ resultCategory: finishedTest == true ? "success" : "fail"
897
+ };
898
+ } else if (typeof result == "boolean") {
899
+ return { result, resultCategory: result == true ? "success" : "fail" };
900
+ } else if (typeof result == "function") {
901
+ console.log("function");
902
+ return { result: `[A function was returned]`, resultCategory: "none" };
903
+ } else if (result instanceof HTMLElement || typeof result == "string") {
904
+ return { result, resultCategory: "none" };
1040
905
  } else if (typeof result == "object") {
1041
906
  const objectResult = result;
907
+ const className = finishedTest == true ? "success-message" : "error-message";
1042
908
  if (objectResult.success != void 0 && objectResult.expected != void 0 && objectResult.value != void 0) {
1043
- const trueMessage = beforeOrAfter == void 0 ? "Passed" : "Success";
1044
- const falseMessage = beforeOrAfter == void 0 ? "Failed" : "Fail";
1045
- const defaultResult = this.#createDefaultResult(
1046
- `${objectResult.success == true ? `${trueMessage}:` : `${falseMessage}:`}
909
+ return {
910
+ result: `<code class="code" part="code">
911
+ <pre class="pre ${className}" part="pre ${className}">${objectResult.success == true ? "Passed" : "Failed"}
1047
912
  Expected:${objectResult.expected}
1048
- Result:${objectResult.value}`,
1049
- objectResult.success,
1050
- beforeOrAfter
1051
- );
1052
- this.#setTestResult(testElement, defaultResult, finishedTest, beforeOrAfter);
913
+ Result:${objectResult.value}</pre>
914
+ </code>`,
915
+ resultCategory: objectResult.success == true ? "success" : "fail"
916
+ };
917
+ } else if (objectResult.success != void 0) {
918
+ return {
919
+ result: `<code class="code" part="code">
920
+ <pre class="pre ${className}" part="pre ${className}">${JSON.stringify(result, void 0, 2)}</pre>
921
+ </code>`,
922
+ resultCategory: objectResult.success == true ? "success" : "fail"
923
+ };
924
+ } else {
925
+ const className2 = finishedTest == true ? "success-message" : "error-message";
926
+ return {
927
+ result: `<code class="code" part="code">
928
+ <pre class="pre ${className2}" part="pre ${className2}">${JSON.stringify(result, void 0, 2)}</pre>
929
+ </code>`,
930
+ resultCategory: finishedTest == true ? "success" : "fail"
931
+ };
1053
932
  }
1054
933
  }
1055
- const detailsElement = testElement.querySelector("details");
1056
- if (detailsElement != null) {
1057
- detailsElement.open = true;
934
+ throw new Error("Unable to parse result type: Unknown result type");
935
+ }
936
+ async createTestContext(testElement) {
937
+ const context = {
938
+ detail: {},
939
+ codeTestsElement: this.codeTestsElement,
940
+ testElement,
941
+ messageElement: testElement?.findElement(".message")
942
+ };
943
+ if (this.codeTestsElement.state.contextHook != null) {
944
+ await this.codeTestsElement.state.contextHook(context);
1058
945
  }
946
+ this.codeTestsElement.dispatchEvent(new CustomEvent(CodeTestEvent.Context, { bubbles: true, composed: true, detail: { context } }));
947
+ return context;
1059
948
  }
1060
- #handleHookResult(result, finishedTest, beforeOrAfter, required, error) {
1061
- if (result instanceof HTMLElement) {
1062
- this.#setHookResult(result, finishedTest, beforeOrAfter, required);
1063
- } else {
1064
- let defaultResult;
1065
- if (result == void 0) {
1066
- defaultResult = this.#createDefaultResult(finishedTest == true ? "Hook Ran Successfully" : `Failed${error != null ? `:
1067
- ${error.message}` : ""}`, finishedTest);
1068
- this.#setHookResult(defaultResult, finishedTest, beforeOrAfter, required);
1069
- } else if (typeof result == "string") {
1070
- defaultResult = this.#createDefaultResult(`${result}${error == null ? "" : `:
1071
- ${error.message}`}`, finishedTest);
1072
- this.#setHookResult(defaultResult, finishedTest, beforeOrAfter, required);
1073
- } else if (typeof result == "object") {
1074
- const objectResult = result;
1075
- if (objectResult.success != void 0 && objectResult.expected != void 0 && objectResult.value != void 0) {
1076
- defaultResult = this.#createDefaultResult(
1077
- `${objectResult.success == true ? "Success:" : "Fail:"}
1078
- Expected:${objectResult.expected}
1079
- Result:${objectResult.value}`,
1080
- objectResult.success
1081
- );
1082
- this.#setHookResult(defaultResult, finishedTest, beforeOrAfter, required);
1083
- }
1084
- }
949
+ //#endregion Utils
950
+ }
951
+ function generateId() {
952
+ const rnd = new Uint8Array(20);
953
+ crypto.getRandomValues(rnd);
954
+ const b64 = [].slice.apply(rnd).map(function(ch) {
955
+ return String.fromCharCode(ch);
956
+ }).join("");
957
+ const secret = btoa(b64).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
958
+ return secret;
959
+ }
960
+ class TestPromise extends Promise {
961
+ async toBeDefined(valueName) {
962
+ const target = await this;
963
+ if (target == void 0) {
964
+ throw new Error(`${valueName != null ? valueName : "Value"} is undefined`);
1085
965
  }
1086
- const detailsElement = this.getElement(`${beforeOrAfter}-all-details`);
1087
- if (detailsElement != null) {
1088
- detailsElement.open = true;
966
+ }
967
+ async toBe(value, exact = false) {
968
+ const target = await this;
969
+ const result = exact == true ? target === value : target == value;
970
+ if (result == false) {
971
+ throw new Error(` Value is not equal.
972
+ Expected: ${value}
973
+ Result: ${target}`);
1089
974
  }
1090
975
  }
1091
- static create(properties) {
1092
- const element = document.createElement("code-tests");
1093
- return element;
976
+ async toContainText(value) {
977
+ const target = await this;
978
+ if (target instanceof HTMLElement) {
979
+ return { success: target.textContent.includes(value), index: target.textContent.indexOf(value) };
980
+ }
981
+ if (typeof target != "string") {
982
+ return false;
983
+ }
984
+ return { success: target.includes(value), index: target.indexOf(value) };
1094
985
  }
1095
- #tests = /* @__PURE__ */ new Map();
1096
- #addTest(description, test) {
1097
- const testId = generateId();
1098
- this.#tests.set(testId, test);
1099
- const testElement = this.#createTest(testId, description);
1100
- this.getElement("tests").append(testElement);
1101
- return testId;
986
+ async toHaveAttribute(value) {
987
+ const target = await this;
988
+ if (!(target instanceof HTMLElement)) {
989
+ throw new Error("Unable to check for attribute on non-HTMLElement target");
990
+ }
991
+ if (target.getAttribute(value)) {
992
+ throw new Error("Target does not have attribute");
993
+ }
1102
994
  }
1103
- #createTest(testId, description) {
1104
- const testElement = document.createElement("li");
1105
- testElement.dataset.testId = testId;
1106
- testElement.classList.add("test");
1107
- testElement.part.add("test");
1108
- const detailsElement = document.createElement("details");
1109
- detailsElement.classList.add("test-details");
1110
- detailsElement.part.add("test-details");
1111
- const summaryElement = document.createElement("summary");
1112
- summaryElement.classList.add("test-summary");
1113
- summaryElement.part.add("test-summary");
1114
- const resultIcon = document.createElement("div");
1115
- resultIcon.classList.add("result-icon");
1116
- resultIcon.part.add("result-icon");
1117
- summaryElement.append(resultIcon);
1118
- const descriptionElement = document.createElement("span");
1119
- descriptionElement.classList.add("description", "test-description");
1120
- descriptionElement.textContent = description;
1121
- summaryElement.append(descriptionElement);
1122
- const runButton = document.createElement("button");
1123
- runButton.classList.add("run", "test-run");
1124
- runButton.part.add("run", "test-run");
1125
- runButton.textContent = "Run Test";
1126
- runButton.title = "Run Test";
1127
- summaryElement.append(runButton);
1128
- const beforeResultElement = document.createElement("div");
1129
- beforeResultElement.classList.add("before-result", "test-before-result");
1130
- beforeResultElement.part.add("before-result", "test-before-result");
1131
- const resultElement = document.createElement("div");
1132
- resultElement.classList.add("result", "test-result");
1133
- resultElement.part.add("result", "test-result");
1134
- const afterResultElement = document.createElement("div");
1135
- afterResultElement.classList.add("after-result", "test-after-result");
1136
- afterResultElement.part.add("after-result", "test-after-result");
1137
- detailsElement.append(summaryElement);
1138
- detailsElement.append(beforeResultElement);
1139
- detailsElement.append(resultElement);
1140
- detailsElement.append(afterResultElement);
1141
- testElement.append(detailsElement);
1142
- return testElement;
995
+ }
996
+ const DEFAULT_ELEMENT_SELECTOR = ":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";
997
+ function assignClassAndIdToPart(shadowRoot) {
998
+ assignIdToPart(shadowRoot);
999
+ assignClassToPart(shadowRoot);
1000
+ }
1001
+ function assignIdToPart(shadowRoot) {
1002
+ const identifiedElements = [...shadowRoot.querySelectorAll(`${DEFAULT_ELEMENT_SELECTOR}[id]`)];
1003
+ for (let i = 0; i < identifiedElements.length; i++) {
1004
+ identifiedElements[i].part.add(identifiedElements[i].id);
1143
1005
  }
1144
- #setTestResult(testElement, valueElement, success, beforeOrAfter) {
1145
- testElement.setAttribute("success", success == true ? "true" : "false");
1146
- testElement.classList.toggle("success", success);
1147
- testElement.part.toggle("success", success);
1148
- testElement.classList.toggle("fail", !success);
1149
- testElement.part.toggle("fail", !success);
1150
- const iconElement = testElement.querySelector(".result-icon");
1151
- iconElement?.classList.toggle("success", success);
1152
- iconElement?.part.toggle("success", success);
1153
- iconElement?.classList.toggle("fail", !success);
1154
- iconElement?.part.toggle("fail", !success);
1155
- const resultElement = testElement.querySelector(`.${beforeOrAfter == void 0 ? "result" : beforeOrAfter == "before" ? "before-result" : "after-result"}`);
1156
- if (resultElement == null) {
1157
- this.#addProcessError(`Unable to find result element`);
1006
+ }
1007
+ function assignClassToPart(shadowRoot) {
1008
+ const classedElements = [...shadowRoot.querySelectorAll(`${DEFAULT_ELEMENT_SELECTOR}[class]`)];
1009
+ for (let i = 0; i < classedElements.length; i++) {
1010
+ classedElements[i].part.add(...classedElements[i].classList);
1011
+ }
1012
+ }
1013
+ const Hook = {
1014
+ BeforeAll: "beforeall",
1015
+ AfterAll: "afterall",
1016
+ BeforeEach: "beforeeach",
1017
+ AfterEach: "aftereach",
1018
+ RequiredBeforeAny: "requiredbeforeany",
1019
+ RequiredAfterAny: "requiredafterany",
1020
+ Reset: "reset",
1021
+ Context: "context"
1022
+ };
1023
+ const COMPONENT_STYLESHEET = new CSSStyleSheet();
1024
+ COMPONENT_STYLESHEET.replaceSync(style);
1025
+ const COMPONENT_TAG_NAME = "code-tests";
1026
+ class CodeTestsElement extends HTMLElement {
1027
+ state = {
1028
+ isCanceled: false,
1029
+ beforeAllState: void 0,
1030
+ afterAllState: void 0,
1031
+ beforeEachState: void 0,
1032
+ afterEachState: void 0,
1033
+ requiredBeforeAnyState: void 0,
1034
+ requiredAfterAnyState: void 0,
1035
+ resetHook: void 0,
1036
+ contextHook: void 0
1037
+ };
1038
+ setState(state) {
1039
+ this.state = state;
1040
+ this.#render();
1041
+ }
1042
+ setStateProperties(state) {
1043
+ this.setState({
1044
+ ...this.state,
1045
+ ...state
1046
+ });
1047
+ }
1048
+ setTestStateProperties(key, state) {
1049
+ if (this.state[key] == null) {
1158
1050
  return;
1159
1051
  }
1160
- resultElement.innerHTML = "";
1161
- resultElement.appendChild(valueElement);
1052
+ this.setState({
1053
+ ...this.state,
1054
+ [key]: {
1055
+ ...this.state[key],
1056
+ ...state
1057
+ }
1058
+ });
1162
1059
  }
1163
- #createDefaultResult(message, success, beforeOrAfter) {
1164
- const codeElement = document.createElement("code");
1165
- codeElement.classList.add("code");
1166
- codeElement.part.add("code");
1167
- const preElement = document.createElement("pre");
1168
- preElement.textContent = message;
1169
- const className = success == true ? "success-message" : "error-message";
1170
- preElement.classList.add("pre", className);
1171
- preElement.part.add("pre", className);
1172
- codeElement.appendChild(preElement);
1173
- return codeElement;
1060
+ findElement(query) {
1061
+ return this.shadowRoot.querySelector(query);
1174
1062
  }
1175
- #setHookResult(valueElement, success, beforeOrAfter, required) {
1176
- const selector = required == true ? `required-${beforeOrAfter}-any` : `${beforeOrAfter}-all`;
1177
- const detailsElement = this.getElement(`${selector}-details`);
1178
- const resultsElement = this.getElement(`${selector}-results`);
1179
- detailsElement.setAttribute("success", success == true ? "true" : "false");
1180
- detailsElement.classList.toggle("success", success);
1181
- detailsElement.part.toggle("success", success);
1182
- detailsElement.classList.toggle("fail", !success);
1183
- detailsElement.part.toggle("fail", !success);
1184
- resultsElement.innerHTML = "";
1185
- resultsElement.appendChild(valueElement);
1063
+ findElements(query) {
1064
+ return Array.from(this.shadowRoot.querySelectorAll(query));
1186
1065
  }
1187
- #addProcessError(message, error) {
1188
- if (error instanceof Error) {
1189
- message += `
1190
- ${error.message}`;
1191
- console.error(error);
1192
- }
1193
- const errorElement = document.createElement("li");
1194
- errorElement.classList.add("error", "process-error");
1195
- errorElement.part.add("error", "process-error");
1196
- const codeElement = document.createElement("code");
1197
- codeElement.classList.add("code", "process-error-code");
1198
- codeElement.part.add("code", "process-error-code");
1199
- const preElement = document.createElement("pre");
1200
- preElement.classList.add("pre", "process-error-pre");
1201
- preElement.part.add("pre", "process-error-pre");
1202
- preElement.textContent = message;
1203
- codeElement.append(preElement);
1204
- errorElement.append(codeElement);
1205
- this.getElement("tests").append(errorElement);
1066
+ getIsRunning() {
1067
+ const testsAreRunning = this.findElements("code-test").find((item) => item.isRunning() == true) != null;
1068
+ return testsAreRunning == true || this.state.requiredBeforeAnyState?.isRunning == true || this.state.requiredAfterAnyState?.isRunning == true || this.state.beforeAllState?.isRunning == true || this.state.afterAllState?.isRunning == true;
1206
1069
  }
1207
- #updateListType(type) {
1208
- if (type == "ordered") {
1209
- const list = this.shadowRoot.querySelector("ul");
1210
- if (list == null) {
1211
- return;
1070
+ getResultCategory() {
1071
+ const testCategory = this.findElements("code-test").reduce((result, item, _index) => {
1072
+ const category = item.resultCategory();
1073
+ if (result == "fail" || category == "fail") {
1074
+ return "fail";
1212
1075
  }
1213
- const items = this.shadowRoot?.querySelectorAll("li");
1214
- const newList = document.createElement("ol");
1215
- if (items != null) {
1216
- newList.append(...items);
1076
+ if ((result == "success" || result == "") && category == "success") {
1077
+ return "success";
1217
1078
  }
1218
- newList.id = "tests";
1219
- list.replaceWith(newList);
1220
- } else {
1221
- const list = this.shadowRoot.querySelector("ol");
1222
- if (list == null) {
1223
- return;
1079
+ if (category == "none") {
1080
+ return "none";
1224
1081
  }
1225
- const items = this.shadowRoot?.querySelectorAll("li");
1226
- const newList = document.createElement("ul");
1227
- newList.id = "tests";
1228
- if (items != null) {
1229
- newList.append(...items);
1082
+ return "none";
1083
+ }, "");
1084
+ const states = [
1085
+ this.state.requiredBeforeAnyState,
1086
+ this.state.requiredAfterAnyState,
1087
+ this.state.beforeAllState,
1088
+ this.state.afterAllState
1089
+ ];
1090
+ const statesCategory = states.reduce((result, item, _index) => {
1091
+ if (item == null) {
1092
+ return null;
1230
1093
  }
1231
- list.replaceWith(newList);
1094
+ const category = item?.resultCategory;
1095
+ if (result == "fail" || category == "fail") {
1096
+ return "fail";
1097
+ }
1098
+ if ((result == "success" || result == "") && category == "success") {
1099
+ return "success";
1100
+ }
1101
+ if (category == "none") {
1102
+ return "none";
1103
+ }
1104
+ return "none";
1105
+ }, "");
1106
+ if (testCategory == "none" && statesCategory == null) {
1107
+ return "none";
1108
+ } else if (testCategory == "fail" || statesCategory == "fail") {
1109
+ return "fail";
1110
+ } else if (testCategory == "success" && statesCategory == "success") {
1111
+ return "success";
1112
+ }
1113
+ return "none";
1114
+ }
1115
+ #contextManager;
1116
+ constructor() {
1117
+ super();
1118
+ this.attachShadow({ mode: "open" });
1119
+ this.shadowRoot.innerHTML = html;
1120
+ this.shadowRoot.adoptedStyleSheets.push(COMPONENT_STYLESHEET);
1121
+ }
1122
+ connectedCallback() {
1123
+ this.#init();
1124
+ }
1125
+ disconnectedCallback() {
1126
+ this.#destroy();
1127
+ }
1128
+ #isInitialized = false;
1129
+ async #init() {
1130
+ if (this.#isInitialized == true) {
1131
+ return;
1232
1132
  }
1133
+ assignClassAndIdToPart(this.shadowRoot);
1134
+ this.addEventListener("click", this.#boundClickHandler);
1135
+ await new Promise((resolve) => requestAnimationFrame(() => {
1136
+ this.#contextManager = new ContextManager(this);
1137
+ resolve();
1138
+ }));
1139
+ this.#isInitialized = true;
1140
+ if (this.getAttribute("auto") == "false") {
1141
+ return;
1142
+ }
1143
+ this.reloadTests();
1144
+ }
1145
+ #destroy() {
1146
+ this.removeEventListener("click", this.#boundClickHandler);
1233
1147
  }
1234
- static observedAttributes = ["in-order"];
1235
- attributeChangedCallback(attributeName, oldValue, newValue) {
1236
- if (attributeName == "in-order") {
1237
- if (newValue == void 0) {
1238
- this.#updateListType("unordered");
1148
+ #boundClickHandler = this.#onClick.bind(this);
1149
+ #onClick(event) {
1150
+ const runAllButton = event.composedPath().find((item) => item instanceof HTMLButtonElement && item.id == "run-all-button");
1151
+ if (runAllButton != null) {
1152
+ if (this.classList.contains("running")) {
1153
+ this.cancel();
1154
+ } else if (this.classList.contains("fail") || this.classList.contains("success")) {
1155
+ this.reset();
1239
1156
  } else {
1240
- this.#updateListType("ordered");
1157
+ this.runTests();
1158
+ }
1159
+ return;
1160
+ }
1161
+ const reloadButton = event.composedPath().find((item) => item instanceof HTMLButtonElement && item.id == "reload-button");
1162
+ if (reloadButton != null) {
1163
+ this.reloadTests();
1164
+ }
1165
+ const runButton = event.composedPath().find((item) => item instanceof HTMLButtonElement && item.classList.contains("run-test-button"));
1166
+ if (runButton == null) {
1167
+ return;
1168
+ }
1169
+ const test = runButton.closest("code-test") ?? void 0;
1170
+ this.#contextManager.runTest(test, false);
1171
+ }
1172
+ #getCurrentTestsPath() {
1173
+ return this.getAttribute("src") ?? this.getAttribute("test") ?? this.getAttribute("tests") ?? this.getAttribute("run") ?? this.getAttribute("path") ?? void 0;
1174
+ }
1175
+ #render() {
1176
+ const isRunning = this.getIsRunning();
1177
+ const resultCategory = this.getResultCategory();
1178
+ const hasBeforeAllState = this.state.beforeAllState != null;
1179
+ const hasBeforeEachState = this.state.beforeEachState != null;
1180
+ const hasRequiredBeforeAnyState = this.state.requiredAfterAnyState != null;
1181
+ const hasAfterAllState = this.state.beforeAllState != null;
1182
+ const hasAfterEachState = this.state.beforeEachState != null;
1183
+ const hasRequiredAfterAnyState = this.state.requiredAfterAnyState != null;
1184
+ const hasBeforeHook = hasRequiredBeforeAnyState == true || hasBeforeAllState == true || hasBeforeEachState == true;
1185
+ const hasAfterHook = hasRequiredAfterAnyState == true || hasAfterAllState == true || hasAfterEachState == true;
1186
+ this.classList.toggle("canceled", this.state.isCanceled);
1187
+ this.part.toggle("canceled", this.state.isCanceled);
1188
+ this.classList.toggle("running", isRunning == true);
1189
+ this.part.toggle("running", isRunning == true);
1190
+ this.toggleAttribute("success", resultCategory == "success");
1191
+ this.classList.toggle("success", resultCategory == "success");
1192
+ this.part.toggle("success", resultCategory == "success");
1193
+ this.classList.toggle("fail", resultCategory == "fail");
1194
+ this.part.toggle("fail", resultCategory == "fail");
1195
+ this.classList.toggle("has-before-hook", hasBeforeHook);
1196
+ this.part.toggle("has-before-hook", hasBeforeHook);
1197
+ this.classList.toggle("has-after-hook", hasAfterHook);
1198
+ this.part.toggle("has-after-hook", hasAfterHook);
1199
+ this.classList.toggle("has-before-all-hook", hasBeforeAllState);
1200
+ this.part.toggle("has-before-all-hook", hasBeforeAllState);
1201
+ this.classList.toggle("has-after-all-hook", hasAfterAllState);
1202
+ this.part.toggle("has-after-all-hook", hasAfterAllState);
1203
+ this.classList.toggle("has-before-each-hook", hasBeforeEachState);
1204
+ this.part.toggle("has-before-each-hook", hasBeforeEachState);
1205
+ this.classList.toggle("has-after-each-hook", hasAfterEachState);
1206
+ this.part.toggle("has-after-each-hook", hasAfterEachState);
1207
+ this.classList.toggle("has-required-before-hook", hasRequiredBeforeAnyState);
1208
+ this.part.toggle("has-required-before-hook", hasRequiredBeforeAnyState);
1209
+ this.classList.toggle("has-required-after-hook", hasRequiredAfterAnyState);
1210
+ this.part.toggle("has-required-after-hook", hasRequiredAfterAnyState);
1211
+ const runAllButtonLabel = this.findElement(".run-all-button-label");
1212
+ if (runAllButtonLabel != null) {
1213
+ runAllButtonLabel.textContent = isRunning == true ? "Cancel" : resultCategory == "fail" ? "Reset" : "Run Tests";
1214
+ runAllButtonLabel.title = isRunning == true ? "Cancel the testing" : resultCategory == "fail" ? "Reset the tests so they can be run again" : "Run the tests";
1215
+ }
1216
+ const runAllIcon = this.findElement(".run-all-button-icon");
1217
+ if (runAllIcon != null) {
1218
+ runAllIcon.innerHTML = isRunning == true ? '<use href="#icon-definition_cancel"></use>' : resultCategory == "fail" ? '<use href="#icon-definition_reset"></use>' : '<use href="#icon-definition_arrow"></use>';
1219
+ }
1220
+ this.#renderHook(this.state.beforeAllState, "#before-all-results");
1221
+ this.#renderHook(this.state.afterAllState, "#after-all-results");
1222
+ this.#renderHook(this.state.requiredBeforeAnyState, "#required-before-any-results");
1223
+ this.#renderHook(this.state.requiredAfterAnyState, "#required-after-any-results");
1224
+ const title = this.findElement("#title");
1225
+ if (title != null) {
1226
+ title.textContent = this.getAttribute("label") ?? "Tests";
1227
+ }
1228
+ this.#renderGroupResults();
1229
+ }
1230
+ #renderHook(hookState, elementSelector) {
1231
+ const resultsElement = this.findElement(elementSelector);
1232
+ if (hookState?.resultContent instanceof HTMLElement) {
1233
+ resultsElement.append(hookState.resultContent);
1234
+ } else if (typeof hookState?.resultContent == "string") {
1235
+ resultsElement.innerHTML = hookState.resultContent;
1236
+ }
1237
+ const detailsElement = resultsElement.closest("details");
1238
+ detailsElement.toggleAttribute("open", hookState != void 0 && hookState.resultCategory != "none");
1239
+ detailsElement.classList.toggle("running", hookState?.isRunning == true);
1240
+ detailsElement.part.toggle("running", hookState?.isRunning == true);
1241
+ detailsElement.toggleAttribute("success", hookState?.resultCategory == "success");
1242
+ detailsElement.classList.toggle("success", hookState?.resultCategory == "success");
1243
+ detailsElement.part.toggle("success", hookState?.resultCategory == "success");
1244
+ detailsElement.classList.toggle("fail", hookState?.resultCategory == "fail");
1245
+ detailsElement.part.toggle("fail", hookState?.resultCategory == "fail");
1246
+ }
1247
+ #renderGroupResults() {
1248
+ const results = this.collectTestResults();
1249
+ const progress = this.findElement("#results-progress-value");
1250
+ if (progress != null) {
1251
+ progress.max = results.totalTests;
1252
+ progress.value = results.totalPassed;
1253
+ }
1254
+ const totalPassedElement = this.findElement("#total-tests-passed-value");
1255
+ if (totalPassedElement != null) {
1256
+ totalPassedElement.textContent = results.totalPassed.toString();
1257
+ }
1258
+ const totalTestsElement = this.findElement("#total-tests-count-value");
1259
+ if (totalTestsElement != null) {
1260
+ totalTestsElement.textContent = results.totalTests.toString();
1261
+ }
1262
+ const totalPercentElement = this.findElement("#passed-total-percent-value");
1263
+ if (totalPercentElement != null) {
1264
+ totalPercentElement.textContent = results.totalPercentage.toFixed(1);
1265
+ }
1266
+ const durationElement = this.findElement("#duration-value");
1267
+ if (durationElement != null) {
1268
+ durationElement.textContent = results.duration > 10 ? results.duration.toFixed(0) : results.duration.toFixed(2);
1269
+ }
1270
+ }
1271
+ collectTestResults() {
1272
+ const tests = this.findElements("code-test");
1273
+ const totalTests = tests.length;
1274
+ const totalPassed = tests.filter((item) => item.state.testState?.resultCategory == "success").length;
1275
+ const totalPercentage = totalTests == 0 ? 0 : totalPassed / totalTests * 100;
1276
+ const duration = tests.reduce((result, item, _index) => {
1277
+ return result + (item.state.testState?.duration ?? 0);
1278
+ }, 0);
1279
+ const results = {
1280
+ totalTests,
1281
+ totalPassed,
1282
+ totalPercentage,
1283
+ duration
1284
+ };
1285
+ return results;
1286
+ }
1287
+ async runTests() {
1288
+ const tests = this.findElements("code-test");
1289
+ return this.#contextManager.runTests(tests);
1290
+ }
1291
+ async reloadTests() {
1292
+ this.findElement("#tests").innerHTML = "";
1293
+ await this.reset();
1294
+ const testsPath = this.#getCurrentTestsPath();
1295
+ this.#contextManager.loadTests(testsPath);
1296
+ }
1297
+ async reset() {
1298
+ const tests = this.findElements("code-test");
1299
+ for (let i = 0; i < tests.length; i++) {
1300
+ const test = tests[i];
1301
+ const beforeEachState2 = this.state.beforeEachState != null ? {
1302
+ resultCategory: "none",
1303
+ resultContent: "",
1304
+ hasRun: this.state.beforeEachState.hasRun,
1305
+ isRunning: this.state.beforeEachState.isRunning,
1306
+ duration: 0
1307
+ } : void 0;
1308
+ const afterEachState2 = this.state.afterEachState != null ? {
1309
+ resultCategory: "none",
1310
+ resultContent: "",
1311
+ hasRun: this.state.afterEachState.hasRun,
1312
+ isRunning: this.state.afterEachState.isRunning,
1313
+ duration: 0
1314
+ } : void 0;
1315
+ if (beforeEachState2 != null) {
1316
+ test.state.beforeEachState = beforeEachState2;
1317
+ }
1318
+ if (afterEachState2 != null) {
1319
+ test.state.afterEachState = afterEachState2;
1320
+ }
1321
+ test.reset();
1322
+ }
1323
+ const beforeAllState = this.state.beforeAllState == void 0 ? void 0 : { resultContent: "", resultCategory: "none", test: this.state.beforeAllState.test, isRunning: false, hasRun: false, duration: 0 };
1324
+ const afterAllState = this.state.afterAllState == void 0 ? void 0 : { resultContent: "", resultCategory: "none", test: this.state.afterAllState.test, isRunning: false, hasRun: false, duration: 0 };
1325
+ const beforeEachState = this.state.beforeEachState == void 0 ? void 0 : { resultContent: "", resultCategory: "none", test: this.state.beforeEachState.test, isRunning: false, hasRun: false, duration: 0 };
1326
+ const afterEachState = this.state.afterEachState == void 0 ? void 0 : { resultContent: "", resultCategory: "none", test: this.state.afterEachState.test, isRunning: false, hasRun: false, duration: 0 };
1327
+ const requiredBeforeAnyState = this.state.requiredBeforeAnyState == void 0 ? void 0 : { resultContent: "", resultCategory: "none", test: this.state.requiredBeforeAnyState.test, isRunning: false, hasRun: false, duration: 0 };
1328
+ const requiredAfterAnyState = this.state.requiredAfterAnyState == void 0 ? void 0 : { resultContent: "", resultCategory: "none", test: this.state.requiredAfterAnyState.test, isRunning: false, hasRun: false, duration: 0 };
1329
+ this.setStateProperties({
1330
+ isCanceled: false,
1331
+ beforeAllState,
1332
+ afterAllState,
1333
+ beforeEachState,
1334
+ afterEachState,
1335
+ requiredAfterAnyState,
1336
+ requiredBeforeAnyState
1337
+ });
1338
+ this.#contextManager.shouldContinueRunningTests = true;
1339
+ if (this.state.resetHook != null) {
1340
+ await this.state.resetHook(await this.#contextManager.createTestContext());
1341
+ }
1342
+ this.dispatchEvent(new CustomEvent(CodeTestEvent.Reset, { bubbles: true, composed: true }));
1343
+ }
1344
+ cancel() {
1345
+ this.state.isCanceled = true;
1346
+ this.#contextManager.shouldContinueRunningTests = false;
1347
+ this.classList.add("canceled");
1348
+ this.part.add("canceled");
1349
+ this.dispatchEvent(new CustomEvent(CodeTestEvent.Cancel, { bubbles: true, composed: true }));
1350
+ }
1351
+ static observedAttributes = ["open", "label"];
1352
+ attributeChangedCallback(attributeName, _oldValue, newValue) {
1353
+ if (attributeName == "open") {
1354
+ this.findElement("#component-details").toggleAttribute("open", newValue != void 0);
1355
+ } else if (attributeName == "label") {
1356
+ const title = this.findElement("#title");
1357
+ if (title != null) {
1358
+ title.textContent = newValue ?? "Tests";
1241
1359
  }
1242
1360
  }
1243
1361
  }
1244
- };
1245
- function generateId() {
1246
- const rnd = new Uint8Array(20);
1247
- crypto.getRandomValues(rnd);
1248
- const b64 = [].slice.apply(rnd).map(function(ch) {
1249
- return String.fromCharCode(ch);
1250
- }).join("");
1251
- const secret = btoa(b64).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
1252
- return secret;
1253
1362
  }
1254
1363
  if (customElements.get(COMPONENT_TAG_NAME) == null) {
1255
1364
  customElements.define(COMPONENT_TAG_NAME, CodeTestsElement);
1256
1365
  }
1366
+ function expect(value) {
1367
+ const promise = new TestPromise(async (resolve, _reject) => {
1368
+ if (value instanceof Promise) {
1369
+ const result = await value;
1370
+ resolve(result);
1371
+ return;
1372
+ }
1373
+ resolve(value);
1374
+ });
1375
+ return promise;
1376
+ }
1377
+ async function prompt(host, parentElement, message, options) {
1378
+ return new Promise((resolve, _reject) => {
1379
+ const template = options?.template ?? host.querySelector(".prompt-template") ?? host.findElement("#prompt-template");
1380
+ const promptElement = createElementFromTemplate(template);
1381
+ promptElement.querySelector(".label").textContent = message;
1382
+ const clickHandler = (event) => {
1383
+ const composedPath = event.composedPath();
1384
+ const acceptButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("accept"));
1385
+ if (acceptButton != null) {
1386
+ const result = options?.onAccept?.() ?? true;
1387
+ promptElement.removeEventListener("click", clickHandler);
1388
+ resolve(result);
1389
+ return;
1390
+ }
1391
+ const rejectButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("reject"));
1392
+ if (rejectButton != null) {
1393
+ const result = options?.onReject?.() ?? false;
1394
+ promptElement.removeEventListener("click", clickHandler);
1395
+ resolve(result);
1396
+ return;
1397
+ }
1398
+ };
1399
+ promptElement.addEventListener("click", clickHandler);
1400
+ if (options?.acceptLabel != null) {
1401
+ promptElement.querySelector(".accept").textContent = options.acceptLabel;
1402
+ }
1403
+ if (options?.rejectLabel != null) {
1404
+ promptElement.querySelector(".reject").textContent = options.rejectLabel;
1405
+ }
1406
+ parentElement.append(promptElement);
1407
+ });
1408
+ }
1409
+ function createElementFromTemplate(target, parent) {
1410
+ const templateNode = target instanceof HTMLTemplateElement ? target : document.querySelector(target);
1411
+ if (templateNode == null) {
1412
+ throw new Error(`Unable to find template element from selector: ${target}`);
1413
+ }
1414
+ const firstChild = templateNode.content.cloneNode(true).firstElementChild;
1415
+ if (firstChild == null) {
1416
+ throw new Error(`Unable to find first child of template element`);
1417
+ }
1418
+ parent?.append(firstChild);
1419
+ return firstChild;
1420
+ }
1257
1421
  export {
1258
- CodeTestEventType,
1259
- CodeTests,
1422
+ CodeTestElement,
1423
+ CodeTestEvent,
1260
1424
  CodeTestsElement,
1261
- HookType,
1425
+ Hook,
1426
+ TestPromise,
1427
+ createElementFromTemplate,
1262
1428
  expect,
1263
1429
  prompt
1264
1430
  };