@magnit-ce/code-tests 0.0.19 → 0.1.0

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.
@@ -12,7 +12,7 @@ export declare class CodeTestElement extends HTMLElement {
12
12
  connectedCallback(): void;
13
13
  enable(): void;
14
14
  disable(): void;
15
- runTest(contextManager: ContextManager, testContext: TestContext): Promise<void>;
15
+ runTest(contextManager: CodeTestsContext, testContext: TestContext): Promise<void>;
16
16
  reset(): void;
17
17
  getMessageElement(): HTMLElement;
18
18
  static observedAttributes: string[];
@@ -31,6 +31,22 @@ export declare const CodeTestEvent: {
31
31
  Reset: string;
32
32
  };
33
33
 
34
+ declare class CodeTestsContext {
35
+ #private;
36
+ codeTestsElement: CodeTestsElement;
37
+ constructor(parent: CodeTestsElement);
38
+ loadTests(path?: string): Promise<void>;
39
+ shouldContinueRunningTests: boolean;
40
+ runTests(tests: CodeTestElement[]): Promise<void>;
41
+ runTest(test: CodeTestElement | undefined, inLoop: boolean, testContext?: TestContext): Promise<void>;
42
+ runHook(testStateName: keyof Pick<CodeTestsState, 'requiredBeforeAnyState' | 'requiredAfterAnyState' | 'beforeEachState' | 'afterEachState' | 'beforeAllState' | 'afterAllState'>, test: CodeTestElement | undefined, testContext: TestContext): Promise<string | void | HTMLElement | TestResult | typeof NOTESTDEFINED>;
43
+ parseTestResult(result: TestResultType | typeof NOTESTDEFINED, finishedTest: boolean, error?: Error): {
44
+ result: string | HTMLElement;
45
+ resultCategory: TestResultCategory;
46
+ };
47
+ createTestContext(testElement?: CodeTestElement): Promise<TestContext>;
48
+ }
49
+
34
50
  export declare class CodeTestsElement extends HTMLElement {
35
51
  #private;
36
52
  state: CodeTestsState;
@@ -74,22 +90,6 @@ export declare type CodeTestState = {
74
90
  afterEachState?: TestResultState;
75
91
  };
76
92
 
77
- declare class ContextManager {
78
- #private;
79
- codeTestsElement: CodeTestsElement;
80
- constructor(parent: CodeTestsElement);
81
- loadTests(path?: string): Promise<void>;
82
- shouldContinueRunningTests: boolean;
83
- runTests(tests: CodeTestElement[]): Promise<void>;
84
- runTest(test: CodeTestElement | undefined, inLoop: boolean, testContext?: TestContext): Promise<void>;
85
- runHook(testStateName: keyof Pick<CodeTestsState, 'requiredBeforeAnyState' | 'requiredAfterAnyState' | 'beforeEachState' | 'afterEachState' | 'beforeAllState' | 'afterAllState'>, test: CodeTestElement | undefined, testContext: TestContext): Promise<string | void | HTMLElement | TestResult | typeof NOTESTDEFINED>;
86
- parseTestResult(result: TestResultType | typeof NOTESTDEFINED, finishedTest: boolean, error?: Error): {
87
- result: string | HTMLElement;
88
- resultCategory: TestResultCategory;
89
- };
90
- createTestContext(testElement?: CodeTestElement): Promise<TestContext>;
91
- }
92
-
93
93
  export declare function createElementFromTemplate(target: string | HTMLTemplateElement, parent?: HTMLElement): HTMLElement;
94
94
 
95
95
  export declare function expect<T>(value: T): TestPromise<T>;
@@ -45,7 +45,6 @@ const style = `:host
45
45
  display: flex;
46
46
  align-items: center;
47
47
  gap: var(--gap);
48
- padding: var(--gap-small) var(--gap);
49
48
  }
50
49
  #title
51
50
  {
@@ -104,7 +103,7 @@ summary:not(#component-summary)
104
103
  }
105
104
  #component-summary
106
105
  {
107
- padding-block: var(--gap-small);
106
+ padding: var(--gap-small)
108
107
  }
109
108
 
110
109
 
@@ -128,6 +127,15 @@ details[open] > summary > .arrow-icon
128
127
  transform: rotate(0);
129
128
  }
130
129
 
130
+ #enabled
131
+ {
132
+ display: none;
133
+ }
134
+ :host([optional]) #enabled
135
+ {
136
+ display: block;
137
+ }
138
+
131
139
  /* Result Icon */
132
140
  .result-icon
133
141
  {
@@ -341,7 +349,7 @@ code-test > details > summary > .description
341
349
  from { transform: rotate(0deg); }
342
350
  to { transform: rotate(360deg); }
343
351
  }`;
344
- const html = '<details id="component-details" class="details">\n <summary id="component-summary" class="summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <slot name="header">\n <header id="header">\n <span id="component-result-icon" class="result-icon"></span>\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="reload-button">\n <button type="button" id="reload-button" title="Reload">\n <slot name="reload-button-content">\n <slot name="reload-button-icon"><svg class="icon reset-icon reload-button-icon"><use href="#icon-definition_reset"></use></svg></slot>\n <slot name="reload-button-label"><span class="reload-button-label button-label label icon">Reload</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="run-all-button">\n <button type="button" id="run-all-button" title="Run All Tests">\n <slot name="run-all-button-content">\n <slot name="run-all-button-icon"><svg class="icon arrow-icon run-button-icon run-all-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-all-button-label"><span class="run-all-button-label run-button-label button-label label icon">Run Tests</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="header-details"></slot>\n </header>\n </slot>\n </summary>\n <div id="component-content" class="content">\n <details id="required-before-any-details" class="hook">\n <summary id="required-before-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-before-any-result-icon" class="result-icon"></span>\n <span id="required-before-any-description" class="description hook-name">Required Before Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-before-any-results" class="result message"></div>\n </div>\n </details>\n <details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description hook-name">Before All Hook</span>\n </summary>\n <div class="results">\n <div id="before-all-results" class="result message"></div>\n </div>\n </details>\n <div id="tests"></div>\n <details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description hook-name">After All Hook</span>\n </summary>\n <div class="results">\n <div id="after-all-results" class="result message"></div>\n </div>\n </details>\n <details id="required-after-any-details" class="hook">\n <summary id="required-after-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-after-any-result-icon" class="result-icon"></span>\n <span id="required-after-any-description" class="description hook-name">Required After Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-after-any-results" class="result message"></div>\n </div>\n </details>\n </div>\n \n <slot name="footer">\n <foooter id="footer">\n <span id="group-results">\n <span id="duration">\n <span id="duration-label">Duration</span>\n <span id="duration-value"></span>\n <span id="duration-unit">ms</span>\n </span>\n <span id="results-progress">\n <progress id="results-progress-value"></progress>\n </span>\n <span id="passed-total-pair">\n <span id="total-tests-passed-value"></span>\n <span id="passed-total-delimiter">of</span>\n <span id="total-tests-count-value"></span>\n <span id="total-tests-passed-label">Passed</span>\n </span>\n <span id="passed-total-percent">\n <span id="passed-total-percent-value"></span>\n <span id="passed-total-percent-label">%</span>\n </span>\n </span>\n </foooter>\n </slot>\n</details>\n<template id="prompt-template">\n <div class="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>\n<div id="icon-definitions" style="display: none;">\n <svg id="icon-definition_arrow" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path d="m3.26,6.81l-2.93,-4.69c-0.37,-0.58 0.05,-1.34 0.74,-1.34l5.87,0c0.69,0 1.11,0.76 0.74,1.34l-2.93,4.69c-0.35,0.55 -1.14,0.55 -1.49,0z" fill="var(--fill-color, currentcolor)" />\n </svg>\n <svg id="icon-definition_reset" class="icon reset" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M 5.484375 0.43359375 A 1.5224222 1.5224222 0 0 0 4.2558594 1.2011719 L 0.99804688 6.9453125 A 1.5224222 1.5224222 0 0 0 2.5488281 9.2011719 L 9.34375 8.171875 A 1.5224222 1.5224222 0 0 0 10.332031 5.7539062 L 9.4746094 4.6113281 C 11.949333 3.8016718 14.718209 4.258351 16.822266 5.9570312 C 19.510764 8.1275534 20.456787 11.785479 19.160156 14.988281 C 17.863527 18.191083 14.6405 20.15873 11.199219 19.847656 C 7.7579362 19.536584 4.9376009 17.022073 4.2363281 13.638672 A 1.5 1.5 0 0 0 2.4628906 12.474609 A 1.5 1.5 0 0 0 1.2988281 14.248047 C 2.2656928 18.912838 6.1831413 22.407052 10.927734 22.835938 C 15.672328 23.264824 20.153706 20.531029 21.941406 16.115234 C 23.729107 11.699441 22.413741 6.6156073 18.707031 3.6230469 C 16.853677 2.1267667 14.61485 1.3255701 12.347656 1.2324219 C 10.738216 1.1662975 9.1150542 1.4598646 7.6035156 2.1132812 L 6.7988281 1.0390625 A 1.5224222 1.5224222 0 0 0 5.484375 0.43359375 z " />\n </svg>\n <svg id="icon-definition_cancel" class="icon cancel" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M -7.063234 9.5244002 C -5.8135728 7.6769245 -5.0820528 5.453265 -5.0820528 3.0633809 C -5.0820529 -3.3096433 -10.278145 -8.5098163 -16.65117 -8.5098163 C -23.024193 -8.5098163 -28.22385 -3.3110105 -28.22385 3.0620137 C -28.22385 9.4350379 -23.025043 14.634694 -16.65202 14.634694 C -12.668879 14.634694 -9.1460028 12.603526 -7.063234 9.5244002 z M -9.5406311 7.8637601 C -11.076991 10.143147 -13.683157 11.63463 -16.652974 11.63463 C -19.960499 11.63463 -22.814085 9.782061 -24.244824 7.0543029 L -24.236684 7.0527515 L -8.1332524 3.983715 L -8.1305391 3.9831979 C -8.2815631 5.4121635 -8.7798709 6.7350751 -9.5406311 7.8637601 z M -9.0610781 -0.92890828 L -9.069218 -0.92735695 L -25.17265 2.1416796 L -25.175363 2.1421967 C -24.719122 -2.1725739 -21.093311 -5.5092358 -16.652928 -5.5092358 C -13.345403 -5.5092358 -10.491243 -3.6566663 -9.0610781 -0.92890828 z "\n transform="rotate(-124.20981)" />\n </svg>\n</div>';
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"></span>\n <span id="duration-unit">ms</span>\n </span>\n <span id="results-progress">\n <progress id="results-progress-value"></progress>\n </span>\n <span id="passed-total-pair">\n <span id="total-tests-passed-value"></span>\n <span id="passed-total-delimiter">of</span>\n <span id="total-tests-count-value"></span>\n <span id="total-tests-passed-label">Passed</span>\n </span>\n <span id="passed-total-percent">\n <span id="passed-total-percent-value"></span>\n <span id="passed-total-percent-label">%</span>\n </span>\n </span>\n </foooter>\n </slot>\n</details>\n<template id="prompt-template">\n <div class="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>\n<div id="icon-definitions" style="display: none;">\n <svg id="icon-definition_arrow" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path d="m3.26,6.81l-2.93,-4.69c-0.37,-0.58 0.05,-1.34 0.74,-1.34l5.87,0c0.69,0 1.11,0.76 0.74,1.34l-2.93,4.69c-0.35,0.55 -1.14,0.55 -1.49,0z" fill="var(--fill-color, currentcolor)" />\n </svg>\n <svg id="icon-definition_reset" class="icon reset" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M 5.484375 0.43359375 A 1.5224222 1.5224222 0 0 0 4.2558594 1.2011719 L 0.99804688 6.9453125 A 1.5224222 1.5224222 0 0 0 2.5488281 9.2011719 L 9.34375 8.171875 A 1.5224222 1.5224222 0 0 0 10.332031 5.7539062 L 9.4746094 4.6113281 C 11.949333 3.8016718 14.718209 4.258351 16.822266 5.9570312 C 19.510764 8.1275534 20.456787 11.785479 19.160156 14.988281 C 17.863527 18.191083 14.6405 20.15873 11.199219 19.847656 C 7.7579362 19.536584 4.9376009 17.022073 4.2363281 13.638672 A 1.5 1.5 0 0 0 2.4628906 12.474609 A 1.5 1.5 0 0 0 1.2988281 14.248047 C 2.2656928 18.912838 6.1831413 22.407052 10.927734 22.835938 C 15.672328 23.264824 20.153706 20.531029 21.941406 16.115234 C 23.729107 11.699441 22.413741 6.6156073 18.707031 3.6230469 C 16.853677 2.1267667 14.61485 1.3255701 12.347656 1.2324219 C 10.738216 1.1662975 9.1150542 1.4598646 7.6035156 2.1132812 L 6.7988281 1.0390625 A 1.5224222 1.5224222 0 0 0 5.484375 0.43359375 z " />\n </svg>\n <svg id="icon-definition_cancel" class="icon cancel" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M -7.063234 9.5244002 C -5.8135728 7.6769245 -5.0820528 5.453265 -5.0820528 3.0633809 C -5.0820529 -3.3096433 -10.278145 -8.5098163 -16.65117 -8.5098163 C -23.024193 -8.5098163 -28.22385 -3.3110105 -28.22385 3.0620137 C -28.22385 9.4350379 -23.025043 14.634694 -16.65202 14.634694 C -12.668879 14.634694 -9.1460028 12.603526 -7.063234 9.5244002 z M -9.5406311 7.8637601 C -11.076991 10.143147 -13.683157 11.63463 -16.652974 11.63463 C -19.960499 11.63463 -22.814085 9.782061 -24.244824 7.0543029 L -24.236684 7.0527515 L -8.1332524 3.983715 L -8.1305391 3.9831979 C -8.2815631 5.4121635 -8.7798709 6.7350751 -9.5406311 7.8637601 z M -9.0610781 -0.92890828 L -9.069218 -0.92735695 L -25.17265 2.1416796 L -25.175363 2.1421967 C -24.719122 -2.1725739 -21.093311 -5.5092358 -16.652928 -5.5092358 C -13.345403 -5.5092358 -10.491243 -3.6566663 -9.0610781 -0.92890828 z "\n transform="rotate(-124.20981)" />\n </svg>\n</div>';
345
353
  const CodeTestEvent = {
346
354
  BeforeAll: "beforeall",
347
355
  AfterAll: "afterall",
@@ -594,7 +602,7 @@ if (customElements.get(COMPONENT_TAG_NAME$1) == null) {
594
602
  customElements.define(COMPONENT_TAG_NAME$1, CodeTestElement);
595
603
  }
596
604
  const NOTESTDEFINED = /* @__PURE__ */ Symbol("No Test Defined");
597
- class ContextManager {
605
+ class CodeTestsContext {
598
606
  codeTestsElement;
599
607
  // testContext?: TestContext;
600
608
  constructor(parent) {
@@ -1107,12 +1115,12 @@ class CodeTestsElement extends HTMLElement {
1107
1115
  return "none";
1108
1116
  } else if (testCategory == "fail" || statesCategory == "fail") {
1109
1117
  return "fail";
1110
- } else if (testCategory == "success" && statesCategory == "success") {
1118
+ } else if (testCategory == "success" || statesCategory == "success") {
1111
1119
  return "success";
1112
1120
  }
1113
1121
  return "none";
1114
1122
  }
1115
- #contextManager;
1123
+ #context;
1116
1124
  constructor() {
1117
1125
  super();
1118
1126
  this.attachShadow({ mode: "open" });
@@ -1134,8 +1142,9 @@ class CodeTestsElement extends HTMLElement {
1134
1142
  this.#isInitializing = true;
1135
1143
  assignClassAndIdToPart(this.shadowRoot);
1136
1144
  this.addEventListener("click", this.#boundClickHandler);
1145
+ this.findElement("#enabled").addEventListener("change", this.#boundEnabledHandler);
1137
1146
  await new Promise((resolve) => requestAnimationFrame(() => {
1138
- this.#contextManager = new ContextManager(this);
1147
+ this.#context = new CodeTestsContext(this);
1139
1148
  this.#isInitialized = true;
1140
1149
  this.#isInitializing = false;
1141
1150
  const allowAutoLoad = this.dispatchEvent(new CustomEvent("init", { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
@@ -1154,7 +1163,9 @@ class CodeTestsElement extends HTMLElement {
1154
1163
  }
1155
1164
  #destroy() {
1156
1165
  this.removeEventListener("click", this.#boundClickHandler);
1166
+ this.findElement("#enabled").removeEventListener("change", this.#boundEnabledHandler);
1157
1167
  this.#isInitialized = false;
1168
+ this.#isInitializing = false;
1158
1169
  }
1159
1170
  #boundClickHandler = this.#onClick.bind(this);
1160
1171
  #onClick(event) {
@@ -1178,7 +1189,17 @@ class CodeTestsElement extends HTMLElement {
1178
1189
  return;
1179
1190
  }
1180
1191
  const test = runButton.closest("code-test") ?? void 0;
1181
- this.#contextManager.runTest(test, false);
1192
+ this.#context.runTest(test, false);
1193
+ }
1194
+ #boundEnabledHandler = this.#enabled_onChange.bind(this);
1195
+ #enabled_onChange(event) {
1196
+ const input = event.target;
1197
+ const allowToggle = this.dispatchEvent(new CustomEvent("enabled", { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
1198
+ if (allowToggle == false) {
1199
+ event.preventDefault();
1200
+ event.stopPropagation();
1201
+ input.checked = !input.checked;
1202
+ }
1182
1203
  }
1183
1204
  #getCurrentTestsPath() {
1184
1205
  return this.getAttribute("src") ?? this.getAttribute("test") ?? this.getAttribute("tests") ?? this.getAttribute("run") ?? this.getAttribute("path") ?? void 0;
@@ -1297,13 +1318,13 @@ class CodeTestsElement extends HTMLElement {
1297
1318
  }
1298
1319
  async runTests() {
1299
1320
  const tests = this.findElements("code-test");
1300
- return this.#contextManager.runTests(tests);
1321
+ return this.#context.runTests(tests);
1301
1322
  }
1302
1323
  async reloadTests() {
1303
1324
  this.findElement("#tests").innerHTML = "";
1304
1325
  await this.reset();
1305
1326
  const testsPath = this.#getCurrentTestsPath();
1306
- this.#contextManager.loadTests(testsPath);
1327
+ this.#context.loadTests(testsPath);
1307
1328
  }
1308
1329
  async reset() {
1309
1330
  const tests = this.findElements("code-test");
@@ -1346,15 +1367,15 @@ class CodeTestsElement extends HTMLElement {
1346
1367
  requiredAfterAnyState,
1347
1368
  requiredBeforeAnyState
1348
1369
  });
1349
- this.#contextManager.shouldContinueRunningTests = true;
1370
+ this.#context.shouldContinueRunningTests = true;
1350
1371
  if (this.state.resetHook != null) {
1351
- await this.state.resetHook(await this.#contextManager.createTestContext());
1372
+ await this.state.resetHook(await this.#context.createTestContext());
1352
1373
  }
1353
1374
  this.dispatchEvent(new CustomEvent(CodeTestEvent.Reset, { bubbles: true, composed: true }));
1354
1375
  }
1355
1376
  cancel() {
1356
1377
  this.state.isCanceled = true;
1357
- this.#contextManager.shouldContinueRunningTests = false;
1378
+ this.#context.shouldContinueRunningTests = false;
1358
1379
  this.classList.add("canceled");
1359
1380
  this.part.add("canceled");
1360
1381
  this.dispatchEvent(new CustomEvent(CodeTestEvent.Cancel, { bubbles: true, composed: true }));
@@ -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 padding: var(--gap-small) 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-block: 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/* 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 <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),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.#u=!1}#d=this.#h.bind(this);#h(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)}#f(){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.#p(this.state.beforeAllState,"#before-all-results"),this.#p(this.state.afterAllState,"#after-all-results"),this.#p(this.state.requiredBeforeAnyState,"#required-before-any-results"),this.#p(this.state.requiredAfterAnyState,"#required-after-any-results");const h=this.findElement("#title");null!=h&&(h.textContent=this.getAttribute("label")??"Tests"),this.#g()}#p(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)}#g(){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.#f();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"},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};
@@ -49,7 +49,6 @@
49
49
  display: flex;
50
50
  align-items: center;
51
51
  gap: var(--gap);
52
- padding: var(--gap-small) var(--gap);
53
52
  }
54
53
  #title
55
54
  {
@@ -108,7 +107,7 @@ summary:not(#component-summary)
108
107
  }
109
108
  #component-summary
110
109
  {
111
- padding-block: var(--gap-small);
110
+ padding: var(--gap-small)
112
111
  }
113
112
 
114
113
 
@@ -132,6 +131,15 @@ details[open] > summary > .arrow-icon
132
131
  transform: rotate(0);
133
132
  }
134
133
 
134
+ #enabled
135
+ {
136
+ display: none;
137
+ }
138
+ :host([optional]) #enabled
139
+ {
140
+ display: block;
141
+ }
142
+
135
143
  /* Result Icon */
136
144
  .result-icon
137
145
  {
@@ -345,7 +353,7 @@ code-test > details > summary > .description
345
353
  from { transform: rotate(0deg); }
346
354
  to { transform: rotate(360deg); }
347
355
  }`;
348
- const html = '<details id="component-details" class="details">\n <summary id="component-summary" class="summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <slot name="header">\n <header id="header">\n <span id="component-result-icon" class="result-icon"></span>\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="reload-button">\n <button type="button" id="reload-button" title="Reload">\n <slot name="reload-button-content">\n <slot name="reload-button-icon"><svg class="icon reset-icon reload-button-icon"><use href="#icon-definition_reset"></use></svg></slot>\n <slot name="reload-button-label"><span class="reload-button-label button-label label icon">Reload</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="run-all-button">\n <button type="button" id="run-all-button" title="Run All Tests">\n <slot name="run-all-button-content">\n <slot name="run-all-button-icon"><svg class="icon arrow-icon run-button-icon run-all-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-all-button-label"><span class="run-all-button-label run-button-label button-label label icon">Run Tests</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="header-details"></slot>\n </header>\n </slot>\n </summary>\n <div id="component-content" class="content">\n <details id="required-before-any-details" class="hook">\n <summary id="required-before-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-before-any-result-icon" class="result-icon"></span>\n <span id="required-before-any-description" class="description hook-name">Required Before Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-before-any-results" class="result message"></div>\n </div>\n </details>\n <details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description hook-name">Before All Hook</span>\n </summary>\n <div class="results">\n <div id="before-all-results" class="result message"></div>\n </div>\n </details>\n <div id="tests"></div>\n <details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description hook-name">After All Hook</span>\n </summary>\n <div class="results">\n <div id="after-all-results" class="result message"></div>\n </div>\n </details>\n <details id="required-after-any-details" class="hook">\n <summary id="required-after-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-after-any-result-icon" class="result-icon"></span>\n <span id="required-after-any-description" class="description hook-name">Required After Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-after-any-results" class="result message"></div>\n </div>\n </details>\n </div>\n \n <slot name="footer">\n <foooter id="footer">\n <span id="group-results">\n <span id="duration">\n <span id="duration-label">Duration</span>\n <span id="duration-value"></span>\n <span id="duration-unit">ms</span>\n </span>\n <span id="results-progress">\n <progress id="results-progress-value"></progress>\n </span>\n <span id="passed-total-pair">\n <span id="total-tests-passed-value"></span>\n <span id="passed-total-delimiter">of</span>\n <span id="total-tests-count-value"></span>\n <span id="total-tests-passed-label">Passed</span>\n </span>\n <span id="passed-total-percent">\n <span id="passed-total-percent-value"></span>\n <span id="passed-total-percent-label">%</span>\n </span>\n </span>\n </foooter>\n </slot>\n</details>\n<template id="prompt-template">\n <div class="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>\n<div id="icon-definitions" style="display: none;">\n <svg id="icon-definition_arrow" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path d="m3.26,6.81l-2.93,-4.69c-0.37,-0.58 0.05,-1.34 0.74,-1.34l5.87,0c0.69,0 1.11,0.76 0.74,1.34l-2.93,4.69c-0.35,0.55 -1.14,0.55 -1.49,0z" fill="var(--fill-color, currentcolor)" />\n </svg>\n <svg id="icon-definition_reset" class="icon reset" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M 5.484375 0.43359375 A 1.5224222 1.5224222 0 0 0 4.2558594 1.2011719 L 0.99804688 6.9453125 A 1.5224222 1.5224222 0 0 0 2.5488281 9.2011719 L 9.34375 8.171875 A 1.5224222 1.5224222 0 0 0 10.332031 5.7539062 L 9.4746094 4.6113281 C 11.949333 3.8016718 14.718209 4.258351 16.822266 5.9570312 C 19.510764 8.1275534 20.456787 11.785479 19.160156 14.988281 C 17.863527 18.191083 14.6405 20.15873 11.199219 19.847656 C 7.7579362 19.536584 4.9376009 17.022073 4.2363281 13.638672 A 1.5 1.5 0 0 0 2.4628906 12.474609 A 1.5 1.5 0 0 0 1.2988281 14.248047 C 2.2656928 18.912838 6.1831413 22.407052 10.927734 22.835938 C 15.672328 23.264824 20.153706 20.531029 21.941406 16.115234 C 23.729107 11.699441 22.413741 6.6156073 18.707031 3.6230469 C 16.853677 2.1267667 14.61485 1.3255701 12.347656 1.2324219 C 10.738216 1.1662975 9.1150542 1.4598646 7.6035156 2.1132812 L 6.7988281 1.0390625 A 1.5224222 1.5224222 0 0 0 5.484375 0.43359375 z " />\n </svg>\n <svg id="icon-definition_cancel" class="icon cancel" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M -7.063234 9.5244002 C -5.8135728 7.6769245 -5.0820528 5.453265 -5.0820528 3.0633809 C -5.0820529 -3.3096433 -10.278145 -8.5098163 -16.65117 -8.5098163 C -23.024193 -8.5098163 -28.22385 -3.3110105 -28.22385 3.0620137 C -28.22385 9.4350379 -23.025043 14.634694 -16.65202 14.634694 C -12.668879 14.634694 -9.1460028 12.603526 -7.063234 9.5244002 z M -9.5406311 7.8637601 C -11.076991 10.143147 -13.683157 11.63463 -16.652974 11.63463 C -19.960499 11.63463 -22.814085 9.782061 -24.244824 7.0543029 L -24.236684 7.0527515 L -8.1332524 3.983715 L -8.1305391 3.9831979 C -8.2815631 5.4121635 -8.7798709 6.7350751 -9.5406311 7.8637601 z M -9.0610781 -0.92890828 L -9.069218 -0.92735695 L -25.17265 2.1416796 L -25.175363 2.1421967 C -24.719122 -2.1725739 -21.093311 -5.5092358 -16.652928 -5.5092358 C -13.345403 -5.5092358 -10.491243 -3.6566663 -9.0610781 -0.92890828 z "\n transform="rotate(-124.20981)" />\n </svg>\n</div>';
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"></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>';
349
357
  const CodeTestEvent = {
350
358
  BeforeAll: "beforeall",
351
359
  AfterAll: "afterall",
@@ -598,7 +606,7 @@ code-test > details > summary > .description
598
606
  customElements.define(COMPONENT_TAG_NAME$1, CodeTestElement);
599
607
  }
600
608
  const NOTESTDEFINED = /* @__PURE__ */ Symbol("No Test Defined");
601
- class ContextManager {
609
+ class CodeTestsContext {
602
610
  codeTestsElement;
603
611
  // testContext?: TestContext;
604
612
  constructor(parent) {
@@ -1111,12 +1119,12 @@ Result:${objectResult.value}</pre>
1111
1119
  return "none";
1112
1120
  } else if (testCategory == "fail" || statesCategory == "fail") {
1113
1121
  return "fail";
1114
- } else if (testCategory == "success" && statesCategory == "success") {
1122
+ } else if (testCategory == "success" || statesCategory == "success") {
1115
1123
  return "success";
1116
1124
  }
1117
1125
  return "none";
1118
1126
  }
1119
- #contextManager;
1127
+ #context;
1120
1128
  constructor() {
1121
1129
  super();
1122
1130
  this.attachShadow({ mode: "open" });
@@ -1138,8 +1146,9 @@ Result:${objectResult.value}</pre>
1138
1146
  this.#isInitializing = true;
1139
1147
  assignClassAndIdToPart(this.shadowRoot);
1140
1148
  this.addEventListener("click", this.#boundClickHandler);
1149
+ this.findElement("#enabled").addEventListener("change", this.#boundEnabledHandler);
1141
1150
  await new Promise((resolve) => requestAnimationFrame(() => {
1142
- this.#contextManager = new ContextManager(this);
1151
+ this.#context = new CodeTestsContext(this);
1143
1152
  this.#isInitialized = true;
1144
1153
  this.#isInitializing = false;
1145
1154
  const allowAutoLoad = this.dispatchEvent(new CustomEvent("init", { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
@@ -1158,7 +1167,9 @@ Result:${objectResult.value}</pre>
1158
1167
  }
1159
1168
  #destroy() {
1160
1169
  this.removeEventListener("click", this.#boundClickHandler);
1170
+ this.findElement("#enabled").removeEventListener("change", this.#boundEnabledHandler);
1161
1171
  this.#isInitialized = false;
1172
+ this.#isInitializing = false;
1162
1173
  }
1163
1174
  #boundClickHandler = this.#onClick.bind(this);
1164
1175
  #onClick(event) {
@@ -1182,7 +1193,17 @@ Result:${objectResult.value}</pre>
1182
1193
  return;
1183
1194
  }
1184
1195
  const test = runButton.closest("code-test") ?? void 0;
1185
- this.#contextManager.runTest(test, false);
1196
+ this.#context.runTest(test, false);
1197
+ }
1198
+ #boundEnabledHandler = this.#enabled_onChange.bind(this);
1199
+ #enabled_onChange(event) {
1200
+ const input = event.target;
1201
+ const allowToggle = this.dispatchEvent(new CustomEvent("enabled", { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
1202
+ if (allowToggle == false) {
1203
+ event.preventDefault();
1204
+ event.stopPropagation();
1205
+ input.checked = !input.checked;
1206
+ }
1186
1207
  }
1187
1208
  #getCurrentTestsPath() {
1188
1209
  return this.getAttribute("src") ?? this.getAttribute("test") ?? this.getAttribute("tests") ?? this.getAttribute("run") ?? this.getAttribute("path") ?? void 0;
@@ -1301,13 +1322,13 @@ Result:${objectResult.value}</pre>
1301
1322
  }
1302
1323
  async runTests() {
1303
1324
  const tests = this.findElements("code-test");
1304
- return this.#contextManager.runTests(tests);
1325
+ return this.#context.runTests(tests);
1305
1326
  }
1306
1327
  async reloadTests() {
1307
1328
  this.findElement("#tests").innerHTML = "";
1308
1329
  await this.reset();
1309
1330
  const testsPath = this.#getCurrentTestsPath();
1310
- this.#contextManager.loadTests(testsPath);
1331
+ this.#context.loadTests(testsPath);
1311
1332
  }
1312
1333
  async reset() {
1313
1334
  const tests = this.findElements("code-test");
@@ -1350,15 +1371,15 @@ Result:${objectResult.value}</pre>
1350
1371
  requiredAfterAnyState,
1351
1372
  requiredBeforeAnyState
1352
1373
  });
1353
- this.#contextManager.shouldContinueRunningTests = true;
1374
+ this.#context.shouldContinueRunningTests = true;
1354
1375
  if (this.state.resetHook != null) {
1355
- await this.state.resetHook(await this.#contextManager.createTestContext());
1376
+ await this.state.resetHook(await this.#context.createTestContext());
1356
1377
  }
1357
1378
  this.dispatchEvent(new CustomEvent(CodeTestEvent.Reset, { bubbles: true, composed: true }));
1358
1379
  }
1359
1380
  cancel() {
1360
1381
  this.state.isCanceled = true;
1361
- this.#contextManager.shouldContinueRunningTests = false;
1382
+ this.#context.shouldContinueRunningTests = false;
1362
1383
  this.classList.add("canceled");
1363
1384
  this.part.add("canceled");
1364
1385
  this.dispatchEvent(new CustomEvent(CodeTestEvent.Cancel, { bubbles: true, composed: true }));
@@ -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 padding: var(--gap-small) 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-block: 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/* 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 <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),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.#u=!1}#d=this.#h.bind(this);#h(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)}#f(){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.#p(this.state.beforeAllState,"#before-all-results"),this.#p(this.state.afterAllState,"#after-all-results"),this.#p(this.state.requiredBeforeAnyState,"#required-before-any-results"),this.#p(this.state.requiredAfterAnyState,"#required-after-any-results");const h=this.findElement("#title");null!=h&&(h.textContent=this.getAttribute("label")??"Tests"),this.#g()}#p(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)}#g(){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.#f();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"},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"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magnit-ce/code-tests",
3
- "version": "0.0.19",
3
+ "version": "0.1.0",
4
4
  "description": "A custom html element that interprets and runs tests in a browser",
5
5
  "main": "dist/code-tests.umd.js",
6
6
  "module": "dist/code-tests.js",
@@ -13,8 +13,8 @@
13
13
  "dev": "vite",
14
14
  "build": "tsc && vite build",
15
15
  "preview": "vite preview",
16
- "test:build": "vite build --config vite.config.tests.ts",
17
- "test": "npm run test:build && web-dev-server --watch --app-index test-runner/index.html",
16
+ "test:build": "echo \"\nThis package cannot build tests because tests rely on referencing this package to build.\nVite/rollup's bundler does not allow excluding references to the entry point, and the entry point in this package is set to the code-tests library.\n\nOther libraries can use this command to convert .test.ts files into .js files in the public/tests directory, but this one must build tests manually.\"",
17
+ "test": "web-dev-server --watch --app-index test-runner/index.html",
18
18
  "changeset": "npx @changesets/cli",
19
19
  "release": "npm run build && npx @changesets/cli publish"
20
20
  },