@magnit-ce/code-tests 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,6 +32,7 @@ export declare const CodeTestEvent: {
32
32
  TestEnd: string;
33
33
  Init: string;
34
34
  Enabled: string;
35
+ PromptResult: string;
35
36
  };
36
37
 
37
38
  declare class CodeTestsContext {
@@ -386,7 +386,8 @@ const CodeTestEvent = {
386
386
  Reset: "reset",
387
387
  TestEnd: "testend",
388
388
  Init: "init",
389
- Enabled: "enabled"
389
+ Enabled: "enabled",
390
+ PromptResult: "promptresult"
390
391
  };
391
392
  const COMPONENT_TAG_NAME$1 = "code-test";
392
393
  class CodeTestElement extends HTMLElement {
@@ -824,6 +825,9 @@ class CodeTestsContext {
824
825
  }
825
826
  }
826
827
  testContext = testContext ?? await this.createTestContext(test);
828
+ if (testContext.testElement == null) {
829
+ testContext.testElement = test;
830
+ }
827
831
  if (inLoop == false) {
828
832
  await this.runHook("requiredBeforeAnyState", void 0, testContext);
829
833
  if (this.shouldContinueRunningTests == false) {
@@ -1435,24 +1439,25 @@ function expect(value) {
1435
1439
  return promise;
1436
1440
  }
1437
1441
  async function prompt(host, parentElement, message, options) {
1438
- return new Promise((resolve, _reject) => {
1442
+ let promptElement = null;
1443
+ const result = await new Promise((resolve, _reject) => {
1439
1444
  const template = options?.template ?? host.querySelector(".prompt-template") ?? host.findElement("#prompt-template");
1440
- const promptElement = createElementFromTemplate(template);
1445
+ promptElement = createElementFromTemplate(template);
1441
1446
  promptElement.querySelector(".label").textContent = message;
1442
1447
  const clickHandler = (event) => {
1443
1448
  const composedPath = event.composedPath();
1444
1449
  const acceptButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("accept"));
1445
1450
  if (acceptButton != null) {
1446
- const result = options?.onAccept?.() ?? true;
1451
+ const result2 = options?.onAccept?.() ?? true;
1447
1452
  promptElement.removeEventListener("click", clickHandler);
1448
- resolve(result);
1453
+ resolve(result2);
1449
1454
  return;
1450
1455
  }
1451
1456
  const rejectButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("reject"));
1452
1457
  if (rejectButton != null) {
1453
- const result = options?.onReject?.() ?? false;
1458
+ const result2 = options?.onReject?.() ?? false;
1454
1459
  promptElement.removeEventListener("click", clickHandler);
1455
- resolve(result);
1460
+ resolve(result2);
1456
1461
  return;
1457
1462
  }
1458
1463
  };
@@ -1465,6 +1470,11 @@ async function prompt(host, parentElement, message, options) {
1465
1470
  }
1466
1471
  parentElement.append(promptElement);
1467
1472
  });
1473
+ if (promptElement != null) {
1474
+ promptElement.remove();
1475
+ }
1476
+ host.dispatchEvent(new CustomEvent(CodeTestEvent.PromptResult, { bubbles: true, composed: true, detail: { target: host, result } }));
1477
+ return result;
1468
1478
  }
1469
1479
  function createElementFromTemplate(target, parent) {
1470
1480
  const templateNode = target instanceof HTMLTemplateElement ? target : document.querySelector(target);
@@ -1 +1 @@
1
- const t={BeforeAll:"beforeall",AfterAll:"afterall",BeforeTest:"beforetest",AfterTest:"aftertest",BeforeHook:"beforehook",AfterHook:"afterhook",Cancel:"cancel",Context:"context",Reset:"reset",TestEnd:"testend",Init:"init",Enabled:"enabled"},e="code-test";class s extends HTMLElement{state={testId:"",description:"none",isDisabled:!1,testState:void 0,beforeEachState:void 0,afterEachState:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.querySelector(t)}findElements(t){return Array.from(this.querySelectorAll(t))}isRunning(){return 1==this.state.testState?.isRunning||1==this.state.beforeEachState?.isRunning||1==this.state.afterEachState?.isRunning}hasRun(){return 1==this.state.testState?.hasRun||1==this.state.beforeEachState?.hasRun||1==this.state.afterEachState?.hasRun}resultCategory(){const t=this.state.testState?.resultCategory??"none",e=this.state.beforeEachState?.resultCategory??"none",s=this.state.afterEachState?.resultCategory??"none";return"none"==t&&"none"==e&&"none"==s?"none":null==this.state.beforeEachState&&null==this.state.afterEachState?t:null!=this.state.beforeEachState&&null==this.state.afterEachState?"fail"==t||"fail"==e?"fail":"success"==t&&"success"==e?"success":"none":null==this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==s?"fail":"success"==t&&"success"==s?"success":"none":null!=this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==e||"fail"==s?"fail":"success"==t&&"success"==e&&"success"==s?"success":"none":void 0}connectedCallback(){this.#t()}#t(){const t=null==this.state.testState?"":"boolean"==typeof this.state.testState.resultContent?1==this.state.testState.resultContent?'<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed</pre></code>':'<code class="code" part="code"><pre class="pre error-message" part="pre error-message">Failed</pre></code>':"number"==typeof this.state.testState.resultContent?`<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed: ${this.state.testState.resultContent.toString()}</pre></code>`:"string"==typeof this.state.testState.resultContent?this.state.testState.resultContent:"";this.innerHTML=`<details class="test-details" part="test-details" ${1==this.isRunning()||1==this.hasRun()?" open":""}>\n <summary class="test-summary" part="test-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="result-icon test-result-icon${"none"!=this.state.testState?.resultCategory?` ${this.state.testState?.resultCategory}`:""}" part="result-icon"></div>\n <span class="test-description description" title="${this.state.description}">${this.state.description}</span>\n ${null!=this.state.testState?.duration&&this.state.testState.duration>0?`<span class="test-duration duration">\n <span class="test-duration-value">${this.state.testState.duration>10?this.state.testState.duration.toFixed(0):this.state.testState.duration.toFixed(2)}</span>\n <span class="test-duration-unit">ms</span>\n </span>`:""}\n <button type="button" class="run-test-button" part="run-test-button" title="Run Test"${1==this.state.isDisabled?" disabled":""}>\n <slot name="run-button-content">\n <slot name="run-button-icon"><svg class="icon arrow-icon run-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-button-label"><span class="run-button-label button-label label icon">Run Test</span></slot>\n </slot>\n </button>\n </summary>\n <div class="results" part="results">\n ${null==this.state.beforeEachState?"":`<details class="before-each-details hook${"none"==this.state.beforeEachState.resultCategory?"":` ${this.state.beforeEachState.resultCategory}`}${1==this.state.beforeEachState.isRunning?" running":""}" part="before-each-details hook">\n <summary class="before-each-summary" part="before-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="before-each-result-icon result-icon${"none"!=this.state.beforeEachState.resultCategory?` ${this.state.beforeEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="before-each-description description hook-name">Before Each Hook</span>\n </summary>\n <div class="before-each-result result message" part="before-each-result result message">${"string"!=typeof this.state.beforeEachState.resultContent?"":this.state.beforeEachState.resultContent}</div>\n </details>`}\n ${null==this.state.testState?"":null==this.state.beforeEachState&&null==this.state.afterEachState?`<div class="test-result result message" part="test-result result message">${t}</div>`:`<details class="processing-details${"none"==this.state.testState.resultCategory?"":` ${this.state.testState.resultCategory}`}${1==this.state.testState.isRunning?" running":""}" part="processing-details"${1==this.state.testState.hasRun?" open":""}>\n <summary class="processing-summary" part="processing-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="processing-result-icon result-icon${"none"!=this.state.testState.resultCategory?` ${this.state.testState.resultCategory}`:""}" part="processing-result-icon result-icon"></div>\n <span class="processing-description description">Test</span>\n </summary>\n <div class="test-result result message" part="test-result result message">${t}</div>\n </details>`} \n ${null==this.state.afterEachState?"":`<details class="after-each-details hook${"none"==this.state.afterEachState.resultCategory?"":` ${this.state.afterEachState.resultCategory}`}${1==this.state.afterEachState.isRunning?" running":""}" part="after-each-detail hooks">\n <summary class="after-each-summary" part="after-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="after-each-result-icon result-icon${"none"!=this.state.afterEachState.resultCategory?` ${this.state.afterEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="after-each-description description hook-name">After Each Hook</span>\n </summary>\n <div class="after-each-result result message" part="after-each-result result message">${"string"!=typeof this.state.afterEachState.resultContent?"":this.state.afterEachState.resultContent}</div>\n </details>`}\n </div>\n </details>`,this.dataset.testId=this.state.testId,this.classList.add("test"),this.part.add("test"),this.toggleAttribute("success","success"==this.resultCategory()),this.classList.toggle("success","success"==this.resultCategory()),this.part.toggle("success","success"==this.resultCategory()),this.classList.toggle("fail","fail"==this.resultCategory()),this.part.toggle("fail","fail"==this.resultCategory()),this.classList.toggle("running",this.isRunning()),this.part.toggle("running",this.isRunning()),this.state.beforeEachState?.resultContent instanceof HTMLElement&&this.querySelector(".before-each-result").append(this.state.beforeEachState.resultContent),this.state.testState?.resultContent instanceof HTMLElement&&this.querySelector(".test-result").append(this.state.testState.resultContent),this.state.afterEachState?.resultContent instanceof HTMLElement&&this.querySelector(".after-each-result").append(this.state.afterEachState.resultContent)}enable(){this.state.isDisabled=!1,this.findElement(".run-test-button").toggleAttribute("disabled",!1)}disable(){this.state.isDisabled=!0,this.findElement(".run-test-button").toggleAttribute("disabled",!0)}async runTest(e,s){if(null==this.state.testState?.test)return;let n;this.reset();let a={},r=0;try{if(0==e.shouldContinueRunningTests)throw new Error("Tests have been disabled from continuing to run.");if(0==this.dispatchEvent(new CustomEvent(t.BeforeTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}})))throw new Error("Test has been prevented.");if(1==s.codeTestsElement.state.isCanceled)throw new Error("Testing has been canceled.");this.setTestStateProperties("testState",{isRunning:!0}),e.codeTestsElement.setState(e.codeTestsElement.state);const o=performance?.now()??Date.now();n=await this.state.testState.test(s);r=(performance?.now()??Date.now())-o,this.setTestStateProperties("testState",{isRunning:!1,hasRun:!0}),e.codeTestsElement.setState(e.codeTestsElement.state);const i=e.parseTestResult(n,!0);a={testState:{test:this.state.testState.test,resultContent:i.result,resultCategory:i.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:r}}}catch(t){const s=e.parseTestResult(n,!1,t);a={testState:{test:this.state.testState.test,resultContent:s.result,resultCategory:s.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:r}},console.error(t),e.shouldContinueRunningTests=!1}finally{this.setStateProperties({...a}),e.codeTestsElement.setState(e.codeTestsElement.state),this.dispatchEvent(new CustomEvent(t.AfterTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}}))}}reset(){const t=null!=this.state.testState?{resultCategory:"none",resultContent:"",test:this.state.testState.test,hasRun:this.state.testState.hasRun,isRunning:this.state.testState.isRunning,duration:0}:void 0;null!=t&&this.setTestStateProperties("testState",t)}getMessageElement(){return this.findElement(".test-result")}static observedAttributes=["open"];attributeChangedCallback(t,e,s){"open"==t&&this.findElement(".test-details").toggleAttribute("open",null!=s)}}null==customElements.get(e)&&customElements.define(e,s);const n=Symbol("No Test Defined");class a{codeTestsElement;constructor(t){this.codeTestsElement=t}async loadTests(t){if(null!=t)try{const{tests:e,hooks:s}=await this.#e(t),n=s[l.BeforeAll],a=s[l.AfterAll],r=s[l.BeforeEach],o=s[l.AfterEach],i=s[l.RequiredBeforeAny],c=s[l.RequiredAfterAny],u=null==n?void 0:{resultCategory:"none",resultContent:"",test:n,hasRun:!1,isRunning:!1,duration:0},d=null==a?void 0:{resultCategory:"none",resultContent:"",test:a,hasRun:!1,isRunning:!1,duration:0},h=null==r?void 0:{resultCategory:"none",resultContent:"",test:r,hasRun:!1,isRunning:!1,duration:0},f=null==o?void 0:{resultCategory:"none",resultContent:"",test:o,hasRun:!1,isRunning:!1,duration:0},p=null==i?void 0:{resultCategory:"none",resultContent:"",test:i,hasRun:!1,isRunning:!1,duration:0},g=null==c?void 0:{resultCategory:"none",resultContent:"",test:c,hasRun:!1,isRunning:!1,duration:0};this.codeTestsElement.state.beforeEachState=h,this.codeTestsElement.state.afterEachState=f;for(const[t,s]of Object.entries(e))this.#s(t,s);this.codeTestsElement.setStateProperties({beforeAllState:u,afterAllState:d,beforeEachState:h,afterEachState:f,requiredBeforeAnyState:p,requiredAfterAnyState:g,resetHook:s.reset,contextHook:s.context})}catch(t){console.error(t)}}async#e(t){const e=await this.#n(t),s=e.tests??e.default;if(null==s)throw new Error(`Unable to find tests definition in file at path: ${t}`);const n={},a=s[l.BeforeAll];null!=a&&(n[l.BeforeAll]=a,delete s[l.BeforeAll]);const r=s[l.AfterAll];null!=r&&(n[l.AfterAll]=r,delete s[l.AfterAll]);const o=s[l.BeforeEach];null!=o&&(n[l.BeforeEach]=o,delete s[l.BeforeEach]);const i=s[l.AfterEach];null!=i&&(n[l.AfterEach]=i,delete s[l.AfterEach]);const c=s[l.RequiredBeforeAny];null!=c&&(n[l.RequiredBeforeAny]=c,delete s[l.RequiredBeforeAny]);const u=s[l.RequiredAfterAny];null!=u&&(n[l.RequiredAfterAny]=u,delete s[l.RequiredAfterAny]);const d=s[l.Reset];null!=d&&(n[l.Reset]=d,delete s[l.Reset]);const h=s[l.Context];return null!=h&&(n[l.Context]=h,delete s[l.Context]),{tests:s,hooks:n}}async#n(t){const e=window.location.href.lastIndexOf("/"),s=1==(-1!=window.location.href.substring(e).indexOf("."))?window.location.href.substring(0,e+1):window.location.href,n=s+t.substring(0,t.lastIndexOf("/")+1),a=s+t;let r=await(await fetch(a)).text();r=r.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g,`'${n}$1'`);const o=new File([r],t.substring(t.lastIndexOf("/")),{type:"text/javascript"}),i=URL.createObjectURL(o);return await import(i)}#s(t,e){const n=function(){const t=new Uint8Array(20);crypto.getRandomValues(t);const e=[].slice.apply(t).map(function(t){return String.fromCharCode(t)}).join("");return btoa(e).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,"")}(),a=new s;return a.setStateProperties({testId:n,description:t,testState:{test:e,resultCategory:"none",resultContent:"",isRunning:!1,hasRun:!1,duration:0},beforeEachState:null==this.codeTestsElement.state.beforeEachState?void 0:{isRunning:this.codeTestsElement.state.beforeEachState.isRunning,hasRun:this.codeTestsElement.state.beforeEachState.hasRun,resultCategory:this.codeTestsElement.state.beforeEachState.resultCategory,resultContent:this.codeTestsElement.state.beforeEachState.resultContent,duration:0},afterEachState:null==this.codeTestsElement.state.afterEachState?void 0:{isRunning:this.codeTestsElement.state.afterEachState.isRunning,hasRun:this.codeTestsElement.state.afterEachState.hasRun,resultCategory:this.codeTestsElement.state.afterEachState.resultCategory,resultContent:this.codeTestsElement.state.afterEachState.resultContent,duration:0}}),this.codeTestsElement.findElement("#tests").append(a),n}shouldContinueRunningTests=!0;async runTests(e){if(0==this.codeTestsElement.dispatchEvent(new CustomEvent(t.BeforeAll,{bubbles:!0,composed:!0,cancelable:!0})))throw new Error("Tests have been prevented.");await this.codeTestsElement.reset();for(let t=0;t<e.length;t++)e[t].disable();const s=await this.createTestContext();if(await this.runHook("requiredBeforeAnyState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(e,s);if(await this.runHook("beforeAllState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(e,s);if(0==("false"!=this.codeTestsElement.getAttribute("ordered"))){const t=e.map(t=>this.runTest(t,!0,s));await Promise.all(t)}else for(let t=0;t<e.length;t++){const n=e[t];if(0==this.shouldContinueRunningTests)break;await this.runTest(n,!0,s)}0!=this.shouldContinueRunningTests?(await this.runHook("afterAllState",void 0,s),await this.#a(e,s)):await this.#a(e,s)}async#a(e,s){await this.runHook("requiredAfterAnyState",void 0,s);for(let t=0;t<e.length;t++)e[t].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(t.AfterAll,{bubbles:!0,composed:!0}))}async runTest(t,e,s){if(null!=t){if(0==e){const t=this.codeTestsElement.findElements("code-test");for(let e=0;e<t.length;e++)t[e].disable()}s=s??await this.createTestContext(t),0!=e||(await this.runHook("requiredBeforeAnyState",void 0,s),0!=this.shouldContinueRunningTests)?(await this.runHook("beforeEachState",t,s),0!=this.shouldContinueRunningTests?(await t.runTest(this,s),0!=this.shouldContinueRunningTests?(await this.runHook("afterEachState",t,s),await this.#r(s,e)):await this.#r(s,e)):await this.#r(s,e)):await this.#r(s,e)}}async#r(e,s){if(1==s)return;await this.runHook("requiredAfterAnyState",void 0,e);const n=this.codeTestsElement.findElements("code-test");for(let t=0;t<n.length;t++)n[t].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(t.TestEnd,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))}async runHook(e,s,a){const r=this.codeTestsElement.state[e];if(null==r)return n;if(1==this.codeTestsElement.state.isCanceled)return{success:!1,value:"Testing has been canceled."};let o;try{if(0==this.shouldContinueRunningTests&&("requiredAfterAnyState"!=e||"error"==this.codeTestsElement.getAttribute("required-after")))throw new Error("Tests have been disabled from continuing to run.");null!=s&&s.setTestStateProperties(e,{isRunning:!0}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!0}),o=await r.test(a),null!=s&&s.setTestStateProperties(e,{isRunning:!1,hasRun:!0}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!1,hasRun:!0});const t=this.parseTestResult(o,!0,void 0);null!=s&&s.setTestStateProperties(e,{resultCategory:t.resultCategory,resultContent:t.result}),this.codeTestsElement.setTestStateProperties(e,{resultCategory:t.resultCategory,resultContent:t.result})}catch(t){console.error(t),this.shouldContinueRunningTests=!1,o={success:!1,value:`Failed: ${t.message}`};const n=this.parseTestResult(o,!1,t);null!=s&&s.setTestStateProperties(e,{isRunning:!1,hasRun:!0,resultContent:n.result,resultCategory:n.resultCategory}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!1,hasRun:!0,resultCategory:n.resultCategory,resultContent:n.result})}finally{return this.codeTestsElement.dispatchEvent(new CustomEvent(t.AfterHook,{bubbles:!0,composed:!0,detail:o})),o}}parseTestResult(t,e,s){if(t==n)return{result:"",resultCategory:"none"};if(null==t){const t=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${t}" part="pre ${t}">${1==e?"Passed":"Failed"+(null!=s?`:\n${s.message}`:"")}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}if("boolean"==typeof t)return{result:t,resultCategory:1==t?"success":"fail"};if("function"==typeof t)return console.log("function"),{result:"[A function was returned]",resultCategory:"none"};if(t instanceof HTMLElement||"string"==typeof t)return{result:t,resultCategory:"none"};if("object"==typeof t){const s=t,n=1==e?"success-message":"error-message";if(null!=s.success&&null!=s.expected&&null!=s.value)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${1==s.success?"Passed":"Failed"}\nExpected:${s.expected}\nResult:${s.value}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};if(null!=s.success)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};{const s=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${s}" part="pre ${s}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}}throw new Error("Unable to parse result type: Unknown result type")}async createTestContext(e){const s={detail:{},codeTestsElement:this.codeTestsElement,testElement:e,messageElement:e?.findElement(".message")};return null!=this.codeTestsElement.state.contextHook&&await this.codeTestsElement.state.contextHook(s),this.codeTestsElement.dispatchEvent(new CustomEvent(t.Context,{bubbles:!0,composed:!0,detail:{context:s}})),s}}class r extends Promise{async toBeDefined(t){if(null==await(this))throw new Error(`${null!=t?t:"Value"} is undefined`)}async toBe(t,e=!1){const s=await(this);if(0==(1==e?s===t:s==t))throw new Error(` Value is not equal.\n Expected: ${t}\n Result: ${s}`)}async toContainText(t){const e=await(this);return e instanceof HTMLElement?{success:e.textContent.includes(t),index:e.textContent.indexOf(t)}:"string"==typeof e&&{success:e.includes(t),index:e.indexOf(t)}}async toHaveAttribute(t){const e=await(this);if(!(e instanceof HTMLElement))throw new Error("Unable to check for attribute on non-HTMLElement target");if(e.getAttribute(t))throw new Error("Target does not have attribute")}}const o=":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";function i(t){!function(t){const e=[...t.querySelectorAll(`${o}[id]`)];for(let t=0;t<e.length;t++)e[t].part.add(e[t].id)}(t),function(t){const e=[...t.querySelectorAll(`${o}[class]`)];for(let t=0;t<e.length;t++)e[t].part.add(...e[t].classList)}(t)}const l={BeforeAll:"beforeall",AfterAll:"afterall",BeforeEach:"beforeeach",AfterEach:"aftereach",RequiredBeforeAny:"requiredbeforeany",RequiredAfterAny:"requiredafterany",Reset:"reset",Context:"context"},c=new CSSStyleSheet;c.replaceSync(":host\n{\n --gap: 7px;\n --gap-small: 3px;\n --gap-medium: 14px;\n --gap-large: 24px;\n \n --surface-success: oklch(93.96% 0.05 148.74);\n --primary-success: oklch(58.83% 0.158 145.05);\n --border-success: solid 1px var(--primary-success);\n\n --surface-fail: oklch(88.98% 0.052 3.28);\n --primary-fail: oklch(45.8% 0.177 17.7);\n --border-fail: solid 1px var(--primary-fail);\n\n --surface-process: oklch(89.66% 0.046 260.67);\n --primary-process: oklch(43.48% 0.17 260.2);\n --border-process: solid 1px var(--primary-process);\n\n\n --surface-footer: rgb(0 0 0 / .04);\n \n --success-icon: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"%232e943a\" d=\"M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z\"/></svg>');\n --info-icon: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2022.812714%2022.814663%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20style%3D%22fill%3Atransparent%3Bstroke%3Atransparent%3Bstroke-width%3A0.999999%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dasharray%3Anone%3Bstroke-dashoffset%3A29.2913%3Bstroke-opacity%3A1%22%20d%3D%22M%2022.295505%2C11.407332%20A%2010.889144%2C10.889144%200%200%201%2011.406424%2C22.296479%2010.889144%2C10.889144%200%200%201%200.51720881%2C11.407332%2010.889144%2C10.889144%200%200%201%2011.406424%2C0.51818382%2010.889144%2C10.889144%200%200%201%2022.295505%2C11.407332%20Z%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22m%2013.945668%2C4.3053761%20c%200.150778%2C-0.96462%20-0.30687%2C-1.43709%20-1.36997%2C-1.43709%20-1.063%2C0%20-1.668452%2C0.47247%20-1.81923%2C1.43709%20-0.150779%2C0.96462%200.306971%2C1.43708%201.369971%2C1.43708%201.004%2C0%201.66845%2C-0.47246%201.819229%2C-1.43708%20z%20M%2011.693889%2C17.829726%2013.373994%2C7.0811161%20h%20-2.9333%20L%208.7605887%2C17.829726%20Z%22%20style%3D%22font-size%3A19.6861px%3Bfont-family%3APassageway%3B-inkscape-font-specification%3APassageway%3Bfill%3A%23a30d30%3Bstroke-width%3A2.5%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dashoffset%3A29.2913%22%20aria-label%3D%22i%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');\n\n\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n font-family: sans-serif;\n font-size: 12px;\n}\n@media (prefers-color-scheme: dark) \n{\n :host\n {\n --surface-footer: rgb(255 255 255 / .1);\n }\n}\n\n#header\n{\n flex: 1;\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\n#title\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n#tests\n,#component-content\n{\n display: grid;\n gap: var(--gap-small);\n grid-auto-rows: max-content;\n}\n\n#header button\n{\n align-self: stretch;\n display: inline-flex;\n align-items: center;\n gap: var(--gap-small);\n}\n\nbutton .reset-icon\n{\n width: 1em;\n height: 1em;\n transform: scaleX(-1);\n margin-inline: 3px;\n}\n\n/* Run button */\nbutton .arrow-icon\n{\n width: .75em;\n height: .75em;\n transform: rotate(-90deg);\n margin-inline: 3px;\n}\n:host(.running) .run-all-button-icon\n,:host(.fail) .run-all-button-icon\n{\n transform: rotate(0);\n}\n\n/* Dropdown Layout */\nsummary > .run-test-button\n, #run-all-button\n{\n justify-self: flex-end;\n margin-left: auto;\n}\n\nsummary:not(#component-summary)\n{\n padding: var(--gap-small);\n}\n#component-summary\n{\n padding: var(--gap) var(--gap-small);\n border-bottom: solid 1px;\n margin-bottom: var(--gap-small);\n}\n\n\n/* Dropdown Markers */\nsummary\n{\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\nsummary > .arrow-icon\n{\n background: var(--arrow-icon);\n transform: rotate(-90deg);\n transition: transform ease-out 90ms;\n width: .6em;\n height: .6em;\n}\ndetails[open] > summary > .arrow-icon\n{\n transform: rotate(0);\n}\n\n#enabled\n{\n display: none;\n}\n:host([optional]) #enabled\n{\n display: block;\n}\n\n/* Result Icon */\n.result-icon\n{\n --background-size: 16px;\n width: var(--background-size);\n height: var(--background-size);\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n border: solid 1px currentColor;\n border-radius: 50%;\n}\n.result-icon::before\n{\n content: '⋯';\n font-size: 10px;\n}\n\n:host(.running) #component-summary .result-icon\n,.test.running .test-summary > .result-icon\n,.hook.running .result-icon\n,.processing-details.running .processing-result-icon\n{\n border: var(--border-process);\n background: var(--surface-process);\n}\n:host(.success) #component-summary .result-icon\n,.test.success .test-summary > .result-icon\n,.hook.success .result-icon\n,.processing-details.success .processing-result-icon\n{\n border: var(--border-success);\n background: var(--surface-success)\n var(--success-icon);\n background-repeat: no-repeat;\n background-position: center;\n background-size: var(--icon-size, 12px) var(--icon-size, 12px);\n}\n:host(.fail) #component-summary .result-icon\n,.test.fail .test-summary > .result-icon\n,.hook.fail .result-icon\n,.processing-details.fail .processing-result-icon\n{\n border: var(--border-fail);\n background: var(--surface-fail)\n var(--info-icon);\n background-size: var(--icon-size, 16px) var(--icon-size, 16px);\n background-repeat: no-repeat;\n background-position: center;\n transform: rotate(175deg);\n}\n:host(:is(.success,.fail)) #component-summary .result-icon::before\n,.test:is(.success,.fail) .test-summary > .result-icon::before\n,.hook:is(.success,.fail) .result-icon::before\n,.processing-details:is(.success,.fail) .processing-result-icon::before\n{\n display: none;\n}\n:host(.running) #component-summary .result-icon::before\n,.test:is(.running) .test-summary > .result-icon::before\n,.hook:is(.running) .result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n content: '';\n --color: var(--primary-process, currentColor);\n --animation-timing-function: linear;\n --animation-duration: 2s;\n width: var(--icon-size, 14px);\n height: var(--icon-size, 14px);\n mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--icon-size, 14px) / 3), black calc(var(--icon-size, 14px) / 3));\n background-image: conic-gradient(transparent, transparent 135deg, var(--color));\n border-radius: 50%;\n animation: var(--animation-timing-function) var(--animation-duration) infinite spin;\n margin: 2px;\n}\n\n/* Smaller Result icon settings for sub-test icons */\n.before-each-result-icon\n,.after-each-result-icon\n,.processing-result-icon\n{\n --background-size: 12px;\n}\n.before-each-result-icon::before\n,.after-each-result-icon::before\n,.processing-result-icon::before\n{\n font-size: 9px;\n}\n.hook.success .before-each-result-icon\n,.hook.success .after-each-result-icon\n,.processing-details.success .processing-result-icon\n{\n --icon-size: 8px;\n}\n.hook.fail .before-each-result-icon\n,.hook.fail .after-each-result-icon\n,.processing-details.fail .processing-result-icon\n{\n --icon-size: 12px;\n}\n.hook:is(.running) .before-each-result-icon::before\n,.hook:is(.running) .after-each-result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n --icon-size: 9px;\n}\n\n/* Hook Display */\n.hook\n{\n display: none;\n}\n:host(.has-before-all-hook) #before-all-details\n,:host(.has-after-all-hook) #after-all-details\n{\n display: initial;\n}\n:host(.has-before-each-hook) .before-each-details\n,:host(.has-after-each-hook) .after-each-details\n{\n display: initial;\n}\n:host(.has-required-before-hook) #required-before-any-details\n,:host(.has-required-after-hook) #required-after-any-details\n{\n display: initial;\n}\n\n/* Test Display */\ncode-test .results\n{\n display: grid;\n gap: var(--gap-small);\n padding-inline-start: 1em;\n}\n\ncode-test .results details .result\n,.hook > .results\n{\n margin-inline-start: 1em;\n}\n\n.result.message:empty\n{\n padding: .5em 1em;\n}\n.result.message:empty::before\n{\n content: '[ this function has not been run ]';\n font-family: monospace;\n font-size: 12px;\n font-style: italic;\n}\n\n/* Ordered Display */\n#tests\n{\n counter-reset: tests;\n}\ncode-test\n{\n counter-increment: tests;\n}\ncode-test > details > summary > .description\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 0; /* hack to make overflow work right; \"contain: inline-size\" is correct fix, but it's too new to implement on jan 25, 2026; */\n}\n:host(:not([ordered=\"false\"])) code-test > details > summary > .description::before\n{\n content: counter(tests) \". \";\n}\n\n/* Hook Name */\n.hook-name,.processing-description\n{\n border-radius: 3px;\n border: solid 1px;\n font-family: monospace;\n text-transform: uppercase;\n font-size: 11px;\n padding: 3px 7px;\n}\n\n#footer\n{\n display: flex;\n justify-content: flex-end;\n border-top: solid 1px;\n border-bottom: solid 1px;\n background: var(--surface-footer);\n margin-top: var(--gap-small);\n}\n#group-results\n{\n display: flex;\n gap: var(--gap);\n padding: var(--gap);\n}\n\n#results-progress-value\n{\n min-width: 40px;\n width: auto;\n}\n\n#duration\n,#passed-total-pair\n,#passed-total-percent\n{\n white-space: nowrap;\n}\n\n#passed-total-percent::before\n{\n content: '(';\n}\n#passed-total-percent::after\n{\n content: ')';\n}\n\n@keyframes spin\n{\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}");const u="code-tests";class d extends HTMLElement{state={isCanceled:!1,beforeAllState:void 0,afterAllState:void 0,beforeEachState:void 0,afterEachState:void 0,requiredBeforeAnyState:void 0,requiredAfterAnyState:void 0,resetHook:void 0,contextHook:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.shadowRoot.querySelector(t)}findElements(t){return Array.from(this.shadowRoot.querySelectorAll(t))}getIsRunning(){return 1==(null!=this.findElements("code-test").find(t=>1==t.isRunning()))||1==this.state.requiredBeforeAnyState?.isRunning||1==this.state.requiredAfterAnyState?.isRunning||1==this.state.beforeAllState?.isRunning||1==this.state.afterAllState?.isRunning}getResultCategory(){const t=this.findElements("code-test").reduce((t,e,s)=>{const n=e.resultCategory();return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},""),e=[this.state.requiredBeforeAnyState,this.state.requiredAfterAnyState,this.state.beforeAllState,this.state.afterAllState].reduce((t,e,s)=>{if(null==e)return null;const n=e?.resultCategory;return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},"");return"none"==t&&null==e?"none":"fail"==t||"fail"==e?"fail":"success"==t||"success"==e?"success":"none"}#o;constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML='<details id="component-details" class="details">\n <summary id="component-summary" class="summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <slot name="header">\n <header id="header">\n <span id="component-result-icon" class="result-icon"></span>\n <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="reload-button">\n <button type="button" id="reload-button" title="Reload">\n <slot name="reload-button-content">\n <slot name="reload-button-icon"><svg class="icon reset-icon reload-button-icon"><use href="#icon-definition_reset"></use></svg></slot>\n <slot name="reload-button-label"><span class="reload-button-label button-label label icon">Reload</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="run-all-button">\n <button type="button" id="run-all-button" title="Run All Tests">\n <slot name="run-all-button-content">\n <slot name="run-all-button-icon"><svg class="icon arrow-icon run-button-icon run-all-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-all-button-label"><span class="run-all-button-label run-button-label button-label label icon">Run Tests</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="header-details"></slot>\n </header>\n </slot>\n </summary>\n <div id="component-content" class="content">\n <details id="required-before-any-details" class="hook">\n <summary id="required-before-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-before-any-result-icon" class="result-icon"></span>\n <span id="required-before-any-description" class="description hook-name">Required Before Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-before-any-results" class="result message"></div>\n </div>\n </details>\n <details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description hook-name">Before All Hook</span>\n </summary>\n <div class="results">\n <div id="before-all-results" class="result message"></div>\n </div>\n </details>\n <div id="tests"></div>\n <details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description hook-name">After All Hook</span>\n </summary>\n <div class="results">\n <div id="after-all-results" class="result message"></div>\n </div>\n </details>\n <details id="required-after-any-details" class="hook">\n <summary id="required-after-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-after-any-result-icon" class="result-icon"></span>\n <span id="required-after-any-description" class="description hook-name">Required After Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-after-any-results" class="result message"></div>\n </div>\n </details>\n </div>\n \n <slot name="footer">\n <foooter id="footer">\n <span id="group-results">\n <span id="duration">\n <span id="duration-label">Duration</span>\n <span id="duration-value">0</span>\n <span id="duration-unit">ms</span>\n </span>\n <span id="results-progress">\n <progress id="results-progress-value"></progress>\n </span>\n <span id="passed-total-pair">\n <span id="total-tests-passed-value"></span>\n <span id="passed-total-delimiter">of</span>\n <span id="total-tests-count-value"></span>\n <span id="total-tests-passed-label">Passed</span>\n </span>\n <span id="passed-total-percent">\n <span id="passed-total-percent-value">0</span>\n <span id="passed-total-percent-label">%</span>\n </span>\n </span>\n </foooter>\n </slot>\n</details>\n<template id="prompt-template">\n <div class="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>\n<div id="icon-definitions" style="display: none;">\n <svg id="icon-definition_arrow" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path d="m3.26,6.81l-2.93,-4.69c-0.37,-0.58 0.05,-1.34 0.74,-1.34l5.87,0c0.69,0 1.11,0.76 0.74,1.34l-2.93,4.69c-0.35,0.55 -1.14,0.55 -1.49,0z" fill="var(--fill-color, currentcolor)" />\n </svg>\n <svg id="icon-definition_reset" class="icon reset" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M 5.484375 0.43359375 A 1.5224222 1.5224222 0 0 0 4.2558594 1.2011719 L 0.99804688 6.9453125 A 1.5224222 1.5224222 0 0 0 2.5488281 9.2011719 L 9.34375 8.171875 A 1.5224222 1.5224222 0 0 0 10.332031 5.7539062 L 9.4746094 4.6113281 C 11.949333 3.8016718 14.718209 4.258351 16.822266 5.9570312 C 19.510764 8.1275534 20.456787 11.785479 19.160156 14.988281 C 17.863527 18.191083 14.6405 20.15873 11.199219 19.847656 C 7.7579362 19.536584 4.9376009 17.022073 4.2363281 13.638672 A 1.5 1.5 0 0 0 2.4628906 12.474609 A 1.5 1.5 0 0 0 1.2988281 14.248047 C 2.2656928 18.912838 6.1831413 22.407052 10.927734 22.835938 C 15.672328 23.264824 20.153706 20.531029 21.941406 16.115234 C 23.729107 11.699441 22.413741 6.6156073 18.707031 3.6230469 C 16.853677 2.1267667 14.61485 1.3255701 12.347656 1.2324219 C 10.738216 1.1662975 9.1150542 1.4598646 7.6035156 2.1132812 L 6.7988281 1.0390625 A 1.5224222 1.5224222 0 0 0 5.484375 0.43359375 z " />\n </svg>\n <svg id="icon-definition_cancel" class="icon cancel" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M -7.063234 9.5244002 C -5.8135728 7.6769245 -5.0820528 5.453265 -5.0820528 3.0633809 C -5.0820529 -3.3096433 -10.278145 -8.5098163 -16.65117 -8.5098163 C -23.024193 -8.5098163 -28.22385 -3.3110105 -28.22385 3.0620137 C -28.22385 9.4350379 -23.025043 14.634694 -16.65202 14.634694 C -12.668879 14.634694 -9.1460028 12.603526 -7.063234 9.5244002 z M -9.5406311 7.8637601 C -11.076991 10.143147 -13.683157 11.63463 -16.652974 11.63463 C -19.960499 11.63463 -22.814085 9.782061 -24.244824 7.0543029 L -24.236684 7.0527515 L -8.1332524 3.983715 L -8.1305391 3.9831979 C -8.2815631 5.4121635 -8.7798709 6.7350751 -9.5406311 7.8637601 z M -9.0610781 -0.92890828 L -9.069218 -0.92735695 L -25.17265 2.1416796 L -25.175363 2.1421967 C -24.719122 -2.1725739 -21.093311 -5.5092358 -16.652928 -5.5092358 C -13.345403 -5.5092358 -10.491243 -3.6566663 -9.0610781 -0.92890828 z "\n transform="rotate(-124.20981)" />\n </svg>\n</div>',this.shadowRoot.adoptedStyleSheets.push(c)}connectedCallback(){this.#i()}disconnectedCallback(){this.#l()}#c=!1;#u=!1;async#i(){1!=this.#c&&1!=this.#u&&(this.#c=!0,i(this.shadowRoot),this.addEventListener("click",this.#d),this.findElement("#enabled").addEventListener("change",this.#h),await new Promise(e=>requestAnimationFrame(()=>{this.#o=new a(this),this.#u=!0,this.#c=!1;if(0==this.dispatchEvent(new CustomEvent(t.Init,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}})))return void e();"false"!=this.getAttribute("auto")?(this.reloadTests(),e()):e()})))}#l(){this.removeEventListener("click",this.#d),this.findElement("#enabled").removeEventListener("change",this.#h),this.#u=!1,this.#c=!1}#d=this.#f.bind(this);#f(t){if(null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"run-all-button"==t.id))return void(this.classList.contains("running")?this.cancel():this.classList.contains("fail")||this.classList.contains("success")?this.reset():this.runTests());null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"reload-button"==t.id)&&this.reloadTests();const e=t.composedPath().find(t=>t instanceof HTMLButtonElement&&t.classList.contains("run-test-button"));if(null==e)return;const s=e.closest("code-test")??void 0;this.#o.runTest(s,!1)}#h=this.#p.bind(this);#p(e){const s=e.target;0==this.dispatchEvent(new CustomEvent(t.Enabled,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))&&(e.preventDefault(),e.stopPropagation(),s.checked=!s.checked)}#g(){return this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path")??void 0}#t(){const t=this.getIsRunning(),e=this.getResultCategory(),s=null!=this.state.beforeAllState,n=null!=this.state.beforeEachState,a=null!=this.state.requiredAfterAnyState,r=null!=this.state.beforeAllState,o=null!=this.state.beforeEachState,i=null!=this.state.requiredAfterAnyState,l=1==a||1==s||1==n,c=1==i||1==r||1==o;this.classList.toggle("canceled",this.state.isCanceled),this.part.toggle("canceled",this.state.isCanceled),this.classList.toggle("running",1==t),this.part.toggle("running",1==t),this.toggleAttribute("success","success"==e),this.classList.toggle("success","success"==e),this.part.toggle("success","success"==e),this.classList.toggle("fail","fail"==e),this.part.toggle("fail","fail"==e),this.classList.toggle("has-before-hook",l),this.part.toggle("has-before-hook",l),this.classList.toggle("has-after-hook",c),this.part.toggle("has-after-hook",c),this.classList.toggle("has-before-all-hook",s),this.part.toggle("has-before-all-hook",s),this.classList.toggle("has-after-all-hook",r),this.part.toggle("has-after-all-hook",r),this.classList.toggle("has-before-each-hook",n),this.part.toggle("has-before-each-hook",n),this.classList.toggle("has-after-each-hook",o),this.part.toggle("has-after-each-hook",o),this.classList.toggle("has-required-before-hook",a),this.part.toggle("has-required-before-hook",a),this.classList.toggle("has-required-after-hook",i),this.part.toggle("has-required-after-hook",i);const u=this.findElement(".run-all-button-label");null!=u&&(u.textContent=1==t?"Cancel":"fail"==e||"success"==e?"Reset":"Run Tests",u.title=1==t?"Cancel the testing":"fail"==e||"success"==e?"Reset the tests so they can be run again":"Run the tests");const d=this.findElement(".run-all-button-icon");null!=d&&(d.innerHTML=1==t?'<use href="#icon-definition_cancel"></use>':"fail"==e||"success"==e?'<use href="#icon-definition_reset"></use>':'<use href="#icon-definition_arrow"></use>'),this.#m(this.state.beforeAllState,"#before-all-results"),this.#m(this.state.afterAllState,"#after-all-results"),this.#m(this.state.requiredBeforeAnyState,"#required-before-any-results"),this.#m(this.state.requiredAfterAnyState,"#required-after-any-results");const h=this.findElement("#title");null!=h&&(h.textContent=this.getAttribute("label")??"Tests"),this.#b()}#m(t,e){const s=this.findElement(e);t?.resultContent instanceof HTMLElement?s.append(t.resultContent):"string"==typeof t?.resultContent&&(s.innerHTML=t.resultContent);const n=s.closest("details");n.toggleAttribute("open",null!=t&&"none"!=t.resultCategory),n.classList.toggle("running",1==t?.isRunning),n.part.toggle("running",1==t?.isRunning),n.toggleAttribute("success","success"==t?.resultCategory),n.classList.toggle("success","success"==t?.resultCategory),n.part.toggle("success","success"==t?.resultCategory),n.classList.toggle("fail","fail"==t?.resultCategory),n.part.toggle("fail","fail"==t?.resultCategory)}#b(){const t=this.collectTestResults(),e=this.findElement("#results-progress-value");null!=e&&(e.max=t.totalTests,e.value=t.totalPassed);const s=this.findElement("#total-tests-passed-value");null!=s&&(s.textContent=t.totalPassed.toString());const n=this.findElement("#total-tests-count-value");null!=n&&(n.textContent=t.totalTests.toString());const a=this.findElement("#passed-total-percent-value");null!=a&&(a.textContent=t.totalPercentage.toFixed(1));const r=this.findElement("#duration-value");null!=r&&(r.textContent=t.duration>10?t.duration.toFixed(0):t.duration.toFixed(2))}collectTestResults(){const t=this.findElements("code-test"),e=t.length,s=t.filter(t=>"success"==t.state.testState?.resultCategory).length;return{totalTests:e,totalPassed:s,totalPercentage:0==e?0:s/e*100,duration:t.reduce((t,e,s)=>t+(e.state.testState?.duration??0),0)}}async runTests(){const t=this.findElements("code-test");return this.#o.runTests(t)}async reloadTests(){this.findElement("#tests").innerHTML="",await this.reset();const t=this.#g();this.#o.loadTests(t)}async reset(){const e=this.findElements("code-test");for(let t=0;t<e.length;t++){const s=e[t],n=null!=this.state.beforeEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.beforeEachState.hasRun,isRunning:this.state.beforeEachState.isRunning,duration:0}:void 0,a=null!=this.state.afterEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.afterEachState.hasRun,isRunning:this.state.afterEachState.isRunning,duration:0}:void 0;null!=n&&(s.state.beforeEachState=n),null!=a&&(s.state.afterEachState=a),s.reset()}const s=null==this.state.beforeAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeAllState.test,isRunning:!1,hasRun:!1,duration:0},n=null==this.state.afterAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterAllState.test,isRunning:!1,hasRun:!1,duration:0},a=null==this.state.beforeEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeEachState.test,isRunning:!1,hasRun:!1,duration:0},r=null==this.state.afterEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterEachState.test,isRunning:!1,hasRun:!1,duration:0},o=null==this.state.requiredBeforeAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredBeforeAnyState.test,isRunning:!1,hasRun:!1,duration:0},i=null==this.state.requiredAfterAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredAfterAnyState.test,isRunning:!1,hasRun:!1,duration:0};this.setStateProperties({isCanceled:!1,beforeAllState:s,afterAllState:n,beforeEachState:a,afterEachState:r,requiredAfterAnyState:i,requiredBeforeAnyState:o}),this.#o.shouldContinueRunningTests=!0,null!=this.state.resetHook&&await this.state.resetHook(await this.#o.createTestContext()),this.dispatchEvent(new CustomEvent(t.Reset,{bubbles:!0,composed:!0}))}cancel(){this.state.isCanceled=!0,this.#o.shouldContinueRunningTests=!1,this.classList.add("canceled"),this.part.add("canceled"),this.dispatchEvent(new CustomEvent(t.Cancel,{bubbles:!0,composed:!0}))}static observedAttributes=["open","label"];attributeChangedCallback(t,e,s){if("open"==t)this.findElement("#component-details").toggleAttribute("open",null!=s);else if("label"==t){const t=this.findElement("#title");null!=t&&(t.textContent=s??"Tests")}}}function h(t){return new r(async(e,s)=>{if(t instanceof Promise){return void e(await t)}e(t)})}async function f(t,e,s,n){return new Promise((a,r)=>{const o=p(n?.template??t.querySelector(".prompt-template")??t.findElement("#prompt-template"));o.querySelector(".label").textContent=s;const i=t=>{const e=t.composedPath();if(null!=e.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("accept"))){const t=n?.onAccept?.()??!0;return o.removeEventListener("click",i),void a(t)}if(null!=e.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("reject"))){const t=n?.onReject?.()??!1;return o.removeEventListener("click",i),void a(t)}};o.addEventListener("click",i),null!=n?.acceptLabel&&(o.querySelector(".accept").textContent=n.acceptLabel),null!=n?.rejectLabel&&(o.querySelector(".reject").textContent=n.rejectLabel),e.append(o)})}function p(t,e){const s=t instanceof HTMLTemplateElement?t:document.querySelector(t);if(null==s)throw new Error(`Unable to find template element from selector: ${t}`);const n=s.content.cloneNode(!0).firstElementChild;if(null==n)throw new Error("Unable to find first child of template element");return e?.append(n),n}null==customElements.get(u)&&customElements.define(u,d);export{s as CodeTestElement,t as CodeTestEvent,d as CodeTestsElement,l as Hook,r as TestPromise,p as createElementFromTemplate,h as expect,f as prompt};
1
+ const t={BeforeAll:"beforeall",AfterAll:"afterall",BeforeTest:"beforetest",AfterTest:"aftertest",BeforeHook:"beforehook",AfterHook:"afterhook",Cancel:"cancel",Context:"context",Reset:"reset",TestEnd:"testend",Init:"init",Enabled:"enabled",PromptResult:"promptresult"},e="code-test";class s extends HTMLElement{state={testId:"",description:"none",isDisabled:!1,testState:void 0,beforeEachState:void 0,afterEachState:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.querySelector(t)}findElements(t){return Array.from(this.querySelectorAll(t))}isRunning(){return 1==this.state.testState?.isRunning||1==this.state.beforeEachState?.isRunning||1==this.state.afterEachState?.isRunning}hasRun(){return 1==this.state.testState?.hasRun||1==this.state.beforeEachState?.hasRun||1==this.state.afterEachState?.hasRun}resultCategory(){const t=this.state.testState?.resultCategory??"none",e=this.state.beforeEachState?.resultCategory??"none",s=this.state.afterEachState?.resultCategory??"none";return"none"==t&&"none"==e&&"none"==s?"none":null==this.state.beforeEachState&&null==this.state.afterEachState?t:null!=this.state.beforeEachState&&null==this.state.afterEachState?"fail"==t||"fail"==e?"fail":"success"==t&&"success"==e?"success":"none":null==this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==s?"fail":"success"==t&&"success"==s?"success":"none":null!=this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==e||"fail"==s?"fail":"success"==t&&"success"==e&&"success"==s?"success":"none":void 0}connectedCallback(){this.#t()}#t(){const t=null==this.state.testState?"":"boolean"==typeof this.state.testState.resultContent?1==this.state.testState.resultContent?'<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed</pre></code>':'<code class="code" part="code"><pre class="pre error-message" part="pre error-message">Failed</pre></code>':"number"==typeof this.state.testState.resultContent?`<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed: ${this.state.testState.resultContent.toString()}</pre></code>`:"string"==typeof this.state.testState.resultContent?this.state.testState.resultContent:"";this.innerHTML=`<details class="test-details" part="test-details" ${1==this.isRunning()||1==this.hasRun()?" open":""}>\n <summary class="test-summary" part="test-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="result-icon test-result-icon${"none"!=this.state.testState?.resultCategory?` ${this.state.testState?.resultCategory}`:""}" part="result-icon"></div>\n <span class="test-description description" title="${this.state.description}">${this.state.description}</span>\n ${null!=this.state.testState?.duration&&this.state.testState.duration>0?`<span class="test-duration duration">\n <span class="test-duration-value">${this.state.testState.duration>10?this.state.testState.duration.toFixed(0):this.state.testState.duration.toFixed(2)}</span>\n <span class="test-duration-unit">ms</span>\n </span>`:""}\n <button type="button" class="run-test-button" part="run-test-button" title="Run Test"${1==this.state.isDisabled?" disabled":""}>\n <slot name="run-button-content">\n <slot name="run-button-icon"><svg class="icon arrow-icon run-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-button-label"><span class="run-button-label button-label label icon">Run Test</span></slot>\n </slot>\n </button>\n </summary>\n <div class="results" part="results">\n ${null==this.state.beforeEachState?"":`<details class="before-each-details hook${"none"==this.state.beforeEachState.resultCategory?"":` ${this.state.beforeEachState.resultCategory}`}${1==this.state.beforeEachState.isRunning?" running":""}" part="before-each-details hook">\n <summary class="before-each-summary" part="before-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="before-each-result-icon result-icon${"none"!=this.state.beforeEachState.resultCategory?` ${this.state.beforeEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="before-each-description description hook-name">Before Each Hook</span>\n </summary>\n <div class="before-each-result result message" part="before-each-result result message">${"string"!=typeof this.state.beforeEachState.resultContent?"":this.state.beforeEachState.resultContent}</div>\n </details>`}\n ${null==this.state.testState?"":null==this.state.beforeEachState&&null==this.state.afterEachState?`<div class="test-result result message" part="test-result result message">${t}</div>`:`<details class="processing-details${"none"==this.state.testState.resultCategory?"":` ${this.state.testState.resultCategory}`}${1==this.state.testState.isRunning?" running":""}" part="processing-details"${1==this.state.testState.hasRun?" open":""}>\n <summary class="processing-summary" part="processing-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="processing-result-icon result-icon${"none"!=this.state.testState.resultCategory?` ${this.state.testState.resultCategory}`:""}" part="processing-result-icon result-icon"></div>\n <span class="processing-description description">Test</span>\n </summary>\n <div class="test-result result message" part="test-result result message">${t}</div>\n </details>`} \n ${null==this.state.afterEachState?"":`<details class="after-each-details hook${"none"==this.state.afterEachState.resultCategory?"":` ${this.state.afterEachState.resultCategory}`}${1==this.state.afterEachState.isRunning?" running":""}" part="after-each-detail hooks">\n <summary class="after-each-summary" part="after-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="after-each-result-icon result-icon${"none"!=this.state.afterEachState.resultCategory?` ${this.state.afterEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="after-each-description description hook-name">After Each Hook</span>\n </summary>\n <div class="after-each-result result message" part="after-each-result result message">${"string"!=typeof this.state.afterEachState.resultContent?"":this.state.afterEachState.resultContent}</div>\n </details>`}\n </div>\n </details>`,this.dataset.testId=this.state.testId,this.classList.add("test"),this.part.add("test"),this.toggleAttribute("success","success"==this.resultCategory()),this.classList.toggle("success","success"==this.resultCategory()),this.part.toggle("success","success"==this.resultCategory()),this.classList.toggle("fail","fail"==this.resultCategory()),this.part.toggle("fail","fail"==this.resultCategory()),this.classList.toggle("running",this.isRunning()),this.part.toggle("running",this.isRunning()),this.state.beforeEachState?.resultContent instanceof HTMLElement&&this.querySelector(".before-each-result").append(this.state.beforeEachState.resultContent),this.state.testState?.resultContent instanceof HTMLElement&&this.querySelector(".test-result").append(this.state.testState.resultContent),this.state.afterEachState?.resultContent instanceof HTMLElement&&this.querySelector(".after-each-result").append(this.state.afterEachState.resultContent)}enable(){this.state.isDisabled=!1,this.findElement(".run-test-button").toggleAttribute("disabled",!1)}disable(){this.state.isDisabled=!0,this.findElement(".run-test-button").toggleAttribute("disabled",!0)}async runTest(e,s){if(null==this.state.testState?.test)return;let n;this.reset();let a={},o=0;try{if(0==e.shouldContinueRunningTests)throw new Error("Tests have been disabled from continuing to run.");if(0==this.dispatchEvent(new CustomEvent(t.BeforeTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}})))throw new Error("Test has been prevented.");if(1==s.codeTestsElement.state.isCanceled)throw new Error("Testing has been canceled.");this.setTestStateProperties("testState",{isRunning:!0}),e.codeTestsElement.setState(e.codeTestsElement.state);const r=performance?.now()??Date.now();n=await this.state.testState.test(s);o=(performance?.now()??Date.now())-r,this.setTestStateProperties("testState",{isRunning:!1,hasRun:!0}),e.codeTestsElement.setState(e.codeTestsElement.state);const i=e.parseTestResult(n,!0);a={testState:{test:this.state.testState.test,resultContent:i.result,resultCategory:i.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:o}}}catch(t){const s=e.parseTestResult(n,!1,t);a={testState:{test:this.state.testState.test,resultContent:s.result,resultCategory:s.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:o}},console.error(t),e.shouldContinueRunningTests=!1}finally{this.setStateProperties({...a}),e.codeTestsElement.setState(e.codeTestsElement.state),this.dispatchEvent(new CustomEvent(t.AfterTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}}))}}reset(){const t=null!=this.state.testState?{resultCategory:"none",resultContent:"",test:this.state.testState.test,hasRun:this.state.testState.hasRun,isRunning:this.state.testState.isRunning,duration:0}:void 0;null!=t&&this.setTestStateProperties("testState",t)}getMessageElement(){return this.findElement(".test-result")}static observedAttributes=["open"];attributeChangedCallback(t,e,s){"open"==t&&this.findElement(".test-details").toggleAttribute("open",null!=s)}}null==customElements.get(e)&&customElements.define(e,s);const n=Symbol("No Test Defined");class a{codeTestsElement;constructor(t){this.codeTestsElement=t}async loadTests(t){if(null!=t)try{const{tests:e,hooks:s}=await this.#e(t),n=s[l.BeforeAll],a=s[l.AfterAll],o=s[l.BeforeEach],r=s[l.AfterEach],i=s[l.RequiredBeforeAny],c=s[l.RequiredAfterAny],u=null==n?void 0:{resultCategory:"none",resultContent:"",test:n,hasRun:!1,isRunning:!1,duration:0},d=null==a?void 0:{resultCategory:"none",resultContent:"",test:a,hasRun:!1,isRunning:!1,duration:0},h=null==o?void 0:{resultCategory:"none",resultContent:"",test:o,hasRun:!1,isRunning:!1,duration:0},f=null==r?void 0:{resultCategory:"none",resultContent:"",test:r,hasRun:!1,isRunning:!1,duration:0},p=null==i?void 0:{resultCategory:"none",resultContent:"",test:i,hasRun:!1,isRunning:!1,duration:0},g=null==c?void 0:{resultCategory:"none",resultContent:"",test:c,hasRun:!1,isRunning:!1,duration:0};this.codeTestsElement.state.beforeEachState=h,this.codeTestsElement.state.afterEachState=f;for(const[t,s]of Object.entries(e))this.#s(t,s);this.codeTestsElement.setStateProperties({beforeAllState:u,afterAllState:d,beforeEachState:h,afterEachState:f,requiredBeforeAnyState:p,requiredAfterAnyState:g,resetHook:s.reset,contextHook:s.context})}catch(t){console.error(t)}}async#e(t){const e=await this.#n(t),s=e.tests??e.default;if(null==s)throw new Error(`Unable to find tests definition in file at path: ${t}`);const n={},a=s[l.BeforeAll];null!=a&&(n[l.BeforeAll]=a,delete s[l.BeforeAll]);const o=s[l.AfterAll];null!=o&&(n[l.AfterAll]=o,delete s[l.AfterAll]);const r=s[l.BeforeEach];null!=r&&(n[l.BeforeEach]=r,delete s[l.BeforeEach]);const i=s[l.AfterEach];null!=i&&(n[l.AfterEach]=i,delete s[l.AfterEach]);const c=s[l.RequiredBeforeAny];null!=c&&(n[l.RequiredBeforeAny]=c,delete s[l.RequiredBeforeAny]);const u=s[l.RequiredAfterAny];null!=u&&(n[l.RequiredAfterAny]=u,delete s[l.RequiredAfterAny]);const d=s[l.Reset];null!=d&&(n[l.Reset]=d,delete s[l.Reset]);const h=s[l.Context];return null!=h&&(n[l.Context]=h,delete s[l.Context]),{tests:s,hooks:n}}async#n(t){const e=window.location.href.lastIndexOf("/"),s=1==(-1!=window.location.href.substring(e).indexOf("."))?window.location.href.substring(0,e+1):window.location.href,n=s+t.substring(0,t.lastIndexOf("/")+1),a=s+t;let o=await(await fetch(a)).text();o=o.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g,`'${n}$1'`);const r=new File([o],t.substring(t.lastIndexOf("/")),{type:"text/javascript"}),i=URL.createObjectURL(r);return await import(i)}#s(t,e){const n=function(){const t=new Uint8Array(20);crypto.getRandomValues(t);const e=[].slice.apply(t).map(function(t){return String.fromCharCode(t)}).join("");return btoa(e).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,"")}(),a=new s;return a.setStateProperties({testId:n,description:t,testState:{test:e,resultCategory:"none",resultContent:"",isRunning:!1,hasRun:!1,duration:0},beforeEachState:null==this.codeTestsElement.state.beforeEachState?void 0:{isRunning:this.codeTestsElement.state.beforeEachState.isRunning,hasRun:this.codeTestsElement.state.beforeEachState.hasRun,resultCategory:this.codeTestsElement.state.beforeEachState.resultCategory,resultContent:this.codeTestsElement.state.beforeEachState.resultContent,duration:0},afterEachState:null==this.codeTestsElement.state.afterEachState?void 0:{isRunning:this.codeTestsElement.state.afterEachState.isRunning,hasRun:this.codeTestsElement.state.afterEachState.hasRun,resultCategory:this.codeTestsElement.state.afterEachState.resultCategory,resultContent:this.codeTestsElement.state.afterEachState.resultContent,duration:0}}),this.codeTestsElement.findElement("#tests").append(a),n}shouldContinueRunningTests=!0;async runTests(e){if(0==this.codeTestsElement.dispatchEvent(new CustomEvent(t.BeforeAll,{bubbles:!0,composed:!0,cancelable:!0})))throw new Error("Tests have been prevented.");await this.codeTestsElement.reset();for(let t=0;t<e.length;t++)e[t].disable();const s=await this.createTestContext();if(await this.runHook("requiredBeforeAnyState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(e,s);if(await this.runHook("beforeAllState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(e,s);if(0==("false"!=this.codeTestsElement.getAttribute("ordered"))){const t=e.map(t=>this.runTest(t,!0,s));await Promise.all(t)}else for(let t=0;t<e.length;t++){const n=e[t];if(0==this.shouldContinueRunningTests)break;await this.runTest(n,!0,s)}0!=this.shouldContinueRunningTests?(await this.runHook("afterAllState",void 0,s),await this.#a(e,s)):await this.#a(e,s)}async#a(e,s){await this.runHook("requiredAfterAnyState",void 0,s);for(let t=0;t<e.length;t++)e[t].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(t.AfterAll,{bubbles:!0,composed:!0}))}async runTest(t,e,s){if(null!=t){if(0==e){const t=this.codeTestsElement.findElements("code-test");for(let e=0;e<t.length;e++)t[e].disable()}null==(s=s??await this.createTestContext(t)).testElement&&(s.testElement=t),0!=e||(await this.runHook("requiredBeforeAnyState",void 0,s),0!=this.shouldContinueRunningTests)?(await this.runHook("beforeEachState",t,s),0!=this.shouldContinueRunningTests?(await t.runTest(this,s),0!=this.shouldContinueRunningTests?(await this.runHook("afterEachState",t,s),await this.#o(s,e)):await this.#o(s,e)):await this.#o(s,e)):await this.#o(s,e)}}async#o(e,s){if(1==s)return;await this.runHook("requiredAfterAnyState",void 0,e);const n=this.codeTestsElement.findElements("code-test");for(let t=0;t<n.length;t++)n[t].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(t.TestEnd,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))}async runHook(e,s,a){const o=this.codeTestsElement.state[e];if(null==o)return n;if(1==this.codeTestsElement.state.isCanceled)return{success:!1,value:"Testing has been canceled."};let r;try{if(0==this.shouldContinueRunningTests&&("requiredAfterAnyState"!=e||"error"==this.codeTestsElement.getAttribute("required-after")))throw new Error("Tests have been disabled from continuing to run.");null!=s&&s.setTestStateProperties(e,{isRunning:!0}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!0}),r=await o.test(a),null!=s&&s.setTestStateProperties(e,{isRunning:!1,hasRun:!0}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!1,hasRun:!0});const t=this.parseTestResult(r,!0,void 0);null!=s&&s.setTestStateProperties(e,{resultCategory:t.resultCategory,resultContent:t.result}),this.codeTestsElement.setTestStateProperties(e,{resultCategory:t.resultCategory,resultContent:t.result})}catch(t){console.error(t),this.shouldContinueRunningTests=!1,r={success:!1,value:`Failed: ${t.message}`};const n=this.parseTestResult(r,!1,t);null!=s&&s.setTestStateProperties(e,{isRunning:!1,hasRun:!0,resultContent:n.result,resultCategory:n.resultCategory}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!1,hasRun:!0,resultCategory:n.resultCategory,resultContent:n.result})}finally{return this.codeTestsElement.dispatchEvent(new CustomEvent(t.AfterHook,{bubbles:!0,composed:!0,detail:r})),r}}parseTestResult(t,e,s){if(t==n)return{result:"",resultCategory:"none"};if(null==t){const t=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${t}" part="pre ${t}">${1==e?"Passed":"Failed"+(null!=s?`:\n${s.message}`:"")}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}if("boolean"==typeof t)return{result:t,resultCategory:1==t?"success":"fail"};if("function"==typeof t)return console.log("function"),{result:"[A function was returned]",resultCategory:"none"};if(t instanceof HTMLElement||"string"==typeof t)return{result:t,resultCategory:"none"};if("object"==typeof t){const s=t,n=1==e?"success-message":"error-message";if(null!=s.success&&null!=s.expected&&null!=s.value)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${1==s.success?"Passed":"Failed"}\nExpected:${s.expected}\nResult:${s.value}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};if(null!=s.success)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};{const s=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${s}" part="pre ${s}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}}throw new Error("Unable to parse result type: Unknown result type")}async createTestContext(e){const s={detail:{},codeTestsElement:this.codeTestsElement,testElement:e,messageElement:e?.findElement(".message")};return null!=this.codeTestsElement.state.contextHook&&await this.codeTestsElement.state.contextHook(s),this.codeTestsElement.dispatchEvent(new CustomEvent(t.Context,{bubbles:!0,composed:!0,detail:{context:s}})),s}}class o extends Promise{async toBeDefined(t){if(null==await(this))throw new Error(`${null!=t?t:"Value"} is undefined`)}async toBe(t,e=!1){const s=await(this);if(0==(1==e?s===t:s==t))throw new Error(` Value is not equal.\n Expected: ${t}\n Result: ${s}`)}async toContainText(t){const e=await(this);return e instanceof HTMLElement?{success:e.textContent.includes(t),index:e.textContent.indexOf(t)}:"string"==typeof e&&{success:e.includes(t),index:e.indexOf(t)}}async toHaveAttribute(t){const e=await(this);if(!(e instanceof HTMLElement))throw new Error("Unable to check for attribute on non-HTMLElement target");if(e.getAttribute(t))throw new Error("Target does not have attribute")}}const r=":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";function i(t){!function(t){const e=[...t.querySelectorAll(`${r}[id]`)];for(let t=0;t<e.length;t++)e[t].part.add(e[t].id)}(t),function(t){const e=[...t.querySelectorAll(`${r}[class]`)];for(let t=0;t<e.length;t++)e[t].part.add(...e[t].classList)}(t)}const l={BeforeAll:"beforeall",AfterAll:"afterall",BeforeEach:"beforeeach",AfterEach:"aftereach",RequiredBeforeAny:"requiredbeforeany",RequiredAfterAny:"requiredafterany",Reset:"reset",Context:"context"},c=new CSSStyleSheet;c.replaceSync(":host\n{\n --gap: 7px;\n --gap-small: 3px;\n --gap-medium: 14px;\n --gap-large: 24px;\n \n --surface-success: oklch(93.96% 0.05 148.74);\n --primary-success: oklch(58.83% 0.158 145.05);\n --border-success: solid 1px var(--primary-success);\n\n --surface-fail: oklch(88.98% 0.052 3.28);\n --primary-fail: oklch(45.8% 0.177 17.7);\n --border-fail: solid 1px var(--primary-fail);\n\n --surface-process: oklch(89.66% 0.046 260.67);\n --primary-process: oklch(43.48% 0.17 260.2);\n --border-process: solid 1px var(--primary-process);\n\n\n --surface-footer: rgb(0 0 0 / .04);\n \n --success-icon: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"%232e943a\" d=\"M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z\"/></svg>');\n --info-icon: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2022.812714%2022.814663%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20style%3D%22fill%3Atransparent%3Bstroke%3Atransparent%3Bstroke-width%3A0.999999%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dasharray%3Anone%3Bstroke-dashoffset%3A29.2913%3Bstroke-opacity%3A1%22%20d%3D%22M%2022.295505%2C11.407332%20A%2010.889144%2C10.889144%200%200%201%2011.406424%2C22.296479%2010.889144%2C10.889144%200%200%201%200.51720881%2C11.407332%2010.889144%2C10.889144%200%200%201%2011.406424%2C0.51818382%2010.889144%2C10.889144%200%200%201%2022.295505%2C11.407332%20Z%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22m%2013.945668%2C4.3053761%20c%200.150778%2C-0.96462%20-0.30687%2C-1.43709%20-1.36997%2C-1.43709%20-1.063%2C0%20-1.668452%2C0.47247%20-1.81923%2C1.43709%20-0.150779%2C0.96462%200.306971%2C1.43708%201.369971%2C1.43708%201.004%2C0%201.66845%2C-0.47246%201.819229%2C-1.43708%20z%20M%2011.693889%2C17.829726%2013.373994%2C7.0811161%20h%20-2.9333%20L%208.7605887%2C17.829726%20Z%22%20style%3D%22font-size%3A19.6861px%3Bfont-family%3APassageway%3B-inkscape-font-specification%3APassageway%3Bfill%3A%23a30d30%3Bstroke-width%3A2.5%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dashoffset%3A29.2913%22%20aria-label%3D%22i%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');\n\n\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n font-family: sans-serif;\n font-size: 12px;\n}\n@media (prefers-color-scheme: dark) \n{\n :host\n {\n --surface-footer: rgb(255 255 255 / .1);\n }\n}\n\n#header\n{\n flex: 1;\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\n#title\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n#tests\n,#component-content\n{\n display: grid;\n gap: var(--gap-small);\n grid-auto-rows: max-content;\n}\n\n#header button\n{\n align-self: stretch;\n display: inline-flex;\n align-items: center;\n gap: var(--gap-small);\n}\n\nbutton .reset-icon\n{\n width: 1em;\n height: 1em;\n transform: scaleX(-1);\n margin-inline: 3px;\n}\n\n/* Run button */\nbutton .arrow-icon\n{\n width: .75em;\n height: .75em;\n transform: rotate(-90deg);\n margin-inline: 3px;\n}\n:host(.running) .run-all-button-icon\n,:host(.fail) .run-all-button-icon\n{\n transform: rotate(0);\n}\n\n/* Dropdown Layout */\nsummary > .run-test-button\n, #run-all-button\n{\n justify-self: flex-end;\n margin-left: auto;\n}\n\nsummary:not(#component-summary)\n{\n padding: var(--gap-small);\n}\n#component-summary\n{\n padding: var(--gap) var(--gap-small);\n border-bottom: solid 1px;\n margin-bottom: var(--gap-small);\n}\n\n\n/* Dropdown Markers */\nsummary\n{\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\nsummary > .arrow-icon\n{\n background: var(--arrow-icon);\n transform: rotate(-90deg);\n transition: transform ease-out 90ms;\n width: .6em;\n height: .6em;\n}\ndetails[open] > summary > .arrow-icon\n{\n transform: rotate(0);\n}\n\n#enabled\n{\n display: none;\n}\n:host([optional]) #enabled\n{\n display: block;\n}\n\n/* Result Icon */\n.result-icon\n{\n --background-size: 16px;\n width: var(--background-size);\n height: var(--background-size);\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n border: solid 1px currentColor;\n border-radius: 50%;\n}\n.result-icon::before\n{\n content: '⋯';\n font-size: 10px;\n}\n\n:host(.running) #component-summary .result-icon\n,.test.running .test-summary > .result-icon\n,.hook.running .result-icon\n,.processing-details.running .processing-result-icon\n{\n border: var(--border-process);\n background: var(--surface-process);\n}\n:host(.success) #component-summary .result-icon\n,.test.success .test-summary > .result-icon\n,.hook.success .result-icon\n,.processing-details.success .processing-result-icon\n{\n border: var(--border-success);\n background: var(--surface-success)\n var(--success-icon);\n background-repeat: no-repeat;\n background-position: center;\n background-size: var(--icon-size, 12px) var(--icon-size, 12px);\n}\n:host(.fail) #component-summary .result-icon\n,.test.fail .test-summary > .result-icon\n,.hook.fail .result-icon\n,.processing-details.fail .processing-result-icon\n{\n border: var(--border-fail);\n background: var(--surface-fail)\n var(--info-icon);\n background-size: var(--icon-size, 16px) var(--icon-size, 16px);\n background-repeat: no-repeat;\n background-position: center;\n transform: rotate(175deg);\n}\n:host(:is(.success,.fail)) #component-summary .result-icon::before\n,.test:is(.success,.fail) .test-summary > .result-icon::before\n,.hook:is(.success,.fail) .result-icon::before\n,.processing-details:is(.success,.fail) .processing-result-icon::before\n{\n display: none;\n}\n:host(.running) #component-summary .result-icon::before\n,.test:is(.running) .test-summary > .result-icon::before\n,.hook:is(.running) .result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n content: '';\n --color: var(--primary-process, currentColor);\n --animation-timing-function: linear;\n --animation-duration: 2s;\n width: var(--icon-size, 14px);\n height: var(--icon-size, 14px);\n mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--icon-size, 14px) / 3), black calc(var(--icon-size, 14px) / 3));\n background-image: conic-gradient(transparent, transparent 135deg, var(--color));\n border-radius: 50%;\n animation: var(--animation-timing-function) var(--animation-duration) infinite spin;\n margin: 2px;\n}\n\n/* Smaller Result icon settings for sub-test icons */\n.before-each-result-icon\n,.after-each-result-icon\n,.processing-result-icon\n{\n --background-size: 12px;\n}\n.before-each-result-icon::before\n,.after-each-result-icon::before\n,.processing-result-icon::before\n{\n font-size: 9px;\n}\n.hook.success .before-each-result-icon\n,.hook.success .after-each-result-icon\n,.processing-details.success .processing-result-icon\n{\n --icon-size: 8px;\n}\n.hook.fail .before-each-result-icon\n,.hook.fail .after-each-result-icon\n,.processing-details.fail .processing-result-icon\n{\n --icon-size: 12px;\n}\n.hook:is(.running) .before-each-result-icon::before\n,.hook:is(.running) .after-each-result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n --icon-size: 9px;\n}\n\n/* Hook Display */\n.hook\n{\n display: none;\n}\n:host(.has-before-all-hook) #before-all-details\n,:host(.has-after-all-hook) #after-all-details\n{\n display: initial;\n}\n:host(.has-before-each-hook) .before-each-details\n,:host(.has-after-each-hook) .after-each-details\n{\n display: initial;\n}\n:host(.has-required-before-hook) #required-before-any-details\n,:host(.has-required-after-hook) #required-after-any-details\n{\n display: initial;\n}\n\n/* Test Display */\ncode-test .results\n{\n display: grid;\n gap: var(--gap-small);\n padding-inline-start: 1em;\n}\n\ncode-test .results details .result\n,.hook > .results\n{\n margin-inline-start: 1em;\n}\n\n.result.message:empty\n{\n padding: .5em 1em;\n}\n.result.message:empty::before\n{\n content: '[ this function has not been run ]';\n font-family: monospace;\n font-size: 12px;\n font-style: italic;\n}\n\n/* Ordered Display */\n#tests\n{\n counter-reset: tests;\n}\ncode-test\n{\n counter-increment: tests;\n}\ncode-test > details > summary > .description\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 0; /* hack to make overflow work right; \"contain: inline-size\" is correct fix, but it's too new to implement on jan 25, 2026; */\n}\n:host(:not([ordered=\"false\"])) code-test > details > summary > .description::before\n{\n content: counter(tests) \". \";\n}\n\n/* Hook Name */\n.hook-name,.processing-description\n{\n border-radius: 3px;\n border: solid 1px;\n font-family: monospace;\n text-transform: uppercase;\n font-size: 11px;\n padding: 3px 7px;\n}\n\n#footer\n{\n display: flex;\n justify-content: flex-end;\n border-top: solid 1px;\n border-bottom: solid 1px;\n background: var(--surface-footer);\n margin-top: var(--gap-small);\n}\n#group-results\n{\n display: flex;\n gap: var(--gap);\n padding: var(--gap);\n}\n\n#results-progress-value\n{\n min-width: 40px;\n width: auto;\n}\n\n#duration\n,#passed-total-pair\n,#passed-total-percent\n{\n white-space: nowrap;\n}\n\n#passed-total-percent::before\n{\n content: '(';\n}\n#passed-total-percent::after\n{\n content: ')';\n}\n\n@keyframes spin\n{\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}");const u="code-tests";class d extends HTMLElement{state={isCanceled:!1,beforeAllState:void 0,afterAllState:void 0,beforeEachState:void 0,afterEachState:void 0,requiredBeforeAnyState:void 0,requiredAfterAnyState:void 0,resetHook:void 0,contextHook:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.shadowRoot.querySelector(t)}findElements(t){return Array.from(this.shadowRoot.querySelectorAll(t))}getIsRunning(){return 1==(null!=this.findElements("code-test").find(t=>1==t.isRunning()))||1==this.state.requiredBeforeAnyState?.isRunning||1==this.state.requiredAfterAnyState?.isRunning||1==this.state.beforeAllState?.isRunning||1==this.state.afterAllState?.isRunning}getResultCategory(){const t=this.findElements("code-test").reduce((t,e,s)=>{const n=e.resultCategory();return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},""),e=[this.state.requiredBeforeAnyState,this.state.requiredAfterAnyState,this.state.beforeAllState,this.state.afterAllState].reduce((t,e,s)=>{if(null==e)return null;const n=e?.resultCategory;return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},"");return"none"==t&&null==e?"none":"fail"==t||"fail"==e?"fail":"success"==t||"success"==e?"success":"none"}#r;constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML='<details id="component-details" class="details">\n <summary id="component-summary" class="summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <slot name="header">\n <header id="header">\n <span id="component-result-icon" class="result-icon"></span>\n <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="reload-button">\n <button type="button" id="reload-button" title="Reload">\n <slot name="reload-button-content">\n <slot name="reload-button-icon"><svg class="icon reset-icon reload-button-icon"><use href="#icon-definition_reset"></use></svg></slot>\n <slot name="reload-button-label"><span class="reload-button-label button-label label icon">Reload</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="run-all-button">\n <button type="button" id="run-all-button" title="Run All Tests">\n <slot name="run-all-button-content">\n <slot name="run-all-button-icon"><svg class="icon arrow-icon run-button-icon run-all-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-all-button-label"><span class="run-all-button-label run-button-label button-label label icon">Run Tests</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="header-details"></slot>\n </header>\n </slot>\n </summary>\n <div id="component-content" class="content">\n <details id="required-before-any-details" class="hook">\n <summary id="required-before-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-before-any-result-icon" class="result-icon"></span>\n <span id="required-before-any-description" class="description hook-name">Required Before Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-before-any-results" class="result message"></div>\n </div>\n </details>\n <details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description hook-name">Before All Hook</span>\n </summary>\n <div class="results">\n <div id="before-all-results" class="result message"></div>\n </div>\n </details>\n <div id="tests"></div>\n <details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description hook-name">After All Hook</span>\n </summary>\n <div class="results">\n <div id="after-all-results" class="result message"></div>\n </div>\n </details>\n <details id="required-after-any-details" class="hook">\n <summary id="required-after-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-after-any-result-icon" class="result-icon"></span>\n <span id="required-after-any-description" class="description hook-name">Required After Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-after-any-results" class="result message"></div>\n </div>\n </details>\n </div>\n \n <slot name="footer">\n <foooter id="footer">\n <span id="group-results">\n <span id="duration">\n <span id="duration-label">Duration</span>\n <span id="duration-value">0</span>\n <span id="duration-unit">ms</span>\n </span>\n <span id="results-progress">\n <progress id="results-progress-value"></progress>\n </span>\n <span id="passed-total-pair">\n <span id="total-tests-passed-value"></span>\n <span id="passed-total-delimiter">of</span>\n <span id="total-tests-count-value"></span>\n <span id="total-tests-passed-label">Passed</span>\n </span>\n <span id="passed-total-percent">\n <span id="passed-total-percent-value">0</span>\n <span id="passed-total-percent-label">%</span>\n </span>\n </span>\n </foooter>\n </slot>\n</details>\n<template id="prompt-template">\n <div class="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>\n<div id="icon-definitions" style="display: none;">\n <svg id="icon-definition_arrow" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path d="m3.26,6.81l-2.93,-4.69c-0.37,-0.58 0.05,-1.34 0.74,-1.34l5.87,0c0.69,0 1.11,0.76 0.74,1.34l-2.93,4.69c-0.35,0.55 -1.14,0.55 -1.49,0z" fill="var(--fill-color, currentcolor)" />\n </svg>\n <svg id="icon-definition_reset" class="icon reset" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M 5.484375 0.43359375 A 1.5224222 1.5224222 0 0 0 4.2558594 1.2011719 L 0.99804688 6.9453125 A 1.5224222 1.5224222 0 0 0 2.5488281 9.2011719 L 9.34375 8.171875 A 1.5224222 1.5224222 0 0 0 10.332031 5.7539062 L 9.4746094 4.6113281 C 11.949333 3.8016718 14.718209 4.258351 16.822266 5.9570312 C 19.510764 8.1275534 20.456787 11.785479 19.160156 14.988281 C 17.863527 18.191083 14.6405 20.15873 11.199219 19.847656 C 7.7579362 19.536584 4.9376009 17.022073 4.2363281 13.638672 A 1.5 1.5 0 0 0 2.4628906 12.474609 A 1.5 1.5 0 0 0 1.2988281 14.248047 C 2.2656928 18.912838 6.1831413 22.407052 10.927734 22.835938 C 15.672328 23.264824 20.153706 20.531029 21.941406 16.115234 C 23.729107 11.699441 22.413741 6.6156073 18.707031 3.6230469 C 16.853677 2.1267667 14.61485 1.3255701 12.347656 1.2324219 C 10.738216 1.1662975 9.1150542 1.4598646 7.6035156 2.1132812 L 6.7988281 1.0390625 A 1.5224222 1.5224222 0 0 0 5.484375 0.43359375 z " />\n </svg>\n <svg id="icon-definition_cancel" class="icon cancel" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M -7.063234 9.5244002 C -5.8135728 7.6769245 -5.0820528 5.453265 -5.0820528 3.0633809 C -5.0820529 -3.3096433 -10.278145 -8.5098163 -16.65117 -8.5098163 C -23.024193 -8.5098163 -28.22385 -3.3110105 -28.22385 3.0620137 C -28.22385 9.4350379 -23.025043 14.634694 -16.65202 14.634694 C -12.668879 14.634694 -9.1460028 12.603526 -7.063234 9.5244002 z M -9.5406311 7.8637601 C -11.076991 10.143147 -13.683157 11.63463 -16.652974 11.63463 C -19.960499 11.63463 -22.814085 9.782061 -24.244824 7.0543029 L -24.236684 7.0527515 L -8.1332524 3.983715 L -8.1305391 3.9831979 C -8.2815631 5.4121635 -8.7798709 6.7350751 -9.5406311 7.8637601 z M -9.0610781 -0.92890828 L -9.069218 -0.92735695 L -25.17265 2.1416796 L -25.175363 2.1421967 C -24.719122 -2.1725739 -21.093311 -5.5092358 -16.652928 -5.5092358 C -13.345403 -5.5092358 -10.491243 -3.6566663 -9.0610781 -0.92890828 z "\n transform="rotate(-124.20981)" />\n </svg>\n</div>',this.shadowRoot.adoptedStyleSheets.push(c)}connectedCallback(){this.#i()}disconnectedCallback(){this.#l()}#c=!1;#u=!1;async#i(){1!=this.#c&&1!=this.#u&&(this.#c=!0,i(this.shadowRoot),this.addEventListener("click",this.#d),this.findElement("#enabled").addEventListener("change",this.#h),await new Promise(e=>requestAnimationFrame(()=>{this.#r=new a(this),this.#u=!0,this.#c=!1;if(0==this.dispatchEvent(new CustomEvent(t.Init,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}})))return void e();"false"!=this.getAttribute("auto")?(this.reloadTests(),e()):e()})))}#l(){this.removeEventListener("click",this.#d),this.findElement("#enabled").removeEventListener("change",this.#h),this.#u=!1,this.#c=!1}#d=this.#f.bind(this);#f(t){if(null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"run-all-button"==t.id))return void(this.classList.contains("running")?this.cancel():this.classList.contains("fail")||this.classList.contains("success")?this.reset():this.runTests());null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"reload-button"==t.id)&&this.reloadTests();const e=t.composedPath().find(t=>t instanceof HTMLButtonElement&&t.classList.contains("run-test-button"));if(null==e)return;const s=e.closest("code-test")??void 0;this.#r.runTest(s,!1)}#h=this.#p.bind(this);#p(e){const s=e.target;0==this.dispatchEvent(new CustomEvent(t.Enabled,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))&&(e.preventDefault(),e.stopPropagation(),s.checked=!s.checked)}#g(){return this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path")??void 0}#t(){const t=this.getIsRunning(),e=this.getResultCategory(),s=null!=this.state.beforeAllState,n=null!=this.state.beforeEachState,a=null!=this.state.requiredAfterAnyState,o=null!=this.state.beforeAllState,r=null!=this.state.beforeEachState,i=null!=this.state.requiredAfterAnyState,l=1==a||1==s||1==n,c=1==i||1==o||1==r;this.classList.toggle("canceled",this.state.isCanceled),this.part.toggle("canceled",this.state.isCanceled),this.classList.toggle("running",1==t),this.part.toggle("running",1==t),this.toggleAttribute("success","success"==e),this.classList.toggle("success","success"==e),this.part.toggle("success","success"==e),this.classList.toggle("fail","fail"==e),this.part.toggle("fail","fail"==e),this.classList.toggle("has-before-hook",l),this.part.toggle("has-before-hook",l),this.classList.toggle("has-after-hook",c),this.part.toggle("has-after-hook",c),this.classList.toggle("has-before-all-hook",s),this.part.toggle("has-before-all-hook",s),this.classList.toggle("has-after-all-hook",o),this.part.toggle("has-after-all-hook",o),this.classList.toggle("has-before-each-hook",n),this.part.toggle("has-before-each-hook",n),this.classList.toggle("has-after-each-hook",r),this.part.toggle("has-after-each-hook",r),this.classList.toggle("has-required-before-hook",a),this.part.toggle("has-required-before-hook",a),this.classList.toggle("has-required-after-hook",i),this.part.toggle("has-required-after-hook",i);const u=this.findElement(".run-all-button-label");null!=u&&(u.textContent=1==t?"Cancel":"fail"==e||"success"==e?"Reset":"Run Tests",u.title=1==t?"Cancel the testing":"fail"==e||"success"==e?"Reset the tests so they can be run again":"Run the tests");const d=this.findElement(".run-all-button-icon");null!=d&&(d.innerHTML=1==t?'<use href="#icon-definition_cancel"></use>':"fail"==e||"success"==e?'<use href="#icon-definition_reset"></use>':'<use href="#icon-definition_arrow"></use>'),this.#m(this.state.beforeAllState,"#before-all-results"),this.#m(this.state.afterAllState,"#after-all-results"),this.#m(this.state.requiredBeforeAnyState,"#required-before-any-results"),this.#m(this.state.requiredAfterAnyState,"#required-after-any-results");const h=this.findElement("#title");null!=h&&(h.textContent=this.getAttribute("label")??"Tests"),this.#b()}#m(t,e){const s=this.findElement(e);t?.resultContent instanceof HTMLElement?s.append(t.resultContent):"string"==typeof t?.resultContent&&(s.innerHTML=t.resultContent);const n=s.closest("details");n.toggleAttribute("open",null!=t&&"none"!=t.resultCategory),n.classList.toggle("running",1==t?.isRunning),n.part.toggle("running",1==t?.isRunning),n.toggleAttribute("success","success"==t?.resultCategory),n.classList.toggle("success","success"==t?.resultCategory),n.part.toggle("success","success"==t?.resultCategory),n.classList.toggle("fail","fail"==t?.resultCategory),n.part.toggle("fail","fail"==t?.resultCategory)}#b(){const t=this.collectTestResults(),e=this.findElement("#results-progress-value");null!=e&&(e.max=t.totalTests,e.value=t.totalPassed);const s=this.findElement("#total-tests-passed-value");null!=s&&(s.textContent=t.totalPassed.toString());const n=this.findElement("#total-tests-count-value");null!=n&&(n.textContent=t.totalTests.toString());const a=this.findElement("#passed-total-percent-value");null!=a&&(a.textContent=t.totalPercentage.toFixed(1));const o=this.findElement("#duration-value");null!=o&&(o.textContent=t.duration>10?t.duration.toFixed(0):t.duration.toFixed(2))}collectTestResults(){const t=this.findElements("code-test"),e=t.length,s=t.filter(t=>"success"==t.state.testState?.resultCategory).length;return{totalTests:e,totalPassed:s,totalPercentage:0==e?0:s/e*100,duration:t.reduce((t,e,s)=>t+(e.state.testState?.duration??0),0)}}async runTests(){const t=this.findElements("code-test");return this.#r.runTests(t)}async reloadTests(){this.findElement("#tests").innerHTML="",await this.reset();const t=this.#g();this.#r.loadTests(t)}async reset(){const e=this.findElements("code-test");for(let t=0;t<e.length;t++){const s=e[t],n=null!=this.state.beforeEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.beforeEachState.hasRun,isRunning:this.state.beforeEachState.isRunning,duration:0}:void 0,a=null!=this.state.afterEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.afterEachState.hasRun,isRunning:this.state.afterEachState.isRunning,duration:0}:void 0;null!=n&&(s.state.beforeEachState=n),null!=a&&(s.state.afterEachState=a),s.reset()}const s=null==this.state.beforeAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeAllState.test,isRunning:!1,hasRun:!1,duration:0},n=null==this.state.afterAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterAllState.test,isRunning:!1,hasRun:!1,duration:0},a=null==this.state.beforeEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeEachState.test,isRunning:!1,hasRun:!1,duration:0},o=null==this.state.afterEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterEachState.test,isRunning:!1,hasRun:!1,duration:0},r=null==this.state.requiredBeforeAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredBeforeAnyState.test,isRunning:!1,hasRun:!1,duration:0},i=null==this.state.requiredAfterAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredAfterAnyState.test,isRunning:!1,hasRun:!1,duration:0};this.setStateProperties({isCanceled:!1,beforeAllState:s,afterAllState:n,beforeEachState:a,afterEachState:o,requiredAfterAnyState:i,requiredBeforeAnyState:r}),this.#r.shouldContinueRunningTests=!0,null!=this.state.resetHook&&await this.state.resetHook(await this.#r.createTestContext()),this.dispatchEvent(new CustomEvent(t.Reset,{bubbles:!0,composed:!0}))}cancel(){this.state.isCanceled=!0,this.#r.shouldContinueRunningTests=!1,this.classList.add("canceled"),this.part.add("canceled"),this.dispatchEvent(new CustomEvent(t.Cancel,{bubbles:!0,composed:!0}))}static observedAttributes=["open","label"];attributeChangedCallback(t,e,s){if("open"==t)this.findElement("#component-details").toggleAttribute("open",null!=s);else if("label"==t){const t=this.findElement("#title");null!=t&&(t.textContent=s??"Tests")}}}function h(t){return new o(async(e,s)=>{if(t instanceof Promise){return void e(await t)}e(t)})}async function f(e,s,n,a){let o=null;const r=await new Promise((t,r)=>{const i=a?.template??e.querySelector(".prompt-template")??e.findElement("#prompt-template");o=p(i),o.querySelector(".label").textContent=n;const l=e=>{const s=e.composedPath();if(null!=s.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("accept"))){const e=a?.onAccept?.()??!0;return o.removeEventListener("click",l),void t(e)}if(null!=s.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("reject"))){const e=a?.onReject?.()??!1;return o.removeEventListener("click",l),void t(e)}};o.addEventListener("click",l),null!=a?.acceptLabel&&(o.querySelector(".accept").textContent=a.acceptLabel),null!=a?.rejectLabel&&(o.querySelector(".reject").textContent=a.rejectLabel),s.append(o)});return null!=o&&o.remove(),e.dispatchEvent(new CustomEvent(t.PromptResult,{bubbles:!0,composed:!0,detail:{target:e,result:r}})),r}function p(t,e){const s=t instanceof HTMLTemplateElement?t:document.querySelector(t);if(null==s)throw new Error(`Unable to find template element from selector: ${t}`);const n=s.content.cloneNode(!0).firstElementChild;if(null==n)throw new Error("Unable to find first child of template element");return e?.append(n),n}null==customElements.get(u)&&customElements.define(u,d);export{s as CodeTestElement,t as CodeTestEvent,d as CodeTestsElement,l as Hook,o as TestPromise,p as createElementFromTemplate,h as expect,f as prompt};
@@ -390,7 +390,8 @@ code-test > details > summary > .description
390
390
  Reset: "reset",
391
391
  TestEnd: "testend",
392
392
  Init: "init",
393
- Enabled: "enabled"
393
+ Enabled: "enabled",
394
+ PromptResult: "promptresult"
394
395
  };
395
396
  const COMPONENT_TAG_NAME$1 = "code-test";
396
397
  class CodeTestElement extends HTMLElement {
@@ -828,6 +829,9 @@ code-test > details > summary > .description
828
829
  }
829
830
  }
830
831
  testContext = testContext ?? await this.createTestContext(test);
832
+ if (testContext.testElement == null) {
833
+ testContext.testElement = test;
834
+ }
831
835
  if (inLoop == false) {
832
836
  await this.runHook("requiredBeforeAnyState", void 0, testContext);
833
837
  if (this.shouldContinueRunningTests == false) {
@@ -1439,24 +1443,25 @@ Result:${objectResult.value}</pre>
1439
1443
  return promise;
1440
1444
  }
1441
1445
  async function prompt(host, parentElement, message, options) {
1442
- return new Promise((resolve, _reject) => {
1446
+ let promptElement = null;
1447
+ const result = await new Promise((resolve, _reject) => {
1443
1448
  const template = options?.template ?? host.querySelector(".prompt-template") ?? host.findElement("#prompt-template");
1444
- const promptElement = createElementFromTemplate(template);
1449
+ promptElement = createElementFromTemplate(template);
1445
1450
  promptElement.querySelector(".label").textContent = message;
1446
1451
  const clickHandler = (event) => {
1447
1452
  const composedPath = event.composedPath();
1448
1453
  const acceptButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("accept"));
1449
1454
  if (acceptButton != null) {
1450
- const result = options?.onAccept?.() ?? true;
1455
+ const result2 = options?.onAccept?.() ?? true;
1451
1456
  promptElement.removeEventListener("click", clickHandler);
1452
- resolve(result);
1457
+ resolve(result2);
1453
1458
  return;
1454
1459
  }
1455
1460
  const rejectButton = composedPath.find((item) => item instanceof HTMLButtonElement && item.classList.contains("reject"));
1456
1461
  if (rejectButton != null) {
1457
- const result = options?.onReject?.() ?? false;
1462
+ const result2 = options?.onReject?.() ?? false;
1458
1463
  promptElement.removeEventListener("click", clickHandler);
1459
- resolve(result);
1464
+ resolve(result2);
1460
1465
  return;
1461
1466
  }
1462
1467
  };
@@ -1469,6 +1474,11 @@ Result:${objectResult.value}</pre>
1469
1474
  }
1470
1475
  parentElement.append(promptElement);
1471
1476
  });
1477
+ if (promptElement != null) {
1478
+ promptElement.remove();
1479
+ }
1480
+ host.dispatchEvent(new CustomEvent(CodeTestEvent.PromptResult, { bubbles: true, composed: true, detail: { target: host, result } }));
1481
+ return result;
1472
1482
  }
1473
1483
  function createElementFromTemplate(target, parent) {
1474
1484
  const templateNode = target instanceof HTMLTemplateElement ? target : document.querySelector(target);
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(((t="undefined"!=typeof globalThis?globalThis:t||self)["code-tests"]=t["code-tests"]||{},t["code-tests"].umd=t["code-tests"].umd||{},t["code-tests"].umd.min=t["code-tests"].umd.min||{},t["code-tests"].umd.min.js={}))}(this,function(t){"use strict";const e={BeforeAll:"beforeall",AfterAll:"afterall",BeforeTest:"beforetest",AfterTest:"aftertest",BeforeHook:"beforehook",AfterHook:"afterhook",Cancel:"cancel",Context:"context",Reset:"reset",TestEnd:"testend",Init:"init",Enabled:"enabled"},s="code-test";class n extends HTMLElement{state={testId:"",description:"none",isDisabled:!1,testState:void 0,beforeEachState:void 0,afterEachState:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.querySelector(t)}findElements(t){return Array.from(this.querySelectorAll(t))}isRunning(){return 1==this.state.testState?.isRunning||1==this.state.beforeEachState?.isRunning||1==this.state.afterEachState?.isRunning}hasRun(){return 1==this.state.testState?.hasRun||1==this.state.beforeEachState?.hasRun||1==this.state.afterEachState?.hasRun}resultCategory(){const t=this.state.testState?.resultCategory??"none",e=this.state.beforeEachState?.resultCategory??"none",s=this.state.afterEachState?.resultCategory??"none";return"none"==t&&"none"==e&&"none"==s?"none":null==this.state.beforeEachState&&null==this.state.afterEachState?t:null!=this.state.beforeEachState&&null==this.state.afterEachState?"fail"==t||"fail"==e?"fail":"success"==t&&"success"==e?"success":"none":null==this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==s?"fail":"success"==t&&"success"==s?"success":"none":null!=this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==e||"fail"==s?"fail":"success"==t&&"success"==e&&"success"==s?"success":"none":void 0}connectedCallback(){this.#t()}#t(){const t=null==this.state.testState?"":"boolean"==typeof this.state.testState.resultContent?1==this.state.testState.resultContent?'<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed</pre></code>':'<code class="code" part="code"><pre class="pre error-message" part="pre error-message">Failed</pre></code>':"number"==typeof this.state.testState.resultContent?`<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed: ${this.state.testState.resultContent.toString()}</pre></code>`:"string"==typeof this.state.testState.resultContent?this.state.testState.resultContent:"";this.innerHTML=`<details class="test-details" part="test-details" ${1==this.isRunning()||1==this.hasRun()?" open":""}>\n <summary class="test-summary" part="test-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="result-icon test-result-icon${"none"!=this.state.testState?.resultCategory?` ${this.state.testState?.resultCategory}`:""}" part="result-icon"></div>\n <span class="test-description description" title="${this.state.description}">${this.state.description}</span>\n ${null!=this.state.testState?.duration&&this.state.testState.duration>0?`<span class="test-duration duration">\n <span class="test-duration-value">${this.state.testState.duration>10?this.state.testState.duration.toFixed(0):this.state.testState.duration.toFixed(2)}</span>\n <span class="test-duration-unit">ms</span>\n </span>`:""}\n <button type="button" class="run-test-button" part="run-test-button" title="Run Test"${1==this.state.isDisabled?" disabled":""}>\n <slot name="run-button-content">\n <slot name="run-button-icon"><svg class="icon arrow-icon run-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-button-label"><span class="run-button-label button-label label icon">Run Test</span></slot>\n </slot>\n </button>\n </summary>\n <div class="results" part="results">\n ${null==this.state.beforeEachState?"":`<details class="before-each-details hook${"none"==this.state.beforeEachState.resultCategory?"":` ${this.state.beforeEachState.resultCategory}`}${1==this.state.beforeEachState.isRunning?" running":""}" part="before-each-details hook">\n <summary class="before-each-summary" part="before-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="before-each-result-icon result-icon${"none"!=this.state.beforeEachState.resultCategory?` ${this.state.beforeEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="before-each-description description hook-name">Before Each Hook</span>\n </summary>\n <div class="before-each-result result message" part="before-each-result result message">${"string"!=typeof this.state.beforeEachState.resultContent?"":this.state.beforeEachState.resultContent}</div>\n </details>`}\n ${null==this.state.testState?"":null==this.state.beforeEachState&&null==this.state.afterEachState?`<div class="test-result result message" part="test-result result message">${t}</div>`:`<details class="processing-details${"none"==this.state.testState.resultCategory?"":` ${this.state.testState.resultCategory}`}${1==this.state.testState.isRunning?" running":""}" part="processing-details"${1==this.state.testState.hasRun?" open":""}>\n <summary class="processing-summary" part="processing-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="processing-result-icon result-icon${"none"!=this.state.testState.resultCategory?` ${this.state.testState.resultCategory}`:""}" part="processing-result-icon result-icon"></div>\n <span class="processing-description description">Test</span>\n </summary>\n <div class="test-result result message" part="test-result result message">${t}</div>\n </details>`} \n ${null==this.state.afterEachState?"":`<details class="after-each-details hook${"none"==this.state.afterEachState.resultCategory?"":` ${this.state.afterEachState.resultCategory}`}${1==this.state.afterEachState.isRunning?" running":""}" part="after-each-detail hooks">\n <summary class="after-each-summary" part="after-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="after-each-result-icon result-icon${"none"!=this.state.afterEachState.resultCategory?` ${this.state.afterEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="after-each-description description hook-name">After Each Hook</span>\n </summary>\n <div class="after-each-result result message" part="after-each-result result message">${"string"!=typeof this.state.afterEachState.resultContent?"":this.state.afterEachState.resultContent}</div>\n </details>`}\n </div>\n </details>`,this.dataset.testId=this.state.testId,this.classList.add("test"),this.part.add("test"),this.toggleAttribute("success","success"==this.resultCategory()),this.classList.toggle("success","success"==this.resultCategory()),this.part.toggle("success","success"==this.resultCategory()),this.classList.toggle("fail","fail"==this.resultCategory()),this.part.toggle("fail","fail"==this.resultCategory()),this.classList.toggle("running",this.isRunning()),this.part.toggle("running",this.isRunning()),this.state.beforeEachState?.resultContent instanceof HTMLElement&&this.querySelector(".before-each-result").append(this.state.beforeEachState.resultContent),this.state.testState?.resultContent instanceof HTMLElement&&this.querySelector(".test-result").append(this.state.testState.resultContent),this.state.afterEachState?.resultContent instanceof HTMLElement&&this.querySelector(".after-each-result").append(this.state.afterEachState.resultContent)}enable(){this.state.isDisabled=!1,this.findElement(".run-test-button").toggleAttribute("disabled",!1)}disable(){this.state.isDisabled=!0,this.findElement(".run-test-button").toggleAttribute("disabled",!0)}async runTest(t,s){if(null==this.state.testState?.test)return;let n;this.reset();let a={},o=0;try{if(0==t.shouldContinueRunningTests)throw new Error("Tests have been disabled from continuing to run.");if(0==this.dispatchEvent(new CustomEvent(e.BeforeTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}})))throw new Error("Test has been prevented.");if(1==s.codeTestsElement.state.isCanceled)throw new Error("Testing has been canceled.");this.setTestStateProperties("testState",{isRunning:!0}),t.codeTestsElement.setState(t.codeTestsElement.state);const r=performance?.now()??Date.now();n=await this.state.testState.test(s);o=(performance?.now()??Date.now())-r,this.setTestStateProperties("testState",{isRunning:!1,hasRun:!0}),t.codeTestsElement.setState(t.codeTestsElement.state);const i=t.parseTestResult(n,!0);a={testState:{test:this.state.testState.test,resultContent:i.result,resultCategory:i.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:o}}}catch(e){const s=t.parseTestResult(n,!1,e);a={testState:{test:this.state.testState.test,resultContent:s.result,resultCategory:s.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:o}},console.error(e),t.shouldContinueRunningTests=!1}finally{this.setStateProperties({...a}),t.codeTestsElement.setState(t.codeTestsElement.state),this.dispatchEvent(new CustomEvent(e.AfterTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}}))}}reset(){const t=null!=this.state.testState?{resultCategory:"none",resultContent:"",test:this.state.testState.test,hasRun:this.state.testState.hasRun,isRunning:this.state.testState.isRunning,duration:0}:void 0;null!=t&&this.setTestStateProperties("testState",t)}getMessageElement(){return this.findElement(".test-result")}static observedAttributes=["open"];attributeChangedCallback(t,e,s){"open"==t&&this.findElement(".test-details").toggleAttribute("open",null!=s)}}null==customElements.get(s)&&customElements.define(s,n);const a=Symbol("No Test Defined");class o{codeTestsElement;constructor(t){this.codeTestsElement=t}async loadTests(t){if(null!=t)try{const{tests:e,hooks:s}=await this.#e(t),n=s[c.BeforeAll],a=s[c.AfterAll],o=s[c.BeforeEach],r=s[c.AfterEach],i=s[c.RequiredBeforeAny],l=s[c.RequiredAfterAny],u=null==n?void 0:{resultCategory:"none",resultContent:"",test:n,hasRun:!1,isRunning:!1,duration:0},d=null==a?void 0:{resultCategory:"none",resultContent:"",test:a,hasRun:!1,isRunning:!1,duration:0},h=null==o?void 0:{resultCategory:"none",resultContent:"",test:o,hasRun:!1,isRunning:!1,duration:0},f=null==r?void 0:{resultCategory:"none",resultContent:"",test:r,hasRun:!1,isRunning:!1,duration:0},p=null==i?void 0:{resultCategory:"none",resultContent:"",test:i,hasRun:!1,isRunning:!1,duration:0},g=null==l?void 0:{resultCategory:"none",resultContent:"",test:l,hasRun:!1,isRunning:!1,duration:0};this.codeTestsElement.state.beforeEachState=h,this.codeTestsElement.state.afterEachState=f;for(const[t,s]of Object.entries(e))this.#s(t,s);this.codeTestsElement.setStateProperties({beforeAllState:u,afterAllState:d,beforeEachState:h,afterEachState:f,requiredBeforeAnyState:p,requiredAfterAnyState:g,resetHook:s.reset,contextHook:s.context})}catch(t){console.error(t)}}async#e(t){const e=await this.#n(t),s=e.tests??e.default;if(null==s)throw new Error(`Unable to find tests definition in file at path: ${t}`);const n={},a=s[c.BeforeAll];null!=a&&(n[c.BeforeAll]=a,delete s[c.BeforeAll]);const o=s[c.AfterAll];null!=o&&(n[c.AfterAll]=o,delete s[c.AfterAll]);const r=s[c.BeforeEach];null!=r&&(n[c.BeforeEach]=r,delete s[c.BeforeEach]);const i=s[c.AfterEach];null!=i&&(n[c.AfterEach]=i,delete s[c.AfterEach]);const l=s[c.RequiredBeforeAny];null!=l&&(n[c.RequiredBeforeAny]=l,delete s[c.RequiredBeforeAny]);const u=s[c.RequiredAfterAny];null!=u&&(n[c.RequiredAfterAny]=u,delete s[c.RequiredAfterAny]);const d=s[c.Reset];null!=d&&(n[c.Reset]=d,delete s[c.Reset]);const h=s[c.Context];return null!=h&&(n[c.Context]=h,delete s[c.Context]),{tests:s,hooks:n}}async#n(t){const e=window.location.href.lastIndexOf("/"),s=1==(-1!=window.location.href.substring(e).indexOf("."))?window.location.href.substring(0,e+1):window.location.href,n=s+t.substring(0,t.lastIndexOf("/")+1),a=s+t;let o=await(await fetch(a)).text();o=o.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g,`'${n}$1'`);const r=new File([o],t.substring(t.lastIndexOf("/")),{type:"text/javascript"}),i=URL.createObjectURL(r);return await import(i)}#s(t,e){const s=function(){const t=new Uint8Array(20);crypto.getRandomValues(t);const e=[].slice.apply(t).map(function(t){return String.fromCharCode(t)}).join("");return btoa(e).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,"")}(),a=new n;return a.setStateProperties({testId:s,description:t,testState:{test:e,resultCategory:"none",resultContent:"",isRunning:!1,hasRun:!1,duration:0},beforeEachState:null==this.codeTestsElement.state.beforeEachState?void 0:{isRunning:this.codeTestsElement.state.beforeEachState.isRunning,hasRun:this.codeTestsElement.state.beforeEachState.hasRun,resultCategory:this.codeTestsElement.state.beforeEachState.resultCategory,resultContent:this.codeTestsElement.state.beforeEachState.resultContent,duration:0},afterEachState:null==this.codeTestsElement.state.afterEachState?void 0:{isRunning:this.codeTestsElement.state.afterEachState.isRunning,hasRun:this.codeTestsElement.state.afterEachState.hasRun,resultCategory:this.codeTestsElement.state.afterEachState.resultCategory,resultContent:this.codeTestsElement.state.afterEachState.resultContent,duration:0}}),this.codeTestsElement.findElement("#tests").append(a),s}shouldContinueRunningTests=!0;async runTests(t){if(0==this.codeTestsElement.dispatchEvent(new CustomEvent(e.BeforeAll,{bubbles:!0,composed:!0,cancelable:!0})))throw new Error("Tests have been prevented.");await this.codeTestsElement.reset();for(let e=0;e<t.length;e++)t[e].disable();const s=await this.createTestContext();if(await this.runHook("requiredBeforeAnyState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(t,s);if(await this.runHook("beforeAllState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(t,s);if(0==("false"!=this.codeTestsElement.getAttribute("ordered"))){const e=t.map(t=>this.runTest(t,!0,s));await Promise.all(e)}else for(let e=0;e<t.length;e++){const n=t[e];if(0==this.shouldContinueRunningTests)break;await this.runTest(n,!0,s)}0!=this.shouldContinueRunningTests?(await this.runHook("afterAllState",void 0,s),await this.#a(t,s)):await this.#a(t,s)}async#a(t,s){await this.runHook("requiredAfterAnyState",void 0,s);for(let e=0;e<t.length;e++)t[e].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(e.AfterAll,{bubbles:!0,composed:!0}))}async runTest(t,e,s){if(null!=t){if(0==e){const t=this.codeTestsElement.findElements("code-test");for(let e=0;e<t.length;e++)t[e].disable()}s=s??await this.createTestContext(t),0!=e||(await this.runHook("requiredBeforeAnyState",void 0,s),0!=this.shouldContinueRunningTests)?(await this.runHook("beforeEachState",t,s),0!=this.shouldContinueRunningTests?(await t.runTest(this,s),0!=this.shouldContinueRunningTests?(await this.runHook("afterEachState",t,s),await this.#o(s,e)):await this.#o(s,e)):await this.#o(s,e)):await this.#o(s,e)}}async#o(t,s){if(1==s)return;await this.runHook("requiredAfterAnyState",void 0,t);const n=this.codeTestsElement.findElements("code-test");for(let t=0;t<n.length;t++)n[t].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(e.TestEnd,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))}async runHook(t,s,n){const o=this.codeTestsElement.state[t];if(null==o)return a;if(1==this.codeTestsElement.state.isCanceled)return{success:!1,value:"Testing has been canceled."};let r;try{if(0==this.shouldContinueRunningTests&&("requiredAfterAnyState"!=t||"error"==this.codeTestsElement.getAttribute("required-after")))throw new Error("Tests have been disabled from continuing to run.");null!=s&&s.setTestStateProperties(t,{isRunning:!0}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!0}),r=await o.test(n),null!=s&&s.setTestStateProperties(t,{isRunning:!1,hasRun:!0}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!1,hasRun:!0});const e=this.parseTestResult(r,!0,void 0);null!=s&&s.setTestStateProperties(t,{resultCategory:e.resultCategory,resultContent:e.result}),this.codeTestsElement.setTestStateProperties(t,{resultCategory:e.resultCategory,resultContent:e.result})}catch(e){console.error(e),this.shouldContinueRunningTests=!1,r={success:!1,value:`Failed: ${e.message}`};const n=this.parseTestResult(r,!1,e);null!=s&&s.setTestStateProperties(t,{isRunning:!1,hasRun:!0,resultContent:n.result,resultCategory:n.resultCategory}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!1,hasRun:!0,resultCategory:n.resultCategory,resultContent:n.result})}finally{return this.codeTestsElement.dispatchEvent(new CustomEvent(e.AfterHook,{bubbles:!0,composed:!0,detail:r})),r}}parseTestResult(t,e,s){if(t==a)return{result:"",resultCategory:"none"};if(null==t){const t=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${t}" part="pre ${t}">${1==e?"Passed":"Failed"+(null!=s?`:\n${s.message}`:"")}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}if("boolean"==typeof t)return{result:t,resultCategory:1==t?"success":"fail"};if("function"==typeof t)return console.log("function"),{result:"[A function was returned]",resultCategory:"none"};if(t instanceof HTMLElement||"string"==typeof t)return{result:t,resultCategory:"none"};if("object"==typeof t){const s=t,n=1==e?"success-message":"error-message";if(null!=s.success&&null!=s.expected&&null!=s.value)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${1==s.success?"Passed":"Failed"}\nExpected:${s.expected}\nResult:${s.value}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};if(null!=s.success)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};{const s=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${s}" part="pre ${s}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}}throw new Error("Unable to parse result type: Unknown result type")}async createTestContext(t){const s={detail:{},codeTestsElement:this.codeTestsElement,testElement:t,messageElement:t?.findElement(".message")};return null!=this.codeTestsElement.state.contextHook&&await this.codeTestsElement.state.contextHook(s),this.codeTestsElement.dispatchEvent(new CustomEvent(e.Context,{bubbles:!0,composed:!0,detail:{context:s}})),s}}class r extends Promise{async toBeDefined(t){if(null==await(this))throw new Error(`${null!=t?t:"Value"} is undefined`)}async toBe(t,e=!1){const s=await(this);if(0==(1==e?s===t:s==t))throw new Error(` Value is not equal.\n Expected: ${t}\n Result: ${s}`)}async toContainText(t){const e=await(this);return e instanceof HTMLElement?{success:e.textContent.includes(t),index:e.textContent.indexOf(t)}:"string"==typeof e&&{success:e.includes(t),index:e.indexOf(t)}}async toHaveAttribute(t){const e=await(this);if(!(e instanceof HTMLElement))throw new Error("Unable to check for attribute on non-HTMLElement target");if(e.getAttribute(t))throw new Error("Target does not have attribute")}}const i=":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";function l(t){!function(t){const e=[...t.querySelectorAll(`${i}[id]`)];for(let t=0;t<e.length;t++)e[t].part.add(e[t].id)}(t),function(t){const e=[...t.querySelectorAll(`${i}[class]`)];for(let t=0;t<e.length;t++)e[t].part.add(...e[t].classList)}(t)}const c={BeforeAll:"beforeall",AfterAll:"afterall",BeforeEach:"beforeeach",AfterEach:"aftereach",RequiredBeforeAny:"requiredbeforeany",RequiredAfterAny:"requiredafterany",Reset:"reset",Context:"context"},u=new CSSStyleSheet;u.replaceSync(":host\n{\n --gap: 7px;\n --gap-small: 3px;\n --gap-medium: 14px;\n --gap-large: 24px;\n \n --surface-success: oklch(93.96% 0.05 148.74);\n --primary-success: oklch(58.83% 0.158 145.05);\n --border-success: solid 1px var(--primary-success);\n\n --surface-fail: oklch(88.98% 0.052 3.28);\n --primary-fail: oklch(45.8% 0.177 17.7);\n --border-fail: solid 1px var(--primary-fail);\n\n --surface-process: oklch(89.66% 0.046 260.67);\n --primary-process: oklch(43.48% 0.17 260.2);\n --border-process: solid 1px var(--primary-process);\n\n\n --surface-footer: rgb(0 0 0 / .04);\n \n --success-icon: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"%232e943a\" d=\"M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z\"/></svg>');\n --info-icon: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2022.812714%2022.814663%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20style%3D%22fill%3Atransparent%3Bstroke%3Atransparent%3Bstroke-width%3A0.999999%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dasharray%3Anone%3Bstroke-dashoffset%3A29.2913%3Bstroke-opacity%3A1%22%20d%3D%22M%2022.295505%2C11.407332%20A%2010.889144%2C10.889144%200%200%201%2011.406424%2C22.296479%2010.889144%2C10.889144%200%200%201%200.51720881%2C11.407332%2010.889144%2C10.889144%200%200%201%2011.406424%2C0.51818382%2010.889144%2C10.889144%200%200%201%2022.295505%2C11.407332%20Z%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22m%2013.945668%2C4.3053761%20c%200.150778%2C-0.96462%20-0.30687%2C-1.43709%20-1.36997%2C-1.43709%20-1.063%2C0%20-1.668452%2C0.47247%20-1.81923%2C1.43709%20-0.150779%2C0.96462%200.306971%2C1.43708%201.369971%2C1.43708%201.004%2C0%201.66845%2C-0.47246%201.819229%2C-1.43708%20z%20M%2011.693889%2C17.829726%2013.373994%2C7.0811161%20h%20-2.9333%20L%208.7605887%2C17.829726%20Z%22%20style%3D%22font-size%3A19.6861px%3Bfont-family%3APassageway%3B-inkscape-font-specification%3APassageway%3Bfill%3A%23a30d30%3Bstroke-width%3A2.5%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dashoffset%3A29.2913%22%20aria-label%3D%22i%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');\n\n\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n font-family: sans-serif;\n font-size: 12px;\n}\n@media (prefers-color-scheme: dark) \n{\n :host\n {\n --surface-footer: rgb(255 255 255 / .1);\n }\n}\n\n#header\n{\n flex: 1;\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\n#title\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n#tests\n,#component-content\n{\n display: grid;\n gap: var(--gap-small);\n grid-auto-rows: max-content;\n}\n\n#header button\n{\n align-self: stretch;\n display: inline-flex;\n align-items: center;\n gap: var(--gap-small);\n}\n\nbutton .reset-icon\n{\n width: 1em;\n height: 1em;\n transform: scaleX(-1);\n margin-inline: 3px;\n}\n\n/* Run button */\nbutton .arrow-icon\n{\n width: .75em;\n height: .75em;\n transform: rotate(-90deg);\n margin-inline: 3px;\n}\n:host(.running) .run-all-button-icon\n,:host(.fail) .run-all-button-icon\n{\n transform: rotate(0);\n}\n\n/* Dropdown Layout */\nsummary > .run-test-button\n, #run-all-button\n{\n justify-self: flex-end;\n margin-left: auto;\n}\n\nsummary:not(#component-summary)\n{\n padding: var(--gap-small);\n}\n#component-summary\n{\n padding: var(--gap) var(--gap-small);\n border-bottom: solid 1px;\n margin-bottom: var(--gap-small);\n}\n\n\n/* Dropdown Markers */\nsummary\n{\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\nsummary > .arrow-icon\n{\n background: var(--arrow-icon);\n transform: rotate(-90deg);\n transition: transform ease-out 90ms;\n width: .6em;\n height: .6em;\n}\ndetails[open] > summary > .arrow-icon\n{\n transform: rotate(0);\n}\n\n#enabled\n{\n display: none;\n}\n:host([optional]) #enabled\n{\n display: block;\n}\n\n/* Result Icon */\n.result-icon\n{\n --background-size: 16px;\n width: var(--background-size);\n height: var(--background-size);\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n border: solid 1px currentColor;\n border-radius: 50%;\n}\n.result-icon::before\n{\n content: '⋯';\n font-size: 10px;\n}\n\n:host(.running) #component-summary .result-icon\n,.test.running .test-summary > .result-icon\n,.hook.running .result-icon\n,.processing-details.running .processing-result-icon\n{\n border: var(--border-process);\n background: var(--surface-process);\n}\n:host(.success) #component-summary .result-icon\n,.test.success .test-summary > .result-icon\n,.hook.success .result-icon\n,.processing-details.success .processing-result-icon\n{\n border: var(--border-success);\n background: var(--surface-success)\n var(--success-icon);\n background-repeat: no-repeat;\n background-position: center;\n background-size: var(--icon-size, 12px) var(--icon-size, 12px);\n}\n:host(.fail) #component-summary .result-icon\n,.test.fail .test-summary > .result-icon\n,.hook.fail .result-icon\n,.processing-details.fail .processing-result-icon\n{\n border: var(--border-fail);\n background: var(--surface-fail)\n var(--info-icon);\n background-size: var(--icon-size, 16px) var(--icon-size, 16px);\n background-repeat: no-repeat;\n background-position: center;\n transform: rotate(175deg);\n}\n:host(:is(.success,.fail)) #component-summary .result-icon::before\n,.test:is(.success,.fail) .test-summary > .result-icon::before\n,.hook:is(.success,.fail) .result-icon::before\n,.processing-details:is(.success,.fail) .processing-result-icon::before\n{\n display: none;\n}\n:host(.running) #component-summary .result-icon::before\n,.test:is(.running) .test-summary > .result-icon::before\n,.hook:is(.running) .result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n content: '';\n --color: var(--primary-process, currentColor);\n --animation-timing-function: linear;\n --animation-duration: 2s;\n width: var(--icon-size, 14px);\n height: var(--icon-size, 14px);\n mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--icon-size, 14px) / 3), black calc(var(--icon-size, 14px) / 3));\n background-image: conic-gradient(transparent, transparent 135deg, var(--color));\n border-radius: 50%;\n animation: var(--animation-timing-function) var(--animation-duration) infinite spin;\n margin: 2px;\n}\n\n/* Smaller Result icon settings for sub-test icons */\n.before-each-result-icon\n,.after-each-result-icon\n,.processing-result-icon\n{\n --background-size: 12px;\n}\n.before-each-result-icon::before\n,.after-each-result-icon::before\n,.processing-result-icon::before\n{\n font-size: 9px;\n}\n.hook.success .before-each-result-icon\n,.hook.success .after-each-result-icon\n,.processing-details.success .processing-result-icon\n{\n --icon-size: 8px;\n}\n.hook.fail .before-each-result-icon\n,.hook.fail .after-each-result-icon\n,.processing-details.fail .processing-result-icon\n{\n --icon-size: 12px;\n}\n.hook:is(.running) .before-each-result-icon::before\n,.hook:is(.running) .after-each-result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n --icon-size: 9px;\n}\n\n/* Hook Display */\n.hook\n{\n display: none;\n}\n:host(.has-before-all-hook) #before-all-details\n,:host(.has-after-all-hook) #after-all-details\n{\n display: initial;\n}\n:host(.has-before-each-hook) .before-each-details\n,:host(.has-after-each-hook) .after-each-details\n{\n display: initial;\n}\n:host(.has-required-before-hook) #required-before-any-details\n,:host(.has-required-after-hook) #required-after-any-details\n{\n display: initial;\n}\n\n/* Test Display */\ncode-test .results\n{\n display: grid;\n gap: var(--gap-small);\n padding-inline-start: 1em;\n}\n\ncode-test .results details .result\n,.hook > .results\n{\n margin-inline-start: 1em;\n}\n\n.result.message:empty\n{\n padding: .5em 1em;\n}\n.result.message:empty::before\n{\n content: '[ this function has not been run ]';\n font-family: monospace;\n font-size: 12px;\n font-style: italic;\n}\n\n/* Ordered Display */\n#tests\n{\n counter-reset: tests;\n}\ncode-test\n{\n counter-increment: tests;\n}\ncode-test > details > summary > .description\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 0; /* hack to make overflow work right; \"contain: inline-size\" is correct fix, but it's too new to implement on jan 25, 2026; */\n}\n:host(:not([ordered=\"false\"])) code-test > details > summary > .description::before\n{\n content: counter(tests) \". \";\n}\n\n/* Hook Name */\n.hook-name,.processing-description\n{\n border-radius: 3px;\n border: solid 1px;\n font-family: monospace;\n text-transform: uppercase;\n font-size: 11px;\n padding: 3px 7px;\n}\n\n#footer\n{\n display: flex;\n justify-content: flex-end;\n border-top: solid 1px;\n border-bottom: solid 1px;\n background: var(--surface-footer);\n margin-top: var(--gap-small);\n}\n#group-results\n{\n display: flex;\n gap: var(--gap);\n padding: var(--gap);\n}\n\n#results-progress-value\n{\n min-width: 40px;\n width: auto;\n}\n\n#duration\n,#passed-total-pair\n,#passed-total-percent\n{\n white-space: nowrap;\n}\n\n#passed-total-percent::before\n{\n content: '(';\n}\n#passed-total-percent::after\n{\n content: ')';\n}\n\n@keyframes spin\n{\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}");const d="code-tests";class h extends HTMLElement{state={isCanceled:!1,beforeAllState:void 0,afterAllState:void 0,beforeEachState:void 0,afterEachState:void 0,requiredBeforeAnyState:void 0,requiredAfterAnyState:void 0,resetHook:void 0,contextHook:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.shadowRoot.querySelector(t)}findElements(t){return Array.from(this.shadowRoot.querySelectorAll(t))}getIsRunning(){return 1==(null!=this.findElements("code-test").find(t=>1==t.isRunning()))||1==this.state.requiredBeforeAnyState?.isRunning||1==this.state.requiredAfterAnyState?.isRunning||1==this.state.beforeAllState?.isRunning||1==this.state.afterAllState?.isRunning}getResultCategory(){const t=this.findElements("code-test").reduce((t,e,s)=>{const n=e.resultCategory();return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},""),e=[this.state.requiredBeforeAnyState,this.state.requiredAfterAnyState,this.state.beforeAllState,this.state.afterAllState].reduce((t,e,s)=>{if(null==e)return null;const n=e?.resultCategory;return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},"");return"none"==t&&null==e?"none":"fail"==t||"fail"==e?"fail":"success"==t||"success"==e?"success":"none"}#r;constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML='<details id="component-details" class="details">\n <summary id="component-summary" class="summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <slot name="header">\n <header id="header">\n <span id="component-result-icon" class="result-icon"></span>\n <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="reload-button">\n <button type="button" id="reload-button" title="Reload">\n <slot name="reload-button-content">\n <slot name="reload-button-icon"><svg class="icon reset-icon reload-button-icon"><use href="#icon-definition_reset"></use></svg></slot>\n <slot name="reload-button-label"><span class="reload-button-label button-label label icon">Reload</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="run-all-button">\n <button type="button" id="run-all-button" title="Run All Tests">\n <slot name="run-all-button-content">\n <slot name="run-all-button-icon"><svg class="icon arrow-icon run-button-icon run-all-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-all-button-label"><span class="run-all-button-label run-button-label button-label label icon">Run Tests</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="header-details"></slot>\n </header>\n </slot>\n </summary>\n <div id="component-content" class="content">\n <details id="required-before-any-details" class="hook">\n <summary id="required-before-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-before-any-result-icon" class="result-icon"></span>\n <span id="required-before-any-description" class="description hook-name">Required Before Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-before-any-results" class="result message"></div>\n </div>\n </details>\n <details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description hook-name">Before All Hook</span>\n </summary>\n <div class="results">\n <div id="before-all-results" class="result message"></div>\n </div>\n </details>\n <div id="tests"></div>\n <details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description hook-name">After All Hook</span>\n </summary>\n <div class="results">\n <div id="after-all-results" class="result message"></div>\n </div>\n </details>\n <details id="required-after-any-details" class="hook">\n <summary id="required-after-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-after-any-result-icon" class="result-icon"></span>\n <span id="required-after-any-description" class="description hook-name">Required After Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-after-any-results" class="result message"></div>\n </div>\n </details>\n </div>\n \n <slot name="footer">\n <foooter id="footer">\n <span id="group-results">\n <span id="duration">\n <span id="duration-label">Duration</span>\n <span id="duration-value">0</span>\n <span id="duration-unit">ms</span>\n </span>\n <span id="results-progress">\n <progress id="results-progress-value"></progress>\n </span>\n <span id="passed-total-pair">\n <span id="total-tests-passed-value"></span>\n <span id="passed-total-delimiter">of</span>\n <span id="total-tests-count-value"></span>\n <span id="total-tests-passed-label">Passed</span>\n </span>\n <span id="passed-total-percent">\n <span id="passed-total-percent-value">0</span>\n <span id="passed-total-percent-label">%</span>\n </span>\n </span>\n </foooter>\n </slot>\n</details>\n<template id="prompt-template">\n <div class="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>\n<div id="icon-definitions" style="display: none;">\n <svg id="icon-definition_arrow" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path d="m3.26,6.81l-2.93,-4.69c-0.37,-0.58 0.05,-1.34 0.74,-1.34l5.87,0c0.69,0 1.11,0.76 0.74,1.34l-2.93,4.69c-0.35,0.55 -1.14,0.55 -1.49,0z" fill="var(--fill-color, currentcolor)" />\n </svg>\n <svg id="icon-definition_reset" class="icon reset" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M 5.484375 0.43359375 A 1.5224222 1.5224222 0 0 0 4.2558594 1.2011719 L 0.99804688 6.9453125 A 1.5224222 1.5224222 0 0 0 2.5488281 9.2011719 L 9.34375 8.171875 A 1.5224222 1.5224222 0 0 0 10.332031 5.7539062 L 9.4746094 4.6113281 C 11.949333 3.8016718 14.718209 4.258351 16.822266 5.9570312 C 19.510764 8.1275534 20.456787 11.785479 19.160156 14.988281 C 17.863527 18.191083 14.6405 20.15873 11.199219 19.847656 C 7.7579362 19.536584 4.9376009 17.022073 4.2363281 13.638672 A 1.5 1.5 0 0 0 2.4628906 12.474609 A 1.5 1.5 0 0 0 1.2988281 14.248047 C 2.2656928 18.912838 6.1831413 22.407052 10.927734 22.835938 C 15.672328 23.264824 20.153706 20.531029 21.941406 16.115234 C 23.729107 11.699441 22.413741 6.6156073 18.707031 3.6230469 C 16.853677 2.1267667 14.61485 1.3255701 12.347656 1.2324219 C 10.738216 1.1662975 9.1150542 1.4598646 7.6035156 2.1132812 L 6.7988281 1.0390625 A 1.5224222 1.5224222 0 0 0 5.484375 0.43359375 z " />\n </svg>\n <svg id="icon-definition_cancel" class="icon cancel" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M -7.063234 9.5244002 C -5.8135728 7.6769245 -5.0820528 5.453265 -5.0820528 3.0633809 C -5.0820529 -3.3096433 -10.278145 -8.5098163 -16.65117 -8.5098163 C -23.024193 -8.5098163 -28.22385 -3.3110105 -28.22385 3.0620137 C -28.22385 9.4350379 -23.025043 14.634694 -16.65202 14.634694 C -12.668879 14.634694 -9.1460028 12.603526 -7.063234 9.5244002 z M -9.5406311 7.8637601 C -11.076991 10.143147 -13.683157 11.63463 -16.652974 11.63463 C -19.960499 11.63463 -22.814085 9.782061 -24.244824 7.0543029 L -24.236684 7.0527515 L -8.1332524 3.983715 L -8.1305391 3.9831979 C -8.2815631 5.4121635 -8.7798709 6.7350751 -9.5406311 7.8637601 z M -9.0610781 -0.92890828 L -9.069218 -0.92735695 L -25.17265 2.1416796 L -25.175363 2.1421967 C -24.719122 -2.1725739 -21.093311 -5.5092358 -16.652928 -5.5092358 C -13.345403 -5.5092358 -10.491243 -3.6566663 -9.0610781 -0.92890828 z "\n transform="rotate(-124.20981)" />\n </svg>\n</div>',this.shadowRoot.adoptedStyleSheets.push(u)}connectedCallback(){this.#i()}disconnectedCallback(){this.#l()}#c=!1;#u=!1;async#i(){1!=this.#c&&1!=this.#u&&(this.#c=!0,l(this.shadowRoot),this.addEventListener("click",this.#d),this.findElement("#enabled").addEventListener("change",this.#h),await new Promise(t=>requestAnimationFrame(()=>{this.#r=new o(this),this.#u=!0,this.#c=!1;if(0==this.dispatchEvent(new CustomEvent(e.Init,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}})))return void t();"false"!=this.getAttribute("auto")?(this.reloadTests(),t()):t()})))}#l(){this.removeEventListener("click",this.#d),this.findElement("#enabled").removeEventListener("change",this.#h),this.#u=!1,this.#c=!1}#d=this.#f.bind(this);#f(t){if(null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"run-all-button"==t.id))return void(this.classList.contains("running")?this.cancel():this.classList.contains("fail")||this.classList.contains("success")?this.reset():this.runTests());null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"reload-button"==t.id)&&this.reloadTests();const e=t.composedPath().find(t=>t instanceof HTMLButtonElement&&t.classList.contains("run-test-button"));if(null==e)return;const s=e.closest("code-test")??void 0;this.#r.runTest(s,!1)}#h=this.#p.bind(this);#p(t){const s=t.target;0==this.dispatchEvent(new CustomEvent(e.Enabled,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))&&(t.preventDefault(),t.stopPropagation(),s.checked=!s.checked)}#g(){return this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path")??void 0}#t(){const t=this.getIsRunning(),e=this.getResultCategory(),s=null!=this.state.beforeAllState,n=null!=this.state.beforeEachState,a=null!=this.state.requiredAfterAnyState,o=null!=this.state.beforeAllState,r=null!=this.state.beforeEachState,i=null!=this.state.requiredAfterAnyState,l=1==a||1==s||1==n,c=1==i||1==o||1==r;this.classList.toggle("canceled",this.state.isCanceled),this.part.toggle("canceled",this.state.isCanceled),this.classList.toggle("running",1==t),this.part.toggle("running",1==t),this.toggleAttribute("success","success"==e),this.classList.toggle("success","success"==e),this.part.toggle("success","success"==e),this.classList.toggle("fail","fail"==e),this.part.toggle("fail","fail"==e),this.classList.toggle("has-before-hook",l),this.part.toggle("has-before-hook",l),this.classList.toggle("has-after-hook",c),this.part.toggle("has-after-hook",c),this.classList.toggle("has-before-all-hook",s),this.part.toggle("has-before-all-hook",s),this.classList.toggle("has-after-all-hook",o),this.part.toggle("has-after-all-hook",o),this.classList.toggle("has-before-each-hook",n),this.part.toggle("has-before-each-hook",n),this.classList.toggle("has-after-each-hook",r),this.part.toggle("has-after-each-hook",r),this.classList.toggle("has-required-before-hook",a),this.part.toggle("has-required-before-hook",a),this.classList.toggle("has-required-after-hook",i),this.part.toggle("has-required-after-hook",i);const u=this.findElement(".run-all-button-label");null!=u&&(u.textContent=1==t?"Cancel":"fail"==e||"success"==e?"Reset":"Run Tests",u.title=1==t?"Cancel the testing":"fail"==e||"success"==e?"Reset the tests so they can be run again":"Run the tests");const d=this.findElement(".run-all-button-icon");null!=d&&(d.innerHTML=1==t?'<use href="#icon-definition_cancel"></use>':"fail"==e||"success"==e?'<use href="#icon-definition_reset"></use>':'<use href="#icon-definition_arrow"></use>'),this.#m(this.state.beforeAllState,"#before-all-results"),this.#m(this.state.afterAllState,"#after-all-results"),this.#m(this.state.requiredBeforeAnyState,"#required-before-any-results"),this.#m(this.state.requiredAfterAnyState,"#required-after-any-results");const h=this.findElement("#title");null!=h&&(h.textContent=this.getAttribute("label")??"Tests"),this.#b()}#m(t,e){const s=this.findElement(e);t?.resultContent instanceof HTMLElement?s.append(t.resultContent):"string"==typeof t?.resultContent&&(s.innerHTML=t.resultContent);const n=s.closest("details");n.toggleAttribute("open",null!=t&&"none"!=t.resultCategory),n.classList.toggle("running",1==t?.isRunning),n.part.toggle("running",1==t?.isRunning),n.toggleAttribute("success","success"==t?.resultCategory),n.classList.toggle("success","success"==t?.resultCategory),n.part.toggle("success","success"==t?.resultCategory),n.classList.toggle("fail","fail"==t?.resultCategory),n.part.toggle("fail","fail"==t?.resultCategory)}#b(){const t=this.collectTestResults(),e=this.findElement("#results-progress-value");null!=e&&(e.max=t.totalTests,e.value=t.totalPassed);const s=this.findElement("#total-tests-passed-value");null!=s&&(s.textContent=t.totalPassed.toString());const n=this.findElement("#total-tests-count-value");null!=n&&(n.textContent=t.totalTests.toString());const a=this.findElement("#passed-total-percent-value");null!=a&&(a.textContent=t.totalPercentage.toFixed(1));const o=this.findElement("#duration-value");null!=o&&(o.textContent=t.duration>10?t.duration.toFixed(0):t.duration.toFixed(2))}collectTestResults(){const t=this.findElements("code-test"),e=t.length,s=t.filter(t=>"success"==t.state.testState?.resultCategory).length;return{totalTests:e,totalPassed:s,totalPercentage:0==e?0:s/e*100,duration:t.reduce((t,e,s)=>t+(e.state.testState?.duration??0),0)}}async runTests(){const t=this.findElements("code-test");return this.#r.runTests(t)}async reloadTests(){this.findElement("#tests").innerHTML="",await this.reset();const t=this.#g();this.#r.loadTests(t)}async reset(){const t=this.findElements("code-test");for(let e=0;e<t.length;e++){const s=t[e],n=null!=this.state.beforeEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.beforeEachState.hasRun,isRunning:this.state.beforeEachState.isRunning,duration:0}:void 0,a=null!=this.state.afterEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.afterEachState.hasRun,isRunning:this.state.afterEachState.isRunning,duration:0}:void 0;null!=n&&(s.state.beforeEachState=n),null!=a&&(s.state.afterEachState=a),s.reset()}const s=null==this.state.beforeAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeAllState.test,isRunning:!1,hasRun:!1,duration:0},n=null==this.state.afterAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterAllState.test,isRunning:!1,hasRun:!1,duration:0},a=null==this.state.beforeEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeEachState.test,isRunning:!1,hasRun:!1,duration:0},o=null==this.state.afterEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterEachState.test,isRunning:!1,hasRun:!1,duration:0},r=null==this.state.requiredBeforeAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredBeforeAnyState.test,isRunning:!1,hasRun:!1,duration:0},i=null==this.state.requiredAfterAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredAfterAnyState.test,isRunning:!1,hasRun:!1,duration:0};this.setStateProperties({isCanceled:!1,beforeAllState:s,afterAllState:n,beforeEachState:a,afterEachState:o,requiredAfterAnyState:i,requiredBeforeAnyState:r}),this.#r.shouldContinueRunningTests=!0,null!=this.state.resetHook&&await this.state.resetHook(await this.#r.createTestContext()),this.dispatchEvent(new CustomEvent(e.Reset,{bubbles:!0,composed:!0}))}cancel(){this.state.isCanceled=!0,this.#r.shouldContinueRunningTests=!1,this.classList.add("canceled"),this.part.add("canceled"),this.dispatchEvent(new CustomEvent(e.Cancel,{bubbles:!0,composed:!0}))}static observedAttributes=["open","label"];attributeChangedCallback(t,e,s){if("open"==t)this.findElement("#component-details").toggleAttribute("open",null!=s);else if("label"==t){const t=this.findElement("#title");null!=t&&(t.textContent=s??"Tests")}}}function f(t,e){const s=t instanceof HTMLTemplateElement?t:document.querySelector(t);if(null==s)throw new Error(`Unable to find template element from selector: ${t}`);const n=s.content.cloneNode(!0).firstElementChild;if(null==n)throw new Error("Unable to find first child of template element");return e?.append(n),n}null==customElements.get(d)&&customElements.define(d,h),t.CodeTestElement=n,t.CodeTestEvent=e,t.CodeTestsElement=h,t.Hook=c,t.TestPromise=r,t.createElementFromTemplate=f,t.expect=function(t){return new r(async(e,s)=>{if(t instanceof Promise){return void e(await t)}e(t)})},t.prompt=async function(t,e,s,n){return new Promise((a,o)=>{const r=f(n?.template??t.querySelector(".prompt-template")??t.findElement("#prompt-template"));r.querySelector(".label").textContent=s;const i=t=>{const e=t.composedPath();if(null!=e.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("accept"))){const t=n?.onAccept?.()??!0;return r.removeEventListener("click",i),void a(t)}if(null!=e.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("reject"))){const t=n?.onReject?.()??!1;return r.removeEventListener("click",i),void a(t)}};r.addEventListener("click",i),null!=n?.acceptLabel&&(r.querySelector(".accept").textContent=n.acceptLabel),null!=n?.rejectLabel&&(r.querySelector(".reject").textContent=n.rejectLabel),e.append(r)})},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(((t="undefined"!=typeof globalThis?globalThis:t||self)["code-tests"]=t["code-tests"]||{},t["code-tests"].umd=t["code-tests"].umd||{},t["code-tests"].umd.min=t["code-tests"].umd.min||{},t["code-tests"].umd.min.js={}))}(this,function(t){"use strict";const e={BeforeAll:"beforeall",AfterAll:"afterall",BeforeTest:"beforetest",AfterTest:"aftertest",BeforeHook:"beforehook",AfterHook:"afterhook",Cancel:"cancel",Context:"context",Reset:"reset",TestEnd:"testend",Init:"init",Enabled:"enabled",PromptResult:"promptresult"},s="code-test";class n extends HTMLElement{state={testId:"",description:"none",isDisabled:!1,testState:void 0,beforeEachState:void 0,afterEachState:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.querySelector(t)}findElements(t){return Array.from(this.querySelectorAll(t))}isRunning(){return 1==this.state.testState?.isRunning||1==this.state.beforeEachState?.isRunning||1==this.state.afterEachState?.isRunning}hasRun(){return 1==this.state.testState?.hasRun||1==this.state.beforeEachState?.hasRun||1==this.state.afterEachState?.hasRun}resultCategory(){const t=this.state.testState?.resultCategory??"none",e=this.state.beforeEachState?.resultCategory??"none",s=this.state.afterEachState?.resultCategory??"none";return"none"==t&&"none"==e&&"none"==s?"none":null==this.state.beforeEachState&&null==this.state.afterEachState?t:null!=this.state.beforeEachState&&null==this.state.afterEachState?"fail"==t||"fail"==e?"fail":"success"==t&&"success"==e?"success":"none":null==this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==s?"fail":"success"==t&&"success"==s?"success":"none":null!=this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==e||"fail"==s?"fail":"success"==t&&"success"==e&&"success"==s?"success":"none":void 0}connectedCallback(){this.#t()}#t(){const t=null==this.state.testState?"":"boolean"==typeof this.state.testState.resultContent?1==this.state.testState.resultContent?'<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed</pre></code>':'<code class="code" part="code"><pre class="pre error-message" part="pre error-message">Failed</pre></code>':"number"==typeof this.state.testState.resultContent?`<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed: ${this.state.testState.resultContent.toString()}</pre></code>`:"string"==typeof this.state.testState.resultContent?this.state.testState.resultContent:"";this.innerHTML=`<details class="test-details" part="test-details" ${1==this.isRunning()||1==this.hasRun()?" open":""}>\n <summary class="test-summary" part="test-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="result-icon test-result-icon${"none"!=this.state.testState?.resultCategory?` ${this.state.testState?.resultCategory}`:""}" part="result-icon"></div>\n <span class="test-description description" title="${this.state.description}">${this.state.description}</span>\n ${null!=this.state.testState?.duration&&this.state.testState.duration>0?`<span class="test-duration duration">\n <span class="test-duration-value">${this.state.testState.duration>10?this.state.testState.duration.toFixed(0):this.state.testState.duration.toFixed(2)}</span>\n <span class="test-duration-unit">ms</span>\n </span>`:""}\n <button type="button" class="run-test-button" part="run-test-button" title="Run Test"${1==this.state.isDisabled?" disabled":""}>\n <slot name="run-button-content">\n <slot name="run-button-icon"><svg class="icon arrow-icon run-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-button-label"><span class="run-button-label button-label label icon">Run Test</span></slot>\n </slot>\n </button>\n </summary>\n <div class="results" part="results">\n ${null==this.state.beforeEachState?"":`<details class="before-each-details hook${"none"==this.state.beforeEachState.resultCategory?"":` ${this.state.beforeEachState.resultCategory}`}${1==this.state.beforeEachState.isRunning?" running":""}" part="before-each-details hook">\n <summary class="before-each-summary" part="before-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="before-each-result-icon result-icon${"none"!=this.state.beforeEachState.resultCategory?` ${this.state.beforeEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="before-each-description description hook-name">Before Each Hook</span>\n </summary>\n <div class="before-each-result result message" part="before-each-result result message">${"string"!=typeof this.state.beforeEachState.resultContent?"":this.state.beforeEachState.resultContent}</div>\n </details>`}\n ${null==this.state.testState?"":null==this.state.beforeEachState&&null==this.state.afterEachState?`<div class="test-result result message" part="test-result result message">${t}</div>`:`<details class="processing-details${"none"==this.state.testState.resultCategory?"":` ${this.state.testState.resultCategory}`}${1==this.state.testState.isRunning?" running":""}" part="processing-details"${1==this.state.testState.hasRun?" open":""}>\n <summary class="processing-summary" part="processing-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="processing-result-icon result-icon${"none"!=this.state.testState.resultCategory?` ${this.state.testState.resultCategory}`:""}" part="processing-result-icon result-icon"></div>\n <span class="processing-description description">Test</span>\n </summary>\n <div class="test-result result message" part="test-result result message">${t}</div>\n </details>`} \n ${null==this.state.afterEachState?"":`<details class="after-each-details hook${"none"==this.state.afterEachState.resultCategory?"":` ${this.state.afterEachState.resultCategory}`}${1==this.state.afterEachState.isRunning?" running":""}" part="after-each-detail hooks">\n <summary class="after-each-summary" part="after-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="after-each-result-icon result-icon${"none"!=this.state.afterEachState.resultCategory?` ${this.state.afterEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="after-each-description description hook-name">After Each Hook</span>\n </summary>\n <div class="after-each-result result message" part="after-each-result result message">${"string"!=typeof this.state.afterEachState.resultContent?"":this.state.afterEachState.resultContent}</div>\n </details>`}\n </div>\n </details>`,this.dataset.testId=this.state.testId,this.classList.add("test"),this.part.add("test"),this.toggleAttribute("success","success"==this.resultCategory()),this.classList.toggle("success","success"==this.resultCategory()),this.part.toggle("success","success"==this.resultCategory()),this.classList.toggle("fail","fail"==this.resultCategory()),this.part.toggle("fail","fail"==this.resultCategory()),this.classList.toggle("running",this.isRunning()),this.part.toggle("running",this.isRunning()),this.state.beforeEachState?.resultContent instanceof HTMLElement&&this.querySelector(".before-each-result").append(this.state.beforeEachState.resultContent),this.state.testState?.resultContent instanceof HTMLElement&&this.querySelector(".test-result").append(this.state.testState.resultContent),this.state.afterEachState?.resultContent instanceof HTMLElement&&this.querySelector(".after-each-result").append(this.state.afterEachState.resultContent)}enable(){this.state.isDisabled=!1,this.findElement(".run-test-button").toggleAttribute("disabled",!1)}disable(){this.state.isDisabled=!0,this.findElement(".run-test-button").toggleAttribute("disabled",!0)}async runTest(t,s){if(null==this.state.testState?.test)return;let n;this.reset();let a={},o=0;try{if(0==t.shouldContinueRunningTests)throw new Error("Tests have been disabled from continuing to run.");if(0==this.dispatchEvent(new CustomEvent(e.BeforeTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}})))throw new Error("Test has been prevented.");if(1==s.codeTestsElement.state.isCanceled)throw new Error("Testing has been canceled.");this.setTestStateProperties("testState",{isRunning:!0}),t.codeTestsElement.setState(t.codeTestsElement.state);const r=performance?.now()??Date.now();n=await this.state.testState.test(s);o=(performance?.now()??Date.now())-r,this.setTestStateProperties("testState",{isRunning:!1,hasRun:!0}),t.codeTestsElement.setState(t.codeTestsElement.state);const i=t.parseTestResult(n,!0);a={testState:{test:this.state.testState.test,resultContent:i.result,resultCategory:i.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:o}}}catch(e){const s=t.parseTestResult(n,!1,e);a={testState:{test:this.state.testState.test,resultContent:s.result,resultCategory:s.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:o}},console.error(e),t.shouldContinueRunningTests=!1}finally{this.setStateProperties({...a}),t.codeTestsElement.setState(t.codeTestsElement.state),this.dispatchEvent(new CustomEvent(e.AfterTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}}))}}reset(){const t=null!=this.state.testState?{resultCategory:"none",resultContent:"",test:this.state.testState.test,hasRun:this.state.testState.hasRun,isRunning:this.state.testState.isRunning,duration:0}:void 0;null!=t&&this.setTestStateProperties("testState",t)}getMessageElement(){return this.findElement(".test-result")}static observedAttributes=["open"];attributeChangedCallback(t,e,s){"open"==t&&this.findElement(".test-details").toggleAttribute("open",null!=s)}}null==customElements.get(s)&&customElements.define(s,n);const a=Symbol("No Test Defined");class o{codeTestsElement;constructor(t){this.codeTestsElement=t}async loadTests(t){if(null!=t)try{const{tests:e,hooks:s}=await this.#e(t),n=s[c.BeforeAll],a=s[c.AfterAll],o=s[c.BeforeEach],r=s[c.AfterEach],i=s[c.RequiredBeforeAny],l=s[c.RequiredAfterAny],u=null==n?void 0:{resultCategory:"none",resultContent:"",test:n,hasRun:!1,isRunning:!1,duration:0},d=null==a?void 0:{resultCategory:"none",resultContent:"",test:a,hasRun:!1,isRunning:!1,duration:0},h=null==o?void 0:{resultCategory:"none",resultContent:"",test:o,hasRun:!1,isRunning:!1,duration:0},f=null==r?void 0:{resultCategory:"none",resultContent:"",test:r,hasRun:!1,isRunning:!1,duration:0},p=null==i?void 0:{resultCategory:"none",resultContent:"",test:i,hasRun:!1,isRunning:!1,duration:0},g=null==l?void 0:{resultCategory:"none",resultContent:"",test:l,hasRun:!1,isRunning:!1,duration:0};this.codeTestsElement.state.beforeEachState=h,this.codeTestsElement.state.afterEachState=f;for(const[t,s]of Object.entries(e))this.#s(t,s);this.codeTestsElement.setStateProperties({beforeAllState:u,afterAllState:d,beforeEachState:h,afterEachState:f,requiredBeforeAnyState:p,requiredAfterAnyState:g,resetHook:s.reset,contextHook:s.context})}catch(t){console.error(t)}}async#e(t){const e=await this.#n(t),s=e.tests??e.default;if(null==s)throw new Error(`Unable to find tests definition in file at path: ${t}`);const n={},a=s[c.BeforeAll];null!=a&&(n[c.BeforeAll]=a,delete s[c.BeforeAll]);const o=s[c.AfterAll];null!=o&&(n[c.AfterAll]=o,delete s[c.AfterAll]);const r=s[c.BeforeEach];null!=r&&(n[c.BeforeEach]=r,delete s[c.BeforeEach]);const i=s[c.AfterEach];null!=i&&(n[c.AfterEach]=i,delete s[c.AfterEach]);const l=s[c.RequiredBeforeAny];null!=l&&(n[c.RequiredBeforeAny]=l,delete s[c.RequiredBeforeAny]);const u=s[c.RequiredAfterAny];null!=u&&(n[c.RequiredAfterAny]=u,delete s[c.RequiredAfterAny]);const d=s[c.Reset];null!=d&&(n[c.Reset]=d,delete s[c.Reset]);const h=s[c.Context];return null!=h&&(n[c.Context]=h,delete s[c.Context]),{tests:s,hooks:n}}async#n(t){const e=window.location.href.lastIndexOf("/"),s=1==(-1!=window.location.href.substring(e).indexOf("."))?window.location.href.substring(0,e+1):window.location.href,n=s+t.substring(0,t.lastIndexOf("/")+1),a=s+t;let o=await(await fetch(a)).text();o=o.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g,`'${n}$1'`);const r=new File([o],t.substring(t.lastIndexOf("/")),{type:"text/javascript"}),i=URL.createObjectURL(r);return await import(i)}#s(t,e){const s=function(){const t=new Uint8Array(20);crypto.getRandomValues(t);const e=[].slice.apply(t).map(function(t){return String.fromCharCode(t)}).join("");return btoa(e).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,"")}(),a=new n;return a.setStateProperties({testId:s,description:t,testState:{test:e,resultCategory:"none",resultContent:"",isRunning:!1,hasRun:!1,duration:0},beforeEachState:null==this.codeTestsElement.state.beforeEachState?void 0:{isRunning:this.codeTestsElement.state.beforeEachState.isRunning,hasRun:this.codeTestsElement.state.beforeEachState.hasRun,resultCategory:this.codeTestsElement.state.beforeEachState.resultCategory,resultContent:this.codeTestsElement.state.beforeEachState.resultContent,duration:0},afterEachState:null==this.codeTestsElement.state.afterEachState?void 0:{isRunning:this.codeTestsElement.state.afterEachState.isRunning,hasRun:this.codeTestsElement.state.afterEachState.hasRun,resultCategory:this.codeTestsElement.state.afterEachState.resultCategory,resultContent:this.codeTestsElement.state.afterEachState.resultContent,duration:0}}),this.codeTestsElement.findElement("#tests").append(a),s}shouldContinueRunningTests=!0;async runTests(t){if(0==this.codeTestsElement.dispatchEvent(new CustomEvent(e.BeforeAll,{bubbles:!0,composed:!0,cancelable:!0})))throw new Error("Tests have been prevented.");await this.codeTestsElement.reset();for(let e=0;e<t.length;e++)t[e].disable();const s=await this.createTestContext();if(await this.runHook("requiredBeforeAnyState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(t,s);if(await this.runHook("beforeAllState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(t,s);if(0==("false"!=this.codeTestsElement.getAttribute("ordered"))){const e=t.map(t=>this.runTest(t,!0,s));await Promise.all(e)}else for(let e=0;e<t.length;e++){const n=t[e];if(0==this.shouldContinueRunningTests)break;await this.runTest(n,!0,s)}0!=this.shouldContinueRunningTests?(await this.runHook("afterAllState",void 0,s),await this.#a(t,s)):await this.#a(t,s)}async#a(t,s){await this.runHook("requiredAfterAnyState",void 0,s);for(let e=0;e<t.length;e++)t[e].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(e.AfterAll,{bubbles:!0,composed:!0}))}async runTest(t,e,s){if(null!=t){if(0==e){const t=this.codeTestsElement.findElements("code-test");for(let e=0;e<t.length;e++)t[e].disable()}null==(s=s??await this.createTestContext(t)).testElement&&(s.testElement=t),0!=e||(await this.runHook("requiredBeforeAnyState",void 0,s),0!=this.shouldContinueRunningTests)?(await this.runHook("beforeEachState",t,s),0!=this.shouldContinueRunningTests?(await t.runTest(this,s),0!=this.shouldContinueRunningTests?(await this.runHook("afterEachState",t,s),await this.#o(s,e)):await this.#o(s,e)):await this.#o(s,e)):await this.#o(s,e)}}async#o(t,s){if(1==s)return;await this.runHook("requiredAfterAnyState",void 0,t);const n=this.codeTestsElement.findElements("code-test");for(let t=0;t<n.length;t++)n[t].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(e.TestEnd,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))}async runHook(t,s,n){const o=this.codeTestsElement.state[t];if(null==o)return a;if(1==this.codeTestsElement.state.isCanceled)return{success:!1,value:"Testing has been canceled."};let r;try{if(0==this.shouldContinueRunningTests&&("requiredAfterAnyState"!=t||"error"==this.codeTestsElement.getAttribute("required-after")))throw new Error("Tests have been disabled from continuing to run.");null!=s&&s.setTestStateProperties(t,{isRunning:!0}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!0}),r=await o.test(n),null!=s&&s.setTestStateProperties(t,{isRunning:!1,hasRun:!0}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!1,hasRun:!0});const e=this.parseTestResult(r,!0,void 0);null!=s&&s.setTestStateProperties(t,{resultCategory:e.resultCategory,resultContent:e.result}),this.codeTestsElement.setTestStateProperties(t,{resultCategory:e.resultCategory,resultContent:e.result})}catch(e){console.error(e),this.shouldContinueRunningTests=!1,r={success:!1,value:`Failed: ${e.message}`};const n=this.parseTestResult(r,!1,e);null!=s&&s.setTestStateProperties(t,{isRunning:!1,hasRun:!0,resultContent:n.result,resultCategory:n.resultCategory}),this.codeTestsElement.setTestStateProperties(t,{isRunning:!1,hasRun:!0,resultCategory:n.resultCategory,resultContent:n.result})}finally{return this.codeTestsElement.dispatchEvent(new CustomEvent(e.AfterHook,{bubbles:!0,composed:!0,detail:r})),r}}parseTestResult(t,e,s){if(t==a)return{result:"",resultCategory:"none"};if(null==t){const t=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${t}" part="pre ${t}">${1==e?"Passed":"Failed"+(null!=s?`:\n${s.message}`:"")}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}if("boolean"==typeof t)return{result:t,resultCategory:1==t?"success":"fail"};if("function"==typeof t)return console.log("function"),{result:"[A function was returned]",resultCategory:"none"};if(t instanceof HTMLElement||"string"==typeof t)return{result:t,resultCategory:"none"};if("object"==typeof t){const s=t,n=1==e?"success-message":"error-message";if(null!=s.success&&null!=s.expected&&null!=s.value)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${1==s.success?"Passed":"Failed"}\nExpected:${s.expected}\nResult:${s.value}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};if(null!=s.success)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};{const s=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${s}" part="pre ${s}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}}throw new Error("Unable to parse result type: Unknown result type")}async createTestContext(t){const s={detail:{},codeTestsElement:this.codeTestsElement,testElement:t,messageElement:t?.findElement(".message")};return null!=this.codeTestsElement.state.contextHook&&await this.codeTestsElement.state.contextHook(s),this.codeTestsElement.dispatchEvent(new CustomEvent(e.Context,{bubbles:!0,composed:!0,detail:{context:s}})),s}}class r extends Promise{async toBeDefined(t){if(null==await(this))throw new Error(`${null!=t?t:"Value"} is undefined`)}async toBe(t,e=!1){const s=await(this);if(0==(1==e?s===t:s==t))throw new Error(` Value is not equal.\n Expected: ${t}\n Result: ${s}`)}async toContainText(t){const e=await(this);return e instanceof HTMLElement?{success:e.textContent.includes(t),index:e.textContent.indexOf(t)}:"string"==typeof e&&{success:e.includes(t),index:e.indexOf(t)}}async toHaveAttribute(t){const e=await(this);if(!(e instanceof HTMLElement))throw new Error("Unable to check for attribute on non-HTMLElement target");if(e.getAttribute(t))throw new Error("Target does not have attribute")}}const i=":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";function l(t){!function(t){const e=[...t.querySelectorAll(`${i}[id]`)];for(let t=0;t<e.length;t++)e[t].part.add(e[t].id)}(t),function(t){const e=[...t.querySelectorAll(`${i}[class]`)];for(let t=0;t<e.length;t++)e[t].part.add(...e[t].classList)}(t)}const c={BeforeAll:"beforeall",AfterAll:"afterall",BeforeEach:"beforeeach",AfterEach:"aftereach",RequiredBeforeAny:"requiredbeforeany",RequiredAfterAny:"requiredafterany",Reset:"reset",Context:"context"},u=new CSSStyleSheet;u.replaceSync(":host\n{\n --gap: 7px;\n --gap-small: 3px;\n --gap-medium: 14px;\n --gap-large: 24px;\n \n --surface-success: oklch(93.96% 0.05 148.74);\n --primary-success: oklch(58.83% 0.158 145.05);\n --border-success: solid 1px var(--primary-success);\n\n --surface-fail: oklch(88.98% 0.052 3.28);\n --primary-fail: oklch(45.8% 0.177 17.7);\n --border-fail: solid 1px var(--primary-fail);\n\n --surface-process: oklch(89.66% 0.046 260.67);\n --primary-process: oklch(43.48% 0.17 260.2);\n --border-process: solid 1px var(--primary-process);\n\n\n --surface-footer: rgb(0 0 0 / .04);\n \n --success-icon: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"%232e943a\" d=\"M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z\"/></svg>');\n --info-icon: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2022.812714%2022.814663%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20style%3D%22fill%3Atransparent%3Bstroke%3Atransparent%3Bstroke-width%3A0.999999%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dasharray%3Anone%3Bstroke-dashoffset%3A29.2913%3Bstroke-opacity%3A1%22%20d%3D%22M%2022.295505%2C11.407332%20A%2010.889144%2C10.889144%200%200%201%2011.406424%2C22.296479%2010.889144%2C10.889144%200%200%201%200.51720881%2C11.407332%2010.889144%2C10.889144%200%200%201%2011.406424%2C0.51818382%2010.889144%2C10.889144%200%200%201%2022.295505%2C11.407332%20Z%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22m%2013.945668%2C4.3053761%20c%200.150778%2C-0.96462%20-0.30687%2C-1.43709%20-1.36997%2C-1.43709%20-1.063%2C0%20-1.668452%2C0.47247%20-1.81923%2C1.43709%20-0.150779%2C0.96462%200.306971%2C1.43708%201.369971%2C1.43708%201.004%2C0%201.66845%2C-0.47246%201.819229%2C-1.43708%20z%20M%2011.693889%2C17.829726%2013.373994%2C7.0811161%20h%20-2.9333%20L%208.7605887%2C17.829726%20Z%22%20style%3D%22font-size%3A19.6861px%3Bfont-family%3APassageway%3B-inkscape-font-specification%3APassageway%3Bfill%3A%23a30d30%3Bstroke-width%3A2.5%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dashoffset%3A29.2913%22%20aria-label%3D%22i%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');\n\n\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n font-family: sans-serif;\n font-size: 12px;\n}\n@media (prefers-color-scheme: dark) \n{\n :host\n {\n --surface-footer: rgb(255 255 255 / .1);\n }\n}\n\n#header\n{\n flex: 1;\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\n#title\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n#tests\n,#component-content\n{\n display: grid;\n gap: var(--gap-small);\n grid-auto-rows: max-content;\n}\n\n#header button\n{\n align-self: stretch;\n display: inline-flex;\n align-items: center;\n gap: var(--gap-small);\n}\n\nbutton .reset-icon\n{\n width: 1em;\n height: 1em;\n transform: scaleX(-1);\n margin-inline: 3px;\n}\n\n/* Run button */\nbutton .arrow-icon\n{\n width: .75em;\n height: .75em;\n transform: rotate(-90deg);\n margin-inline: 3px;\n}\n:host(.running) .run-all-button-icon\n,:host(.fail) .run-all-button-icon\n{\n transform: rotate(0);\n}\n\n/* Dropdown Layout */\nsummary > .run-test-button\n, #run-all-button\n{\n justify-self: flex-end;\n margin-left: auto;\n}\n\nsummary:not(#component-summary)\n{\n padding: var(--gap-small);\n}\n#component-summary\n{\n padding: var(--gap) var(--gap-small);\n border-bottom: solid 1px;\n margin-bottom: var(--gap-small);\n}\n\n\n/* Dropdown Markers */\nsummary\n{\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\nsummary > .arrow-icon\n{\n background: var(--arrow-icon);\n transform: rotate(-90deg);\n transition: transform ease-out 90ms;\n width: .6em;\n height: .6em;\n}\ndetails[open] > summary > .arrow-icon\n{\n transform: rotate(0);\n}\n\n#enabled\n{\n display: none;\n}\n:host([optional]) #enabled\n{\n display: block;\n}\n\n/* Result Icon */\n.result-icon\n{\n --background-size: 16px;\n width: var(--background-size);\n height: var(--background-size);\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n border: solid 1px currentColor;\n border-radius: 50%;\n}\n.result-icon::before\n{\n content: '⋯';\n font-size: 10px;\n}\n\n:host(.running) #component-summary .result-icon\n,.test.running .test-summary > .result-icon\n,.hook.running .result-icon\n,.processing-details.running .processing-result-icon\n{\n border: var(--border-process);\n background: var(--surface-process);\n}\n:host(.success) #component-summary .result-icon\n,.test.success .test-summary > .result-icon\n,.hook.success .result-icon\n,.processing-details.success .processing-result-icon\n{\n border: var(--border-success);\n background: var(--surface-success)\n var(--success-icon);\n background-repeat: no-repeat;\n background-position: center;\n background-size: var(--icon-size, 12px) var(--icon-size, 12px);\n}\n:host(.fail) #component-summary .result-icon\n,.test.fail .test-summary > .result-icon\n,.hook.fail .result-icon\n,.processing-details.fail .processing-result-icon\n{\n border: var(--border-fail);\n background: var(--surface-fail)\n var(--info-icon);\n background-size: var(--icon-size, 16px) var(--icon-size, 16px);\n background-repeat: no-repeat;\n background-position: center;\n transform: rotate(175deg);\n}\n:host(:is(.success,.fail)) #component-summary .result-icon::before\n,.test:is(.success,.fail) .test-summary > .result-icon::before\n,.hook:is(.success,.fail) .result-icon::before\n,.processing-details:is(.success,.fail) .processing-result-icon::before\n{\n display: none;\n}\n:host(.running) #component-summary .result-icon::before\n,.test:is(.running) .test-summary > .result-icon::before\n,.hook:is(.running) .result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n content: '';\n --color: var(--primary-process, currentColor);\n --animation-timing-function: linear;\n --animation-duration: 2s;\n width: var(--icon-size, 14px);\n height: var(--icon-size, 14px);\n mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--icon-size, 14px) / 3), black calc(var(--icon-size, 14px) / 3));\n background-image: conic-gradient(transparent, transparent 135deg, var(--color));\n border-radius: 50%;\n animation: var(--animation-timing-function) var(--animation-duration) infinite spin;\n margin: 2px;\n}\n\n/* Smaller Result icon settings for sub-test icons */\n.before-each-result-icon\n,.after-each-result-icon\n,.processing-result-icon\n{\n --background-size: 12px;\n}\n.before-each-result-icon::before\n,.after-each-result-icon::before\n,.processing-result-icon::before\n{\n font-size: 9px;\n}\n.hook.success .before-each-result-icon\n,.hook.success .after-each-result-icon\n,.processing-details.success .processing-result-icon\n{\n --icon-size: 8px;\n}\n.hook.fail .before-each-result-icon\n,.hook.fail .after-each-result-icon\n,.processing-details.fail .processing-result-icon\n{\n --icon-size: 12px;\n}\n.hook:is(.running) .before-each-result-icon::before\n,.hook:is(.running) .after-each-result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n --icon-size: 9px;\n}\n\n/* Hook Display */\n.hook\n{\n display: none;\n}\n:host(.has-before-all-hook) #before-all-details\n,:host(.has-after-all-hook) #after-all-details\n{\n display: initial;\n}\n:host(.has-before-each-hook) .before-each-details\n,:host(.has-after-each-hook) .after-each-details\n{\n display: initial;\n}\n:host(.has-required-before-hook) #required-before-any-details\n,:host(.has-required-after-hook) #required-after-any-details\n{\n display: initial;\n}\n\n/* Test Display */\ncode-test .results\n{\n display: grid;\n gap: var(--gap-small);\n padding-inline-start: 1em;\n}\n\ncode-test .results details .result\n,.hook > .results\n{\n margin-inline-start: 1em;\n}\n\n.result.message:empty\n{\n padding: .5em 1em;\n}\n.result.message:empty::before\n{\n content: '[ this function has not been run ]';\n font-family: monospace;\n font-size: 12px;\n font-style: italic;\n}\n\n/* Ordered Display */\n#tests\n{\n counter-reset: tests;\n}\ncode-test\n{\n counter-increment: tests;\n}\ncode-test > details > summary > .description\n{\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 0; /* hack to make overflow work right; \"contain: inline-size\" is correct fix, but it's too new to implement on jan 25, 2026; */\n}\n:host(:not([ordered=\"false\"])) code-test > details > summary > .description::before\n{\n content: counter(tests) \". \";\n}\n\n/* Hook Name */\n.hook-name,.processing-description\n{\n border-radius: 3px;\n border: solid 1px;\n font-family: monospace;\n text-transform: uppercase;\n font-size: 11px;\n padding: 3px 7px;\n}\n\n#footer\n{\n display: flex;\n justify-content: flex-end;\n border-top: solid 1px;\n border-bottom: solid 1px;\n background: var(--surface-footer);\n margin-top: var(--gap-small);\n}\n#group-results\n{\n display: flex;\n gap: var(--gap);\n padding: var(--gap);\n}\n\n#results-progress-value\n{\n min-width: 40px;\n width: auto;\n}\n\n#duration\n,#passed-total-pair\n,#passed-total-percent\n{\n white-space: nowrap;\n}\n\n#passed-total-percent::before\n{\n content: '(';\n}\n#passed-total-percent::after\n{\n content: ')';\n}\n\n@keyframes spin\n{\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}");const d="code-tests";class h extends HTMLElement{state={isCanceled:!1,beforeAllState:void 0,afterAllState:void 0,beforeEachState:void 0,afterEachState:void 0,requiredBeforeAnyState:void 0,requiredAfterAnyState:void 0,resetHook:void 0,contextHook:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.shadowRoot.querySelector(t)}findElements(t){return Array.from(this.shadowRoot.querySelectorAll(t))}getIsRunning(){return 1==(null!=this.findElements("code-test").find(t=>1==t.isRunning()))||1==this.state.requiredBeforeAnyState?.isRunning||1==this.state.requiredAfterAnyState?.isRunning||1==this.state.beforeAllState?.isRunning||1==this.state.afterAllState?.isRunning}getResultCategory(){const t=this.findElements("code-test").reduce((t,e,s)=>{const n=e.resultCategory();return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},""),e=[this.state.requiredBeforeAnyState,this.state.requiredAfterAnyState,this.state.beforeAllState,this.state.afterAllState].reduce((t,e,s)=>{if(null==e)return null;const n=e?.resultCategory;return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},"");return"none"==t&&null==e?"none":"fail"==t||"fail"==e?"fail":"success"==t||"success"==e?"success":"none"}#r;constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML='<details id="component-details" class="details">\n <summary id="component-summary" class="summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <slot name="header">\n <header id="header">\n <span id="component-result-icon" class="result-icon"></span>\n <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="reload-button">\n <button type="button" id="reload-button" title="Reload">\n <slot name="reload-button-content">\n <slot name="reload-button-icon"><svg class="icon reset-icon reload-button-icon"><use href="#icon-definition_reset"></use></svg></slot>\n <slot name="reload-button-label"><span class="reload-button-label button-label label icon">Reload</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="run-all-button">\n <button type="button" id="run-all-button" title="Run All Tests">\n <slot name="run-all-button-content">\n <slot name="run-all-button-icon"><svg class="icon arrow-icon run-button-icon run-all-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-all-button-label"><span class="run-all-button-label run-button-label button-label label icon">Run Tests</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="header-details"></slot>\n </header>\n </slot>\n </summary>\n <div id="component-content" class="content">\n <details id="required-before-any-details" class="hook">\n <summary id="required-before-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-before-any-result-icon" class="result-icon"></span>\n <span id="required-before-any-description" class="description hook-name">Required Before Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-before-any-results" class="result message"></div>\n </div>\n </details>\n <details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description hook-name">Before All Hook</span>\n </summary>\n <div class="results">\n <div id="before-all-results" class="result message"></div>\n </div>\n </details>\n <div id="tests"></div>\n <details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description hook-name">After All Hook</span>\n </summary>\n <div class="results">\n <div id="after-all-results" class="result message"></div>\n </div>\n </details>\n <details id="required-after-any-details" class="hook">\n <summary id="required-after-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-after-any-result-icon" class="result-icon"></span>\n <span id="required-after-any-description" class="description hook-name">Required After Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-after-any-results" class="result message"></div>\n </div>\n </details>\n </div>\n \n <slot name="footer">\n <foooter id="footer">\n <span id="group-results">\n <span id="duration">\n <span id="duration-label">Duration</span>\n <span id="duration-value">0</span>\n <span id="duration-unit">ms</span>\n </span>\n <span id="results-progress">\n <progress id="results-progress-value"></progress>\n </span>\n <span id="passed-total-pair">\n <span id="total-tests-passed-value"></span>\n <span id="passed-total-delimiter">of</span>\n <span id="total-tests-count-value"></span>\n <span id="total-tests-passed-label">Passed</span>\n </span>\n <span id="passed-total-percent">\n <span id="passed-total-percent-value">0</span>\n <span id="passed-total-percent-label">%</span>\n </span>\n </span>\n </foooter>\n </slot>\n</details>\n<template id="prompt-template">\n <div class="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>\n<div id="icon-definitions" style="display: none;">\n <svg id="icon-definition_arrow" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path d="m3.26,6.81l-2.93,-4.69c-0.37,-0.58 0.05,-1.34 0.74,-1.34l5.87,0c0.69,0 1.11,0.76 0.74,1.34l-2.93,4.69c-0.35,0.55 -1.14,0.55 -1.49,0z" fill="var(--fill-color, currentcolor)" />\n </svg>\n <svg id="icon-definition_reset" class="icon reset" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M 5.484375 0.43359375 A 1.5224222 1.5224222 0 0 0 4.2558594 1.2011719 L 0.99804688 6.9453125 A 1.5224222 1.5224222 0 0 0 2.5488281 9.2011719 L 9.34375 8.171875 A 1.5224222 1.5224222 0 0 0 10.332031 5.7539062 L 9.4746094 4.6113281 C 11.949333 3.8016718 14.718209 4.258351 16.822266 5.9570312 C 19.510764 8.1275534 20.456787 11.785479 19.160156 14.988281 C 17.863527 18.191083 14.6405 20.15873 11.199219 19.847656 C 7.7579362 19.536584 4.9376009 17.022073 4.2363281 13.638672 A 1.5 1.5 0 0 0 2.4628906 12.474609 A 1.5 1.5 0 0 0 1.2988281 14.248047 C 2.2656928 18.912838 6.1831413 22.407052 10.927734 22.835938 C 15.672328 23.264824 20.153706 20.531029 21.941406 16.115234 C 23.729107 11.699441 22.413741 6.6156073 18.707031 3.6230469 C 16.853677 2.1267667 14.61485 1.3255701 12.347656 1.2324219 C 10.738216 1.1662975 9.1150542 1.4598646 7.6035156 2.1132812 L 6.7988281 1.0390625 A 1.5224222 1.5224222 0 0 0 5.484375 0.43359375 z " />\n </svg>\n <svg id="icon-definition_cancel" class="icon cancel" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M -7.063234 9.5244002 C -5.8135728 7.6769245 -5.0820528 5.453265 -5.0820528 3.0633809 C -5.0820529 -3.3096433 -10.278145 -8.5098163 -16.65117 -8.5098163 C -23.024193 -8.5098163 -28.22385 -3.3110105 -28.22385 3.0620137 C -28.22385 9.4350379 -23.025043 14.634694 -16.65202 14.634694 C -12.668879 14.634694 -9.1460028 12.603526 -7.063234 9.5244002 z M -9.5406311 7.8637601 C -11.076991 10.143147 -13.683157 11.63463 -16.652974 11.63463 C -19.960499 11.63463 -22.814085 9.782061 -24.244824 7.0543029 L -24.236684 7.0527515 L -8.1332524 3.983715 L -8.1305391 3.9831979 C -8.2815631 5.4121635 -8.7798709 6.7350751 -9.5406311 7.8637601 z M -9.0610781 -0.92890828 L -9.069218 -0.92735695 L -25.17265 2.1416796 L -25.175363 2.1421967 C -24.719122 -2.1725739 -21.093311 -5.5092358 -16.652928 -5.5092358 C -13.345403 -5.5092358 -10.491243 -3.6566663 -9.0610781 -0.92890828 z "\n transform="rotate(-124.20981)" />\n </svg>\n</div>',this.shadowRoot.adoptedStyleSheets.push(u)}connectedCallback(){this.#i()}disconnectedCallback(){this.#l()}#c=!1;#u=!1;async#i(){1!=this.#c&&1!=this.#u&&(this.#c=!0,l(this.shadowRoot),this.addEventListener("click",this.#d),this.findElement("#enabled").addEventListener("change",this.#h),await new Promise(t=>requestAnimationFrame(()=>{this.#r=new o(this),this.#u=!0,this.#c=!1;if(0==this.dispatchEvent(new CustomEvent(e.Init,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}})))return void t();"false"!=this.getAttribute("auto")?(this.reloadTests(),t()):t()})))}#l(){this.removeEventListener("click",this.#d),this.findElement("#enabled").removeEventListener("change",this.#h),this.#u=!1,this.#c=!1}#d=this.#f.bind(this);#f(t){if(null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"run-all-button"==t.id))return void(this.classList.contains("running")?this.cancel():this.classList.contains("fail")||this.classList.contains("success")?this.reset():this.runTests());null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"reload-button"==t.id)&&this.reloadTests();const e=t.composedPath().find(t=>t instanceof HTMLButtonElement&&t.classList.contains("run-test-button"));if(null==e)return;const s=e.closest("code-test")??void 0;this.#r.runTest(s,!1)}#h=this.#p.bind(this);#p(t){const s=t.target;0==this.dispatchEvent(new CustomEvent(e.Enabled,{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}}))&&(t.preventDefault(),t.stopPropagation(),s.checked=!s.checked)}#g(){return this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path")??void 0}#t(){const t=this.getIsRunning(),e=this.getResultCategory(),s=null!=this.state.beforeAllState,n=null!=this.state.beforeEachState,a=null!=this.state.requiredAfterAnyState,o=null!=this.state.beforeAllState,r=null!=this.state.beforeEachState,i=null!=this.state.requiredAfterAnyState,l=1==a||1==s||1==n,c=1==i||1==o||1==r;this.classList.toggle("canceled",this.state.isCanceled),this.part.toggle("canceled",this.state.isCanceled),this.classList.toggle("running",1==t),this.part.toggle("running",1==t),this.toggleAttribute("success","success"==e),this.classList.toggle("success","success"==e),this.part.toggle("success","success"==e),this.classList.toggle("fail","fail"==e),this.part.toggle("fail","fail"==e),this.classList.toggle("has-before-hook",l),this.part.toggle("has-before-hook",l),this.classList.toggle("has-after-hook",c),this.part.toggle("has-after-hook",c),this.classList.toggle("has-before-all-hook",s),this.part.toggle("has-before-all-hook",s),this.classList.toggle("has-after-all-hook",o),this.part.toggle("has-after-all-hook",o),this.classList.toggle("has-before-each-hook",n),this.part.toggle("has-before-each-hook",n),this.classList.toggle("has-after-each-hook",r),this.part.toggle("has-after-each-hook",r),this.classList.toggle("has-required-before-hook",a),this.part.toggle("has-required-before-hook",a),this.classList.toggle("has-required-after-hook",i),this.part.toggle("has-required-after-hook",i);const u=this.findElement(".run-all-button-label");null!=u&&(u.textContent=1==t?"Cancel":"fail"==e||"success"==e?"Reset":"Run Tests",u.title=1==t?"Cancel the testing":"fail"==e||"success"==e?"Reset the tests so they can be run again":"Run the tests");const d=this.findElement(".run-all-button-icon");null!=d&&(d.innerHTML=1==t?'<use href="#icon-definition_cancel"></use>':"fail"==e||"success"==e?'<use href="#icon-definition_reset"></use>':'<use href="#icon-definition_arrow"></use>'),this.#m(this.state.beforeAllState,"#before-all-results"),this.#m(this.state.afterAllState,"#after-all-results"),this.#m(this.state.requiredBeforeAnyState,"#required-before-any-results"),this.#m(this.state.requiredAfterAnyState,"#required-after-any-results");const h=this.findElement("#title");null!=h&&(h.textContent=this.getAttribute("label")??"Tests"),this.#b()}#m(t,e){const s=this.findElement(e);t?.resultContent instanceof HTMLElement?s.append(t.resultContent):"string"==typeof t?.resultContent&&(s.innerHTML=t.resultContent);const n=s.closest("details");n.toggleAttribute("open",null!=t&&"none"!=t.resultCategory),n.classList.toggle("running",1==t?.isRunning),n.part.toggle("running",1==t?.isRunning),n.toggleAttribute("success","success"==t?.resultCategory),n.classList.toggle("success","success"==t?.resultCategory),n.part.toggle("success","success"==t?.resultCategory),n.classList.toggle("fail","fail"==t?.resultCategory),n.part.toggle("fail","fail"==t?.resultCategory)}#b(){const t=this.collectTestResults(),e=this.findElement("#results-progress-value");null!=e&&(e.max=t.totalTests,e.value=t.totalPassed);const s=this.findElement("#total-tests-passed-value");null!=s&&(s.textContent=t.totalPassed.toString());const n=this.findElement("#total-tests-count-value");null!=n&&(n.textContent=t.totalTests.toString());const a=this.findElement("#passed-total-percent-value");null!=a&&(a.textContent=t.totalPercentage.toFixed(1));const o=this.findElement("#duration-value");null!=o&&(o.textContent=t.duration>10?t.duration.toFixed(0):t.duration.toFixed(2))}collectTestResults(){const t=this.findElements("code-test"),e=t.length,s=t.filter(t=>"success"==t.state.testState?.resultCategory).length;return{totalTests:e,totalPassed:s,totalPercentage:0==e?0:s/e*100,duration:t.reduce((t,e,s)=>t+(e.state.testState?.duration??0),0)}}async runTests(){const t=this.findElements("code-test");return this.#r.runTests(t)}async reloadTests(){this.findElement("#tests").innerHTML="",await this.reset();const t=this.#g();this.#r.loadTests(t)}async reset(){const t=this.findElements("code-test");for(let e=0;e<t.length;e++){const s=t[e],n=null!=this.state.beforeEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.beforeEachState.hasRun,isRunning:this.state.beforeEachState.isRunning,duration:0}:void 0,a=null!=this.state.afterEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.afterEachState.hasRun,isRunning:this.state.afterEachState.isRunning,duration:0}:void 0;null!=n&&(s.state.beforeEachState=n),null!=a&&(s.state.afterEachState=a),s.reset()}const s=null==this.state.beforeAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeAllState.test,isRunning:!1,hasRun:!1,duration:0},n=null==this.state.afterAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterAllState.test,isRunning:!1,hasRun:!1,duration:0},a=null==this.state.beforeEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeEachState.test,isRunning:!1,hasRun:!1,duration:0},o=null==this.state.afterEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterEachState.test,isRunning:!1,hasRun:!1,duration:0},r=null==this.state.requiredBeforeAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredBeforeAnyState.test,isRunning:!1,hasRun:!1,duration:0},i=null==this.state.requiredAfterAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredAfterAnyState.test,isRunning:!1,hasRun:!1,duration:0};this.setStateProperties({isCanceled:!1,beforeAllState:s,afterAllState:n,beforeEachState:a,afterEachState:o,requiredAfterAnyState:i,requiredBeforeAnyState:r}),this.#r.shouldContinueRunningTests=!0,null!=this.state.resetHook&&await this.state.resetHook(await this.#r.createTestContext()),this.dispatchEvent(new CustomEvent(e.Reset,{bubbles:!0,composed:!0}))}cancel(){this.state.isCanceled=!0,this.#r.shouldContinueRunningTests=!1,this.classList.add("canceled"),this.part.add("canceled"),this.dispatchEvent(new CustomEvent(e.Cancel,{bubbles:!0,composed:!0}))}static observedAttributes=["open","label"];attributeChangedCallback(t,e,s){if("open"==t)this.findElement("#component-details").toggleAttribute("open",null!=s);else if("label"==t){const t=this.findElement("#title");null!=t&&(t.textContent=s??"Tests")}}}function f(t,e){const s=t instanceof HTMLTemplateElement?t:document.querySelector(t);if(null==s)throw new Error(`Unable to find template element from selector: ${t}`);const n=s.content.cloneNode(!0).firstElementChild;if(null==n)throw new Error("Unable to find first child of template element");return e?.append(n),n}null==customElements.get(d)&&customElements.define(d,h),t.CodeTestElement=n,t.CodeTestEvent=e,t.CodeTestsElement=h,t.Hook=c,t.TestPromise=r,t.createElementFromTemplate=f,t.expect=function(t){return new r(async(e,s)=>{if(t instanceof Promise){return void e(await t)}e(t)})},t.prompt=async function(t,s,n,a){let o=null;const r=await new Promise((e,r)=>{const i=a?.template??t.querySelector(".prompt-template")??t.findElement("#prompt-template");o=f(i),o.querySelector(".label").textContent=n;const l=t=>{const s=t.composedPath();if(null!=s.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("accept"))){const t=a?.onAccept?.()??!0;return o.removeEventListener("click",l),void e(t)}if(null!=s.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("reject"))){const t=a?.onReject?.()??!1;return o.removeEventListener("click",l),void e(t)}};o.addEventListener("click",l),null!=a?.acceptLabel&&(o.querySelector(".accept").textContent=a.acceptLabel),null!=a?.rejectLabel&&(o.querySelector(".reject").textContent=a.rejectLabel),s.append(o)});return null!=o&&o.remove(),t.dispatchEvent(new CustomEvent(e.PromptResult,{bubbles:!0,composed:!0,detail:{target:t,result:r}})),r},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magnit-ce/code-tests",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
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",