@magnit-ce/code-tests 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/code-tests.d.ts +4 -0
- package/dist/code-tests.js +65 -27
- package/dist/code-tests.min.js +1 -1
- package/dist/code-tests.umd.js +65 -27
- package/dist/code-tests.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/code-tests.d.ts
CHANGED
package/dist/code-tests.js
CHANGED
|
@@ -18,15 +18,7 @@ const style = `:host
|
|
|
18
18
|
--border-process: solid 1px var(--primary-process);
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
--surface-test-summary: var(--uchu-gray);
|
|
23
|
-
--surface-hook-summary: var(--uchu-light-purple);
|
|
24
|
-
--surface-hook-any-summary: var(--uchu-light-blue);
|
|
25
|
-
|
|
26
|
-
--border-test: solid 1px var(--uchu-dark-gray);
|
|
27
|
-
--border-hook: solid 1px var(--uchu-dark-purple);
|
|
28
|
-
--border-hook-any: solid 1px var(--uchu-dark-blue);
|
|
29
|
-
--border-button: solid 1px var(--uchu-blue);
|
|
21
|
+
--surface-footer: rgb(0 0 0 / .04);
|
|
30
22
|
|
|
31
23
|
--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>');
|
|
32
24
|
--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');
|
|
@@ -38,6 +30,13 @@ const style = `:host
|
|
|
38
30
|
font-family: sans-serif;
|
|
39
31
|
font-size: 12px;
|
|
40
32
|
}
|
|
33
|
+
@media (prefers-color-scheme: dark)
|
|
34
|
+
{
|
|
35
|
+
:host
|
|
36
|
+
{
|
|
37
|
+
--surface-footer: rgb(255 255 255 / .1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
41
40
|
|
|
42
41
|
#header
|
|
43
42
|
{
|
|
@@ -49,13 +48,16 @@ const style = `:host
|
|
|
49
48
|
#title
|
|
50
49
|
{
|
|
51
50
|
flex: 1;
|
|
51
|
+
white-space: nowrap;
|
|
52
|
+
overflow: hidden;
|
|
53
|
+
text-overflow: ellipsis;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
#tests
|
|
55
57
|
,#component-content
|
|
56
58
|
{
|
|
57
59
|
display: grid;
|
|
58
|
-
gap: var(--gap);
|
|
60
|
+
gap: var(--gap-small);
|
|
59
61
|
grid-auto-rows: max-content;
|
|
60
62
|
}
|
|
61
63
|
|
|
@@ -99,11 +101,13 @@ summary > .run-test-button
|
|
|
99
101
|
|
|
100
102
|
summary:not(#component-summary)
|
|
101
103
|
{
|
|
102
|
-
padding: var(--gap-small)
|
|
104
|
+
padding: var(--gap-small);
|
|
103
105
|
}
|
|
104
106
|
#component-summary
|
|
105
107
|
{
|
|
106
|
-
padding: var(--gap-small)
|
|
108
|
+
padding: var(--gap) var(--gap-small);
|
|
109
|
+
border-bottom: solid 1px;
|
|
110
|
+
margin-bottom: var(--gap-small);
|
|
107
111
|
}
|
|
108
112
|
|
|
109
113
|
|
|
@@ -305,6 +309,10 @@ code-test
|
|
|
305
309
|
code-test > details > summary > .description
|
|
306
310
|
{
|
|
307
311
|
flex: 1;
|
|
312
|
+
white-space: nowrap;
|
|
313
|
+
overflow: hidden;
|
|
314
|
+
text-overflow: ellipsis;
|
|
315
|
+
width: 0; /* hack to make overflow work right; "contain: inline-size" is correct fix, but it's too new to implement on jan 25, 2026; */
|
|
308
316
|
}
|
|
309
317
|
:host(:not([ordered="false"])) code-test > details > summary > .description::before
|
|
310
318
|
{
|
|
@@ -316,7 +324,6 @@ code-test > details > summary > .description
|
|
|
316
324
|
{
|
|
317
325
|
border-radius: 3px;
|
|
318
326
|
border: solid 1px;
|
|
319
|
-
/* background: rgb(0 0 0 / .2); */
|
|
320
327
|
font-family: monospace;
|
|
321
328
|
text-transform: uppercase;
|
|
322
329
|
font-size: 11px;
|
|
@@ -327,6 +334,10 @@ code-test > details > summary > .description
|
|
|
327
334
|
{
|
|
328
335
|
display: flex;
|
|
329
336
|
justify-content: flex-end;
|
|
337
|
+
border-top: solid 1px;
|
|
338
|
+
border-bottom: solid 1px;
|
|
339
|
+
background: var(--surface-footer);
|
|
340
|
+
margin-top: var(--gap-small);
|
|
330
341
|
}
|
|
331
342
|
#group-results
|
|
332
343
|
{
|
|
@@ -335,6 +346,19 @@ code-test > details > summary > .description
|
|
|
335
346
|
padding: var(--gap);
|
|
336
347
|
}
|
|
337
348
|
|
|
349
|
+
#results-progress-value
|
|
350
|
+
{
|
|
351
|
+
min-width: 40px;
|
|
352
|
+
width: auto;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
#duration
|
|
356
|
+
,#passed-total-pair
|
|
357
|
+
,#passed-total-percent
|
|
358
|
+
{
|
|
359
|
+
white-space: nowrap;
|
|
360
|
+
}
|
|
361
|
+
|
|
338
362
|
#passed-total-percent::before
|
|
339
363
|
{
|
|
340
364
|
content: '(';
|
|
@@ -349,7 +373,7 @@ code-test > details > summary > .description
|
|
|
349
373
|
from { transform: rotate(0deg); }
|
|
350
374
|
to { transform: rotate(360deg); }
|
|
351
375
|
}`;
|
|
352
|
-
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 <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\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"
|
|
376
|
+
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 <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\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">0</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">0</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>';
|
|
353
377
|
const CodeTestEvent = {
|
|
354
378
|
BeforeAll: "beforeall",
|
|
355
379
|
AfterAll: "afterall",
|
|
@@ -359,7 +383,11 @@ const CodeTestEvent = {
|
|
|
359
383
|
AfterHook: "afterhook",
|
|
360
384
|
Cancel: "cancel",
|
|
361
385
|
Context: "context",
|
|
362
|
-
Reset: "reset"
|
|
386
|
+
Reset: "reset",
|
|
387
|
+
TestEnd: "testend",
|
|
388
|
+
Init: "init",
|
|
389
|
+
Enabled: "enabled",
|
|
390
|
+
PromptResult: "promptresult"
|
|
363
391
|
};
|
|
364
392
|
const COMPONENT_TAG_NAME$1 = "code-test";
|
|
365
393
|
class CodeTestElement extends HTMLElement {
|
|
@@ -449,7 +477,7 @@ class CodeTestElement extends HTMLElement {
|
|
|
449
477
|
<summary class="test-summary" part="test-summary">
|
|
450
478
|
<svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>
|
|
451
479
|
<div class="result-icon test-result-icon${this.state.testState?.resultCategory != "none" ? ` ${this.state.testState?.resultCategory}` : ""}" part="result-icon"></div>
|
|
452
|
-
<span class="test-description description">${this.state.description}</span>
|
|
480
|
+
<span class="test-description description" title="${this.state.description}">${this.state.description}</span>
|
|
453
481
|
${this.state.testState?.duration != null && this.state.testState.duration > 0 ? `<span class="test-duration duration">
|
|
454
482
|
<span class="test-duration-value">${this.state.testState.duration > 10 ? this.state.testState.duration.toFixed(0) : this.state.testState.duration.toFixed(2)}</span>
|
|
455
483
|
<span class="test-duration-unit">ms</span>
|
|
@@ -797,6 +825,9 @@ class CodeTestsContext {
|
|
|
797
825
|
}
|
|
798
826
|
}
|
|
799
827
|
testContext = testContext ?? await this.createTestContext(test);
|
|
828
|
+
if (testContext.testElement == null) {
|
|
829
|
+
testContext.testElement = test;
|
|
830
|
+
}
|
|
800
831
|
if (inLoop == false) {
|
|
801
832
|
await this.runHook("requiredBeforeAnyState", void 0, testContext);
|
|
802
833
|
if (this.shouldContinueRunningTests == false) {
|
|
@@ -826,6 +857,7 @@ class CodeTestsContext {
|
|
|
826
857
|
for (let i = 0; i < tests.length; i++) {
|
|
827
858
|
tests[i].enable();
|
|
828
859
|
}
|
|
860
|
+
this.codeTestsElement.dispatchEvent(new CustomEvent(CodeTestEvent.TestEnd, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
829
861
|
}
|
|
830
862
|
async runHook(testStateName, test, testContext) {
|
|
831
863
|
const testState = this.codeTestsElement.state[testStateName];
|
|
@@ -1147,7 +1179,7 @@ class CodeTestsElement extends HTMLElement {
|
|
|
1147
1179
|
this.#context = new CodeTestsContext(this);
|
|
1148
1180
|
this.#isInitialized = true;
|
|
1149
1181
|
this.#isInitializing = false;
|
|
1150
|
-
const allowAutoLoad = this.dispatchEvent(new CustomEvent(
|
|
1182
|
+
const allowAutoLoad = this.dispatchEvent(new CustomEvent(CodeTestEvent.Init, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
1151
1183
|
if (allowAutoLoad == false) {
|
|
1152
1184
|
resolve();
|
|
1153
1185
|
return;
|
|
@@ -1194,7 +1226,7 @@ class CodeTestsElement extends HTMLElement {
|
|
|
1194
1226
|
#boundEnabledHandler = this.#enabled_onChange.bind(this);
|
|
1195
1227
|
#enabled_onChange(event) {
|
|
1196
1228
|
const input = event.target;
|
|
1197
|
-
const allowToggle = this.dispatchEvent(new CustomEvent(
|
|
1229
|
+
const allowToggle = this.dispatchEvent(new CustomEvent(CodeTestEvent.Enabled, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
1198
1230
|
if (allowToggle == false) {
|
|
1199
1231
|
event.preventDefault();
|
|
1200
1232
|
event.stopPropagation();
|
|
@@ -1242,12 +1274,12 @@ class CodeTestsElement extends HTMLElement {
|
|
|
1242
1274
|
this.part.toggle("has-required-after-hook", hasRequiredAfterAnyState);
|
|
1243
1275
|
const runAllButtonLabel = this.findElement(".run-all-button-label");
|
|
1244
1276
|
if (runAllButtonLabel != null) {
|
|
1245
|
-
runAllButtonLabel.textContent = isRunning == true ? "Cancel" : resultCategory == "fail" ? "Reset" : "Run Tests";
|
|
1246
|
-
runAllButtonLabel.title = isRunning == true ? "Cancel the testing" : resultCategory == "fail" ? "Reset the tests so they can be run again" : "Run the tests";
|
|
1277
|
+
runAllButtonLabel.textContent = isRunning == true ? "Cancel" : resultCategory == "fail" || resultCategory == "success" ? "Reset" : "Run Tests";
|
|
1278
|
+
runAllButtonLabel.title = isRunning == true ? "Cancel the testing" : resultCategory == "fail" || resultCategory == "success" ? "Reset the tests so they can be run again" : "Run the tests";
|
|
1247
1279
|
}
|
|
1248
1280
|
const runAllIcon = this.findElement(".run-all-button-icon");
|
|
1249
1281
|
if (runAllIcon != null) {
|
|
1250
|
-
runAllIcon.innerHTML = isRunning == true ? '<use href="#icon-definition_cancel"></use>' : resultCategory == "fail" ? '<use href="#icon-definition_reset"></use>' : '<use href="#icon-definition_arrow"></use>';
|
|
1282
|
+
runAllIcon.innerHTML = isRunning == true ? '<use href="#icon-definition_cancel"></use>' : resultCategory == "fail" || resultCategory == "success" ? '<use href="#icon-definition_reset"></use>' : '<use href="#icon-definition_arrow"></use>';
|
|
1251
1283
|
}
|
|
1252
1284
|
this.#renderHook(this.state.beforeAllState, "#before-all-results");
|
|
1253
1285
|
this.#renderHook(this.state.afterAllState, "#after-all-results");
|
|
@@ -1407,24 +1439,25 @@ function expect(value) {
|
|
|
1407
1439
|
return promise;
|
|
1408
1440
|
}
|
|
1409
1441
|
async function prompt(host, parentElement, message, options) {
|
|
1410
|
-
|
|
1442
|
+
let promptElement = null;
|
|
1443
|
+
const result = await new Promise((resolve, _reject) => {
|
|
1411
1444
|
const template = options?.template ?? host.querySelector(".prompt-template") ?? host.findElement("#prompt-template");
|
|
1412
|
-
|
|
1445
|
+
promptElement = createElementFromTemplate(template);
|
|
1413
1446
|
promptElement.querySelector(".label").textContent = message;
|
|
1414
1447
|
const clickHandler = (event) => {
|
|
1415
1448
|
const composedPath = event.composedPath();
|
|
1416
1449
|
const acceptButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("accept"));
|
|
1417
1450
|
if (acceptButton != null) {
|
|
1418
|
-
const
|
|
1451
|
+
const result2 = options?.onAccept?.() ?? true;
|
|
1419
1452
|
promptElement.removeEventListener("click", clickHandler);
|
|
1420
|
-
resolve(
|
|
1453
|
+
resolve(result2);
|
|
1421
1454
|
return;
|
|
1422
1455
|
}
|
|
1423
1456
|
const rejectButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("reject"));
|
|
1424
1457
|
if (rejectButton != null) {
|
|
1425
|
-
const
|
|
1458
|
+
const result2 = options?.onReject?.() ?? false;
|
|
1426
1459
|
promptElement.removeEventListener("click", clickHandler);
|
|
1427
|
-
resolve(
|
|
1460
|
+
resolve(result2);
|
|
1428
1461
|
return;
|
|
1429
1462
|
}
|
|
1430
1463
|
};
|
|
@@ -1437,6 +1470,11 @@ async function prompt(host, parentElement, message, options) {
|
|
|
1437
1470
|
}
|
|
1438
1471
|
parentElement.append(promptElement);
|
|
1439
1472
|
});
|
|
1473
|
+
if (promptElement != null) {
|
|
1474
|
+
promptElement.remove();
|
|
1475
|
+
}
|
|
1476
|
+
host.dispatchEvent(new CustomEvent(CodeTestEvent.PromptResult, { bubbles: true, composed: true, detail: { target: host, result } }));
|
|
1477
|
+
return result;
|
|
1440
1478
|
}
|
|
1441
1479
|
function createElementFromTemplate(target, parent) {
|
|
1442
1480
|
const templateNode = target instanceof HTMLTemplateElement ? target : document.querySelector(target);
|
package/dist/code-tests.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const t={BeforeAll:"beforeall",AfterAll:"afterall",BeforeTest:"beforetest",AfterTest:"aftertest",BeforeHook:"beforehook",AfterHook:"afterhook",Cancel:"cancel",Context:"context",Reset:"reset"},e="code-test";class s extends HTMLElement{state={testId:"",description:"none",isDisabled:!1,testState:void 0,beforeEachState:void 0,afterEachState:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.querySelector(t)}findElements(t){return Array.from(this.querySelectorAll(t))}isRunning(){return 1==this.state.testState?.isRunning||1==this.state.beforeEachState?.isRunning||1==this.state.afterEachState?.isRunning}hasRun(){return 1==this.state.testState?.hasRun||1==this.state.beforeEachState?.hasRun||1==this.state.afterEachState?.hasRun}resultCategory(){const t=this.state.testState?.resultCategory??"none",e=this.state.beforeEachState?.resultCategory??"none",s=this.state.afterEachState?.resultCategory??"none";return"none"==t&&"none"==e&&"none"==s?"none":null==this.state.beforeEachState&&null==this.state.afterEachState?t:null!=this.state.beforeEachState&&null==this.state.afterEachState?"fail"==t||"fail"==e?"fail":"success"==t&&"success"==e?"success":"none":null==this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==s?"fail":"success"==t&&"success"==s?"success":"none":null!=this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==e||"fail"==s?"fail":"success"==t&&"success"==e&&"success"==s?"success":"none":void 0}connectedCallback(){this.#t()}#t(){const t=null==this.state.testState?"":"boolean"==typeof this.state.testState.resultContent?1==this.state.testState.resultContent?'<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>':"number"==typeof this.state.testState.resultContent?`<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed: ${this.state.testState.resultContent.toString()}</pre></code>`:"string"==typeof this.state.testState.resultContent?this.state.testState.resultContent:"";this.innerHTML=`<details class="test-details" part="test-details" ${1==this.isRunning()||1==this.hasRun()?" open":""}>\n <summary class="test-summary" part="test-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="result-icon test-result-icon${"none"!=this.state.testState?.resultCategory?` ${this.state.testState?.resultCategory}`:""}" part="result-icon"></div>\n <span class="test-description description">${this.state.description}</span>\n ${null!=this.state.testState?.duration&&this.state.testState.duration>0?`<span class="test-duration duration">\n <span class="test-duration-value">${this.state.testState.duration>10?this.state.testState.duration.toFixed(0):this.state.testState.duration.toFixed(2)}</span>\n <span class="test-duration-unit">ms</span>\n </span>`:""}\n <button type="button" class="run-test-button" part="run-test-button" title="Run Test"${1==this.state.isDisabled?" disabled":""}>\n <slot name="run-button-content">\n <slot name="run-button-icon"><svg class="icon arrow-icon run-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-button-label"><span class="run-button-label button-label label icon">Run Test</span></slot>\n </slot>\n </button>\n </summary>\n <div class="results" part="results">\n ${null==this.state.beforeEachState?"":`<details class="before-each-details hook${"none"==this.state.beforeEachState.resultCategory?"":` ${this.state.beforeEachState.resultCategory}`}${1==this.state.beforeEachState.isRunning?" running":""}" part="before-each-details hook">\n <summary class="before-each-summary" part="before-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="before-each-result-icon result-icon${"none"!=this.state.beforeEachState.resultCategory?` ${this.state.beforeEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="before-each-description description hook-name">Before Each Hook</span>\n </summary>\n <div class="before-each-result result message" part="before-each-result result message">${"string"!=typeof this.state.beforeEachState.resultContent?"":this.state.beforeEachState.resultContent}</div>\n </details>`}\n ${null==this.state.testState?"":null==this.state.beforeEachState&&null==this.state.afterEachState?`<div class="test-result result message" part="test-result result message">${t}</div>`:`<details class="processing-details${"none"==this.state.testState.resultCategory?"":` ${this.state.testState.resultCategory}`}${1==this.state.testState.isRunning?" running":""}" part="processing-details"${1==this.state.testState.hasRun?" open":""}>\n <summary class="processing-summary" part="processing-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="processing-result-icon result-icon${"none"!=this.state.testState.resultCategory?` ${this.state.testState.resultCategory}`:""}" part="processing-result-icon result-icon"></div>\n <span class="processing-description description">Test</span>\n </summary>\n <div class="test-result result message" part="test-result result message">${t}</div>\n </details>`} \n ${null==this.state.afterEachState?"":`<details class="after-each-details hook${"none"==this.state.afterEachState.resultCategory?"":` ${this.state.afterEachState.resultCategory}`}${1==this.state.afterEachState.isRunning?" running":""}" part="after-each-detail hooks">\n <summary class="after-each-summary" part="after-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="after-each-result-icon result-icon${"none"!=this.state.afterEachState.resultCategory?` ${this.state.afterEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="after-each-description description hook-name">After Each Hook</span>\n </summary>\n <div class="after-each-result result message" part="after-each-result result message">${"string"!=typeof this.state.afterEachState.resultContent?"":this.state.afterEachState.resultContent}</div>\n </details>`}\n </div>\n </details>`,this.dataset.testId=this.state.testId,this.classList.add("test"),this.part.add("test"),this.toggleAttribute("success","success"==this.resultCategory()),this.classList.toggle("success","success"==this.resultCategory()),this.part.toggle("success","success"==this.resultCategory()),this.classList.toggle("fail","fail"==this.resultCategory()),this.part.toggle("fail","fail"==this.resultCategory()),this.classList.toggle("running",this.isRunning()),this.part.toggle("running",this.isRunning()),this.state.beforeEachState?.resultContent instanceof HTMLElement&&this.querySelector(".before-each-result").append(this.state.beforeEachState.resultContent),this.state.testState?.resultContent instanceof HTMLElement&&this.querySelector(".test-result").append(this.state.testState.resultContent),this.state.afterEachState?.resultContent instanceof HTMLElement&&this.querySelector(".after-each-result").append(this.state.afterEachState.resultContent)}enable(){this.state.isDisabled=!1,this.findElement(".run-test-button").toggleAttribute("disabled",!1)}disable(){this.state.isDisabled=!0,this.findElement(".run-test-button").toggleAttribute("disabled",!0)}async runTest(e,s){if(null==this.state.testState?.test)return;let n;this.reset();let a={},r=0;try{if(0==e.shouldContinueRunningTests)throw new Error("Tests have been disabled from continuing to run.");if(0==this.dispatchEvent(new CustomEvent(t.BeforeTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}})))throw new Error("Test has been prevented.");if(1==s.codeTestsElement.state.isCanceled)throw new Error("Testing has been canceled.");this.setTestStateProperties("testState",{isRunning:!0}),e.codeTestsElement.setState(e.codeTestsElement.state);const o=performance?.now()??Date.now();n=await this.state.testState.test(s);r=(performance?.now()??Date.now())-o,this.setTestStateProperties("testState",{isRunning:!1,hasRun:!0}),e.codeTestsElement.setState(e.codeTestsElement.state);const i=e.parseTestResult(n,!0);a={testState:{test:this.state.testState.test,resultContent:i.result,resultCategory:i.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:r}}}catch(t){const s=e.parseTestResult(n,!1,t);a={testState:{test:this.state.testState.test,resultContent:s.result,resultCategory:s.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:r}},console.error(t),e.shouldContinueRunningTests=!1}finally{this.setStateProperties({...a}),e.codeTestsElement.setState(e.codeTestsElement.state),this.dispatchEvent(new CustomEvent(t.AfterTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}}))}}reset(){const t=null!=this.state.testState?{resultCategory:"none",resultContent:"",test:this.state.testState.test,hasRun:this.state.testState.hasRun,isRunning:this.state.testState.isRunning,duration:0}:void 0;null!=t&&this.setTestStateProperties("testState",t)}getMessageElement(){return this.findElement(".test-result")}static observedAttributes=["open"];attributeChangedCallback(t,e,s){"open"==t&&this.findElement(".test-details").toggleAttribute("open",null!=s)}}null==customElements.get(e)&&customElements.define(e,s);const n=Symbol("No Test Defined");class a{codeTestsElement;constructor(t){this.codeTestsElement=t}async loadTests(t){if(null!=t)try{const{tests:e,hooks:s}=await this.#e(t),n=s[l.BeforeAll],a=s[l.AfterAll],r=s[l.BeforeEach],o=s[l.AfterEach],i=s[l.RequiredBeforeAny],c=s[l.RequiredAfterAny],u=null==n?void 0:{resultCategory:"none",resultContent:"",test:n,hasRun:!1,isRunning:!1,duration:0},d=null==a?void 0:{resultCategory:"none",resultContent:"",test:a,hasRun:!1,isRunning:!1,duration:0},h=null==r?void 0:{resultCategory:"none",resultContent:"",test:r,hasRun:!1,isRunning:!1,duration:0},f=null==o?void 0:{resultCategory:"none",resultContent:"",test:o,hasRun:!1,isRunning:!1,duration:0},p=null==i?void 0:{resultCategory:"none",resultContent:"",test:i,hasRun:!1,isRunning:!1,duration:0},g=null==c?void 0:{resultCategory:"none",resultContent:"",test:c,hasRun:!1,isRunning:!1,duration:0};this.codeTestsElement.state.beforeEachState=h,this.codeTestsElement.state.afterEachState=f;for(const[t,s]of Object.entries(e))this.#s(t,s);this.codeTestsElement.setStateProperties({beforeAllState:u,afterAllState:d,beforeEachState:h,afterEachState:f,requiredBeforeAnyState:p,requiredAfterAnyState:g,resetHook:s.reset,contextHook:s.context})}catch(t){console.error(t)}}async#e(t){const e=await this.#n(t),s=e.tests??e.default;if(null==s)throw new Error(`Unable to find tests definition in file at path: ${t}`);const n={},a=s[l.BeforeAll];null!=a&&(n[l.BeforeAll]=a,delete s[l.BeforeAll]);const r=s[l.AfterAll];null!=r&&(n[l.AfterAll]=r,delete s[l.AfterAll]);const o=s[l.BeforeEach];null!=o&&(n[l.BeforeEach]=o,delete s[l.BeforeEach]);const i=s[l.AfterEach];null!=i&&(n[l.AfterEach]=i,delete s[l.AfterEach]);const c=s[l.RequiredBeforeAny];null!=c&&(n[l.RequiredBeforeAny]=c,delete s[l.RequiredBeforeAny]);const u=s[l.RequiredAfterAny];null!=u&&(n[l.RequiredAfterAny]=u,delete s[l.RequiredAfterAny]);const d=s[l.Reset];null!=d&&(n[l.Reset]=d,delete s[l.Reset]);const h=s[l.Context];return null!=h&&(n[l.Context]=h,delete s[l.Context]),{tests:s,hooks:n}}async#n(t){const e=window.location.href.lastIndexOf("/"),s=1==(-1!=window.location.href.substring(e).indexOf("."))?window.location.href.substring(0,e+1):window.location.href,n=s+t.substring(0,t.lastIndexOf("/")+1),a=s+t;let r=await(await fetch(a)).text();r=r.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g,`'${n}$1'`);const o=new File([r],t.substring(t.lastIndexOf("/")),{type:"text/javascript"}),i=URL.createObjectURL(o);return await import(i)}#s(t,e){const n=function(){const t=new Uint8Array(20);crypto.getRandomValues(t);const e=[].slice.apply(t).map(function(t){return String.fromCharCode(t)}).join("");return btoa(e).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,"")}(),a=new s;return a.setStateProperties({testId:n,description:t,testState:{test:e,resultCategory:"none",resultContent:"",isRunning:!1,hasRun:!1,duration:0},beforeEachState:null==this.codeTestsElement.state.beforeEachState?void 0:{isRunning:this.codeTestsElement.state.beforeEachState.isRunning,hasRun:this.codeTestsElement.state.beforeEachState.hasRun,resultCategory:this.codeTestsElement.state.beforeEachState.resultCategory,resultContent:this.codeTestsElement.state.beforeEachState.resultContent,duration:0},afterEachState:null==this.codeTestsElement.state.afterEachState?void 0:{isRunning:this.codeTestsElement.state.afterEachState.isRunning,hasRun:this.codeTestsElement.state.afterEachState.hasRun,resultCategory:this.codeTestsElement.state.afterEachState.resultCategory,resultContent:this.codeTestsElement.state.afterEachState.resultContent,duration:0}}),this.codeTestsElement.findElement("#tests").append(a),n}shouldContinueRunningTests=!0;async runTests(e){if(0==this.codeTestsElement.dispatchEvent(new CustomEvent(t.BeforeAll,{bubbles:!0,composed:!0,cancelable:!0})))throw new Error("Tests have been prevented.");await this.codeTestsElement.reset();for(let t=0;t<e.length;t++)e[t].disable();const s=await this.createTestContext();if(await this.runHook("requiredBeforeAnyState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(e,s);if(await this.runHook("beforeAllState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(e,s);if(0==("false"!=this.codeTestsElement.getAttribute("ordered"))){const t=e.map(t=>this.runTest(t,!0,s));await Promise.all(t)}else for(let t=0;t<e.length;t++){const n=e[t];if(0==this.shouldContinueRunningTests)break;await this.runTest(n,!0,s)}0!=this.shouldContinueRunningTests?(await this.runHook("afterAllState",void 0,s),await this.#a(e,s)):await this.#a(e,s)}async#a(e,s){await this.runHook("requiredAfterAnyState",void 0,s);for(let t=0;t<e.length;t++)e[t].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(t.AfterAll,{bubbles:!0,composed:!0}))}async runTest(t,e,s){if(null!=t){if(0==e){const t=this.codeTestsElement.findElements("code-test");for(let e=0;e<t.length;e++)t[e].disable()}s=s??await this.createTestContext(t),0!=e||(await this.runHook("requiredBeforeAnyState",void 0,s),0!=this.shouldContinueRunningTests)?(await this.runHook("beforeEachState",t,s),0!=this.shouldContinueRunningTests?(await t.runTest(this,s),0!=this.shouldContinueRunningTests?(await this.runHook("afterEachState",t,s),await this.#r(s,e)):await this.#r(s,e)):await this.#r(s,e)):await this.#r(s,e)}}async#r(t,e){if(1==e)return;await this.runHook("requiredAfterAnyState",void 0,t);const s=this.codeTestsElement.findElements("code-test");for(let t=0;t<s.length;t++)s[t].enable()}async runHook(e,s,a){const r=this.codeTestsElement.state[e];if(null==r)return n;if(1==this.codeTestsElement.state.isCanceled)return{success:!1,value:"Testing has been canceled."};let o;try{if(0==this.shouldContinueRunningTests&&("requiredAfterAnyState"!=e||"error"==this.codeTestsElement.getAttribute("required-after")))throw new Error("Tests have been disabled from continuing to run.");null!=s&&s.setTestStateProperties(e,{isRunning:!0}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!0}),o=await r.test(a),null!=s&&s.setTestStateProperties(e,{isRunning:!1,hasRun:!0}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!1,hasRun:!0});const t=this.parseTestResult(o,!0,void 0);null!=s&&s.setTestStateProperties(e,{resultCategory:t.resultCategory,resultContent:t.result}),this.codeTestsElement.setTestStateProperties(e,{resultCategory:t.resultCategory,resultContent:t.result})}catch(t){console.error(t),this.shouldContinueRunningTests=!1,o={success:!1,value:`Failed: ${t.message}`};const n=this.parseTestResult(o,!1,t);null!=s&&s.setTestStateProperties(e,{isRunning:!1,hasRun:!0,resultContent:n.result,resultCategory:n.resultCategory}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!1,hasRun:!0,resultCategory:n.resultCategory,resultContent:n.result})}finally{return this.codeTestsElement.dispatchEvent(new CustomEvent(t.AfterHook,{bubbles:!0,composed:!0,detail:o})),o}}parseTestResult(t,e,s){if(t==n)return{result:"",resultCategory:"none"};if(null==t){const t=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${t}" part="pre ${t}">${1==e?"Passed":"Failed"+(null!=s?`:\n${s.message}`:"")}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}if("boolean"==typeof t)return{result:t,resultCategory:1==t?"success":"fail"};if("function"==typeof t)return console.log("function"),{result:"[A function was returned]",resultCategory:"none"};if(t instanceof HTMLElement||"string"==typeof t)return{result:t,resultCategory:"none"};if("object"==typeof t){const s=t,n=1==e?"success-message":"error-message";if(null!=s.success&&null!=s.expected&&null!=s.value)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${1==s.success?"Passed":"Failed"}\nExpected:${s.expected}\nResult:${s.value}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};if(null!=s.success)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};{const s=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${s}" part="pre ${s}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}}throw new Error("Unable to parse result type: Unknown result type")}async createTestContext(e){const s={detail:{},codeTestsElement:this.codeTestsElement,testElement:e,messageElement:e?.findElement(".message")};return null!=this.codeTestsElement.state.contextHook&&await this.codeTestsElement.state.contextHook(s),this.codeTestsElement.dispatchEvent(new CustomEvent(t.Context,{bubbles:!0,composed:!0,detail:{context:s}})),s}}class r extends Promise{async toBeDefined(t){if(null==await(this))throw new Error(`${null!=t?t:"Value"} is undefined`)}async toBe(t,e=!1){const s=await(this);if(0==(1==e?s===t:s==t))throw new Error(` Value is not equal.\n Expected: ${t}\n Result: ${s}`)}async toContainText(t){const e=await(this);return e instanceof HTMLElement?{success:e.textContent.includes(t),index:e.textContent.indexOf(t)}:"string"==typeof e&&{success:e.includes(t),index:e.indexOf(t)}}async toHaveAttribute(t){const e=await(this);if(!(e instanceof HTMLElement))throw new Error("Unable to check for attribute on non-HTMLElement target");if(e.getAttribute(t))throw new Error("Target does not have attribute")}}const o=":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";function i(t){!function(t){const e=[...t.querySelectorAll(`${o}[id]`)];for(let t=0;t<e.length;t++)e[t].part.add(e[t].id)}(t),function(t){const e=[...t.querySelectorAll(`${o}[class]`)];for(let t=0;t<e.length;t++)e[t].part.add(...e[t].classList)}(t)}const l={BeforeAll:"beforeall",AfterAll:"afterall",BeforeEach:"beforeeach",AfterEach:"aftereach",RequiredBeforeAny:"requiredbeforeany",RequiredAfterAny:"requiredafterany",Reset:"reset",Context:"context"},c=new CSSStyleSheet;c.replaceSync(":host\n{\n --gap: 7px;\n --gap-small: 3px;\n --gap-medium: 14px;\n --gap-large: 24px;\n \n --surface-success: oklch(93.96% 0.05 148.74);\n --primary-success: oklch(58.83% 0.158 145.05);\n --border-success: solid 1px var(--primary-success);\n\n --surface-fail: oklch(88.98% 0.052 3.28);\n --primary-fail: oklch(45.8% 0.177 17.7);\n --border-fail: solid 1px var(--primary-fail);\n\n --surface-process: oklch(89.66% 0.046 260.67);\n --primary-process: oklch(43.48% 0.17 260.2);\n --border-process: solid 1px var(--primary-process);\n\n\n\n --surface-test-summary: var(--uchu-gray);\n --surface-hook-summary: var(--uchu-light-purple);\n --surface-hook-any-summary: var(--uchu-light-blue);\n \n --border-test: solid 1px var(--uchu-dark-gray);\n --border-hook: solid 1px var(--uchu-dark-purple);\n --border-hook-any: solid 1px var(--uchu-dark-blue);\n --border-button: solid 1px var(--uchu-blue);\n \n --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>');\n --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');\n\n\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n font-family: sans-serif;\n font-size: 12px;\n}\n\n#header\n{\n flex: 1;\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\n#title\n{\n flex: 1;\n}\n\n#tests\n,#component-content\n{\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n}\n\n#header button\n{\n align-self: stretch;\n display: inline-flex;\n align-items: center;\n gap: var(--gap-small);\n}\n\nbutton .reset-icon\n{\n width: 1em;\n height: 1em;\n transform: scaleX(-1);\n margin-inline: 3px;\n}\n\n/* Run button */\nbutton .arrow-icon\n{\n width: .75em;\n height: .75em;\n transform: rotate(-90deg);\n margin-inline: 3px;\n}\n:host(.running) .run-all-button-icon\n,:host(.fail) .run-all-button-icon\n{\n transform: rotate(0);\n}\n\n/* Dropdown Layout */\nsummary > .run-test-button\n, #run-all-button\n{\n justify-self: flex-end;\n margin-left: auto;\n}\n\nsummary:not(#component-summary)\n{\n padding: var(--gap-small) var(--gap);\n}\n#component-summary\n{\n padding: var(--gap-small)\n}\n\n\n/* Dropdown Markers */\nsummary\n{\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\nsummary > .arrow-icon\n{\n background: var(--arrow-icon);\n transform: rotate(-90deg);\n transition: transform ease-out 90ms;\n width: .6em;\n height: .6em;\n}\ndetails[open] > summary > .arrow-icon\n{\n transform: rotate(0);\n}\n\n#enabled\n{\n display: none;\n}\n:host([optional]) #enabled\n{\n display: block;\n}\n\n/* Result Icon */\n.result-icon\n{\n --background-size: 16px;\n width: var(--background-size);\n height: var(--background-size);\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n border: solid 1px currentColor;\n border-radius: 50%;\n}\n.result-icon::before\n{\n content: '⋯';\n font-size: 10px;\n}\n\n:host(.running) #component-summary .result-icon\n,.test.running .test-summary > .result-icon\n,.hook.running .result-icon\n,.processing-details.running .processing-result-icon\n{\n border: var(--border-process);\n background: var(--surface-process);\n}\n:host(.success) #component-summary .result-icon\n,.test.success .test-summary > .result-icon\n,.hook.success .result-icon\n,.processing-details.success .processing-result-icon\n{\n border: var(--border-success);\n background: var(--surface-success)\n var(--success-icon);\n background-repeat: no-repeat;\n background-position: center;\n background-size: var(--icon-size, 12px) var(--icon-size, 12px);\n}\n:host(.fail) #component-summary .result-icon\n,.test.fail .test-summary > .result-icon\n,.hook.fail .result-icon\n,.processing-details.fail .processing-result-icon\n{\n border: var(--border-fail);\n background: var(--surface-fail)\n var(--info-icon);\n background-size: var(--icon-size, 16px) var(--icon-size, 16px);\n background-repeat: no-repeat;\n background-position: center;\n transform: rotate(175deg);\n}\n:host(:is(.success,.fail)) #component-summary .result-icon::before\n,.test:is(.success,.fail) .test-summary > .result-icon::before\n,.hook:is(.success,.fail) .result-icon::before\n,.processing-details:is(.success,.fail) .processing-result-icon::before\n{\n display: none;\n}\n:host(.running) #component-summary .result-icon::before\n,.test:is(.running) .test-summary > .result-icon::before\n,.hook:is(.running) .result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n content: '';\n --color: var(--primary-process, currentColor);\n --animation-timing-function: linear;\n --animation-duration: 2s;\n width: var(--icon-size, 14px);\n height: var(--icon-size, 14px);\n mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--icon-size, 14px) / 3), black calc(var(--icon-size, 14px) / 3));\n background-image: conic-gradient(transparent, transparent 135deg, var(--color));\n border-radius: 50%;\n animation: var(--animation-timing-function) var(--animation-duration) infinite spin;\n margin: 2px;\n}\n\n/* Smaller Result icon settings for sub-test icons */\n.before-each-result-icon\n,.after-each-result-icon\n,.processing-result-icon\n{\n --background-size: 12px;\n}\n.before-each-result-icon::before\n,.after-each-result-icon::before\n,.processing-result-icon::before\n{\n font-size: 9px;\n}\n.hook.success .before-each-result-icon\n,.hook.success .after-each-result-icon\n,.processing-details.success .processing-result-icon\n{\n --icon-size: 8px;\n}\n.hook.fail .before-each-result-icon\n,.hook.fail .after-each-result-icon\n,.processing-details.fail .processing-result-icon\n{\n --icon-size: 12px;\n}\n.hook:is(.running) .before-each-result-icon::before\n,.hook:is(.running) .after-each-result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n --icon-size: 9px;\n}\n\n/* Hook Display */\n.hook\n{\n display: none;\n}\n:host(.has-before-all-hook) #before-all-details\n,:host(.has-after-all-hook) #after-all-details\n{\n display: initial;\n}\n:host(.has-before-each-hook) .before-each-details\n,:host(.has-after-each-hook) .after-each-details\n{\n display: initial;\n}\n:host(.has-required-before-hook) #required-before-any-details\n,:host(.has-required-after-hook) #required-after-any-details\n{\n display: initial;\n}\n\n/* Test Display */\ncode-test .results\n{\n display: grid;\n gap: var(--gap-small);\n padding-inline-start: 1em;\n}\n\ncode-test .results details .result\n,.hook > .results\n{\n margin-inline-start: 1em;\n}\n\n.result.message:empty\n{\n padding: .5em 1em;\n}\n.result.message:empty::before\n{\n content: '[ this function has not been run ]';\n font-family: monospace;\n font-size: 12px;\n font-style: italic;\n}\n\n/* Ordered Display */\n#tests\n{\n counter-reset: tests;\n}\ncode-test\n{\n counter-increment: tests;\n}\ncode-test > details > summary > .description\n{\n flex: 1;\n}\n:host(:not([ordered=\"false\"])) code-test > details > summary > .description::before\n{\n content: counter(tests) \". \";\n}\n\n/* Hook Name */\n.hook-name,.processing-description\n{\n border-radius: 3px;\n border: solid 1px;\n /* background: rgb(0 0 0 / .2); */\n font-family: monospace;\n text-transform: uppercase;\n font-size: 11px;\n padding: 3px 7px;\n}\n\n#footer\n{\n display: flex;\n justify-content: flex-end;\n}\n#group-results\n{\n display: flex;\n gap: var(--gap);\n padding: var(--gap);\n}\n\n#passed-total-percent::before\n{\n content: '(';\n}\n#passed-total-percent::after\n{\n content: ')';\n}\n\n@keyframes spin\n{\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}");const u="code-tests";class d extends HTMLElement{state={isCanceled:!1,beforeAllState:void 0,afterAllState:void 0,beforeEachState:void 0,afterEachState:void 0,requiredBeforeAnyState:void 0,requiredAfterAnyState:void 0,resetHook:void 0,contextHook:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.shadowRoot.querySelector(t)}findElements(t){return Array.from(this.shadowRoot.querySelectorAll(t))}getIsRunning(){return 1==(null!=this.findElements("code-test").find(t=>1==t.isRunning()))||1==this.state.requiredBeforeAnyState?.isRunning||1==this.state.requiredAfterAnyState?.isRunning||1==this.state.beforeAllState?.isRunning||1==this.state.afterAllState?.isRunning}getResultCategory(){const t=this.findElements("code-test").reduce((t,e,s)=>{const n=e.resultCategory();return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},""),e=[this.state.requiredBeforeAnyState,this.state.requiredAfterAnyState,this.state.beforeAllState,this.state.afterAllState].reduce((t,e,s)=>{if(null==e)return null;const n=e?.resultCategory;return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},"");return"none"==t&&null==e?"none":"fail"==t||"fail"==e?"fail":"success"==t||"success"==e?"success":"none"}#o;constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML='<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 <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\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>',this.shadowRoot.adoptedStyleSheets.push(c)}connectedCallback(){this.#i()}disconnectedCallback(){this.#l()}#c=!1;#u=!1;async#i(){1!=this.#c&&1!=this.#u&&(this.#c=!0,i(this.shadowRoot),this.addEventListener("click",this.#d),this.findElement("#enabled").addEventListener("change",this.#h),await new Promise(t=>requestAnimationFrame(()=>{this.#o=new a(this),this.#u=!0,this.#c=!1;if(0==this.dispatchEvent(new CustomEvent("init",{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}})))return void t();"false"!=this.getAttribute("auto")?(this.reloadTests(),t()):t()})))}#l(){this.removeEventListener("click",this.#d),this.findElement("#enabled").removeEventListener("change",this.#h),this.#u=!1,this.#c=!1}#d=this.#f.bind(this);#f(t){if(null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"run-all-button"==t.id))return void(this.classList.contains("running")?this.cancel():this.classList.contains("fail")||this.classList.contains("success")?this.reset():this.runTests());null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"reload-button"==t.id)&&this.reloadTests();const e=t.composedPath().find(t=>t instanceof HTMLButtonElement&&t.classList.contains("run-test-button"));if(null==e)return;const s=e.closest("code-test")??void 0;this.#o.runTest(s,!1)}#h=this.#p.bind(this);#p(t){const e=t.target;0==this.dispatchEvent(new CustomEvent("enabled",{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))&&(t.preventDefault(),t.stopPropagation(),e.checked=!e.checked)}#g(){return this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path")??void 0}#t(){const t=this.getIsRunning(),e=this.getResultCategory(),s=null!=this.state.beforeAllState,n=null!=this.state.beforeEachState,a=null!=this.state.requiredAfterAnyState,r=null!=this.state.beforeAllState,o=null!=this.state.beforeEachState,i=null!=this.state.requiredAfterAnyState,l=1==a||1==s||1==n,c=1==i||1==r||1==o;this.classList.toggle("canceled",this.state.isCanceled),this.part.toggle("canceled",this.state.isCanceled),this.classList.toggle("running",1==t),this.part.toggle("running",1==t),this.toggleAttribute("success","success"==e),this.classList.toggle("success","success"==e),this.part.toggle("success","success"==e),this.classList.toggle("fail","fail"==e),this.part.toggle("fail","fail"==e),this.classList.toggle("has-before-hook",l),this.part.toggle("has-before-hook",l),this.classList.toggle("has-after-hook",c),this.part.toggle("has-after-hook",c),this.classList.toggle("has-before-all-hook",s),this.part.toggle("has-before-all-hook",s),this.classList.toggle("has-after-all-hook",r),this.part.toggle("has-after-all-hook",r),this.classList.toggle("has-before-each-hook",n),this.part.toggle("has-before-each-hook",n),this.classList.toggle("has-after-each-hook",o),this.part.toggle("has-after-each-hook",o),this.classList.toggle("has-required-before-hook",a),this.part.toggle("has-required-before-hook",a),this.classList.toggle("has-required-after-hook",i),this.part.toggle("has-required-after-hook",i);const u=this.findElement(".run-all-button-label");null!=u&&(u.textContent=1==t?"Cancel":"fail"==e?"Reset":"Run Tests",u.title=1==t?"Cancel the testing":"fail"==e?"Reset the tests so they can be run again":"Run the tests");const d=this.findElement(".run-all-button-icon");null!=d&&(d.innerHTML=1==t?'<use href="#icon-definition_cancel"></use>':"fail"==e?'<use href="#icon-definition_reset"></use>':'<use href="#icon-definition_arrow"></use>'),this.#m(this.state.beforeAllState,"#before-all-results"),this.#m(this.state.afterAllState,"#after-all-results"),this.#m(this.state.requiredBeforeAnyState,"#required-before-any-results"),this.#m(this.state.requiredAfterAnyState,"#required-after-any-results");const h=this.findElement("#title");null!=h&&(h.textContent=this.getAttribute("label")??"Tests"),this.#b()}#m(t,e){const s=this.findElement(e);t?.resultContent instanceof HTMLElement?s.append(t.resultContent):"string"==typeof t?.resultContent&&(s.innerHTML=t.resultContent);const n=s.closest("details");n.toggleAttribute("open",null!=t&&"none"!=t.resultCategory),n.classList.toggle("running",1==t?.isRunning),n.part.toggle("running",1==t?.isRunning),n.toggleAttribute("success","success"==t?.resultCategory),n.classList.toggle("success","success"==t?.resultCategory),n.part.toggle("success","success"==t?.resultCategory),n.classList.toggle("fail","fail"==t?.resultCategory),n.part.toggle("fail","fail"==t?.resultCategory)}#b(){const t=this.collectTestResults(),e=this.findElement("#results-progress-value");null!=e&&(e.max=t.totalTests,e.value=t.totalPassed);const s=this.findElement("#total-tests-passed-value");null!=s&&(s.textContent=t.totalPassed.toString());const n=this.findElement("#total-tests-count-value");null!=n&&(n.textContent=t.totalTests.toString());const a=this.findElement("#passed-total-percent-value");null!=a&&(a.textContent=t.totalPercentage.toFixed(1));const r=this.findElement("#duration-value");null!=r&&(r.textContent=t.duration>10?t.duration.toFixed(0):t.duration.toFixed(2))}collectTestResults(){const t=this.findElements("code-test"),e=t.length,s=t.filter(t=>"success"==t.state.testState?.resultCategory).length;return{totalTests:e,totalPassed:s,totalPercentage:0==e?0:s/e*100,duration:t.reduce((t,e,s)=>t+(e.state.testState?.duration??0),0)}}async runTests(){const t=this.findElements("code-test");return this.#o.runTests(t)}async reloadTests(){this.findElement("#tests").innerHTML="",await this.reset();const t=this.#g();this.#o.loadTests(t)}async reset(){const e=this.findElements("code-test");for(let t=0;t<e.length;t++){const s=e[t],n=null!=this.state.beforeEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.beforeEachState.hasRun,isRunning:this.state.beforeEachState.isRunning,duration:0}:void 0,a=null!=this.state.afterEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.afterEachState.hasRun,isRunning:this.state.afterEachState.isRunning,duration:0}:void 0;null!=n&&(s.state.beforeEachState=n),null!=a&&(s.state.afterEachState=a),s.reset()}const s=null==this.state.beforeAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeAllState.test,isRunning:!1,hasRun:!1,duration:0},n=null==this.state.afterAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterAllState.test,isRunning:!1,hasRun:!1,duration:0},a=null==this.state.beforeEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeEachState.test,isRunning:!1,hasRun:!1,duration:0},r=null==this.state.afterEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterEachState.test,isRunning:!1,hasRun:!1,duration:0},o=null==this.state.requiredBeforeAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredBeforeAnyState.test,isRunning:!1,hasRun:!1,duration:0},i=null==this.state.requiredAfterAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredAfterAnyState.test,isRunning:!1,hasRun:!1,duration:0};this.setStateProperties({isCanceled:!1,beforeAllState:s,afterAllState:n,beforeEachState:a,afterEachState:r,requiredAfterAnyState:i,requiredBeforeAnyState:o}),this.#o.shouldContinueRunningTests=!0,null!=this.state.resetHook&&await this.state.resetHook(await this.#o.createTestContext()),this.dispatchEvent(new CustomEvent(t.Reset,{bubbles:!0,composed:!0}))}cancel(){this.state.isCanceled=!0,this.#o.shouldContinueRunningTests=!1,this.classList.add("canceled"),this.part.add("canceled"),this.dispatchEvent(new CustomEvent(t.Cancel,{bubbles:!0,composed:!0}))}static observedAttributes=["open","label"];attributeChangedCallback(t,e,s){if("open"==t)this.findElement("#component-details").toggleAttribute("open",null!=s);else if("label"==t){const t=this.findElement("#title");null!=t&&(t.textContent=s??"Tests")}}}function h(t){return new r(async(e,s)=>{if(t instanceof Promise){return void e(await t)}e(t)})}async function f(t,e,s,n){return new Promise((a,r)=>{const o=p(n?.template??t.querySelector(".prompt-template")??t.findElement("#prompt-template"));o.querySelector(".label").textContent=s;const i=t=>{const e=t.composedPath();if(null!=e.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("accept"))){const t=n?.onAccept?.()??!0;return o.removeEventListener("click",i),void a(t)}if(null!=e.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("reject"))){const t=n?.onReject?.()??!1;return o.removeEventListener("click",i),void a(t)}};o.addEventListener("click",i),null!=n?.acceptLabel&&(o.querySelector(".accept").textContent=n.acceptLabel),null!=n?.rejectLabel&&(o.querySelector(".reject").textContent=n.rejectLabel),e.append(o)})}function p(t,e){const s=t instanceof HTMLTemplateElement?t:document.querySelector(t);if(null==s)throw new Error(`Unable to find template element from selector: ${t}`);const n=s.content.cloneNode(!0).firstElementChild;if(null==n)throw new Error("Unable to find first child of template element");return e?.append(n),n}null==customElements.get(u)&&customElements.define(u,d);export{s as CodeTestElement,t as CodeTestEvent,d as CodeTestsElement,l as Hook,r as TestPromise,p as createElementFromTemplate,h as expect,f as prompt};
|
|
1
|
+
const t={BeforeAll:"beforeall",AfterAll:"afterall",BeforeTest:"beforetest",AfterTest:"aftertest",BeforeHook:"beforehook",AfterHook:"afterhook",Cancel:"cancel",Context:"context",Reset:"reset",TestEnd:"testend",Init:"init",Enabled:"enabled",PromptResult:"promptresult"},e="code-test";class s extends HTMLElement{state={testId:"",description:"none",isDisabled:!1,testState:void 0,beforeEachState:void 0,afterEachState:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.querySelector(t)}findElements(t){return Array.from(this.querySelectorAll(t))}isRunning(){return 1==this.state.testState?.isRunning||1==this.state.beforeEachState?.isRunning||1==this.state.afterEachState?.isRunning}hasRun(){return 1==this.state.testState?.hasRun||1==this.state.beforeEachState?.hasRun||1==this.state.afterEachState?.hasRun}resultCategory(){const t=this.state.testState?.resultCategory??"none",e=this.state.beforeEachState?.resultCategory??"none",s=this.state.afterEachState?.resultCategory??"none";return"none"==t&&"none"==e&&"none"==s?"none":null==this.state.beforeEachState&&null==this.state.afterEachState?t:null!=this.state.beforeEachState&&null==this.state.afterEachState?"fail"==t||"fail"==e?"fail":"success"==t&&"success"==e?"success":"none":null==this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==s?"fail":"success"==t&&"success"==s?"success":"none":null!=this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==e||"fail"==s?"fail":"success"==t&&"success"==e&&"success"==s?"success":"none":void 0}connectedCallback(){this.#t()}#t(){const t=null==this.state.testState?"":"boolean"==typeof this.state.testState.resultContent?1==this.state.testState.resultContent?'<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>':"number"==typeof this.state.testState.resultContent?`<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed: ${this.state.testState.resultContent.toString()}</pre></code>`:"string"==typeof this.state.testState.resultContent?this.state.testState.resultContent:"";this.innerHTML=`<details class="test-details" part="test-details" ${1==this.isRunning()||1==this.hasRun()?" open":""}>\n <summary class="test-summary" part="test-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="result-icon test-result-icon${"none"!=this.state.testState?.resultCategory?` ${this.state.testState?.resultCategory}`:""}" part="result-icon"></div>\n <span class="test-description description" title="${this.state.description}">${this.state.description}</span>\n ${null!=this.state.testState?.duration&&this.state.testState.duration>0?`<span class="test-duration duration">\n <span class="test-duration-value">${this.state.testState.duration>10?this.state.testState.duration.toFixed(0):this.state.testState.duration.toFixed(2)}</span>\n <span class="test-duration-unit">ms</span>\n </span>`:""}\n <button type="button" class="run-test-button" part="run-test-button" title="Run Test"${1==this.state.isDisabled?" disabled":""}>\n <slot name="run-button-content">\n <slot name="run-button-icon"><svg class="icon arrow-icon run-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-button-label"><span class="run-button-label button-label label icon">Run Test</span></slot>\n </slot>\n </button>\n </summary>\n <div class="results" part="results">\n ${null==this.state.beforeEachState?"":`<details class="before-each-details hook${"none"==this.state.beforeEachState.resultCategory?"":` ${this.state.beforeEachState.resultCategory}`}${1==this.state.beforeEachState.isRunning?" running":""}" part="before-each-details hook">\n <summary class="before-each-summary" part="before-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="before-each-result-icon result-icon${"none"!=this.state.beforeEachState.resultCategory?` ${this.state.beforeEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="before-each-description description hook-name">Before Each Hook</span>\n </summary>\n <div class="before-each-result result message" part="before-each-result result message">${"string"!=typeof this.state.beforeEachState.resultContent?"":this.state.beforeEachState.resultContent}</div>\n </details>`}\n ${null==this.state.testState?"":null==this.state.beforeEachState&&null==this.state.afterEachState?`<div class="test-result result message" part="test-result result message">${t}</div>`:`<details class="processing-details${"none"==this.state.testState.resultCategory?"":` ${this.state.testState.resultCategory}`}${1==this.state.testState.isRunning?" running":""}" part="processing-details"${1==this.state.testState.hasRun?" open":""}>\n <summary class="processing-summary" part="processing-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="processing-result-icon result-icon${"none"!=this.state.testState.resultCategory?` ${this.state.testState.resultCategory}`:""}" part="processing-result-icon result-icon"></div>\n <span class="processing-description description">Test</span>\n </summary>\n <div class="test-result result message" part="test-result result message">${t}</div>\n </details>`} \n ${null==this.state.afterEachState?"":`<details class="after-each-details hook${"none"==this.state.afterEachState.resultCategory?"":` ${this.state.afterEachState.resultCategory}`}${1==this.state.afterEachState.isRunning?" running":""}" part="after-each-detail hooks">\n <summary class="after-each-summary" part="after-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="after-each-result-icon result-icon${"none"!=this.state.afterEachState.resultCategory?` ${this.state.afterEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="after-each-description description hook-name">After Each Hook</span>\n </summary>\n <div class="after-each-result result message" part="after-each-result result message">${"string"!=typeof this.state.afterEachState.resultContent?"":this.state.afterEachState.resultContent}</div>\n </details>`}\n </div>\n </details>`,this.dataset.testId=this.state.testId,this.classList.add("test"),this.part.add("test"),this.toggleAttribute("success","success"==this.resultCategory()),this.classList.toggle("success","success"==this.resultCategory()),this.part.toggle("success","success"==this.resultCategory()),this.classList.toggle("fail","fail"==this.resultCategory()),this.part.toggle("fail","fail"==this.resultCategory()),this.classList.toggle("running",this.isRunning()),this.part.toggle("running",this.isRunning()),this.state.beforeEachState?.resultContent instanceof HTMLElement&&this.querySelector(".before-each-result").append(this.state.beforeEachState.resultContent),this.state.testState?.resultContent instanceof HTMLElement&&this.querySelector(".test-result").append(this.state.testState.resultContent),this.state.afterEachState?.resultContent instanceof HTMLElement&&this.querySelector(".after-each-result").append(this.state.afterEachState.resultContent)}enable(){this.state.isDisabled=!1,this.findElement(".run-test-button").toggleAttribute("disabled",!1)}disable(){this.state.isDisabled=!0,this.findElement(".run-test-button").toggleAttribute("disabled",!0)}async runTest(e,s){if(null==this.state.testState?.test)return;let n;this.reset();let a={},o=0;try{if(0==e.shouldContinueRunningTests)throw new Error("Tests have been disabled from continuing to run.");if(0==this.dispatchEvent(new CustomEvent(t.BeforeTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}})))throw new Error("Test has been prevented.");if(1==s.codeTestsElement.state.isCanceled)throw new Error("Testing has been canceled.");this.setTestStateProperties("testState",{isRunning:!0}),e.codeTestsElement.setState(e.codeTestsElement.state);const r=performance?.now()??Date.now();n=await this.state.testState.test(s);o=(performance?.now()??Date.now())-r,this.setTestStateProperties("testState",{isRunning:!1,hasRun:!0}),e.codeTestsElement.setState(e.codeTestsElement.state);const i=e.parseTestResult(n,!0);a={testState:{test:this.state.testState.test,resultContent:i.result,resultCategory:i.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:o}}}catch(t){const s=e.parseTestResult(n,!1,t);a={testState:{test:this.state.testState.test,resultContent:s.result,resultCategory:s.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:o}},console.error(t),e.shouldContinueRunningTests=!1}finally{this.setStateProperties({...a}),e.codeTestsElement.setState(e.codeTestsElement.state),this.dispatchEvent(new CustomEvent(t.AfterTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}}))}}reset(){const t=null!=this.state.testState?{resultCategory:"none",resultContent:"",test:this.state.testState.test,hasRun:this.state.testState.hasRun,isRunning:this.state.testState.isRunning,duration:0}:void 0;null!=t&&this.setTestStateProperties("testState",t)}getMessageElement(){return this.findElement(".test-result")}static observedAttributes=["open"];attributeChangedCallback(t,e,s){"open"==t&&this.findElement(".test-details").toggleAttribute("open",null!=s)}}null==customElements.get(e)&&customElements.define(e,s);const n=Symbol("No Test Defined");class a{codeTestsElement;constructor(t){this.codeTestsElement=t}async loadTests(t){if(null!=t)try{const{tests:e,hooks:s}=await this.#e(t),n=s[l.BeforeAll],a=s[l.AfterAll],o=s[l.BeforeEach],r=s[l.AfterEach],i=s[l.RequiredBeforeAny],c=s[l.RequiredAfterAny],u=null==n?void 0:{resultCategory:"none",resultContent:"",test:n,hasRun:!1,isRunning:!1,duration:0},d=null==a?void 0:{resultCategory:"none",resultContent:"",test:a,hasRun:!1,isRunning:!1,duration:0},h=null==o?void 0:{resultCategory:"none",resultContent:"",test:o,hasRun:!1,isRunning:!1,duration:0},f=null==r?void 0:{resultCategory:"none",resultContent:"",test:r,hasRun:!1,isRunning:!1,duration:0},p=null==i?void 0:{resultCategory:"none",resultContent:"",test:i,hasRun:!1,isRunning:!1,duration:0},g=null==c?void 0:{resultCategory:"none",resultContent:"",test:c,hasRun:!1,isRunning:!1,duration:0};this.codeTestsElement.state.beforeEachState=h,this.codeTestsElement.state.afterEachState=f;for(const[t,s]of Object.entries(e))this.#s(t,s);this.codeTestsElement.setStateProperties({beforeAllState:u,afterAllState:d,beforeEachState:h,afterEachState:f,requiredBeforeAnyState:p,requiredAfterAnyState:g,resetHook:s.reset,contextHook:s.context})}catch(t){console.error(t)}}async#e(t){const e=await this.#n(t),s=e.tests??e.default;if(null==s)throw new Error(`Unable to find tests definition in file at path: ${t}`);const n={},a=s[l.BeforeAll];null!=a&&(n[l.BeforeAll]=a,delete s[l.BeforeAll]);const o=s[l.AfterAll];null!=o&&(n[l.AfterAll]=o,delete s[l.AfterAll]);const r=s[l.BeforeEach];null!=r&&(n[l.BeforeEach]=r,delete s[l.BeforeEach]);const i=s[l.AfterEach];null!=i&&(n[l.AfterEach]=i,delete s[l.AfterEach]);const c=s[l.RequiredBeforeAny];null!=c&&(n[l.RequiredBeforeAny]=c,delete s[l.RequiredBeforeAny]);const u=s[l.RequiredAfterAny];null!=u&&(n[l.RequiredAfterAny]=u,delete s[l.RequiredAfterAny]);const d=s[l.Reset];null!=d&&(n[l.Reset]=d,delete s[l.Reset]);const h=s[l.Context];return null!=h&&(n[l.Context]=h,delete s[l.Context]),{tests:s,hooks:n}}async#n(t){const e=window.location.href.lastIndexOf("/"),s=1==(-1!=window.location.href.substring(e).indexOf("."))?window.location.href.substring(0,e+1):window.location.href,n=s+t.substring(0,t.lastIndexOf("/")+1),a=s+t;let o=await(await fetch(a)).text();o=o.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g,`'${n}$1'`);const r=new File([o],t.substring(t.lastIndexOf("/")),{type:"text/javascript"}),i=URL.createObjectURL(r);return await import(i)}#s(t,e){const n=function(){const t=new Uint8Array(20);crypto.getRandomValues(t);const e=[].slice.apply(t).map(function(t){return String.fromCharCode(t)}).join("");return btoa(e).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,"")}(),a=new s;return a.setStateProperties({testId:n,description:t,testState:{test:e,resultCategory:"none",resultContent:"",isRunning:!1,hasRun:!1,duration:0},beforeEachState:null==this.codeTestsElement.state.beforeEachState?void 0:{isRunning:this.codeTestsElement.state.beforeEachState.isRunning,hasRun:this.codeTestsElement.state.beforeEachState.hasRun,resultCategory:this.codeTestsElement.state.beforeEachState.resultCategory,resultContent:this.codeTestsElement.state.beforeEachState.resultContent,duration:0},afterEachState:null==this.codeTestsElement.state.afterEachState?void 0:{isRunning:this.codeTestsElement.state.afterEachState.isRunning,hasRun:this.codeTestsElement.state.afterEachState.hasRun,resultCategory:this.codeTestsElement.state.afterEachState.resultCategory,resultContent:this.codeTestsElement.state.afterEachState.resultContent,duration:0}}),this.codeTestsElement.findElement("#tests").append(a),n}shouldContinueRunningTests=!0;async runTests(e){if(0==this.codeTestsElement.dispatchEvent(new CustomEvent(t.BeforeAll,{bubbles:!0,composed:!0,cancelable:!0})))throw new Error("Tests have been prevented.");await this.codeTestsElement.reset();for(let t=0;t<e.length;t++)e[t].disable();const s=await this.createTestContext();if(await this.runHook("requiredBeforeAnyState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(e,s);if(await this.runHook("beforeAllState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(e,s);if(0==("false"!=this.codeTestsElement.getAttribute("ordered"))){const t=e.map(t=>this.runTest(t,!0,s));await Promise.all(t)}else for(let t=0;t<e.length;t++){const n=e[t];if(0==this.shouldContinueRunningTests)break;await this.runTest(n,!0,s)}0!=this.shouldContinueRunningTests?(await this.runHook("afterAllState",void 0,s),await this.#a(e,s)):await this.#a(e,s)}async#a(e,s){await this.runHook("requiredAfterAnyState",void 0,s);for(let t=0;t<e.length;t++)e[t].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(t.AfterAll,{bubbles:!0,composed:!0}))}async runTest(t,e,s){if(null!=t){if(0==e){const t=this.codeTestsElement.findElements("code-test");for(let e=0;e<t.length;e++)t[e].disable()}null==(s=s??await this.createTestContext(t)).testElement&&(s.testElement=t),0!=e||(await this.runHook("requiredBeforeAnyState",void 0,s),0!=this.shouldContinueRunningTests)?(await this.runHook("beforeEachState",t,s),0!=this.shouldContinueRunningTests?(await t.runTest(this,s),0!=this.shouldContinueRunningTests?(await this.runHook("afterEachState",t,s),await this.#o(s,e)):await this.#o(s,e)):await this.#o(s,e)):await this.#o(s,e)}}async#o(e,s){if(1==s)return;await this.runHook("requiredAfterAnyState",void 0,e);const n=this.codeTestsElement.findElements("code-test");for(let t=0;t<n.length;t++)n[t].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(t.TestEnd,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))}async runHook(e,s,a){const o=this.codeTestsElement.state[e];if(null==o)return n;if(1==this.codeTestsElement.state.isCanceled)return{success:!1,value:"Testing has been canceled."};let r;try{if(0==this.shouldContinueRunningTests&&("requiredAfterAnyState"!=e||"error"==this.codeTestsElement.getAttribute("required-after")))throw new Error("Tests have been disabled from continuing to run.");null!=s&&s.setTestStateProperties(e,{isRunning:!0}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!0}),r=await o.test(a),null!=s&&s.setTestStateProperties(e,{isRunning:!1,hasRun:!0}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!1,hasRun:!0});const t=this.parseTestResult(r,!0,void 0);null!=s&&s.setTestStateProperties(e,{resultCategory:t.resultCategory,resultContent:t.result}),this.codeTestsElement.setTestStateProperties(e,{resultCategory:t.resultCategory,resultContent:t.result})}catch(t){console.error(t),this.shouldContinueRunningTests=!1,r={success:!1,value:`Failed: ${t.message}`};const n=this.parseTestResult(r,!1,t);null!=s&&s.setTestStateProperties(e,{isRunning:!1,hasRun:!0,resultContent:n.result,resultCategory:n.resultCategory}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!1,hasRun:!0,resultCategory:n.resultCategory,resultContent:n.result})}finally{return this.codeTestsElement.dispatchEvent(new CustomEvent(t.AfterHook,{bubbles:!0,composed:!0,detail:r})),r}}parseTestResult(t,e,s){if(t==n)return{result:"",resultCategory:"none"};if(null==t){const t=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${t}" part="pre ${t}">${1==e?"Passed":"Failed"+(null!=s?`:\n${s.message}`:"")}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}if("boolean"==typeof t)return{result:t,resultCategory:1==t?"success":"fail"};if("function"==typeof t)return console.log("function"),{result:"[A function was returned]",resultCategory:"none"};if(t instanceof HTMLElement||"string"==typeof t)return{result:t,resultCategory:"none"};if("object"==typeof t){const s=t,n=1==e?"success-message":"error-message";if(null!=s.success&&null!=s.expected&&null!=s.value)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${1==s.success?"Passed":"Failed"}\nExpected:${s.expected}\nResult:${s.value}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};if(null!=s.success)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};{const s=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${s}" part="pre ${s}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}}throw new Error("Unable to parse result type: Unknown result type")}async createTestContext(e){const s={detail:{},codeTestsElement:this.codeTestsElement,testElement:e,messageElement:e?.findElement(".message")};return null!=this.codeTestsElement.state.contextHook&&await this.codeTestsElement.state.contextHook(s),this.codeTestsElement.dispatchEvent(new CustomEvent(t.Context,{bubbles:!0,composed:!0,detail:{context:s}})),s}}class o extends Promise{async toBeDefined(t){if(null==await(this))throw new Error(`${null!=t?t:"Value"} is undefined`)}async toBe(t,e=!1){const s=await(this);if(0==(1==e?s===t:s==t))throw new Error(` Value is not equal.\n Expected: ${t}\n Result: ${s}`)}async toContainText(t){const e=await(this);return e instanceof HTMLElement?{success:e.textContent.includes(t),index:e.textContent.indexOf(t)}:"string"==typeof e&&{success:e.includes(t),index:e.indexOf(t)}}async toHaveAttribute(t){const e=await(this);if(!(e instanceof HTMLElement))throw new Error("Unable to check for attribute on non-HTMLElement target");if(e.getAttribute(t))throw new Error("Target does not have attribute")}}const r=":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";function i(t){!function(t){const e=[...t.querySelectorAll(`${r}[id]`)];for(let t=0;t<e.length;t++)e[t].part.add(e[t].id)}(t),function(t){const e=[...t.querySelectorAll(`${r}[class]`)];for(let t=0;t<e.length;t++)e[t].part.add(...e[t].classList)}(t)}const l={BeforeAll:"beforeall",AfterAll:"afterall",BeforeEach:"beforeeach",AfterEach:"aftereach",RequiredBeforeAny:"requiredbeforeany",RequiredAfterAny:"requiredafterany",Reset:"reset",Context:"context"},c=new CSSStyleSheet;c.replaceSync(":host\n{\n --gap: 7px;\n --gap-small: 3px;\n --gap-medium: 14px;\n --gap-large: 24px;\n \n --surface-success: oklch(93.96% 0.05 148.74);\n --primary-success: oklch(58.83% 0.158 145.05);\n --border-success: solid 1px var(--primary-success);\n\n --surface-fail: oklch(88.98% 0.052 3.28);\n --primary-fail: oklch(45.8% 0.177 17.7);\n --border-fail: solid 1px var(--primary-fail);\n\n --surface-process: oklch(89.66% 0.046 260.67);\n --primary-process: oklch(43.48% 0.17 260.2);\n --border-process: solid 1px var(--primary-process);\n\n\n --surface-footer: rgb(0 0 0 / .04);\n \n --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>');\n --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');\n\n\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n font-family: sans-serif;\n font-size: 12px;\n}\n@media (prefers-color-scheme: dark) \n{\n :host\n {\n --surface-footer: rgb(255 255 255 / .1);\n }\n}\n\n#header\n{\n flex: 1;\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\n#title\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n#tests\n,#component-content\n{\n display: grid;\n gap: var(--gap-small);\n grid-auto-rows: max-content;\n}\n\n#header button\n{\n align-self: stretch;\n display: inline-flex;\n align-items: center;\n gap: var(--gap-small);\n}\n\nbutton .reset-icon\n{\n width: 1em;\n height: 1em;\n transform: scaleX(-1);\n margin-inline: 3px;\n}\n\n/* Run button */\nbutton .arrow-icon\n{\n width: .75em;\n height: .75em;\n transform: rotate(-90deg);\n margin-inline: 3px;\n}\n:host(.running) .run-all-button-icon\n,:host(.fail) .run-all-button-icon\n{\n transform: rotate(0);\n}\n\n/* Dropdown Layout */\nsummary > .run-test-button\n, #run-all-button\n{\n justify-self: flex-end;\n margin-left: auto;\n}\n\nsummary:not(#component-summary)\n{\n padding: var(--gap-small);\n}\n#component-summary\n{\n padding: var(--gap) var(--gap-small);\n border-bottom: solid 1px;\n margin-bottom: var(--gap-small);\n}\n\n\n/* Dropdown Markers */\nsummary\n{\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\nsummary > .arrow-icon\n{\n background: var(--arrow-icon);\n transform: rotate(-90deg);\n transition: transform ease-out 90ms;\n width: .6em;\n height: .6em;\n}\ndetails[open] > summary > .arrow-icon\n{\n transform: rotate(0);\n}\n\n#enabled\n{\n display: none;\n}\n:host([optional]) #enabled\n{\n display: block;\n}\n\n/* Result Icon */\n.result-icon\n{\n --background-size: 16px;\n width: var(--background-size);\n height: var(--background-size);\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n border: solid 1px currentColor;\n border-radius: 50%;\n}\n.result-icon::before\n{\n content: '⋯';\n font-size: 10px;\n}\n\n:host(.running) #component-summary .result-icon\n,.test.running .test-summary > .result-icon\n,.hook.running .result-icon\n,.processing-details.running .processing-result-icon\n{\n border: var(--border-process);\n background: var(--surface-process);\n}\n:host(.success) #component-summary .result-icon\n,.test.success .test-summary > .result-icon\n,.hook.success .result-icon\n,.processing-details.success .processing-result-icon\n{\n border: var(--border-success);\n background: var(--surface-success)\n var(--success-icon);\n background-repeat: no-repeat;\n background-position: center;\n background-size: var(--icon-size, 12px) var(--icon-size, 12px);\n}\n:host(.fail) #component-summary .result-icon\n,.test.fail .test-summary > .result-icon\n,.hook.fail .result-icon\n,.processing-details.fail .processing-result-icon\n{\n border: var(--border-fail);\n background: var(--surface-fail)\n var(--info-icon);\n background-size: var(--icon-size, 16px) var(--icon-size, 16px);\n background-repeat: no-repeat;\n background-position: center;\n transform: rotate(175deg);\n}\n:host(:is(.success,.fail)) #component-summary .result-icon::before\n,.test:is(.success,.fail) .test-summary > .result-icon::before\n,.hook:is(.success,.fail) .result-icon::before\n,.processing-details:is(.success,.fail) .processing-result-icon::before\n{\n display: none;\n}\n:host(.running) #component-summary .result-icon::before\n,.test:is(.running) .test-summary > .result-icon::before\n,.hook:is(.running) .result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n content: '';\n --color: var(--primary-process, currentColor);\n --animation-timing-function: linear;\n --animation-duration: 2s;\n width: var(--icon-size, 14px);\n height: var(--icon-size, 14px);\n mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--icon-size, 14px) / 3), black calc(var(--icon-size, 14px) / 3));\n background-image: conic-gradient(transparent, transparent 135deg, var(--color));\n border-radius: 50%;\n animation: var(--animation-timing-function) var(--animation-duration) infinite spin;\n margin: 2px;\n}\n\n/* Smaller Result icon settings for sub-test icons */\n.before-each-result-icon\n,.after-each-result-icon\n,.processing-result-icon\n{\n --background-size: 12px;\n}\n.before-each-result-icon::before\n,.after-each-result-icon::before\n,.processing-result-icon::before\n{\n font-size: 9px;\n}\n.hook.success .before-each-result-icon\n,.hook.success .after-each-result-icon\n,.processing-details.success .processing-result-icon\n{\n --icon-size: 8px;\n}\n.hook.fail .before-each-result-icon\n,.hook.fail .after-each-result-icon\n,.processing-details.fail .processing-result-icon\n{\n --icon-size: 12px;\n}\n.hook:is(.running) .before-each-result-icon::before\n,.hook:is(.running) .after-each-result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n --icon-size: 9px;\n}\n\n/* Hook Display */\n.hook\n{\n display: none;\n}\n:host(.has-before-all-hook) #before-all-details\n,:host(.has-after-all-hook) #after-all-details\n{\n display: initial;\n}\n:host(.has-before-each-hook) .before-each-details\n,:host(.has-after-each-hook) .after-each-details\n{\n display: initial;\n}\n:host(.has-required-before-hook) #required-before-any-details\n,:host(.has-required-after-hook) #required-after-any-details\n{\n display: initial;\n}\n\n/* Test Display */\ncode-test .results\n{\n display: grid;\n gap: var(--gap-small);\n padding-inline-start: 1em;\n}\n\ncode-test .results details .result\n,.hook > .results\n{\n margin-inline-start: 1em;\n}\n\n.result.message:empty\n{\n padding: .5em 1em;\n}\n.result.message:empty::before\n{\n content: '[ this function has not been run ]';\n font-family: monospace;\n font-size: 12px;\n font-style: italic;\n}\n\n/* Ordered Display */\n#tests\n{\n counter-reset: tests;\n}\ncode-test\n{\n counter-increment: tests;\n}\ncode-test > details > summary > .description\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 0; /* hack to make overflow work right; \"contain: inline-size\" is correct fix, but it's too new to implement on jan 25, 2026; */\n}\n:host(:not([ordered=\"false\"])) code-test > details > summary > .description::before\n{\n content: counter(tests) \". \";\n}\n\n/* Hook Name */\n.hook-name,.processing-description\n{\n border-radius: 3px;\n border: solid 1px;\n font-family: monospace;\n text-transform: uppercase;\n font-size: 11px;\n padding: 3px 7px;\n}\n\n#footer\n{\n display: flex;\n justify-content: flex-end;\n border-top: solid 1px;\n border-bottom: solid 1px;\n background: var(--surface-footer);\n margin-top: var(--gap-small);\n}\n#group-results\n{\n display: flex;\n gap: var(--gap);\n padding: var(--gap);\n}\n\n#results-progress-value\n{\n min-width: 40px;\n width: auto;\n}\n\n#duration\n,#passed-total-pair\n,#passed-total-percent\n{\n white-space: nowrap;\n}\n\n#passed-total-percent::before\n{\n content: '(';\n}\n#passed-total-percent::after\n{\n content: ')';\n}\n\n@keyframes spin\n{\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}");const u="code-tests";class d extends HTMLElement{state={isCanceled:!1,beforeAllState:void 0,afterAllState:void 0,beforeEachState:void 0,afterEachState:void 0,requiredBeforeAnyState:void 0,requiredAfterAnyState:void 0,resetHook:void 0,contextHook:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.shadowRoot.querySelector(t)}findElements(t){return Array.from(this.shadowRoot.querySelectorAll(t))}getIsRunning(){return 1==(null!=this.findElements("code-test").find(t=>1==t.isRunning()))||1==this.state.requiredBeforeAnyState?.isRunning||1==this.state.requiredAfterAnyState?.isRunning||1==this.state.beforeAllState?.isRunning||1==this.state.afterAllState?.isRunning}getResultCategory(){const t=this.findElements("code-test").reduce((t,e,s)=>{const n=e.resultCategory();return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},""),e=[this.state.requiredBeforeAnyState,this.state.requiredAfterAnyState,this.state.beforeAllState,this.state.afterAllState].reduce((t,e,s)=>{if(null==e)return null;const n=e?.resultCategory;return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},"");return"none"==t&&null==e?"none":"fail"==t||"fail"==e?"fail":"success"==t||"success"==e?"success":"none"}#r;constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML='<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 <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\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">0</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">0</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>',this.shadowRoot.adoptedStyleSheets.push(c)}connectedCallback(){this.#i()}disconnectedCallback(){this.#l()}#c=!1;#u=!1;async#i(){1!=this.#c&&1!=this.#u&&(this.#c=!0,i(this.shadowRoot),this.addEventListener("click",this.#d),this.findElement("#enabled").addEventListener("change",this.#h),await new Promise(e=>requestAnimationFrame(()=>{this.#r=new a(this),this.#u=!0,this.#c=!1;if(0==this.dispatchEvent(new CustomEvent(t.Init,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}})))return void e();"false"!=this.getAttribute("auto")?(this.reloadTests(),e()):e()})))}#l(){this.removeEventListener("click",this.#d),this.findElement("#enabled").removeEventListener("change",this.#h),this.#u=!1,this.#c=!1}#d=this.#f.bind(this);#f(t){if(null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"run-all-button"==t.id))return void(this.classList.contains("running")?this.cancel():this.classList.contains("fail")||this.classList.contains("success")?this.reset():this.runTests());null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"reload-button"==t.id)&&this.reloadTests();const e=t.composedPath().find(t=>t instanceof HTMLButtonElement&&t.classList.contains("run-test-button"));if(null==e)return;const s=e.closest("code-test")??void 0;this.#r.runTest(s,!1)}#h=this.#p.bind(this);#p(e){const s=e.target;0==this.dispatchEvent(new CustomEvent(t.Enabled,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))&&(e.preventDefault(),e.stopPropagation(),s.checked=!s.checked)}#g(){return this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path")??void 0}#t(){const t=this.getIsRunning(),e=this.getResultCategory(),s=null!=this.state.beforeAllState,n=null!=this.state.beforeEachState,a=null!=this.state.requiredAfterAnyState,o=null!=this.state.beforeAllState,r=null!=this.state.beforeEachState,i=null!=this.state.requiredAfterAnyState,l=1==a||1==s||1==n,c=1==i||1==o||1==r;this.classList.toggle("canceled",this.state.isCanceled),this.part.toggle("canceled",this.state.isCanceled),this.classList.toggle("running",1==t),this.part.toggle("running",1==t),this.toggleAttribute("success","success"==e),this.classList.toggle("success","success"==e),this.part.toggle("success","success"==e),this.classList.toggle("fail","fail"==e),this.part.toggle("fail","fail"==e),this.classList.toggle("has-before-hook",l),this.part.toggle("has-before-hook",l),this.classList.toggle("has-after-hook",c),this.part.toggle("has-after-hook",c),this.classList.toggle("has-before-all-hook",s),this.part.toggle("has-before-all-hook",s),this.classList.toggle("has-after-all-hook",o),this.part.toggle("has-after-all-hook",o),this.classList.toggle("has-before-each-hook",n),this.part.toggle("has-before-each-hook",n),this.classList.toggle("has-after-each-hook",r),this.part.toggle("has-after-each-hook",r),this.classList.toggle("has-required-before-hook",a),this.part.toggle("has-required-before-hook",a),this.classList.toggle("has-required-after-hook",i),this.part.toggle("has-required-after-hook",i);const u=this.findElement(".run-all-button-label");null!=u&&(u.textContent=1==t?"Cancel":"fail"==e||"success"==e?"Reset":"Run Tests",u.title=1==t?"Cancel the testing":"fail"==e||"success"==e?"Reset the tests so they can be run again":"Run the tests");const d=this.findElement(".run-all-button-icon");null!=d&&(d.innerHTML=1==t?'<use href="#icon-definition_cancel"></use>':"fail"==e||"success"==e?'<use href="#icon-definition_reset"></use>':'<use href="#icon-definition_arrow"></use>'),this.#m(this.state.beforeAllState,"#before-all-results"),this.#m(this.state.afterAllState,"#after-all-results"),this.#m(this.state.requiredBeforeAnyState,"#required-before-any-results"),this.#m(this.state.requiredAfterAnyState,"#required-after-any-results");const h=this.findElement("#title");null!=h&&(h.textContent=this.getAttribute("label")??"Tests"),this.#b()}#m(t,e){const s=this.findElement(e);t?.resultContent instanceof HTMLElement?s.append(t.resultContent):"string"==typeof t?.resultContent&&(s.innerHTML=t.resultContent);const n=s.closest("details");n.toggleAttribute("open",null!=t&&"none"!=t.resultCategory),n.classList.toggle("running",1==t?.isRunning),n.part.toggle("running",1==t?.isRunning),n.toggleAttribute("success","success"==t?.resultCategory),n.classList.toggle("success","success"==t?.resultCategory),n.part.toggle("success","success"==t?.resultCategory),n.classList.toggle("fail","fail"==t?.resultCategory),n.part.toggle("fail","fail"==t?.resultCategory)}#b(){const t=this.collectTestResults(),e=this.findElement("#results-progress-value");null!=e&&(e.max=t.totalTests,e.value=t.totalPassed);const s=this.findElement("#total-tests-passed-value");null!=s&&(s.textContent=t.totalPassed.toString());const n=this.findElement("#total-tests-count-value");null!=n&&(n.textContent=t.totalTests.toString());const a=this.findElement("#passed-total-percent-value");null!=a&&(a.textContent=t.totalPercentage.toFixed(1));const o=this.findElement("#duration-value");null!=o&&(o.textContent=t.duration>10?t.duration.toFixed(0):t.duration.toFixed(2))}collectTestResults(){const t=this.findElements("code-test"),e=t.length,s=t.filter(t=>"success"==t.state.testState?.resultCategory).length;return{totalTests:e,totalPassed:s,totalPercentage:0==e?0:s/e*100,duration:t.reduce((t,e,s)=>t+(e.state.testState?.duration??0),0)}}async runTests(){const t=this.findElements("code-test");return this.#r.runTests(t)}async reloadTests(){this.findElement("#tests").innerHTML="",await this.reset();const t=this.#g();this.#r.loadTests(t)}async reset(){const e=this.findElements("code-test");for(let t=0;t<e.length;t++){const s=e[t],n=null!=this.state.beforeEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.beforeEachState.hasRun,isRunning:this.state.beforeEachState.isRunning,duration:0}:void 0,a=null!=this.state.afterEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.afterEachState.hasRun,isRunning:this.state.afterEachState.isRunning,duration:0}:void 0;null!=n&&(s.state.beforeEachState=n),null!=a&&(s.state.afterEachState=a),s.reset()}const s=null==this.state.beforeAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeAllState.test,isRunning:!1,hasRun:!1,duration:0},n=null==this.state.afterAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterAllState.test,isRunning:!1,hasRun:!1,duration:0},a=null==this.state.beforeEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeEachState.test,isRunning:!1,hasRun:!1,duration:0},o=null==this.state.afterEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterEachState.test,isRunning:!1,hasRun:!1,duration:0},r=null==this.state.requiredBeforeAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredBeforeAnyState.test,isRunning:!1,hasRun:!1,duration:0},i=null==this.state.requiredAfterAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredAfterAnyState.test,isRunning:!1,hasRun:!1,duration:0};this.setStateProperties({isCanceled:!1,beforeAllState:s,afterAllState:n,beforeEachState:a,afterEachState:o,requiredAfterAnyState:i,requiredBeforeAnyState:r}),this.#r.shouldContinueRunningTests=!0,null!=this.state.resetHook&&await this.state.resetHook(await this.#r.createTestContext()),this.dispatchEvent(new CustomEvent(t.Reset,{bubbles:!0,composed:!0}))}cancel(){this.state.isCanceled=!0,this.#r.shouldContinueRunningTests=!1,this.classList.add("canceled"),this.part.add("canceled"),this.dispatchEvent(new CustomEvent(t.Cancel,{bubbles:!0,composed:!0}))}static observedAttributes=["open","label"];attributeChangedCallback(t,e,s){if("open"==t)this.findElement("#component-details").toggleAttribute("open",null!=s);else if("label"==t){const t=this.findElement("#title");null!=t&&(t.textContent=s??"Tests")}}}function h(t){return new o(async(e,s)=>{if(t instanceof Promise){return void e(await t)}e(t)})}async function f(e,s,n,a){let o=null;const r=await new Promise((t,r)=>{const i=a?.template??e.querySelector(".prompt-template")??e.findElement("#prompt-template");o=p(i),o.querySelector(".label").textContent=n;const l=e=>{const s=e.composedPath();if(null!=s.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("accept"))){const e=a?.onAccept?.()??!0;return o.removeEventListener("click",l),void t(e)}if(null!=s.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("reject"))){const e=a?.onReject?.()??!1;return o.removeEventListener("click",l),void t(e)}};o.addEventListener("click",l),null!=a?.acceptLabel&&(o.querySelector(".accept").textContent=a.acceptLabel),null!=a?.rejectLabel&&(o.querySelector(".reject").textContent=a.rejectLabel),s.append(o)});return null!=o&&o.remove(),e.dispatchEvent(new CustomEvent(t.PromptResult,{bubbles:!0,composed:!0,detail:{target:e,result:r}})),r}function p(t,e){const s=t instanceof HTMLTemplateElement?t:document.querySelector(t);if(null==s)throw new Error(`Unable to find template element from selector: ${t}`);const n=s.content.cloneNode(!0).firstElementChild;if(null==n)throw new Error("Unable to find first child of template element");return e?.append(n),n}null==customElements.get(u)&&customElements.define(u,d);export{s as CodeTestElement,t as CodeTestEvent,d as CodeTestsElement,l as Hook,o as TestPromise,p as createElementFromTemplate,h as expect,f as prompt};
|
package/dist/code-tests.umd.js
CHANGED
|
@@ -22,15 +22,7 @@
|
|
|
22
22
|
--border-process: solid 1px var(--primary-process);
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
--surface-test-summary: var(--uchu-gray);
|
|
27
|
-
--surface-hook-summary: var(--uchu-light-purple);
|
|
28
|
-
--surface-hook-any-summary: var(--uchu-light-blue);
|
|
29
|
-
|
|
30
|
-
--border-test: solid 1px var(--uchu-dark-gray);
|
|
31
|
-
--border-hook: solid 1px var(--uchu-dark-purple);
|
|
32
|
-
--border-hook-any: solid 1px var(--uchu-dark-blue);
|
|
33
|
-
--border-button: solid 1px var(--uchu-blue);
|
|
25
|
+
--surface-footer: rgb(0 0 0 / .04);
|
|
34
26
|
|
|
35
27
|
--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>');
|
|
36
28
|
--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');
|
|
@@ -42,6 +34,13 @@
|
|
|
42
34
|
font-family: sans-serif;
|
|
43
35
|
font-size: 12px;
|
|
44
36
|
}
|
|
37
|
+
@media (prefers-color-scheme: dark)
|
|
38
|
+
{
|
|
39
|
+
:host
|
|
40
|
+
{
|
|
41
|
+
--surface-footer: rgb(255 255 255 / .1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
45
44
|
|
|
46
45
|
#header
|
|
47
46
|
{
|
|
@@ -53,13 +52,16 @@
|
|
|
53
52
|
#title
|
|
54
53
|
{
|
|
55
54
|
flex: 1;
|
|
55
|
+
white-space: nowrap;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
text-overflow: ellipsis;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
#tests
|
|
59
61
|
,#component-content
|
|
60
62
|
{
|
|
61
63
|
display: grid;
|
|
62
|
-
gap: var(--gap);
|
|
64
|
+
gap: var(--gap-small);
|
|
63
65
|
grid-auto-rows: max-content;
|
|
64
66
|
}
|
|
65
67
|
|
|
@@ -103,11 +105,13 @@ summary > .run-test-button
|
|
|
103
105
|
|
|
104
106
|
summary:not(#component-summary)
|
|
105
107
|
{
|
|
106
|
-
padding: var(--gap-small)
|
|
108
|
+
padding: var(--gap-small);
|
|
107
109
|
}
|
|
108
110
|
#component-summary
|
|
109
111
|
{
|
|
110
|
-
padding: var(--gap-small)
|
|
112
|
+
padding: var(--gap) var(--gap-small);
|
|
113
|
+
border-bottom: solid 1px;
|
|
114
|
+
margin-bottom: var(--gap-small);
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
|
|
@@ -309,6 +313,10 @@ code-test
|
|
|
309
313
|
code-test > details > summary > .description
|
|
310
314
|
{
|
|
311
315
|
flex: 1;
|
|
316
|
+
white-space: nowrap;
|
|
317
|
+
overflow: hidden;
|
|
318
|
+
text-overflow: ellipsis;
|
|
319
|
+
width: 0; /* hack to make overflow work right; "contain: inline-size" is correct fix, but it's too new to implement on jan 25, 2026; */
|
|
312
320
|
}
|
|
313
321
|
:host(:not([ordered="false"])) code-test > details > summary > .description::before
|
|
314
322
|
{
|
|
@@ -320,7 +328,6 @@ code-test > details > summary > .description
|
|
|
320
328
|
{
|
|
321
329
|
border-radius: 3px;
|
|
322
330
|
border: solid 1px;
|
|
323
|
-
/* background: rgb(0 0 0 / .2); */
|
|
324
331
|
font-family: monospace;
|
|
325
332
|
text-transform: uppercase;
|
|
326
333
|
font-size: 11px;
|
|
@@ -331,6 +338,10 @@ code-test > details > summary > .description
|
|
|
331
338
|
{
|
|
332
339
|
display: flex;
|
|
333
340
|
justify-content: flex-end;
|
|
341
|
+
border-top: solid 1px;
|
|
342
|
+
border-bottom: solid 1px;
|
|
343
|
+
background: var(--surface-footer);
|
|
344
|
+
margin-top: var(--gap-small);
|
|
334
345
|
}
|
|
335
346
|
#group-results
|
|
336
347
|
{
|
|
@@ -339,6 +350,19 @@ code-test > details > summary > .description
|
|
|
339
350
|
padding: var(--gap);
|
|
340
351
|
}
|
|
341
352
|
|
|
353
|
+
#results-progress-value
|
|
354
|
+
{
|
|
355
|
+
min-width: 40px;
|
|
356
|
+
width: auto;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
#duration
|
|
360
|
+
,#passed-total-pair
|
|
361
|
+
,#passed-total-percent
|
|
362
|
+
{
|
|
363
|
+
white-space: nowrap;
|
|
364
|
+
}
|
|
365
|
+
|
|
342
366
|
#passed-total-percent::before
|
|
343
367
|
{
|
|
344
368
|
content: '(';
|
|
@@ -353,7 +377,7 @@ code-test > details > summary > .description
|
|
|
353
377
|
from { transform: rotate(0deg); }
|
|
354
378
|
to { transform: rotate(360deg); }
|
|
355
379
|
}`;
|
|
356
|
-
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 <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\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"
|
|
380
|
+
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 <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\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">0</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">0</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>';
|
|
357
381
|
const CodeTestEvent = {
|
|
358
382
|
BeforeAll: "beforeall",
|
|
359
383
|
AfterAll: "afterall",
|
|
@@ -363,7 +387,11 @@ code-test > details > summary > .description
|
|
|
363
387
|
AfterHook: "afterhook",
|
|
364
388
|
Cancel: "cancel",
|
|
365
389
|
Context: "context",
|
|
366
|
-
Reset: "reset"
|
|
390
|
+
Reset: "reset",
|
|
391
|
+
TestEnd: "testend",
|
|
392
|
+
Init: "init",
|
|
393
|
+
Enabled: "enabled",
|
|
394
|
+
PromptResult: "promptresult"
|
|
367
395
|
};
|
|
368
396
|
const COMPONENT_TAG_NAME$1 = "code-test";
|
|
369
397
|
class CodeTestElement extends HTMLElement {
|
|
@@ -453,7 +481,7 @@ code-test > details > summary > .description
|
|
|
453
481
|
<summary class="test-summary" part="test-summary">
|
|
454
482
|
<svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>
|
|
455
483
|
<div class="result-icon test-result-icon${this.state.testState?.resultCategory != "none" ? ` ${this.state.testState?.resultCategory}` : ""}" part="result-icon"></div>
|
|
456
|
-
<span class="test-description description">${this.state.description}</span>
|
|
484
|
+
<span class="test-description description" title="${this.state.description}">${this.state.description}</span>
|
|
457
485
|
${this.state.testState?.duration != null && this.state.testState.duration > 0 ? `<span class="test-duration duration">
|
|
458
486
|
<span class="test-duration-value">${this.state.testState.duration > 10 ? this.state.testState.duration.toFixed(0) : this.state.testState.duration.toFixed(2)}</span>
|
|
459
487
|
<span class="test-duration-unit">ms</span>
|
|
@@ -801,6 +829,9 @@ code-test > details > summary > .description
|
|
|
801
829
|
}
|
|
802
830
|
}
|
|
803
831
|
testContext = testContext ?? await this.createTestContext(test);
|
|
832
|
+
if (testContext.testElement == null) {
|
|
833
|
+
testContext.testElement = test;
|
|
834
|
+
}
|
|
804
835
|
if (inLoop == false) {
|
|
805
836
|
await this.runHook("requiredBeforeAnyState", void 0, testContext);
|
|
806
837
|
if (this.shouldContinueRunningTests == false) {
|
|
@@ -830,6 +861,7 @@ code-test > details > summary > .description
|
|
|
830
861
|
for (let i = 0; i < tests.length; i++) {
|
|
831
862
|
tests[i].enable();
|
|
832
863
|
}
|
|
864
|
+
this.codeTestsElement.dispatchEvent(new CustomEvent(CodeTestEvent.TestEnd, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
833
865
|
}
|
|
834
866
|
async runHook(testStateName, test, testContext) {
|
|
835
867
|
const testState = this.codeTestsElement.state[testStateName];
|
|
@@ -1151,7 +1183,7 @@ Result:${objectResult.value}</pre>
|
|
|
1151
1183
|
this.#context = new CodeTestsContext(this);
|
|
1152
1184
|
this.#isInitialized = true;
|
|
1153
1185
|
this.#isInitializing = false;
|
|
1154
|
-
const allowAutoLoad = this.dispatchEvent(new CustomEvent(
|
|
1186
|
+
const allowAutoLoad = this.dispatchEvent(new CustomEvent(CodeTestEvent.Init, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
1155
1187
|
if (allowAutoLoad == false) {
|
|
1156
1188
|
resolve();
|
|
1157
1189
|
return;
|
|
@@ -1198,7 +1230,7 @@ Result:${objectResult.value}</pre>
|
|
|
1198
1230
|
#boundEnabledHandler = this.#enabled_onChange.bind(this);
|
|
1199
1231
|
#enabled_onChange(event) {
|
|
1200
1232
|
const input = event.target;
|
|
1201
|
-
const allowToggle = this.dispatchEvent(new CustomEvent(
|
|
1233
|
+
const allowToggle = this.dispatchEvent(new CustomEvent(CodeTestEvent.Enabled, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
1202
1234
|
if (allowToggle == false) {
|
|
1203
1235
|
event.preventDefault();
|
|
1204
1236
|
event.stopPropagation();
|
|
@@ -1246,12 +1278,12 @@ Result:${objectResult.value}</pre>
|
|
|
1246
1278
|
this.part.toggle("has-required-after-hook", hasRequiredAfterAnyState);
|
|
1247
1279
|
const runAllButtonLabel = this.findElement(".run-all-button-label");
|
|
1248
1280
|
if (runAllButtonLabel != null) {
|
|
1249
|
-
runAllButtonLabel.textContent = isRunning == true ? "Cancel" : resultCategory == "fail" ? "Reset" : "Run Tests";
|
|
1250
|
-
runAllButtonLabel.title = isRunning == true ? "Cancel the testing" : resultCategory == "fail" ? "Reset the tests so they can be run again" : "Run the tests";
|
|
1281
|
+
runAllButtonLabel.textContent = isRunning == true ? "Cancel" : resultCategory == "fail" || resultCategory == "success" ? "Reset" : "Run Tests";
|
|
1282
|
+
runAllButtonLabel.title = isRunning == true ? "Cancel the testing" : resultCategory == "fail" || resultCategory == "success" ? "Reset the tests so they can be run again" : "Run the tests";
|
|
1251
1283
|
}
|
|
1252
1284
|
const runAllIcon = this.findElement(".run-all-button-icon");
|
|
1253
1285
|
if (runAllIcon != null) {
|
|
1254
|
-
runAllIcon.innerHTML = isRunning == true ? '<use href="#icon-definition_cancel"></use>' : resultCategory == "fail" ? '<use href="#icon-definition_reset"></use>' : '<use href="#icon-definition_arrow"></use>';
|
|
1286
|
+
runAllIcon.innerHTML = isRunning == true ? '<use href="#icon-definition_cancel"></use>' : resultCategory == "fail" || resultCategory == "success" ? '<use href="#icon-definition_reset"></use>' : '<use href="#icon-definition_arrow"></use>';
|
|
1255
1287
|
}
|
|
1256
1288
|
this.#renderHook(this.state.beforeAllState, "#before-all-results");
|
|
1257
1289
|
this.#renderHook(this.state.afterAllState, "#after-all-results");
|
|
@@ -1411,24 +1443,25 @@ Result:${objectResult.value}</pre>
|
|
|
1411
1443
|
return promise;
|
|
1412
1444
|
}
|
|
1413
1445
|
async function prompt(host, parentElement, message, options) {
|
|
1414
|
-
|
|
1446
|
+
let promptElement = null;
|
|
1447
|
+
const result = await new Promise((resolve, _reject) => {
|
|
1415
1448
|
const template = options?.template ?? host.querySelector(".prompt-template") ?? host.findElement("#prompt-template");
|
|
1416
|
-
|
|
1449
|
+
promptElement = createElementFromTemplate(template);
|
|
1417
1450
|
promptElement.querySelector(".label").textContent = message;
|
|
1418
1451
|
const clickHandler = (event) => {
|
|
1419
1452
|
const composedPath = event.composedPath();
|
|
1420
1453
|
const acceptButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("accept"));
|
|
1421
1454
|
if (acceptButton != null) {
|
|
1422
|
-
const
|
|
1455
|
+
const result2 = options?.onAccept?.() ?? true;
|
|
1423
1456
|
promptElement.removeEventListener("click", clickHandler);
|
|
1424
|
-
resolve(
|
|
1457
|
+
resolve(result2);
|
|
1425
1458
|
return;
|
|
1426
1459
|
}
|
|
1427
1460
|
const rejectButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("reject"));
|
|
1428
1461
|
if (rejectButton != null) {
|
|
1429
|
-
const
|
|
1462
|
+
const result2 = options?.onReject?.() ?? false;
|
|
1430
1463
|
promptElement.removeEventListener("click", clickHandler);
|
|
1431
|
-
resolve(
|
|
1464
|
+
resolve(result2);
|
|
1432
1465
|
return;
|
|
1433
1466
|
}
|
|
1434
1467
|
};
|
|
@@ -1441,6 +1474,11 @@ Result:${objectResult.value}</pre>
|
|
|
1441
1474
|
}
|
|
1442
1475
|
parentElement.append(promptElement);
|
|
1443
1476
|
});
|
|
1477
|
+
if (promptElement != null) {
|
|
1478
|
+
promptElement.remove();
|
|
1479
|
+
}
|
|
1480
|
+
host.dispatchEvent(new CustomEvent(CodeTestEvent.PromptResult, { bubbles: true, composed: true, detail: { target: host, result } }));
|
|
1481
|
+
return result;
|
|
1444
1482
|
}
|
|
1445
1483
|
function createElementFromTemplate(target, parent) {
|
|
1446
1484
|
const templateNode = target instanceof HTMLTemplateElement ? target : document.querySelector(target);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(((t="undefined"!=typeof globalThis?globalThis:t||self)["code-tests"]=t["code-tests"]||{},t["code-tests"].umd=t["code-tests"].umd||{},t["code-tests"].umd.min=t["code-tests"].umd.min||{},t["code-tests"].umd.min.js={}))}(this,function(t){"use strict";const e={BeforeAll:"beforeall",AfterAll:"afterall",BeforeTest:"beforetest",AfterTest:"aftertest",BeforeHook:"beforehook",AfterHook:"afterhook",Cancel:"cancel",Context:"context",Reset:"reset"},s="code-test";class n extends HTMLElement{state={testId:"",description:"none",isDisabled:!1,testState:void 0,beforeEachState:void 0,afterEachState:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.querySelector(t)}findElements(t){return Array.from(this.querySelectorAll(t))}isRunning(){return 1==this.state.testState?.isRunning||1==this.state.beforeEachState?.isRunning||1==this.state.afterEachState?.isRunning}hasRun(){return 1==this.state.testState?.hasRun||1==this.state.beforeEachState?.hasRun||1==this.state.afterEachState?.hasRun}resultCategory(){const t=this.state.testState?.resultCategory??"none",e=this.state.beforeEachState?.resultCategory??"none",s=this.state.afterEachState?.resultCategory??"none";return"none"==t&&"none"==e&&"none"==s?"none":null==this.state.beforeEachState&&null==this.state.afterEachState?t:null!=this.state.beforeEachState&&null==this.state.afterEachState?"fail"==t||"fail"==e?"fail":"success"==t&&"success"==e?"success":"none":null==this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==s?"fail":"success"==t&&"success"==s?"success":"none":null!=this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==e||"fail"==s?"fail":"success"==t&&"success"==e&&"success"==s?"success":"none":void 0}connectedCallback(){this.#t()}#t(){const t=null==this.state.testState?"":"boolean"==typeof this.state.testState.resultContent?1==this.state.testState.resultContent?'<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>':"number"==typeof this.state.testState.resultContent?`<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed: ${this.state.testState.resultContent.toString()}</pre></code>`:"string"==typeof this.state.testState.resultContent?this.state.testState.resultContent:"";this.innerHTML=`<details class="test-details" part="test-details" ${1==this.isRunning()||1==this.hasRun()?" open":""}>\n <summary class="test-summary" part="test-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="result-icon test-result-icon${"none"!=this.state.testState?.resultCategory?` ${this.state.testState?.resultCategory}`:""}" part="result-icon"></div>\n <span class="test-description description">${this.state.description}</span>\n ${null!=this.state.testState?.duration&&this.state.testState.duration>0?`<span class="test-duration duration">\n <span class="test-duration-value">${this.state.testState.duration>10?this.state.testState.duration.toFixed(0):this.state.testState.duration.toFixed(2)}</span>\n <span class="test-duration-unit">ms</span>\n </span>`:""}\n <button type="button" class="run-test-button" part="run-test-button" title="Run Test"${1==this.state.isDisabled?" disabled":""}>\n <slot name="run-button-content">\n <slot name="run-button-icon"><svg class="icon arrow-icon run-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-button-label"><span class="run-button-label button-label label icon">Run Test</span></slot>\n </slot>\n </button>\n </summary>\n <div class="results" part="results">\n ${null==this.state.beforeEachState?"":`<details class="before-each-details hook${"none"==this.state.beforeEachState.resultCategory?"":` ${this.state.beforeEachState.resultCategory}`}${1==this.state.beforeEachState.isRunning?" running":""}" part="before-each-details hook">\n <summary class="before-each-summary" part="before-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="before-each-result-icon result-icon${"none"!=this.state.beforeEachState.resultCategory?` ${this.state.beforeEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="before-each-description description hook-name">Before Each Hook</span>\n </summary>\n <div class="before-each-result result message" part="before-each-result result message">${"string"!=typeof this.state.beforeEachState.resultContent?"":this.state.beforeEachState.resultContent}</div>\n </details>`}\n ${null==this.state.testState?"":null==this.state.beforeEachState&&null==this.state.afterEachState?`<div class="test-result result message" part="test-result result message">${t}</div>`:`<details class="processing-details${"none"==this.state.testState.resultCategory?"":` ${this.state.testState.resultCategory}`}${1==this.state.testState.isRunning?" running":""}" part="processing-details"${1==this.state.testState.hasRun?" open":""}>\n <summary class="processing-summary" part="processing-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="processing-result-icon result-icon${"none"!=this.state.testState.resultCategory?` ${this.state.testState.resultCategory}`:""}" part="processing-result-icon result-icon"></div>\n <span class="processing-description description">Test</span>\n </summary>\n <div class="test-result result message" part="test-result result message">${t}</div>\n </details>`} \n ${null==this.state.afterEachState?"":`<details class="after-each-details hook${"none"==this.state.afterEachState.resultCategory?"":` ${this.state.afterEachState.resultCategory}`}${1==this.state.afterEachState.isRunning?" running":""}" part="after-each-detail hooks">\n <summary class="after-each-summary" part="after-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="after-each-result-icon result-icon${"none"!=this.state.afterEachState.resultCategory?` ${this.state.afterEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="after-each-description description hook-name">After Each Hook</span>\n </summary>\n <div class="after-each-result result message" part="after-each-result result message">${"string"!=typeof this.state.afterEachState.resultContent?"":this.state.afterEachState.resultContent}</div>\n </details>`}\n </div>\n </details>`,this.dataset.testId=this.state.testId,this.classList.add("test"),this.part.add("test"),this.toggleAttribute("success","success"==this.resultCategory()),this.classList.toggle("success","success"==this.resultCategory()),this.part.toggle("success","success"==this.resultCategory()),this.classList.toggle("fail","fail"==this.resultCategory()),this.part.toggle("fail","fail"==this.resultCategory()),this.classList.toggle("running",this.isRunning()),this.part.toggle("running",this.isRunning()),this.state.beforeEachState?.resultContent instanceof HTMLElement&&this.querySelector(".before-each-result").append(this.state.beforeEachState.resultContent),this.state.testState?.resultContent instanceof HTMLElement&&this.querySelector(".test-result").append(this.state.testState.resultContent),this.state.afterEachState?.resultContent instanceof HTMLElement&&this.querySelector(".after-each-result").append(this.state.afterEachState.resultContent)}enable(){this.state.isDisabled=!1,this.findElement(".run-test-button").toggleAttribute("disabled",!1)}disable(){this.state.isDisabled=!0,this.findElement(".run-test-button").toggleAttribute("disabled",!0)}async runTest(t,s){if(null==this.state.testState?.test)return;let n;this.reset();let a={},r=0;try{if(0==t.shouldContinueRunningTests)throw new Error("Tests have been disabled from continuing to run.");if(0==this.dispatchEvent(new CustomEvent(e.BeforeTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}})))throw new Error("Test has been prevented.");if(1==s.codeTestsElement.state.isCanceled)throw new Error("Testing has been canceled.");this.setTestStateProperties("testState",{isRunning:!0}),t.codeTestsElement.setState(t.codeTestsElement.state);const o=performance?.now()??Date.now();n=await this.state.testState.test(s);r=(performance?.now()??Date.now())-o,this.setTestStateProperties("testState",{isRunning:!1,hasRun:!0}),t.codeTestsElement.setState(t.codeTestsElement.state);const i=t.parseTestResult(n,!0);a={testState:{test:this.state.testState.test,resultContent:i.result,resultCategory:i.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:r}}}catch(e){const s=t.parseTestResult(n,!1,e);a={testState:{test:this.state.testState.test,resultContent:s.result,resultCategory:s.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:r}},console.error(e),t.shouldContinueRunningTests=!1}finally{this.setStateProperties({...a}),t.codeTestsElement.setState(t.codeTestsElement.state),this.dispatchEvent(new CustomEvent(e.AfterTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}}))}}reset(){const t=null!=this.state.testState?{resultCategory:"none",resultContent:"",test:this.state.testState.test,hasRun:this.state.testState.hasRun,isRunning:this.state.testState.isRunning,duration:0}:void 0;null!=t&&this.setTestStateProperties("testState",t)}getMessageElement(){return this.findElement(".test-result")}static observedAttributes=["open"];attributeChangedCallback(t,e,s){"open"==t&&this.findElement(".test-details").toggleAttribute("open",null!=s)}}null==customElements.get(s)&&customElements.define(s,n);const a=Symbol("No Test Defined");class r{codeTestsElement;constructor(t){this.codeTestsElement=t}async loadTests(t){if(null!=t)try{const{tests:e,hooks:s}=await this.#e(t),n=s[c.BeforeAll],a=s[c.AfterAll],r=s[c.BeforeEach],o=s[c.AfterEach],i=s[c.RequiredBeforeAny],l=s[c.RequiredAfterAny],u=null==n?void 0:{resultCategory:"none",resultContent:"",test:n,hasRun:!1,isRunning:!1,duration:0},d=null==a?void 0:{resultCategory:"none",resultContent:"",test:a,hasRun:!1,isRunning:!1,duration:0},h=null==r?void 0:{resultCategory:"none",resultContent:"",test:r,hasRun:!1,isRunning:!1,duration:0},f=null==o?void 0:{resultCategory:"none",resultContent:"",test:o,hasRun:!1,isRunning:!1,duration:0},p=null==i?void 0:{resultCategory:"none",resultContent:"",test:i,hasRun:!1,isRunning:!1,duration:0},g=null==l?void 0:{resultCategory:"none",resultContent:"",test:l,hasRun:!1,isRunning:!1,duration:0};this.codeTestsElement.state.beforeEachState=h,this.codeTestsElement.state.afterEachState=f;for(const[t,s]of Object.entries(e))this.#s(t,s);this.codeTestsElement.setStateProperties({beforeAllState:u,afterAllState:d,beforeEachState:h,afterEachState:f,requiredBeforeAnyState:p,requiredAfterAnyState:g,resetHook:s.reset,contextHook:s.context})}catch(t){console.error(t)}}async#e(t){const e=await this.#n(t),s=e.tests??e.default;if(null==s)throw new Error(`Unable to find tests definition in file at path: ${t}`);const n={},a=s[c.BeforeAll];null!=a&&(n[c.BeforeAll]=a,delete s[c.BeforeAll]);const r=s[c.AfterAll];null!=r&&(n[c.AfterAll]=r,delete s[c.AfterAll]);const o=s[c.BeforeEach];null!=o&&(n[c.BeforeEach]=o,delete s[c.BeforeEach]);const i=s[c.AfterEach];null!=i&&(n[c.AfterEach]=i,delete s[c.AfterEach]);const l=s[c.RequiredBeforeAny];null!=l&&(n[c.RequiredBeforeAny]=l,delete s[c.RequiredBeforeAny]);const u=s[c.RequiredAfterAny];null!=u&&(n[c.RequiredAfterAny]=u,delete s[c.RequiredAfterAny]);const d=s[c.Reset];null!=d&&(n[c.Reset]=d,delete s[c.Reset]);const h=s[c.Context];return null!=h&&(n[c.Context]=h,delete s[c.Context]),{tests:s,hooks:n}}async#n(t){const e=window.location.href.lastIndexOf("/"),s=1==(-1!=window.location.href.substring(e).indexOf("."))?window.location.href.substring(0,e+1):window.location.href,n=s+t.substring(0,t.lastIndexOf("/")+1),a=s+t;let r=await(await fetch(a)).text();r=r.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g,`'${n}$1'`);const o=new File([r],t.substring(t.lastIndexOf("/")),{type:"text/javascript"}),i=URL.createObjectURL(o);return await import(i)}#s(t,e){const s=function(){const t=new Uint8Array(20);crypto.getRandomValues(t);const e=[].slice.apply(t).map(function(t){return String.fromCharCode(t)}).join("");return btoa(e).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,"")}(),a=new n;return a.setStateProperties({testId:s,description:t,testState:{test:e,resultCategory:"none",resultContent:"",isRunning:!1,hasRun:!1,duration:0},beforeEachState:null==this.codeTestsElement.state.beforeEachState?void 0:{isRunning:this.codeTestsElement.state.beforeEachState.isRunning,hasRun:this.codeTestsElement.state.beforeEachState.hasRun,resultCategory:this.codeTestsElement.state.beforeEachState.resultCategory,resultContent:this.codeTestsElement.state.beforeEachState.resultContent,duration:0},afterEachState:null==this.codeTestsElement.state.afterEachState?void 0:{isRunning:this.codeTestsElement.state.afterEachState.isRunning,hasRun:this.codeTestsElement.state.afterEachState.hasRun,resultCategory:this.codeTestsElement.state.afterEachState.resultCategory,resultContent:this.codeTestsElement.state.afterEachState.resultContent,duration:0}}),this.codeTestsElement.findElement("#tests").append(a),s}shouldContinueRunningTests=!0;async runTests(t){if(0==this.codeTestsElement.dispatchEvent(new CustomEvent(e.BeforeAll,{bubbles:!0,composed:!0,cancelable:!0})))throw new Error("Tests have been prevented.");await this.codeTestsElement.reset();for(let e=0;e<t.length;e++)t[e].disable();const s=await this.createTestContext();if(await this.runHook("requiredBeforeAnyState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(t,s);if(await this.runHook("beforeAllState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(t,s);if(0==("false"!=this.codeTestsElement.getAttribute("ordered"))){const e=t.map(t=>this.runTest(t,!0,s));await Promise.all(e)}else for(let e=0;e<t.length;e++){const n=t[e];if(0==this.shouldContinueRunningTests)break;await this.runTest(n,!0,s)}0!=this.shouldContinueRunningTests?(await this.runHook("afterAllState",void 0,s),await this.#a(t,s)):await this.#a(t,s)}async#a(t,s){await this.runHook("requiredAfterAnyState",void 0,s);for(let e=0;e<t.length;e++)t[e].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(e.AfterAll,{bubbles:!0,composed:!0}))}async runTest(t,e,s){if(null!=t){if(0==e){const t=this.codeTestsElement.findElements("code-test");for(let e=0;e<t.length;e++)t[e].disable()}s=s??await this.createTestContext(t),0!=e||(await this.runHook("requiredBeforeAnyState",void 0,s),0!=this.shouldContinueRunningTests)?(await this.runHook("beforeEachState",t,s),0!=this.shouldContinueRunningTests?(await t.runTest(this,s),0!=this.shouldContinueRunningTests?(await this.runHook("afterEachState",t,s),await this.#r(s,e)):await this.#r(s,e)):await this.#r(s,e)):await this.#r(s,e)}}async#r(t,e){if(1==e)return;await this.runHook("requiredAfterAnyState",void 0,t);const s=this.codeTestsElement.findElements("code-test");for(let t=0;t<s.length;t++)s[t].enable()}async runHook(t,s,n){const r=this.codeTestsElement.state[t];if(null==r)return a;if(1==this.codeTestsElement.state.isCanceled)return{success:!1,value:"Testing has been canceled."};let o;try{if(0==this.shouldContinueRunningTests&&("requiredAfterAnyState"!=t||"error"==this.codeTestsElement.getAttribute("required-after")))throw new Error("Tests have been disabled from continuing to run.");null!=s&&s.setTestStateProperties(t,{isRunning:!0}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!0}),o=await r.test(n),null!=s&&s.setTestStateProperties(t,{isRunning:!1,hasRun:!0}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!1,hasRun:!0});const e=this.parseTestResult(o,!0,void 0);null!=s&&s.setTestStateProperties(t,{resultCategory:e.resultCategory,resultContent:e.result}),this.codeTestsElement.setTestStateProperties(t,{resultCategory:e.resultCategory,resultContent:e.result})}catch(e){console.error(e),this.shouldContinueRunningTests=!1,o={success:!1,value:`Failed: ${e.message}`};const n=this.parseTestResult(o,!1,e);null!=s&&s.setTestStateProperties(t,{isRunning:!1,hasRun:!0,resultContent:n.result,resultCategory:n.resultCategory}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!1,hasRun:!0,resultCategory:n.resultCategory,resultContent:n.result})}finally{return this.codeTestsElement.dispatchEvent(new CustomEvent(e.AfterHook,{bubbles:!0,composed:!0,detail:o})),o}}parseTestResult(t,e,s){if(t==a)return{result:"",resultCategory:"none"};if(null==t){const t=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${t}" part="pre ${t}">${1==e?"Passed":"Failed"+(null!=s?`:\n${s.message}`:"")}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}if("boolean"==typeof t)return{result:t,resultCategory:1==t?"success":"fail"};if("function"==typeof t)return console.log("function"),{result:"[A function was returned]",resultCategory:"none"};if(t instanceof HTMLElement||"string"==typeof t)return{result:t,resultCategory:"none"};if("object"==typeof t){const s=t,n=1==e?"success-message":"error-message";if(null!=s.success&&null!=s.expected&&null!=s.value)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${1==s.success?"Passed":"Failed"}\nExpected:${s.expected}\nResult:${s.value}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};if(null!=s.success)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};{const s=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${s}" part="pre ${s}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}}throw new Error("Unable to parse result type: Unknown result type")}async createTestContext(t){const s={detail:{},codeTestsElement:this.codeTestsElement,testElement:t,messageElement:t?.findElement(".message")};return null!=this.codeTestsElement.state.contextHook&&await this.codeTestsElement.state.contextHook(s),this.codeTestsElement.dispatchEvent(new CustomEvent(e.Context,{bubbles:!0,composed:!0,detail:{context:s}})),s}}class o extends Promise{async toBeDefined(t){if(null==await(this))throw new Error(`${null!=t?t:"Value"} is undefined`)}async toBe(t,e=!1){const s=await(this);if(0==(1==e?s===t:s==t))throw new Error(` Value is not equal.\n Expected: ${t}\n Result: ${s}`)}async toContainText(t){const e=await(this);return e instanceof HTMLElement?{success:e.textContent.includes(t),index:e.textContent.indexOf(t)}:"string"==typeof e&&{success:e.includes(t),index:e.indexOf(t)}}async toHaveAttribute(t){const e=await(this);if(!(e instanceof HTMLElement))throw new Error("Unable to check for attribute on non-HTMLElement target");if(e.getAttribute(t))throw new Error("Target does not have attribute")}}const i=":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";function l(t){!function(t){const e=[...t.querySelectorAll(`${i}[id]`)];for(let t=0;t<e.length;t++)e[t].part.add(e[t].id)}(t),function(t){const e=[...t.querySelectorAll(`${i}[class]`)];for(let t=0;t<e.length;t++)e[t].part.add(...e[t].classList)}(t)}const c={BeforeAll:"beforeall",AfterAll:"afterall",BeforeEach:"beforeeach",AfterEach:"aftereach",RequiredBeforeAny:"requiredbeforeany",RequiredAfterAny:"requiredafterany",Reset:"reset",Context:"context"},u=new CSSStyleSheet;u.replaceSync(":host\n{\n --gap: 7px;\n --gap-small: 3px;\n --gap-medium: 14px;\n --gap-large: 24px;\n \n --surface-success: oklch(93.96% 0.05 148.74);\n --primary-success: oklch(58.83% 0.158 145.05);\n --border-success: solid 1px var(--primary-success);\n\n --surface-fail: oklch(88.98% 0.052 3.28);\n --primary-fail: oklch(45.8% 0.177 17.7);\n --border-fail: solid 1px var(--primary-fail);\n\n --surface-process: oklch(89.66% 0.046 260.67);\n --primary-process: oklch(43.48% 0.17 260.2);\n --border-process: solid 1px var(--primary-process);\n\n\n\n --surface-test-summary: var(--uchu-gray);\n --surface-hook-summary: var(--uchu-light-purple);\n --surface-hook-any-summary: var(--uchu-light-blue);\n \n --border-test: solid 1px var(--uchu-dark-gray);\n --border-hook: solid 1px var(--uchu-dark-purple);\n --border-hook-any: solid 1px var(--uchu-dark-blue);\n --border-button: solid 1px var(--uchu-blue);\n \n --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>');\n --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');\n\n\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n font-family: sans-serif;\n font-size: 12px;\n}\n\n#header\n{\n flex: 1;\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\n#title\n{\n flex: 1;\n}\n\n#tests\n,#component-content\n{\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n}\n\n#header button\n{\n align-self: stretch;\n display: inline-flex;\n align-items: center;\n gap: var(--gap-small);\n}\n\nbutton .reset-icon\n{\n width: 1em;\n height: 1em;\n transform: scaleX(-1);\n margin-inline: 3px;\n}\n\n/* Run button */\nbutton .arrow-icon\n{\n width: .75em;\n height: .75em;\n transform: rotate(-90deg);\n margin-inline: 3px;\n}\n:host(.running) .run-all-button-icon\n,:host(.fail) .run-all-button-icon\n{\n transform: rotate(0);\n}\n\n/* Dropdown Layout */\nsummary > .run-test-button\n, #run-all-button\n{\n justify-self: flex-end;\n margin-left: auto;\n}\n\nsummary:not(#component-summary)\n{\n padding: var(--gap-small) var(--gap);\n}\n#component-summary\n{\n padding: var(--gap-small)\n}\n\n\n/* Dropdown Markers */\nsummary\n{\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\nsummary > .arrow-icon\n{\n background: var(--arrow-icon);\n transform: rotate(-90deg);\n transition: transform ease-out 90ms;\n width: .6em;\n height: .6em;\n}\ndetails[open] > summary > .arrow-icon\n{\n transform: rotate(0);\n}\n\n#enabled\n{\n display: none;\n}\n:host([optional]) #enabled\n{\n display: block;\n}\n\n/* Result Icon */\n.result-icon\n{\n --background-size: 16px;\n width: var(--background-size);\n height: var(--background-size);\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n border: solid 1px currentColor;\n border-radius: 50%;\n}\n.result-icon::before\n{\n content: '⋯';\n font-size: 10px;\n}\n\n:host(.running) #component-summary .result-icon\n,.test.running .test-summary > .result-icon\n,.hook.running .result-icon\n,.processing-details.running .processing-result-icon\n{\n border: var(--border-process);\n background: var(--surface-process);\n}\n:host(.success) #component-summary .result-icon\n,.test.success .test-summary > .result-icon\n,.hook.success .result-icon\n,.processing-details.success .processing-result-icon\n{\n border: var(--border-success);\n background: var(--surface-success)\n var(--success-icon);\n background-repeat: no-repeat;\n background-position: center;\n background-size: var(--icon-size, 12px) var(--icon-size, 12px);\n}\n:host(.fail) #component-summary .result-icon\n,.test.fail .test-summary > .result-icon\n,.hook.fail .result-icon\n,.processing-details.fail .processing-result-icon\n{\n border: var(--border-fail);\n background: var(--surface-fail)\n var(--info-icon);\n background-size: var(--icon-size, 16px) var(--icon-size, 16px);\n background-repeat: no-repeat;\n background-position: center;\n transform: rotate(175deg);\n}\n:host(:is(.success,.fail)) #component-summary .result-icon::before\n,.test:is(.success,.fail) .test-summary > .result-icon::before\n,.hook:is(.success,.fail) .result-icon::before\n,.processing-details:is(.success,.fail) .processing-result-icon::before\n{\n display: none;\n}\n:host(.running) #component-summary .result-icon::before\n,.test:is(.running) .test-summary > .result-icon::before\n,.hook:is(.running) .result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n content: '';\n --color: var(--primary-process, currentColor);\n --animation-timing-function: linear;\n --animation-duration: 2s;\n width: var(--icon-size, 14px);\n height: var(--icon-size, 14px);\n mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--icon-size, 14px) / 3), black calc(var(--icon-size, 14px) / 3));\n background-image: conic-gradient(transparent, transparent 135deg, var(--color));\n border-radius: 50%;\n animation: var(--animation-timing-function) var(--animation-duration) infinite spin;\n margin: 2px;\n}\n\n/* Smaller Result icon settings for sub-test icons */\n.before-each-result-icon\n,.after-each-result-icon\n,.processing-result-icon\n{\n --background-size: 12px;\n}\n.before-each-result-icon::before\n,.after-each-result-icon::before\n,.processing-result-icon::before\n{\n font-size: 9px;\n}\n.hook.success .before-each-result-icon\n,.hook.success .after-each-result-icon\n,.processing-details.success .processing-result-icon\n{\n --icon-size: 8px;\n}\n.hook.fail .before-each-result-icon\n,.hook.fail .after-each-result-icon\n,.processing-details.fail .processing-result-icon\n{\n --icon-size: 12px;\n}\n.hook:is(.running) .before-each-result-icon::before\n,.hook:is(.running) .after-each-result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n --icon-size: 9px;\n}\n\n/* Hook Display */\n.hook\n{\n display: none;\n}\n:host(.has-before-all-hook) #before-all-details\n,:host(.has-after-all-hook) #after-all-details\n{\n display: initial;\n}\n:host(.has-before-each-hook) .before-each-details\n,:host(.has-after-each-hook) .after-each-details\n{\n display: initial;\n}\n:host(.has-required-before-hook) #required-before-any-details\n,:host(.has-required-after-hook) #required-after-any-details\n{\n display: initial;\n}\n\n/* Test Display */\ncode-test .results\n{\n display: grid;\n gap: var(--gap-small);\n padding-inline-start: 1em;\n}\n\ncode-test .results details .result\n,.hook > .results\n{\n margin-inline-start: 1em;\n}\n\n.result.message:empty\n{\n padding: .5em 1em;\n}\n.result.message:empty::before\n{\n content: '[ this function has not been run ]';\n font-family: monospace;\n font-size: 12px;\n font-style: italic;\n}\n\n/* Ordered Display */\n#tests\n{\n counter-reset: tests;\n}\ncode-test\n{\n counter-increment: tests;\n}\ncode-test > details > summary > .description\n{\n flex: 1;\n}\n:host(:not([ordered=\"false\"])) code-test > details > summary > .description::before\n{\n content: counter(tests) \". \";\n}\n\n/* Hook Name */\n.hook-name,.processing-description\n{\n border-radius: 3px;\n border: solid 1px;\n /* background: rgb(0 0 0 / .2); */\n font-family: monospace;\n text-transform: uppercase;\n font-size: 11px;\n padding: 3px 7px;\n}\n\n#footer\n{\n display: flex;\n justify-content: flex-end;\n}\n#group-results\n{\n display: flex;\n gap: var(--gap);\n padding: var(--gap);\n}\n\n#passed-total-percent::before\n{\n content: '(';\n}\n#passed-total-percent::after\n{\n content: ')';\n}\n\n@keyframes spin\n{\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}");const d="code-tests";class h extends HTMLElement{state={isCanceled:!1,beforeAllState:void 0,afterAllState:void 0,beforeEachState:void 0,afterEachState:void 0,requiredBeforeAnyState:void 0,requiredAfterAnyState:void 0,resetHook:void 0,contextHook:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.shadowRoot.querySelector(t)}findElements(t){return Array.from(this.shadowRoot.querySelectorAll(t))}getIsRunning(){return 1==(null!=this.findElements("code-test").find(t=>1==t.isRunning()))||1==this.state.requiredBeforeAnyState?.isRunning||1==this.state.requiredAfterAnyState?.isRunning||1==this.state.beforeAllState?.isRunning||1==this.state.afterAllState?.isRunning}getResultCategory(){const t=this.findElements("code-test").reduce((t,e,s)=>{const n=e.resultCategory();return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},""),e=[this.state.requiredBeforeAnyState,this.state.requiredAfterAnyState,this.state.beforeAllState,this.state.afterAllState].reduce((t,e,s)=>{if(null==e)return null;const n=e?.resultCategory;return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},"");return"none"==t&&null==e?"none":"fail"==t||"fail"==e?"fail":"success"==t||"success"==e?"success":"none"}#o;constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML='<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 <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\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>',this.shadowRoot.adoptedStyleSheets.push(u)}connectedCallback(){this.#i()}disconnectedCallback(){this.#l()}#c=!1;#u=!1;async#i(){1!=this.#c&&1!=this.#u&&(this.#c=!0,l(this.shadowRoot),this.addEventListener("click",this.#d),this.findElement("#enabled").addEventListener("change",this.#h),await new Promise(t=>requestAnimationFrame(()=>{this.#o=new r(this),this.#u=!0,this.#c=!1;if(0==this.dispatchEvent(new CustomEvent("init",{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}})))return void t();"false"!=this.getAttribute("auto")?(this.reloadTests(),t()):t()})))}#l(){this.removeEventListener("click",this.#d),this.findElement("#enabled").removeEventListener("change",this.#h),this.#u=!1,this.#c=!1}#d=this.#f.bind(this);#f(t){if(null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"run-all-button"==t.id))return void(this.classList.contains("running")?this.cancel():this.classList.contains("fail")||this.classList.contains("success")?this.reset():this.runTests());null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"reload-button"==t.id)&&this.reloadTests();const e=t.composedPath().find(t=>t instanceof HTMLButtonElement&&t.classList.contains("run-test-button"));if(null==e)return;const s=e.closest("code-test")??void 0;this.#o.runTest(s,!1)}#h=this.#p.bind(this);#p(t){const e=t.target;0==this.dispatchEvent(new CustomEvent("enabled",{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))&&(t.preventDefault(),t.stopPropagation(),e.checked=!e.checked)}#g(){return this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path")??void 0}#t(){const t=this.getIsRunning(),e=this.getResultCategory(),s=null!=this.state.beforeAllState,n=null!=this.state.beforeEachState,a=null!=this.state.requiredAfterAnyState,r=null!=this.state.beforeAllState,o=null!=this.state.beforeEachState,i=null!=this.state.requiredAfterAnyState,l=1==a||1==s||1==n,c=1==i||1==r||1==o;this.classList.toggle("canceled",this.state.isCanceled),this.part.toggle("canceled",this.state.isCanceled),this.classList.toggle("running",1==t),this.part.toggle("running",1==t),this.toggleAttribute("success","success"==e),this.classList.toggle("success","success"==e),this.part.toggle("success","success"==e),this.classList.toggle("fail","fail"==e),this.part.toggle("fail","fail"==e),this.classList.toggle("has-before-hook",l),this.part.toggle("has-before-hook",l),this.classList.toggle("has-after-hook",c),this.part.toggle("has-after-hook",c),this.classList.toggle("has-before-all-hook",s),this.part.toggle("has-before-all-hook",s),this.classList.toggle("has-after-all-hook",r),this.part.toggle("has-after-all-hook",r),this.classList.toggle("has-before-each-hook",n),this.part.toggle("has-before-each-hook",n),this.classList.toggle("has-after-each-hook",o),this.part.toggle("has-after-each-hook",o),this.classList.toggle("has-required-before-hook",a),this.part.toggle("has-required-before-hook",a),this.classList.toggle("has-required-after-hook",i),this.part.toggle("has-required-after-hook",i);const u=this.findElement(".run-all-button-label");null!=u&&(u.textContent=1==t?"Cancel":"fail"==e?"Reset":"Run Tests",u.title=1==t?"Cancel the testing":"fail"==e?"Reset the tests so they can be run again":"Run the tests");const d=this.findElement(".run-all-button-icon");null!=d&&(d.innerHTML=1==t?'<use href="#icon-definition_cancel"></use>':"fail"==e?'<use href="#icon-definition_reset"></use>':'<use href="#icon-definition_arrow"></use>'),this.#m(this.state.beforeAllState,"#before-all-results"),this.#m(this.state.afterAllState,"#after-all-results"),this.#m(this.state.requiredBeforeAnyState,"#required-before-any-results"),this.#m(this.state.requiredAfterAnyState,"#required-after-any-results");const h=this.findElement("#title");null!=h&&(h.textContent=this.getAttribute("label")??"Tests"),this.#b()}#m(t,e){const s=this.findElement(e);t?.resultContent instanceof HTMLElement?s.append(t.resultContent):"string"==typeof t?.resultContent&&(s.innerHTML=t.resultContent);const n=s.closest("details");n.toggleAttribute("open",null!=t&&"none"!=t.resultCategory),n.classList.toggle("running",1==t?.isRunning),n.part.toggle("running",1==t?.isRunning),n.toggleAttribute("success","success"==t?.resultCategory),n.classList.toggle("success","success"==t?.resultCategory),n.part.toggle("success","success"==t?.resultCategory),n.classList.toggle("fail","fail"==t?.resultCategory),n.part.toggle("fail","fail"==t?.resultCategory)}#b(){const t=this.collectTestResults(),e=this.findElement("#results-progress-value");null!=e&&(e.max=t.totalTests,e.value=t.totalPassed);const s=this.findElement("#total-tests-passed-value");null!=s&&(s.textContent=t.totalPassed.toString());const n=this.findElement("#total-tests-count-value");null!=n&&(n.textContent=t.totalTests.toString());const a=this.findElement("#passed-total-percent-value");null!=a&&(a.textContent=t.totalPercentage.toFixed(1));const r=this.findElement("#duration-value");null!=r&&(r.textContent=t.duration>10?t.duration.toFixed(0):t.duration.toFixed(2))}collectTestResults(){const t=this.findElements("code-test"),e=t.length,s=t.filter(t=>"success"==t.state.testState?.resultCategory).length;return{totalTests:e,totalPassed:s,totalPercentage:0==e?0:s/e*100,duration:t.reduce((t,e,s)=>t+(e.state.testState?.duration??0),0)}}async runTests(){const t=this.findElements("code-test");return this.#o.runTests(t)}async reloadTests(){this.findElement("#tests").innerHTML="",await this.reset();const t=this.#g();this.#o.loadTests(t)}async reset(){const t=this.findElements("code-test");for(let e=0;e<t.length;e++){const s=t[e],n=null!=this.state.beforeEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.beforeEachState.hasRun,isRunning:this.state.beforeEachState.isRunning,duration:0}:void 0,a=null!=this.state.afterEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.afterEachState.hasRun,isRunning:this.state.afterEachState.isRunning,duration:0}:void 0;null!=n&&(s.state.beforeEachState=n),null!=a&&(s.state.afterEachState=a),s.reset()}const s=null==this.state.beforeAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeAllState.test,isRunning:!1,hasRun:!1,duration:0},n=null==this.state.afterAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterAllState.test,isRunning:!1,hasRun:!1,duration:0},a=null==this.state.beforeEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeEachState.test,isRunning:!1,hasRun:!1,duration:0},r=null==this.state.afterEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterEachState.test,isRunning:!1,hasRun:!1,duration:0},o=null==this.state.requiredBeforeAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredBeforeAnyState.test,isRunning:!1,hasRun:!1,duration:0},i=null==this.state.requiredAfterAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredAfterAnyState.test,isRunning:!1,hasRun:!1,duration:0};this.setStateProperties({isCanceled:!1,beforeAllState:s,afterAllState:n,beforeEachState:a,afterEachState:r,requiredAfterAnyState:i,requiredBeforeAnyState:o}),this.#o.shouldContinueRunningTests=!0,null!=this.state.resetHook&&await this.state.resetHook(await this.#o.createTestContext()),this.dispatchEvent(new CustomEvent(e.Reset,{bubbles:!0,composed:!0}))}cancel(){this.state.isCanceled=!0,this.#o.shouldContinueRunningTests=!1,this.classList.add("canceled"),this.part.add("canceled"),this.dispatchEvent(new CustomEvent(e.Cancel,{bubbles:!0,composed:!0}))}static observedAttributes=["open","label"];attributeChangedCallback(t,e,s){if("open"==t)this.findElement("#component-details").toggleAttribute("open",null!=s);else if("label"==t){const t=this.findElement("#title");null!=t&&(t.textContent=s??"Tests")}}}function f(t,e){const s=t instanceof HTMLTemplateElement?t:document.querySelector(t);if(null==s)throw new Error(`Unable to find template element from selector: ${t}`);const n=s.content.cloneNode(!0).firstElementChild;if(null==n)throw new Error("Unable to find first child of template element");return e?.append(n),n}null==customElements.get(d)&&customElements.define(d,h),t.CodeTestElement=n,t.CodeTestEvent=e,t.CodeTestsElement=h,t.Hook=c,t.TestPromise=o,t.createElementFromTemplate=f,t.expect=function(t){return new o(async(e,s)=>{if(t instanceof Promise){return void e(await t)}e(t)})},t.prompt=async function(t,e,s,n){return new Promise((a,r)=>{const o=f(n?.template??t.querySelector(".prompt-template")??t.findElement("#prompt-template"));o.querySelector(".label").textContent=s;const i=t=>{const e=t.composedPath();if(null!=e.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("accept"))){const t=n?.onAccept?.()??!0;return o.removeEventListener("click",i),void a(t)}if(null!=e.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("reject"))){const t=n?.onReject?.()??!1;return o.removeEventListener("click",i),void a(t)}};o.addEventListener("click",i),null!=n?.acceptLabel&&(o.querySelector(".accept").textContent=n.acceptLabel),null!=n?.rejectLabel&&(o.querySelector(".reject").textContent=n.rejectLabel),e.append(o)})},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(((t="undefined"!=typeof globalThis?globalThis:t||self)["code-tests"]=t["code-tests"]||{},t["code-tests"].umd=t["code-tests"].umd||{},t["code-tests"].umd.min=t["code-tests"].umd.min||{},t["code-tests"].umd.min.js={}))}(this,function(t){"use strict";const e={BeforeAll:"beforeall",AfterAll:"afterall",BeforeTest:"beforetest",AfterTest:"aftertest",BeforeHook:"beforehook",AfterHook:"afterhook",Cancel:"cancel",Context:"context",Reset:"reset",TestEnd:"testend",Init:"init",Enabled:"enabled",PromptResult:"promptresult"},s="code-test";class n extends HTMLElement{state={testId:"",description:"none",isDisabled:!1,testState:void 0,beforeEachState:void 0,afterEachState:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.querySelector(t)}findElements(t){return Array.from(this.querySelectorAll(t))}isRunning(){return 1==this.state.testState?.isRunning||1==this.state.beforeEachState?.isRunning||1==this.state.afterEachState?.isRunning}hasRun(){return 1==this.state.testState?.hasRun||1==this.state.beforeEachState?.hasRun||1==this.state.afterEachState?.hasRun}resultCategory(){const t=this.state.testState?.resultCategory??"none",e=this.state.beforeEachState?.resultCategory??"none",s=this.state.afterEachState?.resultCategory??"none";return"none"==t&&"none"==e&&"none"==s?"none":null==this.state.beforeEachState&&null==this.state.afterEachState?t:null!=this.state.beforeEachState&&null==this.state.afterEachState?"fail"==t||"fail"==e?"fail":"success"==t&&"success"==e?"success":"none":null==this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==s?"fail":"success"==t&&"success"==s?"success":"none":null!=this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==e||"fail"==s?"fail":"success"==t&&"success"==e&&"success"==s?"success":"none":void 0}connectedCallback(){this.#t()}#t(){const t=null==this.state.testState?"":"boolean"==typeof this.state.testState.resultContent?1==this.state.testState.resultContent?'<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>':"number"==typeof this.state.testState.resultContent?`<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed: ${this.state.testState.resultContent.toString()}</pre></code>`:"string"==typeof this.state.testState.resultContent?this.state.testState.resultContent:"";this.innerHTML=`<details class="test-details" part="test-details" ${1==this.isRunning()||1==this.hasRun()?" open":""}>\n <summary class="test-summary" part="test-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="result-icon test-result-icon${"none"!=this.state.testState?.resultCategory?` ${this.state.testState?.resultCategory}`:""}" part="result-icon"></div>\n <span class="test-description description" title="${this.state.description}">${this.state.description}</span>\n ${null!=this.state.testState?.duration&&this.state.testState.duration>0?`<span class="test-duration duration">\n <span class="test-duration-value">${this.state.testState.duration>10?this.state.testState.duration.toFixed(0):this.state.testState.duration.toFixed(2)}</span>\n <span class="test-duration-unit">ms</span>\n </span>`:""}\n <button type="button" class="run-test-button" part="run-test-button" title="Run Test"${1==this.state.isDisabled?" disabled":""}>\n <slot name="run-button-content">\n <slot name="run-button-icon"><svg class="icon arrow-icon run-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-button-label"><span class="run-button-label button-label label icon">Run Test</span></slot>\n </slot>\n </button>\n </summary>\n <div class="results" part="results">\n ${null==this.state.beforeEachState?"":`<details class="before-each-details hook${"none"==this.state.beforeEachState.resultCategory?"":` ${this.state.beforeEachState.resultCategory}`}${1==this.state.beforeEachState.isRunning?" running":""}" part="before-each-details hook">\n <summary class="before-each-summary" part="before-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="before-each-result-icon result-icon${"none"!=this.state.beforeEachState.resultCategory?` ${this.state.beforeEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="before-each-description description hook-name">Before Each Hook</span>\n </summary>\n <div class="before-each-result result message" part="before-each-result result message">${"string"!=typeof this.state.beforeEachState.resultContent?"":this.state.beforeEachState.resultContent}</div>\n </details>`}\n ${null==this.state.testState?"":null==this.state.beforeEachState&&null==this.state.afterEachState?`<div class="test-result result message" part="test-result result message">${t}</div>`:`<details class="processing-details${"none"==this.state.testState.resultCategory?"":` ${this.state.testState.resultCategory}`}${1==this.state.testState.isRunning?" running":""}" part="processing-details"${1==this.state.testState.hasRun?" open":""}>\n <summary class="processing-summary" part="processing-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="processing-result-icon result-icon${"none"!=this.state.testState.resultCategory?` ${this.state.testState.resultCategory}`:""}" part="processing-result-icon result-icon"></div>\n <span class="processing-description description">Test</span>\n </summary>\n <div class="test-result result message" part="test-result result message">${t}</div>\n </details>`} \n ${null==this.state.afterEachState?"":`<details class="after-each-details hook${"none"==this.state.afterEachState.resultCategory?"":` ${this.state.afterEachState.resultCategory}`}${1==this.state.afterEachState.isRunning?" running":""}" part="after-each-detail hooks">\n <summary class="after-each-summary" part="after-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="after-each-result-icon result-icon${"none"!=this.state.afterEachState.resultCategory?` ${this.state.afterEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="after-each-description description hook-name">After Each Hook</span>\n </summary>\n <div class="after-each-result result message" part="after-each-result result message">${"string"!=typeof this.state.afterEachState.resultContent?"":this.state.afterEachState.resultContent}</div>\n </details>`}\n </div>\n </details>`,this.dataset.testId=this.state.testId,this.classList.add("test"),this.part.add("test"),this.toggleAttribute("success","success"==this.resultCategory()),this.classList.toggle("success","success"==this.resultCategory()),this.part.toggle("success","success"==this.resultCategory()),this.classList.toggle("fail","fail"==this.resultCategory()),this.part.toggle("fail","fail"==this.resultCategory()),this.classList.toggle("running",this.isRunning()),this.part.toggle("running",this.isRunning()),this.state.beforeEachState?.resultContent instanceof HTMLElement&&this.querySelector(".before-each-result").append(this.state.beforeEachState.resultContent),this.state.testState?.resultContent instanceof HTMLElement&&this.querySelector(".test-result").append(this.state.testState.resultContent),this.state.afterEachState?.resultContent instanceof HTMLElement&&this.querySelector(".after-each-result").append(this.state.afterEachState.resultContent)}enable(){this.state.isDisabled=!1,this.findElement(".run-test-button").toggleAttribute("disabled",!1)}disable(){this.state.isDisabled=!0,this.findElement(".run-test-button").toggleAttribute("disabled",!0)}async runTest(t,s){if(null==this.state.testState?.test)return;let n;this.reset();let a={},o=0;try{if(0==t.shouldContinueRunningTests)throw new Error("Tests have been disabled from continuing to run.");if(0==this.dispatchEvent(new CustomEvent(e.BeforeTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}})))throw new Error("Test has been prevented.");if(1==s.codeTestsElement.state.isCanceled)throw new Error("Testing has been canceled.");this.setTestStateProperties("testState",{isRunning:!0}),t.codeTestsElement.setState(t.codeTestsElement.state);const r=performance?.now()??Date.now();n=await this.state.testState.test(s);o=(performance?.now()??Date.now())-r,this.setTestStateProperties("testState",{isRunning:!1,hasRun:!0}),t.codeTestsElement.setState(t.codeTestsElement.state);const i=t.parseTestResult(n,!0);a={testState:{test:this.state.testState.test,resultContent:i.result,resultCategory:i.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:o}}}catch(e){const s=t.parseTestResult(n,!1,e);a={testState:{test:this.state.testState.test,resultContent:s.result,resultCategory:s.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:o}},console.error(e),t.shouldContinueRunningTests=!1}finally{this.setStateProperties({...a}),t.codeTestsElement.setState(t.codeTestsElement.state),this.dispatchEvent(new CustomEvent(e.AfterTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}}))}}reset(){const t=null!=this.state.testState?{resultCategory:"none",resultContent:"",test:this.state.testState.test,hasRun:this.state.testState.hasRun,isRunning:this.state.testState.isRunning,duration:0}:void 0;null!=t&&this.setTestStateProperties("testState",t)}getMessageElement(){return this.findElement(".test-result")}static observedAttributes=["open"];attributeChangedCallback(t,e,s){"open"==t&&this.findElement(".test-details").toggleAttribute("open",null!=s)}}null==customElements.get(s)&&customElements.define(s,n);const a=Symbol("No Test Defined");class o{codeTestsElement;constructor(t){this.codeTestsElement=t}async loadTests(t){if(null!=t)try{const{tests:e,hooks:s}=await this.#e(t),n=s[c.BeforeAll],a=s[c.AfterAll],o=s[c.BeforeEach],r=s[c.AfterEach],i=s[c.RequiredBeforeAny],l=s[c.RequiredAfterAny],u=null==n?void 0:{resultCategory:"none",resultContent:"",test:n,hasRun:!1,isRunning:!1,duration:0},d=null==a?void 0:{resultCategory:"none",resultContent:"",test:a,hasRun:!1,isRunning:!1,duration:0},h=null==o?void 0:{resultCategory:"none",resultContent:"",test:o,hasRun:!1,isRunning:!1,duration:0},f=null==r?void 0:{resultCategory:"none",resultContent:"",test:r,hasRun:!1,isRunning:!1,duration:0},p=null==i?void 0:{resultCategory:"none",resultContent:"",test:i,hasRun:!1,isRunning:!1,duration:0},g=null==l?void 0:{resultCategory:"none",resultContent:"",test:l,hasRun:!1,isRunning:!1,duration:0};this.codeTestsElement.state.beforeEachState=h,this.codeTestsElement.state.afterEachState=f;for(const[t,s]of Object.entries(e))this.#s(t,s);this.codeTestsElement.setStateProperties({beforeAllState:u,afterAllState:d,beforeEachState:h,afterEachState:f,requiredBeforeAnyState:p,requiredAfterAnyState:g,resetHook:s.reset,contextHook:s.context})}catch(t){console.error(t)}}async#e(t){const e=await this.#n(t),s=e.tests??e.default;if(null==s)throw new Error(`Unable to find tests definition in file at path: ${t}`);const n={},a=s[c.BeforeAll];null!=a&&(n[c.BeforeAll]=a,delete s[c.BeforeAll]);const o=s[c.AfterAll];null!=o&&(n[c.AfterAll]=o,delete s[c.AfterAll]);const r=s[c.BeforeEach];null!=r&&(n[c.BeforeEach]=r,delete s[c.BeforeEach]);const i=s[c.AfterEach];null!=i&&(n[c.AfterEach]=i,delete s[c.AfterEach]);const l=s[c.RequiredBeforeAny];null!=l&&(n[c.RequiredBeforeAny]=l,delete s[c.RequiredBeforeAny]);const u=s[c.RequiredAfterAny];null!=u&&(n[c.RequiredAfterAny]=u,delete s[c.RequiredAfterAny]);const d=s[c.Reset];null!=d&&(n[c.Reset]=d,delete s[c.Reset]);const h=s[c.Context];return null!=h&&(n[c.Context]=h,delete s[c.Context]),{tests:s,hooks:n}}async#n(t){const e=window.location.href.lastIndexOf("/"),s=1==(-1!=window.location.href.substring(e).indexOf("."))?window.location.href.substring(0,e+1):window.location.href,n=s+t.substring(0,t.lastIndexOf("/")+1),a=s+t;let o=await(await fetch(a)).text();o=o.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g,`'${n}$1'`);const r=new File([o],t.substring(t.lastIndexOf("/")),{type:"text/javascript"}),i=URL.createObjectURL(r);return await import(i)}#s(t,e){const s=function(){const t=new Uint8Array(20);crypto.getRandomValues(t);const e=[].slice.apply(t).map(function(t){return String.fromCharCode(t)}).join("");return btoa(e).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,"")}(),a=new n;return a.setStateProperties({testId:s,description:t,testState:{test:e,resultCategory:"none",resultContent:"",isRunning:!1,hasRun:!1,duration:0},beforeEachState:null==this.codeTestsElement.state.beforeEachState?void 0:{isRunning:this.codeTestsElement.state.beforeEachState.isRunning,hasRun:this.codeTestsElement.state.beforeEachState.hasRun,resultCategory:this.codeTestsElement.state.beforeEachState.resultCategory,resultContent:this.codeTestsElement.state.beforeEachState.resultContent,duration:0},afterEachState:null==this.codeTestsElement.state.afterEachState?void 0:{isRunning:this.codeTestsElement.state.afterEachState.isRunning,hasRun:this.codeTestsElement.state.afterEachState.hasRun,resultCategory:this.codeTestsElement.state.afterEachState.resultCategory,resultContent:this.codeTestsElement.state.afterEachState.resultContent,duration:0}}),this.codeTestsElement.findElement("#tests").append(a),s}shouldContinueRunningTests=!0;async runTests(t){if(0==this.codeTestsElement.dispatchEvent(new CustomEvent(e.BeforeAll,{bubbles:!0,composed:!0,cancelable:!0})))throw new Error("Tests have been prevented.");await this.codeTestsElement.reset();for(let e=0;e<t.length;e++)t[e].disable();const s=await this.createTestContext();if(await this.runHook("requiredBeforeAnyState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(t,s);if(await this.runHook("beforeAllState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(t,s);if(0==("false"!=this.codeTestsElement.getAttribute("ordered"))){const e=t.map(t=>this.runTest(t,!0,s));await Promise.all(e)}else for(let e=0;e<t.length;e++){const n=t[e];if(0==this.shouldContinueRunningTests)break;await this.runTest(n,!0,s)}0!=this.shouldContinueRunningTests?(await this.runHook("afterAllState",void 0,s),await this.#a(t,s)):await this.#a(t,s)}async#a(t,s){await this.runHook("requiredAfterAnyState",void 0,s);for(let e=0;e<t.length;e++)t[e].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(e.AfterAll,{bubbles:!0,composed:!0}))}async runTest(t,e,s){if(null!=t){if(0==e){const t=this.codeTestsElement.findElements("code-test");for(let e=0;e<t.length;e++)t[e].disable()}null==(s=s??await this.createTestContext(t)).testElement&&(s.testElement=t),0!=e||(await this.runHook("requiredBeforeAnyState",void 0,s),0!=this.shouldContinueRunningTests)?(await this.runHook("beforeEachState",t,s),0!=this.shouldContinueRunningTests?(await t.runTest(this,s),0!=this.shouldContinueRunningTests?(await this.runHook("afterEachState",t,s),await this.#o(s,e)):await this.#o(s,e)):await this.#o(s,e)):await this.#o(s,e)}}async#o(t,s){if(1==s)return;await this.runHook("requiredAfterAnyState",void 0,t);const n=this.codeTestsElement.findElements("code-test");for(let t=0;t<n.length;t++)n[t].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(e.TestEnd,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))}async runHook(t,s,n){const o=this.codeTestsElement.state[t];if(null==o)return a;if(1==this.codeTestsElement.state.isCanceled)return{success:!1,value:"Testing has been canceled."};let r;try{if(0==this.shouldContinueRunningTests&&("requiredAfterAnyState"!=t||"error"==this.codeTestsElement.getAttribute("required-after")))throw new Error("Tests have been disabled from continuing to run.");null!=s&&s.setTestStateProperties(t,{isRunning:!0}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!0}),r=await o.test(n),null!=s&&s.setTestStateProperties(t,{isRunning:!1,hasRun:!0}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!1,hasRun:!0});const e=this.parseTestResult(r,!0,void 0);null!=s&&s.setTestStateProperties(t,{resultCategory:e.resultCategory,resultContent:e.result}),this.codeTestsElement.setTestStateProperties(t,{resultCategory:e.resultCategory,resultContent:e.result})}catch(e){console.error(e),this.shouldContinueRunningTests=!1,r={success:!1,value:`Failed: ${e.message}`};const n=this.parseTestResult(r,!1,e);null!=s&&s.setTestStateProperties(t,{isRunning:!1,hasRun:!0,resultContent:n.result,resultCategory:n.resultCategory}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!1,hasRun:!0,resultCategory:n.resultCategory,resultContent:n.result})}finally{return this.codeTestsElement.dispatchEvent(new CustomEvent(e.AfterHook,{bubbles:!0,composed:!0,detail:r})),r}}parseTestResult(t,e,s){if(t==a)return{result:"",resultCategory:"none"};if(null==t){const t=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${t}" part="pre ${t}">${1==e?"Passed":"Failed"+(null!=s?`:\n${s.message}`:"")}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}if("boolean"==typeof t)return{result:t,resultCategory:1==t?"success":"fail"};if("function"==typeof t)return console.log("function"),{result:"[A function was returned]",resultCategory:"none"};if(t instanceof HTMLElement||"string"==typeof t)return{result:t,resultCategory:"none"};if("object"==typeof t){const s=t,n=1==e?"success-message":"error-message";if(null!=s.success&&null!=s.expected&&null!=s.value)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${1==s.success?"Passed":"Failed"}\nExpected:${s.expected}\nResult:${s.value}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};if(null!=s.success)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};{const s=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${s}" part="pre ${s}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}}throw new Error("Unable to parse result type: Unknown result type")}async createTestContext(t){const s={detail:{},codeTestsElement:this.codeTestsElement,testElement:t,messageElement:t?.findElement(".message")};return null!=this.codeTestsElement.state.contextHook&&await this.codeTestsElement.state.contextHook(s),this.codeTestsElement.dispatchEvent(new CustomEvent(e.Context,{bubbles:!0,composed:!0,detail:{context:s}})),s}}class r extends Promise{async toBeDefined(t){if(null==await(this))throw new Error(`${null!=t?t:"Value"} is undefined`)}async toBe(t,e=!1){const s=await(this);if(0==(1==e?s===t:s==t))throw new Error(` Value is not equal.\n Expected: ${t}\n Result: ${s}`)}async toContainText(t){const e=await(this);return e instanceof HTMLElement?{success:e.textContent.includes(t),index:e.textContent.indexOf(t)}:"string"==typeof e&&{success:e.includes(t),index:e.indexOf(t)}}async toHaveAttribute(t){const e=await(this);if(!(e instanceof HTMLElement))throw new Error("Unable to check for attribute on non-HTMLElement target");if(e.getAttribute(t))throw new Error("Target does not have attribute")}}const i=":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";function l(t){!function(t){const e=[...t.querySelectorAll(`${i}[id]`)];for(let t=0;t<e.length;t++)e[t].part.add(e[t].id)}(t),function(t){const e=[...t.querySelectorAll(`${i}[class]`)];for(let t=0;t<e.length;t++)e[t].part.add(...e[t].classList)}(t)}const c={BeforeAll:"beforeall",AfterAll:"afterall",BeforeEach:"beforeeach",AfterEach:"aftereach",RequiredBeforeAny:"requiredbeforeany",RequiredAfterAny:"requiredafterany",Reset:"reset",Context:"context"},u=new CSSStyleSheet;u.replaceSync(":host\n{\n --gap: 7px;\n --gap-small: 3px;\n --gap-medium: 14px;\n --gap-large: 24px;\n \n --surface-success: oklch(93.96% 0.05 148.74);\n --primary-success: oklch(58.83% 0.158 145.05);\n --border-success: solid 1px var(--primary-success);\n\n --surface-fail: oklch(88.98% 0.052 3.28);\n --primary-fail: oklch(45.8% 0.177 17.7);\n --border-fail: solid 1px var(--primary-fail);\n\n --surface-process: oklch(89.66% 0.046 260.67);\n --primary-process: oklch(43.48% 0.17 260.2);\n --border-process: solid 1px var(--primary-process);\n\n\n --surface-footer: rgb(0 0 0 / .04);\n \n --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>');\n --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');\n\n\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n font-family: sans-serif;\n font-size: 12px;\n}\n@media (prefers-color-scheme: dark) \n{\n :host\n {\n --surface-footer: rgb(255 255 255 / .1);\n }\n}\n\n#header\n{\n flex: 1;\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\n#title\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n#tests\n,#component-content\n{\n display: grid;\n gap: var(--gap-small);\n grid-auto-rows: max-content;\n}\n\n#header button\n{\n align-self: stretch;\n display: inline-flex;\n align-items: center;\n gap: var(--gap-small);\n}\n\nbutton .reset-icon\n{\n width: 1em;\n height: 1em;\n transform: scaleX(-1);\n margin-inline: 3px;\n}\n\n/* Run button */\nbutton .arrow-icon\n{\n width: .75em;\n height: .75em;\n transform: rotate(-90deg);\n margin-inline: 3px;\n}\n:host(.running) .run-all-button-icon\n,:host(.fail) .run-all-button-icon\n{\n transform: rotate(0);\n}\n\n/* Dropdown Layout */\nsummary > .run-test-button\n, #run-all-button\n{\n justify-self: flex-end;\n margin-left: auto;\n}\n\nsummary:not(#component-summary)\n{\n padding: var(--gap-small);\n}\n#component-summary\n{\n padding: var(--gap) var(--gap-small);\n border-bottom: solid 1px;\n margin-bottom: var(--gap-small);\n}\n\n\n/* Dropdown Markers */\nsummary\n{\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\nsummary > .arrow-icon\n{\n background: var(--arrow-icon);\n transform: rotate(-90deg);\n transition: transform ease-out 90ms;\n width: .6em;\n height: .6em;\n}\ndetails[open] > summary > .arrow-icon\n{\n transform: rotate(0);\n}\n\n#enabled\n{\n display: none;\n}\n:host([optional]) #enabled\n{\n display: block;\n}\n\n/* Result Icon */\n.result-icon\n{\n --background-size: 16px;\n width: var(--background-size);\n height: var(--background-size);\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n border: solid 1px currentColor;\n border-radius: 50%;\n}\n.result-icon::before\n{\n content: '⋯';\n font-size: 10px;\n}\n\n:host(.running) #component-summary .result-icon\n,.test.running .test-summary > .result-icon\n,.hook.running .result-icon\n,.processing-details.running .processing-result-icon\n{\n border: var(--border-process);\n background: var(--surface-process);\n}\n:host(.success) #component-summary .result-icon\n,.test.success .test-summary > .result-icon\n,.hook.success .result-icon\n,.processing-details.success .processing-result-icon\n{\n border: var(--border-success);\n background: var(--surface-success)\n var(--success-icon);\n background-repeat: no-repeat;\n background-position: center;\n background-size: var(--icon-size, 12px) var(--icon-size, 12px);\n}\n:host(.fail) #component-summary .result-icon\n,.test.fail .test-summary > .result-icon\n,.hook.fail .result-icon\n,.processing-details.fail .processing-result-icon\n{\n border: var(--border-fail);\n background: var(--surface-fail)\n var(--info-icon);\n background-size: var(--icon-size, 16px) var(--icon-size, 16px);\n background-repeat: no-repeat;\n background-position: center;\n transform: rotate(175deg);\n}\n:host(:is(.success,.fail)) #component-summary .result-icon::before\n,.test:is(.success,.fail) .test-summary > .result-icon::before\n,.hook:is(.success,.fail) .result-icon::before\n,.processing-details:is(.success,.fail) .processing-result-icon::before\n{\n display: none;\n}\n:host(.running) #component-summary .result-icon::before\n,.test:is(.running) .test-summary > .result-icon::before\n,.hook:is(.running) .result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n content: '';\n --color: var(--primary-process, currentColor);\n --animation-timing-function: linear;\n --animation-duration: 2s;\n width: var(--icon-size, 14px);\n height: var(--icon-size, 14px);\n mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--icon-size, 14px) / 3), black calc(var(--icon-size, 14px) / 3));\n background-image: conic-gradient(transparent, transparent 135deg, var(--color));\n border-radius: 50%;\n animation: var(--animation-timing-function) var(--animation-duration) infinite spin;\n margin: 2px;\n}\n\n/* Smaller Result icon settings for sub-test icons */\n.before-each-result-icon\n,.after-each-result-icon\n,.processing-result-icon\n{\n --background-size: 12px;\n}\n.before-each-result-icon::before\n,.after-each-result-icon::before\n,.processing-result-icon::before\n{\n font-size: 9px;\n}\n.hook.success .before-each-result-icon\n,.hook.success .after-each-result-icon\n,.processing-details.success .processing-result-icon\n{\n --icon-size: 8px;\n}\n.hook.fail .before-each-result-icon\n,.hook.fail .after-each-result-icon\n,.processing-details.fail .processing-result-icon\n{\n --icon-size: 12px;\n}\n.hook:is(.running) .before-each-result-icon::before\n,.hook:is(.running) .after-each-result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n --icon-size: 9px;\n}\n\n/* Hook Display */\n.hook\n{\n display: none;\n}\n:host(.has-before-all-hook) #before-all-details\n,:host(.has-after-all-hook) #after-all-details\n{\n display: initial;\n}\n:host(.has-before-each-hook) .before-each-details\n,:host(.has-after-each-hook) .after-each-details\n{\n display: initial;\n}\n:host(.has-required-before-hook) #required-before-any-details\n,:host(.has-required-after-hook) #required-after-any-details\n{\n display: initial;\n}\n\n/* Test Display */\ncode-test .results\n{\n display: grid;\n gap: var(--gap-small);\n padding-inline-start: 1em;\n}\n\ncode-test .results details .result\n,.hook > .results\n{\n margin-inline-start: 1em;\n}\n\n.result.message:empty\n{\n padding: .5em 1em;\n}\n.result.message:empty::before\n{\n content: '[ this function has not been run ]';\n font-family: monospace;\n font-size: 12px;\n font-style: italic;\n}\n\n/* Ordered Display */\n#tests\n{\n counter-reset: tests;\n}\ncode-test\n{\n counter-increment: tests;\n}\ncode-test > details > summary > .description\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 0; /* hack to make overflow work right; \"contain: inline-size\" is correct fix, but it's too new to implement on jan 25, 2026; */\n}\n:host(:not([ordered=\"false\"])) code-test > details > summary > .description::before\n{\n content: counter(tests) \". \";\n}\n\n/* Hook Name */\n.hook-name,.processing-description\n{\n border-radius: 3px;\n border: solid 1px;\n font-family: monospace;\n text-transform: uppercase;\n font-size: 11px;\n padding: 3px 7px;\n}\n\n#footer\n{\n display: flex;\n justify-content: flex-end;\n border-top: solid 1px;\n border-bottom: solid 1px;\n background: var(--surface-footer);\n margin-top: var(--gap-small);\n}\n#group-results\n{\n display: flex;\n gap: var(--gap);\n padding: var(--gap);\n}\n\n#results-progress-value\n{\n min-width: 40px;\n width: auto;\n}\n\n#duration\n,#passed-total-pair\n,#passed-total-percent\n{\n white-space: nowrap;\n}\n\n#passed-total-percent::before\n{\n content: '(';\n}\n#passed-total-percent::after\n{\n content: ')';\n}\n\n@keyframes spin\n{\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}");const d="code-tests";class h extends HTMLElement{state={isCanceled:!1,beforeAllState:void 0,afterAllState:void 0,beforeEachState:void 0,afterEachState:void 0,requiredBeforeAnyState:void 0,requiredAfterAnyState:void 0,resetHook:void 0,contextHook:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.shadowRoot.querySelector(t)}findElements(t){return Array.from(this.shadowRoot.querySelectorAll(t))}getIsRunning(){return 1==(null!=this.findElements("code-test").find(t=>1==t.isRunning()))||1==this.state.requiredBeforeAnyState?.isRunning||1==this.state.requiredAfterAnyState?.isRunning||1==this.state.beforeAllState?.isRunning||1==this.state.afterAllState?.isRunning}getResultCategory(){const t=this.findElements("code-test").reduce((t,e,s)=>{const n=e.resultCategory();return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},""),e=[this.state.requiredBeforeAnyState,this.state.requiredAfterAnyState,this.state.beforeAllState,this.state.afterAllState].reduce((t,e,s)=>{if(null==e)return null;const n=e?.resultCategory;return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},"");return"none"==t&&null==e?"none":"fail"==t||"fail"==e?"fail":"success"==t||"success"==e?"success":"none"}#r;constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML='<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 <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\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">0</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">0</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>',this.shadowRoot.adoptedStyleSheets.push(u)}connectedCallback(){this.#i()}disconnectedCallback(){this.#l()}#c=!1;#u=!1;async#i(){1!=this.#c&&1!=this.#u&&(this.#c=!0,l(this.shadowRoot),this.addEventListener("click",this.#d),this.findElement("#enabled").addEventListener("change",this.#h),await new Promise(t=>requestAnimationFrame(()=>{this.#r=new o(this),this.#u=!0,this.#c=!1;if(0==this.dispatchEvent(new CustomEvent(e.Init,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}})))return void t();"false"!=this.getAttribute("auto")?(this.reloadTests(),t()):t()})))}#l(){this.removeEventListener("click",this.#d),this.findElement("#enabled").removeEventListener("change",this.#h),this.#u=!1,this.#c=!1}#d=this.#f.bind(this);#f(t){if(null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"run-all-button"==t.id))return void(this.classList.contains("running")?this.cancel():this.classList.contains("fail")||this.classList.contains("success")?this.reset():this.runTests());null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"reload-button"==t.id)&&this.reloadTests();const e=t.composedPath().find(t=>t instanceof HTMLButtonElement&&t.classList.contains("run-test-button"));if(null==e)return;const s=e.closest("code-test")??void 0;this.#r.runTest(s,!1)}#h=this.#p.bind(this);#p(t){const s=t.target;0==this.dispatchEvent(new CustomEvent(e.Enabled,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))&&(t.preventDefault(),t.stopPropagation(),s.checked=!s.checked)}#g(){return this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path")??void 0}#t(){const t=this.getIsRunning(),e=this.getResultCategory(),s=null!=this.state.beforeAllState,n=null!=this.state.beforeEachState,a=null!=this.state.requiredAfterAnyState,o=null!=this.state.beforeAllState,r=null!=this.state.beforeEachState,i=null!=this.state.requiredAfterAnyState,l=1==a||1==s||1==n,c=1==i||1==o||1==r;this.classList.toggle("canceled",this.state.isCanceled),this.part.toggle("canceled",this.state.isCanceled),this.classList.toggle("running",1==t),this.part.toggle("running",1==t),this.toggleAttribute("success","success"==e),this.classList.toggle("success","success"==e),this.part.toggle("success","success"==e),this.classList.toggle("fail","fail"==e),this.part.toggle("fail","fail"==e),this.classList.toggle("has-before-hook",l),this.part.toggle("has-before-hook",l),this.classList.toggle("has-after-hook",c),this.part.toggle("has-after-hook",c),this.classList.toggle("has-before-all-hook",s),this.part.toggle("has-before-all-hook",s),this.classList.toggle("has-after-all-hook",o),this.part.toggle("has-after-all-hook",o),this.classList.toggle("has-before-each-hook",n),this.part.toggle("has-before-each-hook",n),this.classList.toggle("has-after-each-hook",r),this.part.toggle("has-after-each-hook",r),this.classList.toggle("has-required-before-hook",a),this.part.toggle("has-required-before-hook",a),this.classList.toggle("has-required-after-hook",i),this.part.toggle("has-required-after-hook",i);const u=this.findElement(".run-all-button-label");null!=u&&(u.textContent=1==t?"Cancel":"fail"==e||"success"==e?"Reset":"Run Tests",u.title=1==t?"Cancel the testing":"fail"==e||"success"==e?"Reset the tests so they can be run again":"Run the tests");const d=this.findElement(".run-all-button-icon");null!=d&&(d.innerHTML=1==t?'<use href="#icon-definition_cancel"></use>':"fail"==e||"success"==e?'<use href="#icon-definition_reset"></use>':'<use href="#icon-definition_arrow"></use>'),this.#m(this.state.beforeAllState,"#before-all-results"),this.#m(this.state.afterAllState,"#after-all-results"),this.#m(this.state.requiredBeforeAnyState,"#required-before-any-results"),this.#m(this.state.requiredAfterAnyState,"#required-after-any-results");const h=this.findElement("#title");null!=h&&(h.textContent=this.getAttribute("label")??"Tests"),this.#b()}#m(t,e){const s=this.findElement(e);t?.resultContent instanceof HTMLElement?s.append(t.resultContent):"string"==typeof t?.resultContent&&(s.innerHTML=t.resultContent);const n=s.closest("details");n.toggleAttribute("open",null!=t&&"none"!=t.resultCategory),n.classList.toggle("running",1==t?.isRunning),n.part.toggle("running",1==t?.isRunning),n.toggleAttribute("success","success"==t?.resultCategory),n.classList.toggle("success","success"==t?.resultCategory),n.part.toggle("success","success"==t?.resultCategory),n.classList.toggle("fail","fail"==t?.resultCategory),n.part.toggle("fail","fail"==t?.resultCategory)}#b(){const t=this.collectTestResults(),e=this.findElement("#results-progress-value");null!=e&&(e.max=t.totalTests,e.value=t.totalPassed);const s=this.findElement("#total-tests-passed-value");null!=s&&(s.textContent=t.totalPassed.toString());const n=this.findElement("#total-tests-count-value");null!=n&&(n.textContent=t.totalTests.toString());const a=this.findElement("#passed-total-percent-value");null!=a&&(a.textContent=t.totalPercentage.toFixed(1));const o=this.findElement("#duration-value");null!=o&&(o.textContent=t.duration>10?t.duration.toFixed(0):t.duration.toFixed(2))}collectTestResults(){const t=this.findElements("code-test"),e=t.length,s=t.filter(t=>"success"==t.state.testState?.resultCategory).length;return{totalTests:e,totalPassed:s,totalPercentage:0==e?0:s/e*100,duration:t.reduce((t,e,s)=>t+(e.state.testState?.duration??0),0)}}async runTests(){const t=this.findElements("code-test");return this.#r.runTests(t)}async reloadTests(){this.findElement("#tests").innerHTML="",await this.reset();const t=this.#g();this.#r.loadTests(t)}async reset(){const t=this.findElements("code-test");for(let e=0;e<t.length;e++){const s=t[e],n=null!=this.state.beforeEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.beforeEachState.hasRun,isRunning:this.state.beforeEachState.isRunning,duration:0}:void 0,a=null!=this.state.afterEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.afterEachState.hasRun,isRunning:this.state.afterEachState.isRunning,duration:0}:void 0;null!=n&&(s.state.beforeEachState=n),null!=a&&(s.state.afterEachState=a),s.reset()}const s=null==this.state.beforeAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeAllState.test,isRunning:!1,hasRun:!1,duration:0},n=null==this.state.afterAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterAllState.test,isRunning:!1,hasRun:!1,duration:0},a=null==this.state.beforeEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeEachState.test,isRunning:!1,hasRun:!1,duration:0},o=null==this.state.afterEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterEachState.test,isRunning:!1,hasRun:!1,duration:0},r=null==this.state.requiredBeforeAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredBeforeAnyState.test,isRunning:!1,hasRun:!1,duration:0},i=null==this.state.requiredAfterAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredAfterAnyState.test,isRunning:!1,hasRun:!1,duration:0};this.setStateProperties({isCanceled:!1,beforeAllState:s,afterAllState:n,beforeEachState:a,afterEachState:o,requiredAfterAnyState:i,requiredBeforeAnyState:r}),this.#r.shouldContinueRunningTests=!0,null!=this.state.resetHook&&await this.state.resetHook(await this.#r.createTestContext()),this.dispatchEvent(new CustomEvent(e.Reset,{bubbles:!0,composed:!0}))}cancel(){this.state.isCanceled=!0,this.#r.shouldContinueRunningTests=!1,this.classList.add("canceled"),this.part.add("canceled"),this.dispatchEvent(new CustomEvent(e.Cancel,{bubbles:!0,composed:!0}))}static observedAttributes=["open","label"];attributeChangedCallback(t,e,s){if("open"==t)this.findElement("#component-details").toggleAttribute("open",null!=s);else if("label"==t){const t=this.findElement("#title");null!=t&&(t.textContent=s??"Tests")}}}function f(t,e){const s=t instanceof HTMLTemplateElement?t:document.querySelector(t);if(null==s)throw new Error(`Unable to find template element from selector: ${t}`);const n=s.content.cloneNode(!0).firstElementChild;if(null==n)throw new Error("Unable to find first child of template element");return e?.append(n),n}null==customElements.get(d)&&customElements.define(d,h),t.CodeTestElement=n,t.CodeTestEvent=e,t.CodeTestsElement=h,t.Hook=c,t.TestPromise=r,t.createElementFromTemplate=f,t.expect=function(t){return new r(async(e,s)=>{if(t instanceof Promise){return void e(await t)}e(t)})},t.prompt=async function(t,s,n,a){let o=null;const r=await new Promise((e,r)=>{const i=a?.template??t.querySelector(".prompt-template")??t.findElement("#prompt-template");o=f(i),o.querySelector(".label").textContent=n;const l=t=>{const s=t.composedPath();if(null!=s.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("accept"))){const t=a?.onAccept?.()??!0;return o.removeEventListener("click",l),void e(t)}if(null!=s.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("reject"))){const t=a?.onReject?.()??!1;return o.removeEventListener("click",l),void e(t)}};o.addEventListener("click",l),null!=a?.acceptLabel&&(o.querySelector(".accept").textContent=a.acceptLabel),null!=a?.rejectLabel&&(o.querySelector(".reject").textContent=a.rejectLabel),s.append(o)});return null!=o&&o.remove(),t.dispatchEvent(new CustomEvent(e.PromptResult,{bubbles:!0,composed:!0,detail:{target:t,result:r}})),r},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
|