@magnit-ce/code-tests 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/code-tests.d.ts +3 -0
- package/dist/code-tests.js +49 -21
- package/dist/code-tests.min.js +1 -1
- package/dist/code-tests.umd.js +49 -21
- 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,10 @@ 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"
|
|
363
390
|
};
|
|
364
391
|
const COMPONENT_TAG_NAME$1 = "code-test";
|
|
365
392
|
class CodeTestElement extends HTMLElement {
|
|
@@ -449,7 +476,7 @@ class CodeTestElement extends HTMLElement {
|
|
|
449
476
|
<summary class="test-summary" part="test-summary">
|
|
450
477
|
<svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>
|
|
451
478
|
<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>
|
|
479
|
+
<span class="test-description description" title="${this.state.description}">${this.state.description}</span>
|
|
453
480
|
${this.state.testState?.duration != null && this.state.testState.duration > 0 ? `<span class="test-duration duration">
|
|
454
481
|
<span class="test-duration-value">${this.state.testState.duration > 10 ? this.state.testState.duration.toFixed(0) : this.state.testState.duration.toFixed(2)}</span>
|
|
455
482
|
<span class="test-duration-unit">ms</span>
|
|
@@ -826,6 +853,7 @@ class CodeTestsContext {
|
|
|
826
853
|
for (let i = 0; i < tests.length; i++) {
|
|
827
854
|
tests[i].enable();
|
|
828
855
|
}
|
|
856
|
+
this.codeTestsElement.dispatchEvent(new CustomEvent(CodeTestEvent.TestEnd, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
829
857
|
}
|
|
830
858
|
async runHook(testStateName, test, testContext) {
|
|
831
859
|
const testState = this.codeTestsElement.state[testStateName];
|
|
@@ -1147,7 +1175,7 @@ class CodeTestsElement extends HTMLElement {
|
|
|
1147
1175
|
this.#context = new CodeTestsContext(this);
|
|
1148
1176
|
this.#isInitialized = true;
|
|
1149
1177
|
this.#isInitializing = false;
|
|
1150
|
-
const allowAutoLoad = this.dispatchEvent(new CustomEvent(
|
|
1178
|
+
const allowAutoLoad = this.dispatchEvent(new CustomEvent(CodeTestEvent.Init, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
1151
1179
|
if (allowAutoLoad == false) {
|
|
1152
1180
|
resolve();
|
|
1153
1181
|
return;
|
|
@@ -1194,7 +1222,7 @@ class CodeTestsElement extends HTMLElement {
|
|
|
1194
1222
|
#boundEnabledHandler = this.#enabled_onChange.bind(this);
|
|
1195
1223
|
#enabled_onChange(event) {
|
|
1196
1224
|
const input = event.target;
|
|
1197
|
-
const allowToggle = this.dispatchEvent(new CustomEvent(
|
|
1225
|
+
const allowToggle = this.dispatchEvent(new CustomEvent(CodeTestEvent.Enabled, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
1198
1226
|
if (allowToggle == false) {
|
|
1199
1227
|
event.preventDefault();
|
|
1200
1228
|
event.stopPropagation();
|
|
@@ -1242,12 +1270,12 @@ class CodeTestsElement extends HTMLElement {
|
|
|
1242
1270
|
this.part.toggle("has-required-after-hook", hasRequiredAfterAnyState);
|
|
1243
1271
|
const runAllButtonLabel = this.findElement(".run-all-button-label");
|
|
1244
1272
|
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";
|
|
1273
|
+
runAllButtonLabel.textContent = isRunning == true ? "Cancel" : resultCategory == "fail" || resultCategory == "success" ? "Reset" : "Run Tests";
|
|
1274
|
+
runAllButtonLabel.title = isRunning == true ? "Cancel the testing" : resultCategory == "fail" || resultCategory == "success" ? "Reset the tests so they can be run again" : "Run the tests";
|
|
1247
1275
|
}
|
|
1248
1276
|
const runAllIcon = this.findElement(".run-all-button-icon");
|
|
1249
1277
|
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>';
|
|
1278
|
+
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
1279
|
}
|
|
1252
1280
|
this.#renderHook(this.state.beforeAllState, "#before-all-results");
|
|
1253
1281
|
this.#renderHook(this.state.afterAllState, "#after-all-results");
|
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"},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={},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(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 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 --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"}#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">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.#o=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.#o.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,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||"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 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};
|
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,10 @@ 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"
|
|
367
394
|
};
|
|
368
395
|
const COMPONENT_TAG_NAME$1 = "code-test";
|
|
369
396
|
class CodeTestElement extends HTMLElement {
|
|
@@ -453,7 +480,7 @@ code-test > details > summary > .description
|
|
|
453
480
|
<summary class="test-summary" part="test-summary">
|
|
454
481
|
<svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>
|
|
455
482
|
<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>
|
|
483
|
+
<span class="test-description description" title="${this.state.description}">${this.state.description}</span>
|
|
457
484
|
${this.state.testState?.duration != null && this.state.testState.duration > 0 ? `<span class="test-duration duration">
|
|
458
485
|
<span class="test-duration-value">${this.state.testState.duration > 10 ? this.state.testState.duration.toFixed(0) : this.state.testState.duration.toFixed(2)}</span>
|
|
459
486
|
<span class="test-duration-unit">ms</span>
|
|
@@ -830,6 +857,7 @@ code-test > details > summary > .description
|
|
|
830
857
|
for (let i = 0; i < tests.length; i++) {
|
|
831
858
|
tests[i].enable();
|
|
832
859
|
}
|
|
860
|
+
this.codeTestsElement.dispatchEvent(new CustomEvent(CodeTestEvent.TestEnd, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
833
861
|
}
|
|
834
862
|
async runHook(testStateName, test, testContext) {
|
|
835
863
|
const testState = this.codeTestsElement.state[testStateName];
|
|
@@ -1151,7 +1179,7 @@ Result:${objectResult.value}</pre>
|
|
|
1151
1179
|
this.#context = new CodeTestsContext(this);
|
|
1152
1180
|
this.#isInitialized = true;
|
|
1153
1181
|
this.#isInitializing = false;
|
|
1154
|
-
const allowAutoLoad = this.dispatchEvent(new CustomEvent(
|
|
1182
|
+
const allowAutoLoad = this.dispatchEvent(new CustomEvent(CodeTestEvent.Init, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
1155
1183
|
if (allowAutoLoad == false) {
|
|
1156
1184
|
resolve();
|
|
1157
1185
|
return;
|
|
@@ -1198,7 +1226,7 @@ Result:${objectResult.value}</pre>
|
|
|
1198
1226
|
#boundEnabledHandler = this.#enabled_onChange.bind(this);
|
|
1199
1227
|
#enabled_onChange(event) {
|
|
1200
1228
|
const input = event.target;
|
|
1201
|
-
const allowToggle = this.dispatchEvent(new CustomEvent(
|
|
1229
|
+
const allowToggle = this.dispatchEvent(new CustomEvent(CodeTestEvent.Enabled, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
|
|
1202
1230
|
if (allowToggle == false) {
|
|
1203
1231
|
event.preventDefault();
|
|
1204
1232
|
event.stopPropagation();
|
|
@@ -1246,12 +1274,12 @@ Result:${objectResult.value}</pre>
|
|
|
1246
1274
|
this.part.toggle("has-required-after-hook", hasRequiredAfterAnyState);
|
|
1247
1275
|
const runAllButtonLabel = this.findElement(".run-all-button-label");
|
|
1248
1276
|
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";
|
|
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";
|
|
1251
1279
|
}
|
|
1252
1280
|
const runAllIcon = this.findElement(".run-all-button-icon");
|
|
1253
1281
|
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>';
|
|
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>';
|
|
1255
1283
|
}
|
|
1256
1284
|
this.#renderHook(this.state.beforeAllState, "#before-all-results");
|
|
1257
1285
|
this.#renderHook(this.state.afterAllState, "#after-all-results");
|
|
@@ -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"},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()}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.#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,e,s,n){return new Promise((a,o)=>{const r=f(n?.template??t.querySelector(".prompt-template")??t.findElement("#prompt-template"));r.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 r.removeEventListener("click",i),void a(t)}if(null!=e.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("reject"))){const t=n?.onReject?.()??!1;return r.removeEventListener("click",i),void a(t)}};r.addEventListener("click",i),null!=n?.acceptLabel&&(r.querySelector(".accept").textContent=n.acceptLabel),null!=n?.rejectLabel&&(r.querySelector(".reject").textContent=n.rejectLabel),e.append(r)})},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
|