@magnit-ce/code-tests 0.0.20 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- const t={BeforeAll:"beforeall",AfterAll:"afterall",BeforeTest:"beforetest",AfterTest:"aftertest",BeforeHook:"beforehook",AfterHook:"afterhook",Cancel:"cancel",Context:"context",Reset:"reset"},e="code-test";class s extends HTMLElement{state={testId:"",description:"none",isDisabled:!1,testState:void 0,beforeEachState:void 0,afterEachState:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.querySelector(t)}findElements(t){return Array.from(this.querySelectorAll(t))}isRunning(){return 1==this.state.testState?.isRunning||1==this.state.beforeEachState?.isRunning||1==this.state.afterEachState?.isRunning}hasRun(){return 1==this.state.testState?.hasRun||1==this.state.beforeEachState?.hasRun||1==this.state.afterEachState?.hasRun}resultCategory(){const t=this.state.testState?.resultCategory??"none",e=this.state.beforeEachState?.resultCategory??"none",s=this.state.afterEachState?.resultCategory??"none";return"none"==t&&"none"==e&&"none"==s?"none":null==this.state.beforeEachState&&null==this.state.afterEachState?t:null!=this.state.beforeEachState&&null==this.state.afterEachState?"fail"==t||"fail"==e?"fail":"success"==t&&"success"==e?"success":"none":null==this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==s?"fail":"success"==t&&"success"==s?"success":"none":null!=this.state.beforeEachState&&null!=this.state.afterEachState?"fail"==t||"fail"==e||"fail"==s?"fail":"success"==t&&"success"==e&&"success"==s?"success":"none":void 0}connectedCallback(){this.#t()}#t(){const t=null==this.state.testState?"":"boolean"==typeof this.state.testState.resultContent?1==this.state.testState.resultContent?'<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed</pre></code>':'<code class="code" part="code"><pre class="pre error-message" part="pre error-message">Failed</pre></code>':"number"==typeof this.state.testState.resultContent?`<code class="code" part="code"><pre class="pre success-message" part="pre success-message">Passed: ${this.state.testState.resultContent.toString()}</pre></code>`:"string"==typeof this.state.testState.resultContent?this.state.testState.resultContent:"";this.innerHTML=`<details class="test-details" part="test-details" ${1==this.isRunning()||1==this.hasRun()?" open":""}>\n <summary class="test-summary" part="test-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="result-icon test-result-icon${"none"!=this.state.testState?.resultCategory?` ${this.state.testState?.resultCategory}`:""}" part="result-icon"></div>\n <span class="test-description description">${this.state.description}</span>\n ${null!=this.state.testState?.duration&&this.state.testState.duration>0?`<span class="test-duration duration">\n <span class="test-duration-value">${this.state.testState.duration>10?this.state.testState.duration.toFixed(0):this.state.testState.duration.toFixed(2)}</span>\n <span class="test-duration-unit">ms</span>\n </span>`:""}\n <button type="button" class="run-test-button" part="run-test-button" title="Run Test"${1==this.state.isDisabled?" disabled":""}>\n <slot name="run-button-content">\n <slot name="run-button-icon"><svg class="icon arrow-icon run-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-button-label"><span class="run-button-label button-label label icon">Run Test</span></slot>\n </slot>\n </button>\n </summary>\n <div class="results" part="results">\n ${null==this.state.beforeEachState?"":`<details class="before-each-details hook${"none"==this.state.beforeEachState.resultCategory?"":` ${this.state.beforeEachState.resultCategory}`}${1==this.state.beforeEachState.isRunning?" running":""}" part="before-each-details hook">\n <summary class="before-each-summary" part="before-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="before-each-result-icon result-icon${"none"!=this.state.beforeEachState.resultCategory?` ${this.state.beforeEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="before-each-description description hook-name">Before Each Hook</span>\n </summary>\n <div class="before-each-result result message" part="before-each-result result message">${"string"!=typeof this.state.beforeEachState.resultContent?"":this.state.beforeEachState.resultContent}</div>\n </details>`}\n ${null==this.state.testState?"":null==this.state.beforeEachState&&null==this.state.afterEachState?`<div class="test-result result message" part="test-result result message">${t}</div>`:`<details class="processing-details${"none"==this.state.testState.resultCategory?"":` ${this.state.testState.resultCategory}`}${1==this.state.testState.isRunning?" running":""}" part="processing-details"${1==this.state.testState.hasRun?" open":""}>\n <summary class="processing-summary" part="processing-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="processing-result-icon result-icon${"none"!=this.state.testState.resultCategory?` ${this.state.testState.resultCategory}`:""}" part="processing-result-icon result-icon"></div>\n <span class="processing-description description">Test</span>\n </summary>\n <div class="test-result result message" part="test-result result message">${t}</div>\n </details>`} \n ${null==this.state.afterEachState?"":`<details class="after-each-details hook${"none"==this.state.afterEachState.resultCategory?"":` ${this.state.afterEachState.resultCategory}`}${1==this.state.afterEachState.isRunning?" running":""}" part="after-each-detail hooks">\n <summary class="after-each-summary" part="after-each-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <div class="after-each-result-icon result-icon${"none"!=this.state.afterEachState.resultCategory?` ${this.state.afterEachState.resultCategory}`:""}" part="before-each-result-icon"></div>\n <span class="after-each-description description hook-name">After Each Hook</span>\n </summary>\n <div class="after-each-result result message" part="after-each-result result message">${"string"!=typeof this.state.afterEachState.resultContent?"":this.state.afterEachState.resultContent}</div>\n </details>`}\n </div>\n </details>`,this.dataset.testId=this.state.testId,this.classList.add("test"),this.part.add("test"),this.toggleAttribute("success","success"==this.resultCategory()),this.classList.toggle("success","success"==this.resultCategory()),this.part.toggle("success","success"==this.resultCategory()),this.classList.toggle("fail","fail"==this.resultCategory()),this.part.toggle("fail","fail"==this.resultCategory()),this.classList.toggle("running",this.isRunning()),this.part.toggle("running",this.isRunning()),this.state.beforeEachState?.resultContent instanceof HTMLElement&&this.querySelector(".before-each-result").append(this.state.beforeEachState.resultContent),this.state.testState?.resultContent instanceof HTMLElement&&this.querySelector(".test-result").append(this.state.testState.resultContent),this.state.afterEachState?.resultContent instanceof HTMLElement&&this.querySelector(".after-each-result").append(this.state.afterEachState.resultContent)}enable(){this.state.isDisabled=!1,this.findElement(".run-test-button").toggleAttribute("disabled",!1)}disable(){this.state.isDisabled=!0,this.findElement(".run-test-button").toggleAttribute("disabled",!0)}async runTest(e,s){if(null==this.state.testState?.test)return;let n;this.reset();let a={},r=0;try{if(0==e.shouldContinueRunningTests)throw new Error("Tests have been disabled from continuing to run.");if(0==this.dispatchEvent(new CustomEvent(t.BeforeTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}})))throw new Error("Test has been prevented.");if(1==s.codeTestsElement.state.isCanceled)throw new Error("Testing has been canceled.");this.setTestStateProperties("testState",{isRunning:!0}),e.codeTestsElement.setState(e.codeTestsElement.state);const o=performance?.now()??Date.now();n=await this.state.testState.test(s);r=(performance?.now()??Date.now())-o,this.setTestStateProperties("testState",{isRunning:!1,hasRun:!0}),e.codeTestsElement.setState(e.codeTestsElement.state);const i=e.parseTestResult(n,!0);a={testState:{test:this.state.testState.test,resultContent:i.result,resultCategory:i.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:r}}}catch(t){const s=e.parseTestResult(n,!1,t);a={testState:{test:this.state.testState.test,resultContent:s.result,resultCategory:s.resultCategory,hasRun:this.state.testState.hasRun,isRunning:!1,duration:r}},console.error(t),e.shouldContinueRunningTests=!1}finally{this.setStateProperties({...a}),e.codeTestsElement.setState(e.codeTestsElement.state),this.dispatchEvent(new CustomEvent(t.AfterTest,{bubbles:!0,cancelable:!0,composed:!0,detail:{testElement:this}}))}}reset(){const t=null!=this.state.testState?{resultCategory:"none",resultContent:"",test:this.state.testState.test,hasRun:this.state.testState.hasRun,isRunning:this.state.testState.isRunning,duration:0}:void 0;null!=t&&this.setTestStateProperties("testState",t)}getMessageElement(){return this.findElement(".test-result")}static observedAttributes=["open"];attributeChangedCallback(t,e,s){"open"==t&&this.findElement(".test-details").toggleAttribute("open",null!=s)}}null==customElements.get(e)&&customElements.define(e,s);const n=Symbol("No Test Defined");class a{codeTestsElement;constructor(t){this.codeTestsElement=t}async loadTests(t){if(null!=t)try{const{tests:e,hooks:s}=await this.#e(t),n=s[l.BeforeAll],a=s[l.AfterAll],r=s[l.BeforeEach],o=s[l.AfterEach],i=s[l.RequiredBeforeAny],c=s[l.RequiredAfterAny],u=null==n?void 0:{resultCategory:"none",resultContent:"",test:n,hasRun:!1,isRunning:!1,duration:0},d=null==a?void 0:{resultCategory:"none",resultContent:"",test:a,hasRun:!1,isRunning:!1,duration:0},h=null==r?void 0:{resultCategory:"none",resultContent:"",test:r,hasRun:!1,isRunning:!1,duration:0},f=null==o?void 0:{resultCategory:"none",resultContent:"",test:o,hasRun:!1,isRunning:!1,duration:0},p=null==i?void 0:{resultCategory:"none",resultContent:"",test:i,hasRun:!1,isRunning:!1,duration:0},g=null==c?void 0:{resultCategory:"none",resultContent:"",test:c,hasRun:!1,isRunning:!1,duration:0};this.codeTestsElement.state.beforeEachState=h,this.codeTestsElement.state.afterEachState=f;for(const[t,s]of Object.entries(e))this.#s(t,s);this.codeTestsElement.setStateProperties({beforeAllState:u,afterAllState:d,beforeEachState:h,afterEachState:f,requiredBeforeAnyState:p,requiredAfterAnyState:g,resetHook:s.reset,contextHook:s.context})}catch(t){console.error(t)}}async#e(t){const e=await this.#n(t),s=e.tests??e.default;if(null==s)throw new Error(`Unable to find tests definition in file at path: ${t}`);const n={},a=s[l.BeforeAll];null!=a&&(n[l.BeforeAll]=a,delete s[l.BeforeAll]);const r=s[l.AfterAll];null!=r&&(n[l.AfterAll]=r,delete s[l.AfterAll]);const o=s[l.BeforeEach];null!=o&&(n[l.BeforeEach]=o,delete s[l.BeforeEach]);const i=s[l.AfterEach];null!=i&&(n[l.AfterEach]=i,delete s[l.AfterEach]);const c=s[l.RequiredBeforeAny];null!=c&&(n[l.RequiredBeforeAny]=c,delete s[l.RequiredBeforeAny]);const u=s[l.RequiredAfterAny];null!=u&&(n[l.RequiredAfterAny]=u,delete s[l.RequiredAfterAny]);const d=s[l.Reset];null!=d&&(n[l.Reset]=d,delete s[l.Reset]);const h=s[l.Context];return null!=h&&(n[l.Context]=h,delete s[l.Context]),{tests:s,hooks:n}}async#n(t){const e=window.location.href.lastIndexOf("/"),s=1==(-1!=window.location.href.substring(e).indexOf("."))?window.location.href.substring(0,e+1):window.location.href,n=s+t.substring(0,t.lastIndexOf("/")+1),a=s+t;let r=await(await fetch(a)).text();r=r.replaceAll(/['"`](((\.\/)|(\.\.\/))+(.*))['"`]/g,`'${n}$1'`);const o=new File([r],t.substring(t.lastIndexOf("/")),{type:"text/javascript"}),i=URL.createObjectURL(o);return await import(i)}#s(t,e){const n=function(){const t=new Uint8Array(20);crypto.getRandomValues(t);const e=[].slice.apply(t).map(function(t){return String.fromCharCode(t)}).join("");return btoa(e).replace(/\//g,"_").replace(/\+/g,"-").replace(/=/g,"")}(),a=new s;return a.setStateProperties({testId:n,description:t,testState:{test:e,resultCategory:"none",resultContent:"",isRunning:!1,hasRun:!1,duration:0},beforeEachState:null==this.codeTestsElement.state.beforeEachState?void 0:{isRunning:this.codeTestsElement.state.beforeEachState.isRunning,hasRun:this.codeTestsElement.state.beforeEachState.hasRun,resultCategory:this.codeTestsElement.state.beforeEachState.resultCategory,resultContent:this.codeTestsElement.state.beforeEachState.resultContent,duration:0},afterEachState:null==this.codeTestsElement.state.afterEachState?void 0:{isRunning:this.codeTestsElement.state.afterEachState.isRunning,hasRun:this.codeTestsElement.state.afterEachState.hasRun,resultCategory:this.codeTestsElement.state.afterEachState.resultCategory,resultContent:this.codeTestsElement.state.afterEachState.resultContent,duration:0}}),this.codeTestsElement.findElement("#tests").append(a),n}shouldContinueRunningTests=!0;async runTests(e){if(0==this.codeTestsElement.dispatchEvent(new CustomEvent(t.BeforeAll,{bubbles:!0,composed:!0,cancelable:!0})))throw new Error("Tests have been prevented.");await this.codeTestsElement.reset();for(let t=0;t<e.length;t++)e[t].disable();const s=await this.createTestContext();if(await this.runHook("requiredBeforeAnyState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(e,s);if(await this.runHook("beforeAllState",void 0,s),0==this.shouldContinueRunningTests)return void await this.#a(e,s);if(0==("false"!=this.codeTestsElement.getAttribute("ordered"))){const t=e.map(t=>this.runTest(t,!0,s));await Promise.all(t)}else for(let t=0;t<e.length;t++){const n=e[t];if(0==this.shouldContinueRunningTests)break;await this.runTest(n,!0,s)}0!=this.shouldContinueRunningTests?(await this.runHook("afterAllState",void 0,s),await this.#a(e,s)):await this.#a(e,s)}async#a(e,s){await this.runHook("requiredAfterAnyState",void 0,s);for(let t=0;t<e.length;t++)e[t].enable();this.codeTestsElement.dispatchEvent(new CustomEvent(t.AfterAll,{bubbles:!0,composed:!0}))}async runTest(t,e,s){if(null!=t){if(0==e){const t=this.codeTestsElement.findElements("code-test");for(let e=0;e<t.length;e++)t[e].disable()}s=s??await this.createTestContext(t),0!=e||(await this.runHook("requiredBeforeAnyState",void 0,s),0!=this.shouldContinueRunningTests)?(await this.runHook("beforeEachState",t,s),0!=this.shouldContinueRunningTests?(await t.runTest(this,s),0!=this.shouldContinueRunningTests?(await this.runHook("afterEachState",t,s),await this.#r(s,e)):await this.#r(s,e)):await this.#r(s,e)):await this.#r(s,e)}}async#r(t,e){if(1==e)return;await this.runHook("requiredAfterAnyState",void 0,t);const s=this.codeTestsElement.findElements("code-test");for(let t=0;t<s.length;t++)s[t].enable()}async runHook(e,s,a){const r=this.codeTestsElement.state[e];if(null==r)return n;if(1==this.codeTestsElement.state.isCanceled)return{success:!1,value:"Testing has been canceled."};let o;try{if(0==this.shouldContinueRunningTests&&("requiredAfterAnyState"!=e||"error"==this.codeTestsElement.getAttribute("required-after")))throw new Error("Tests have been disabled from continuing to run.");null!=s&&s.setTestStateProperties(e,{isRunning:!0}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!0}),o=await r.test(a),null!=s&&s.setTestStateProperties(e,{isRunning:!1,hasRun:!0}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!1,hasRun:!0});const t=this.parseTestResult(o,!0,void 0);null!=s&&s.setTestStateProperties(e,{resultCategory:t.resultCategory,resultContent:t.result}),this.codeTestsElement.setTestStateProperties(e,{resultCategory:t.resultCategory,resultContent:t.result})}catch(t){console.error(t),this.shouldContinueRunningTests=!1,o={success:!1,value:`Failed: ${t.message}`};const n=this.parseTestResult(o,!1,t);null!=s&&s.setTestStateProperties(e,{isRunning:!1,hasRun:!0,resultContent:n.result,resultCategory:n.resultCategory}),this.codeTestsElement.setTestStateProperties(e,{isRunning:!1,hasRun:!0,resultCategory:n.resultCategory,resultContent:n.result})}finally{return this.codeTestsElement.dispatchEvent(new CustomEvent(t.AfterHook,{bubbles:!0,composed:!0,detail:o})),o}}parseTestResult(t,e,s){if(t==n)return{result:"",resultCategory:"none"};if(null==t){const t=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${t}" part="pre ${t}">${1==e?"Passed":"Failed"+(null!=s?`:\n${s.message}`:"")}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}if("boolean"==typeof t)return{result:t,resultCategory:1==t?"success":"fail"};if("function"==typeof t)return console.log("function"),{result:"[A function was returned]",resultCategory:"none"};if(t instanceof HTMLElement||"string"==typeof t)return{result:t,resultCategory:"none"};if("object"==typeof t){const s=t,n=1==e?"success-message":"error-message";if(null!=s.success&&null!=s.expected&&null!=s.value)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${1==s.success?"Passed":"Failed"}\nExpected:${s.expected}\nResult:${s.value}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};if(null!=s.success)return{result:`<code class="code" part="code">\n <pre class="pre ${n}" part="pre ${n}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==s.success?"success":"fail"};{const s=1==e?"success-message":"error-message";return{result:`<code class="code" part="code">\n <pre class="pre ${s}" part="pre ${s}">${JSON.stringify(t,void 0,2)}</pre>\n </code>`,resultCategory:1==e?"success":"fail"}}}throw new Error("Unable to parse result type: Unknown result type")}async createTestContext(e){const s={detail:{},codeTestsElement:this.codeTestsElement,testElement:e,messageElement:e?.findElement(".message")};return null!=this.codeTestsElement.state.contextHook&&await this.codeTestsElement.state.contextHook(s),this.codeTestsElement.dispatchEvent(new CustomEvent(t.Context,{bubbles:!0,composed:!0,detail:{context:s}})),s}}class r extends Promise{async toBeDefined(t){if(null==await(this))throw new Error(`${null!=t?t:"Value"} is undefined`)}async toBe(t,e=!1){const s=await(this);if(0==(1==e?s===t:s==t))throw new Error(` Value is not equal.\n Expected: ${t}\n Result: ${s}`)}async toContainText(t){const e=await(this);return e instanceof HTMLElement?{success:e.textContent.includes(t),index:e.textContent.indexOf(t)}:"string"==typeof e&&{success:e.includes(t),index:e.indexOf(t)}}async toHaveAttribute(t){const e=await(this);if(!(e instanceof HTMLElement))throw new Error("Unable to check for attribute on non-HTMLElement target");if(e.getAttribute(t))throw new Error("Target does not have attribute")}}const o=":not(slot,defs,g,rect,path,circle,ellipse,line,polygon,text,tspan,use,svg image,svg title,desc,template,template *)";function i(t){!function(t){const e=[...t.querySelectorAll(`${o}[id]`)];for(let t=0;t<e.length;t++)e[t].part.add(e[t].id)}(t),function(t){const e=[...t.querySelectorAll(`${o}[class]`)];for(let t=0;t<e.length;t++)e[t].part.add(...e[t].classList)}(t)}const l={BeforeAll:"beforeall",AfterAll:"afterall",BeforeEach:"beforeeach",AfterEach:"aftereach",RequiredBeforeAny:"requiredbeforeany",RequiredAfterAny:"requiredafterany",Reset:"reset",Context:"context"},c=new CSSStyleSheet;c.replaceSync(":host\n{\n --gap: 7px;\n --gap-small: 3px;\n --gap-medium: 14px;\n --gap-large: 24px;\n \n --surface-success: oklch(93.96% 0.05 148.74);\n --primary-success: oklch(58.83% 0.158 145.05);\n --border-success: solid 1px var(--primary-success);\n\n --surface-fail: oklch(88.98% 0.052 3.28);\n --primary-fail: oklch(45.8% 0.177 17.7);\n --border-fail: solid 1px var(--primary-fail);\n\n --surface-process: oklch(89.66% 0.046 260.67);\n --primary-process: oklch(43.48% 0.17 260.2);\n --border-process: solid 1px var(--primary-process);\n\n\n\n --surface-test-summary: var(--uchu-gray);\n --surface-hook-summary: var(--uchu-light-purple);\n --surface-hook-any-summary: var(--uchu-light-blue);\n \n --border-test: solid 1px var(--uchu-dark-gray);\n --border-hook: solid 1px var(--uchu-dark-purple);\n --border-hook-any: solid 1px var(--uchu-dark-blue);\n --border-button: solid 1px var(--uchu-blue);\n \n --success-icon: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"%232e943a\" d=\"M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z\"/></svg>');\n --info-icon: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2022.812714%2022.814663%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20style%3D%22fill%3Atransparent%3Bstroke%3Atransparent%3Bstroke-width%3A0.999999%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dasharray%3Anone%3Bstroke-dashoffset%3A29.2913%3Bstroke-opacity%3A1%22%20d%3D%22M%2022.295505%2C11.407332%20A%2010.889144%2C10.889144%200%200%201%2011.406424%2C22.296479%2010.889144%2C10.889144%200%200%201%200.51720881%2C11.407332%2010.889144%2C10.889144%200%200%201%2011.406424%2C0.51818382%2010.889144%2C10.889144%200%200%201%2022.295505%2C11.407332%20Z%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22m%2013.945668%2C4.3053761%20c%200.150778%2C-0.96462%20-0.30687%2C-1.43709%20-1.36997%2C-1.43709%20-1.063%2C0%20-1.668452%2C0.47247%20-1.81923%2C1.43709%20-0.150779%2C0.96462%200.306971%2C1.43708%201.369971%2C1.43708%201.004%2C0%201.66845%2C-0.47246%201.819229%2C-1.43708%20z%20M%2011.693889%2C17.829726%2013.373994%2C7.0811161%20h%20-2.9333%20L%208.7605887%2C17.829726%20Z%22%20style%3D%22font-size%3A19.6861px%3Bfont-family%3APassageway%3B-inkscape-font-specification%3APassageway%3Bfill%3A%23a30d30%3Bstroke-width%3A2.5%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dashoffset%3A29.2913%22%20aria-label%3D%22i%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');\n\n\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n font-family: sans-serif;\n font-size: 12px;\n}\n\n#header\n{\n flex: 1;\n display: flex;\n align-items: center;\n gap: var(--gap);\n padding: var(--gap-small) var(--gap);\n}\n#title\n{\n flex: 1;\n}\n\n#tests\n,#component-content\n{\n display: grid;\n gap: var(--gap);\n grid-auto-rows: max-content;\n}\n\n#header button\n{\n align-self: stretch;\n display: inline-flex;\n align-items: center;\n gap: var(--gap-small);\n}\n\nbutton .reset-icon\n{\n width: 1em;\n height: 1em;\n transform: scaleX(-1);\n margin-inline: 3px;\n}\n\n/* Run button */\nbutton .arrow-icon\n{\n width: .75em;\n height: .75em;\n transform: rotate(-90deg);\n margin-inline: 3px;\n}\n:host(.running) .run-all-button-icon\n,:host(.fail) .run-all-button-icon\n{\n transform: rotate(0);\n}\n\n/* Dropdown Layout */\nsummary > .run-test-button\n, #run-all-button\n{\n justify-self: flex-end;\n margin-left: auto;\n}\n\nsummary:not(#component-summary)\n{\n padding: var(--gap-small) var(--gap);\n}\n#component-summary\n{\n padding-block: var(--gap-small);\n}\n\n\n/* Dropdown Markers */\nsummary\n{\n display: flex;\n align-items: center;\n gap: var(--gap);\n}\nsummary > .arrow-icon\n{\n background: var(--arrow-icon);\n transform: rotate(-90deg);\n transition: transform ease-out 90ms;\n width: .6em;\n height: .6em;\n}\ndetails[open] > summary > .arrow-icon\n{\n transform: rotate(0);\n}\n\n/* Result Icon */\n.result-icon\n{\n --background-size: 16px;\n width: var(--background-size);\n height: var(--background-size);\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n border: solid 1px currentColor;\n border-radius: 50%;\n}\n.result-icon::before\n{\n content: '⋯';\n font-size: 10px;\n}\n\n:host(.running) #component-summary .result-icon\n,.test.running .test-summary > .result-icon\n,.hook.running .result-icon\n,.processing-details.running .processing-result-icon\n{\n border: var(--border-process);\n background: var(--surface-process);\n}\n:host(.success) #component-summary .result-icon\n,.test.success .test-summary > .result-icon\n,.hook.success .result-icon\n,.processing-details.success .processing-result-icon\n{\n border: var(--border-success);\n background: var(--surface-success)\n var(--success-icon);\n background-repeat: no-repeat;\n background-position: center;\n background-size: var(--icon-size, 12px) var(--icon-size, 12px);\n}\n:host(.fail) #component-summary .result-icon\n,.test.fail .test-summary > .result-icon\n,.hook.fail .result-icon\n,.processing-details.fail .processing-result-icon\n{\n border: var(--border-fail);\n background: var(--surface-fail)\n var(--info-icon);\n background-size: var(--icon-size, 16px) var(--icon-size, 16px);\n background-repeat: no-repeat;\n background-position: center;\n transform: rotate(175deg);\n}\n:host(:is(.success,.fail)) #component-summary .result-icon::before\n,.test:is(.success,.fail) .test-summary > .result-icon::before\n,.hook:is(.success,.fail) .result-icon::before\n,.processing-details:is(.success,.fail) .processing-result-icon::before\n{\n display: none;\n}\n:host(.running) #component-summary .result-icon::before\n,.test:is(.running) .test-summary > .result-icon::before\n,.hook:is(.running) .result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n content: '';\n --color: var(--primary-process, currentColor);\n --animation-timing-function: linear;\n --animation-duration: 2s;\n width: var(--icon-size, 14px);\n height: var(--icon-size, 14px);\n mask-image: radial-gradient(circle at 50% 50%, transparent calc(var(--icon-size, 14px) / 3), black calc(var(--icon-size, 14px) / 3));\n background-image: conic-gradient(transparent, transparent 135deg, var(--color));\n border-radius: 50%;\n animation: var(--animation-timing-function) var(--animation-duration) infinite spin;\n margin: 2px;\n}\n\n/* Smaller Result icon settings for sub-test icons */\n.before-each-result-icon\n,.after-each-result-icon\n,.processing-result-icon\n{\n --background-size: 12px;\n}\n.before-each-result-icon::before\n,.after-each-result-icon::before\n,.processing-result-icon::before\n{\n font-size: 9px;\n}\n.hook.success .before-each-result-icon\n,.hook.success .after-each-result-icon\n,.processing-details.success .processing-result-icon\n{\n --icon-size: 8px;\n}\n.hook.fail .before-each-result-icon\n,.hook.fail .after-each-result-icon\n,.processing-details.fail .processing-result-icon\n{\n --icon-size: 12px;\n}\n.hook:is(.running) .before-each-result-icon::before\n,.hook:is(.running) .after-each-result-icon::before\n,.processing-details:is(.running) .processing-result-icon::before\n{\n --icon-size: 9px;\n}\n\n/* Hook Display */\n.hook\n{\n display: none;\n}\n:host(.has-before-all-hook) #before-all-details\n,:host(.has-after-all-hook) #after-all-details\n{\n display: initial;\n}\n:host(.has-before-each-hook) .before-each-details\n,:host(.has-after-each-hook) .after-each-details\n{\n display: initial;\n}\n:host(.has-required-before-hook) #required-before-any-details\n,:host(.has-required-after-hook) #required-after-any-details\n{\n display: initial;\n}\n\n/* Test Display */\ncode-test .results\n{\n display: grid;\n gap: var(--gap-small);\n padding-inline-start: 1em;\n}\n\ncode-test .results details .result\n,.hook > .results\n{\n margin-inline-start: 1em;\n}\n\n.result.message:empty\n{\n padding: .5em 1em;\n}\n.result.message:empty::before\n{\n content: '[ this function has not been run ]';\n font-family: monospace;\n font-size: 12px;\n font-style: italic;\n}\n\n/* Ordered Display */\n#tests\n{\n counter-reset: tests;\n}\ncode-test\n{\n counter-increment: tests;\n}\ncode-test > details > summary > .description\n{\n flex: 1;\n}\n:host(:not([ordered=\"false\"])) code-test > details > summary > .description::before\n{\n content: counter(tests) \". \";\n}\n\n/* Hook Name */\n.hook-name,.processing-description\n{\n border-radius: 3px;\n border: solid 1px;\n /* background: rgb(0 0 0 / .2); */\n font-family: monospace;\n text-transform: uppercase;\n font-size: 11px;\n padding: 3px 7px;\n}\n\n#footer\n{\n display: flex;\n justify-content: flex-end;\n}\n#group-results\n{\n display: flex;\n gap: var(--gap);\n padding: var(--gap);\n}\n\n#passed-total-percent::before\n{\n content: '(';\n}\n#passed-total-percent::after\n{\n content: ')';\n}\n\n@keyframes spin\n{\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}");const u="code-tests";class d extends HTMLElement{state={isCanceled:!1,beforeAllState:void 0,afterAllState:void 0,beforeEachState:void 0,afterEachState:void 0,requiredBeforeAnyState:void 0,requiredAfterAnyState:void 0,resetHook:void 0,contextHook:void 0};setState(t){this.state=t,this.#t()}setStateProperties(t){this.setState({...this.state,...t})}setTestStateProperties(t,e){null!=this.state[t]&&this.setState({...this.state,[t]:{...this.state[t],...e}})}findElement(t){return this.shadowRoot.querySelector(t)}findElements(t){return Array.from(this.shadowRoot.querySelectorAll(t))}getIsRunning(){return 1==(null!=this.findElements("code-test").find(t=>1==t.isRunning()))||1==this.state.requiredBeforeAnyState?.isRunning||1==this.state.requiredAfterAnyState?.isRunning||1==this.state.beforeAllState?.isRunning||1==this.state.afterAllState?.isRunning}getResultCategory(){const t=this.findElements("code-test").reduce((t,e,s)=>{const n=e.resultCategory();return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},""),e=[this.state.requiredBeforeAnyState,this.state.requiredAfterAnyState,this.state.beforeAllState,this.state.afterAllState].reduce((t,e,s)=>{if(null==e)return null;const n=e?.resultCategory;return"fail"==t||"fail"==n?"fail":"success"!=t&&""!=t||"success"!=n?"none":"success"},"");return"none"==t&&null==e?"none":"fail"==t||"fail"==e?"fail":"success"==t&&"success"==e?"success":"none"}#o;constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML='<details id="component-details" class="details">\n <summary id="component-summary" class="summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <slot name="header">\n <header id="header">\n <span id="component-result-icon" class="result-icon"></span>\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="reload-button">\n <button type="button" id="reload-button" title="Reload">\n <slot name="reload-button-content">\n <slot name="reload-button-icon"><svg class="icon reset-icon reload-button-icon"><use href="#icon-definition_reset"></use></svg></slot>\n <slot name="reload-button-label"><span class="reload-button-label button-label label icon">Reload</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="run-all-button">\n <button type="button" id="run-all-button" title="Run All Tests">\n <slot name="run-all-button-content">\n <slot name="run-all-button-icon"><svg class="icon arrow-icon run-button-icon run-all-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-all-button-label"><span class="run-all-button-label run-button-label button-label label icon">Run Tests</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="header-details"></slot>\n </header>\n </slot>\n </summary>\n <div id="component-content" class="content">\n <details id="required-before-any-details" class="hook">\n <summary id="required-before-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-before-any-result-icon" class="result-icon"></span>\n <span id="required-before-any-description" class="description hook-name">Required Before Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-before-any-results" class="result message"></div>\n </div>\n </details>\n <details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description hook-name">Before All Hook</span>\n </summary>\n <div class="results">\n <div id="before-all-results" class="result message"></div>\n </div>\n </details>\n <div id="tests"></div>\n <details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description hook-name">After All Hook</span>\n </summary>\n <div class="results">\n <div id="after-all-results" class="result message"></div>\n </div>\n </details>\n <details id="required-after-any-details" class="hook">\n <summary id="required-after-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-after-any-result-icon" class="result-icon"></span>\n <span id="required-after-any-description" class="description hook-name">Required After Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-after-any-results" class="result message"></div>\n </div>\n </details>\n </div>\n \n <slot name="footer">\n <foooter id="footer">\n <span id="group-results">\n <span id="duration">\n <span id="duration-label">Duration</span>\n <span id="duration-value"></span>\n <span id="duration-unit">ms</span>\n </span>\n <span id="results-progress">\n <progress id="results-progress-value"></progress>\n </span>\n <span id="passed-total-pair">\n <span id="total-tests-passed-value"></span>\n <span id="passed-total-delimiter">of</span>\n <span id="total-tests-count-value"></span>\n <span id="total-tests-passed-label">Passed</span>\n </span>\n <span id="passed-total-percent">\n <span id="passed-total-percent-value"></span>\n <span id="passed-total-percent-label">%</span>\n </span>\n </span>\n </foooter>\n </slot>\n</details>\n<template id="prompt-template">\n <div class="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>\n<div id="icon-definitions" style="display: none;">\n <svg id="icon-definition_arrow" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path d="m3.26,6.81l-2.93,-4.69c-0.37,-0.58 0.05,-1.34 0.74,-1.34l5.87,0c0.69,0 1.11,0.76 0.74,1.34l-2.93,4.69c-0.35,0.55 -1.14,0.55 -1.49,0z" fill="var(--fill-color, currentcolor)" />\n </svg>\n <svg id="icon-definition_reset" class="icon reset" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M 5.484375 0.43359375 A 1.5224222 1.5224222 0 0 0 4.2558594 1.2011719 L 0.99804688 6.9453125 A 1.5224222 1.5224222 0 0 0 2.5488281 9.2011719 L 9.34375 8.171875 A 1.5224222 1.5224222 0 0 0 10.332031 5.7539062 L 9.4746094 4.6113281 C 11.949333 3.8016718 14.718209 4.258351 16.822266 5.9570312 C 19.510764 8.1275534 20.456787 11.785479 19.160156 14.988281 C 17.863527 18.191083 14.6405 20.15873 11.199219 19.847656 C 7.7579362 19.536584 4.9376009 17.022073 4.2363281 13.638672 A 1.5 1.5 0 0 0 2.4628906 12.474609 A 1.5 1.5 0 0 0 1.2988281 14.248047 C 2.2656928 18.912838 6.1831413 22.407052 10.927734 22.835938 C 15.672328 23.264824 20.153706 20.531029 21.941406 16.115234 C 23.729107 11.699441 22.413741 6.6156073 18.707031 3.6230469 C 16.853677 2.1267667 14.61485 1.3255701 12.347656 1.2324219 C 10.738216 1.1662975 9.1150542 1.4598646 7.6035156 2.1132812 L 6.7988281 1.0390625 A 1.5224222 1.5224222 0 0 0 5.484375 0.43359375 z " />\n </svg>\n <svg id="icon-definition_cancel" class="icon cancel" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M -7.063234 9.5244002 C -5.8135728 7.6769245 -5.0820528 5.453265 -5.0820528 3.0633809 C -5.0820529 -3.3096433 -10.278145 -8.5098163 -16.65117 -8.5098163 C -23.024193 -8.5098163 -28.22385 -3.3110105 -28.22385 3.0620137 C -28.22385 9.4350379 -23.025043 14.634694 -16.65202 14.634694 C -12.668879 14.634694 -9.1460028 12.603526 -7.063234 9.5244002 z M -9.5406311 7.8637601 C -11.076991 10.143147 -13.683157 11.63463 -16.652974 11.63463 C -19.960499 11.63463 -22.814085 9.782061 -24.244824 7.0543029 L -24.236684 7.0527515 L -8.1332524 3.983715 L -8.1305391 3.9831979 C -8.2815631 5.4121635 -8.7798709 6.7350751 -9.5406311 7.8637601 z M -9.0610781 -0.92890828 L -9.069218 -0.92735695 L -25.17265 2.1416796 L -25.175363 2.1421967 C -24.719122 -2.1725739 -21.093311 -5.5092358 -16.652928 -5.5092358 C -13.345403 -5.5092358 -10.491243 -3.6566663 -9.0610781 -0.92890828 z "\n transform="rotate(-124.20981)" />\n </svg>\n</div>',this.shadowRoot.adoptedStyleSheets.push(c)}connectedCallback(){this.#i()}disconnectedCallback(){this.#l()}#c=!1;#u=!1;async#i(){1!=this.#c&&1!=this.#u&&(this.#c=!0,i(this.shadowRoot),this.addEventListener("click",this.#d),await new Promise(t=>requestAnimationFrame(()=>{this.#o=new a(this),this.#u=!0,this.#c=!1;if(0==this.dispatchEvent(new CustomEvent("init",{bubbles:!0,composed:!0,cancelable:!0,detail:{target:this}})))return void t();"false"!=this.getAttribute("auto")?(this.reloadTests(),t()):t()})))}#l(){this.removeEventListener("click",this.#d),this.#u=!1,this.#c=!1}#d=this.#h.bind(this);#h(t){if(null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"run-all-button"==t.id))return void(this.classList.contains("running")?this.cancel():this.classList.contains("fail")||this.classList.contains("success")?this.reset():this.runTests());null!=t.composedPath().find(t=>t instanceof HTMLButtonElement&&"reload-button"==t.id)&&this.reloadTests();const e=t.composedPath().find(t=>t instanceof HTMLButtonElement&&t.classList.contains("run-test-button"));if(null==e)return;const s=e.closest("code-test")??void 0;this.#o.runTest(s,!1)}#f(){return this.getAttribute("src")??this.getAttribute("test")??this.getAttribute("tests")??this.getAttribute("run")??this.getAttribute("path")??void 0}#t(){const t=this.getIsRunning(),e=this.getResultCategory(),s=null!=this.state.beforeAllState,n=null!=this.state.beforeEachState,a=null!=this.state.requiredAfterAnyState,r=null!=this.state.beforeAllState,o=null!=this.state.beforeEachState,i=null!=this.state.requiredAfterAnyState,l=1==a||1==s||1==n,c=1==i||1==r||1==o;this.classList.toggle("canceled",this.state.isCanceled),this.part.toggle("canceled",this.state.isCanceled),this.classList.toggle("running",1==t),this.part.toggle("running",1==t),this.toggleAttribute("success","success"==e),this.classList.toggle("success","success"==e),this.part.toggle("success","success"==e),this.classList.toggle("fail","fail"==e),this.part.toggle("fail","fail"==e),this.classList.toggle("has-before-hook",l),this.part.toggle("has-before-hook",l),this.classList.toggle("has-after-hook",c),this.part.toggle("has-after-hook",c),this.classList.toggle("has-before-all-hook",s),this.part.toggle("has-before-all-hook",s),this.classList.toggle("has-after-all-hook",r),this.part.toggle("has-after-all-hook",r),this.classList.toggle("has-before-each-hook",n),this.part.toggle("has-before-each-hook",n),this.classList.toggle("has-after-each-hook",o),this.part.toggle("has-after-each-hook",o),this.classList.toggle("has-required-before-hook",a),this.part.toggle("has-required-before-hook",a),this.classList.toggle("has-required-after-hook",i),this.part.toggle("has-required-after-hook",i);const u=this.findElement(".run-all-button-label");null!=u&&(u.textContent=1==t?"Cancel":"fail"==e?"Reset":"Run Tests",u.title=1==t?"Cancel the testing":"fail"==e?"Reset the tests so they can be run again":"Run the tests");const d=this.findElement(".run-all-button-icon");null!=d&&(d.innerHTML=1==t?'<use href="#icon-definition_cancel"></use>':"fail"==e?'<use href="#icon-definition_reset"></use>':'<use href="#icon-definition_arrow"></use>'),this.#p(this.state.beforeAllState,"#before-all-results"),this.#p(this.state.afterAllState,"#after-all-results"),this.#p(this.state.requiredBeforeAnyState,"#required-before-any-results"),this.#p(this.state.requiredAfterAnyState,"#required-after-any-results");const h=this.findElement("#title");null!=h&&(h.textContent=this.getAttribute("label")??"Tests"),this.#g()}#p(t,e){const s=this.findElement(e);t?.resultContent instanceof HTMLElement?s.append(t.resultContent):"string"==typeof t?.resultContent&&(s.innerHTML=t.resultContent);const n=s.closest("details");n.toggleAttribute("open",null!=t&&"none"!=t.resultCategory),n.classList.toggle("running",1==t?.isRunning),n.part.toggle("running",1==t?.isRunning),n.toggleAttribute("success","success"==t?.resultCategory),n.classList.toggle("success","success"==t?.resultCategory),n.part.toggle("success","success"==t?.resultCategory),n.classList.toggle("fail","fail"==t?.resultCategory),n.part.toggle("fail","fail"==t?.resultCategory)}#g(){const t=this.collectTestResults(),e=this.findElement("#results-progress-value");null!=e&&(e.max=t.totalTests,e.value=t.totalPassed);const s=this.findElement("#total-tests-passed-value");null!=s&&(s.textContent=t.totalPassed.toString());const n=this.findElement("#total-tests-count-value");null!=n&&(n.textContent=t.totalTests.toString());const a=this.findElement("#passed-total-percent-value");null!=a&&(a.textContent=t.totalPercentage.toFixed(1));const r=this.findElement("#duration-value");null!=r&&(r.textContent=t.duration>10?t.duration.toFixed(0):t.duration.toFixed(2))}collectTestResults(){const t=this.findElements("code-test"),e=t.length,s=t.filter(t=>"success"==t.state.testState?.resultCategory).length;return{totalTests:e,totalPassed:s,totalPercentage:0==e?0:s/e*100,duration:t.reduce((t,e,s)=>t+(e.state.testState?.duration??0),0)}}async runTests(){const t=this.findElements("code-test");return this.#o.runTests(t)}async reloadTests(){this.findElement("#tests").innerHTML="",await this.reset();const t=this.#f();this.#o.loadTests(t)}async reset(){const e=this.findElements("code-test");for(let t=0;t<e.length;t++){const s=e[t],n=null!=this.state.beforeEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.beforeEachState.hasRun,isRunning:this.state.beforeEachState.isRunning,duration:0}:void 0,a=null!=this.state.afterEachState?{resultCategory:"none",resultContent:"",hasRun:this.state.afterEachState.hasRun,isRunning:this.state.afterEachState.isRunning,duration:0}:void 0;null!=n&&(s.state.beforeEachState=n),null!=a&&(s.state.afterEachState=a),s.reset()}const s=null==this.state.beforeAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeAllState.test,isRunning:!1,hasRun:!1,duration:0},n=null==this.state.afterAllState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterAllState.test,isRunning:!1,hasRun:!1,duration:0},a=null==this.state.beforeEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.beforeEachState.test,isRunning:!1,hasRun:!1,duration:0},r=null==this.state.afterEachState?void 0:{resultContent:"",resultCategory:"none",test:this.state.afterEachState.test,isRunning:!1,hasRun:!1,duration:0},o=null==this.state.requiredBeforeAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredBeforeAnyState.test,isRunning:!1,hasRun:!1,duration:0},i=null==this.state.requiredAfterAnyState?void 0:{resultContent:"",resultCategory:"none",test:this.state.requiredAfterAnyState.test,isRunning:!1,hasRun:!1,duration:0};this.setStateProperties({isCanceled:!1,beforeAllState:s,afterAllState:n,beforeEachState:a,afterEachState:r,requiredAfterAnyState:i,requiredBeforeAnyState:o}),this.#o.shouldContinueRunningTests=!0,null!=this.state.resetHook&&await this.state.resetHook(await this.#o.createTestContext()),this.dispatchEvent(new CustomEvent(t.Reset,{bubbles:!0,composed:!0}))}cancel(){this.state.isCanceled=!0,this.#o.shouldContinueRunningTests=!1,this.classList.add("canceled"),this.part.add("canceled"),this.dispatchEvent(new CustomEvent(t.Cancel,{bubbles:!0,composed:!0}))}static observedAttributes=["open","label"];attributeChangedCallback(t,e,s){if("open"==t)this.findElement("#component-details").toggleAttribute("open",null!=s);else if("label"==t){const t=this.findElement("#title");null!=t&&(t.textContent=s??"Tests")}}}function h(t){return new r(async(e,s)=>{if(t instanceof Promise){return void e(await t)}e(t)})}async function f(t,e,s,n){return new Promise((a,r)=>{const o=p(n?.template??t.querySelector(".prompt-template")??t.findElement("#prompt-template"));o.querySelector(".label").textContent=s;const i=t=>{const e=t.composedPath();if(null!=e.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("accept"))){const t=n?.onAccept?.()??!0;return o.removeEventListener("click",i),void a(t)}if(null!=e.find(t=>t instanceof HTMLButtonElement&&t.classList.contains("reject"))){const t=n?.onReject?.()??!1;return o.removeEventListener("click",i),void a(t)}};o.addEventListener("click",i),null!=n?.acceptLabel&&(o.querySelector(".accept").textContent=n.acceptLabel),null!=n?.rejectLabel&&(o.querySelector(".reject").textContent=n.rejectLabel),e.append(o)})}function p(t,e){const s=t instanceof HTMLTemplateElement?t:document.querySelector(t);if(null==s)throw new Error(`Unable to find template element from selector: ${t}`);const n=s.content.cloneNode(!0).firstElementChild;if(null==n)throw new Error("Unable to find first child of template element");return e?.append(n),n}null==customElements.get(u)&&customElements.define(u,d);export{s as CodeTestElement,t as CodeTestEvent,d as CodeTestsElement,l as Hook,r as TestPromise,p as createElementFromTemplate,h as expect,f as prompt};
1
+ const t={BeforeAll:"beforeall",AfterAll:"afterall",BeforeTest:"beforetest",AfterTest:"aftertest",BeforeHook:"beforehook",AfterHook:"afterhook",Cancel:"cancel",Context:"context",Reset:"reset",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};
@@ -22,15 +22,7 @@
22
22
  --border-process: solid 1px var(--primary-process);
23
23
 
24
24
 
25
-
26
- --surface-test-summary: var(--uchu-gray);
27
- --surface-hook-summary: var(--uchu-light-purple);
28
- --surface-hook-any-summary: var(--uchu-light-blue);
29
-
30
- --border-test: solid 1px var(--uchu-dark-gray);
31
- --border-hook: solid 1px var(--uchu-dark-purple);
32
- --border-hook-any: solid 1px var(--uchu-dark-blue);
33
- --border-button: solid 1px var(--uchu-blue);
25
+ --surface-footer: rgb(0 0 0 / .04);
34
26
 
35
27
  --success-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="%232e943a" d="M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z"/></svg>');
36
28
  --info-icon: url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2022.812714%2022.814663%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20style%3D%22fill%3Atransparent%3Bstroke%3Atransparent%3Bstroke-width%3A0.999999%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dasharray%3Anone%3Bstroke-dashoffset%3A29.2913%3Bstroke-opacity%3A1%22%20d%3D%22M%2022.295505%2C11.407332%20A%2010.889144%2C10.889144%200%200%201%2011.406424%2C22.296479%2010.889144%2C10.889144%200%200%201%200.51720881%2C11.407332%2010.889144%2C10.889144%200%200%201%2011.406424%2C0.51818382%2010.889144%2C10.889144%200%200%201%2022.295505%2C11.407332%20Z%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22m%2013.945668%2C4.3053761%20c%200.150778%2C-0.96462%20-0.30687%2C-1.43709%20-1.36997%2C-1.43709%20-1.063%2C0%20-1.668452%2C0.47247%20-1.81923%2C1.43709%20-0.150779%2C0.96462%200.306971%2C1.43708%201.369971%2C1.43708%201.004%2C0%201.66845%2C-0.47246%201.819229%2C-1.43708%20z%20M%2011.693889%2C17.829726%2013.373994%2C7.0811161%20h%20-2.9333%20L%208.7605887%2C17.829726%20Z%22%20style%3D%22font-size%3A19.6861px%3Bfont-family%3APassageway%3B-inkscape-font-specification%3APassageway%3Bfill%3A%23a30d30%3Bstroke-width%3A2.5%3Bstroke-linejoin%3Around%3Bstroke-miterlimit%3A6.3%3Bstroke-dashoffset%3A29.2913%22%20aria-label%3D%22i%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');
@@ -42,6 +34,13 @@
42
34
  font-family: sans-serif;
43
35
  font-size: 12px;
44
36
  }
37
+ @media (prefers-color-scheme: dark)
38
+ {
39
+ :host
40
+ {
41
+ --surface-footer: rgb(255 255 255 / .1);
42
+ }
43
+ }
45
44
 
46
45
  #header
47
46
  {
@@ -49,18 +48,20 @@
49
48
  display: flex;
50
49
  align-items: center;
51
50
  gap: var(--gap);
52
- padding: var(--gap-small) var(--gap);
53
51
  }
54
52
  #title
55
53
  {
56
54
  flex: 1;
55
+ white-space: nowrap;
56
+ overflow: hidden;
57
+ text-overflow: ellipsis;
57
58
  }
58
59
 
59
60
  #tests
60
61
  ,#component-content
61
62
  {
62
63
  display: grid;
63
- gap: var(--gap);
64
+ gap: var(--gap-small);
64
65
  grid-auto-rows: max-content;
65
66
  }
66
67
 
@@ -104,11 +105,13 @@ summary > .run-test-button
104
105
 
105
106
  summary:not(#component-summary)
106
107
  {
107
- padding: var(--gap-small) var(--gap);
108
+ padding: var(--gap-small);
108
109
  }
109
110
  #component-summary
110
111
  {
111
- padding-block: var(--gap-small);
112
+ padding: var(--gap) var(--gap-small);
113
+ border-bottom: solid 1px;
114
+ margin-bottom: var(--gap-small);
112
115
  }
113
116
 
114
117
 
@@ -132,6 +135,15 @@ details[open] > summary > .arrow-icon
132
135
  transform: rotate(0);
133
136
  }
134
137
 
138
+ #enabled
139
+ {
140
+ display: none;
141
+ }
142
+ :host([optional]) #enabled
143
+ {
144
+ display: block;
145
+ }
146
+
135
147
  /* Result Icon */
136
148
  .result-icon
137
149
  {
@@ -301,6 +313,10 @@ code-test
301
313
  code-test > details > summary > .description
302
314
  {
303
315
  flex: 1;
316
+ white-space: nowrap;
317
+ overflow: hidden;
318
+ text-overflow: ellipsis;
319
+ width: 0; /* hack to make overflow work right; "contain: inline-size" is correct fix, but it's too new to implement on jan 25, 2026; */
304
320
  }
305
321
  :host(:not([ordered="false"])) code-test > details > summary > .description::before
306
322
  {
@@ -312,7 +328,6 @@ code-test > details > summary > .description
312
328
  {
313
329
  border-radius: 3px;
314
330
  border: solid 1px;
315
- /* background: rgb(0 0 0 / .2); */
316
331
  font-family: monospace;
317
332
  text-transform: uppercase;
318
333
  font-size: 11px;
@@ -323,6 +338,10 @@ code-test > details > summary > .description
323
338
  {
324
339
  display: flex;
325
340
  justify-content: flex-end;
341
+ border-top: solid 1px;
342
+ border-bottom: solid 1px;
343
+ background: var(--surface-footer);
344
+ margin-top: var(--gap-small);
326
345
  }
327
346
  #group-results
328
347
  {
@@ -331,6 +350,19 @@ code-test > details > summary > .description
331
350
  padding: var(--gap);
332
351
  }
333
352
 
353
+ #results-progress-value
354
+ {
355
+ min-width: 40px;
356
+ width: auto;
357
+ }
358
+
359
+ #duration
360
+ ,#passed-total-pair
361
+ ,#passed-total-percent
362
+ {
363
+ white-space: nowrap;
364
+ }
365
+
334
366
  #passed-total-percent::before
335
367
  {
336
368
  content: '(';
@@ -345,7 +377,7 @@ code-test > details > summary > .description
345
377
  from { transform: rotate(0deg); }
346
378
  to { transform: rotate(360deg); }
347
379
  }`;
348
- const html = '<details id="component-details" class="details">\n <summary id="component-summary" class="summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <slot name="header">\n <header id="header">\n <span id="component-result-icon" class="result-icon"></span>\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="reload-button">\n <button type="button" id="reload-button" title="Reload">\n <slot name="reload-button-content">\n <slot name="reload-button-icon"><svg class="icon reset-icon reload-button-icon"><use href="#icon-definition_reset"></use></svg></slot>\n <slot name="reload-button-label"><span class="reload-button-label button-label label icon">Reload</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="run-all-button">\n <button type="button" id="run-all-button" title="Run All Tests">\n <slot name="run-all-button-content">\n <slot name="run-all-button-icon"><svg class="icon arrow-icon run-button-icon run-all-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-all-button-label"><span class="run-all-button-label run-button-label button-label label icon">Run Tests</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="header-details"></slot>\n </header>\n </slot>\n </summary>\n <div id="component-content" class="content">\n <details id="required-before-any-details" class="hook">\n <summary id="required-before-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-before-any-result-icon" class="result-icon"></span>\n <span id="required-before-any-description" class="description hook-name">Required Before Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-before-any-results" class="result message"></div>\n </div>\n </details>\n <details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description hook-name">Before All Hook</span>\n </summary>\n <div class="results">\n <div id="before-all-results" class="result message"></div>\n </div>\n </details>\n <div id="tests"></div>\n <details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description hook-name">After All Hook</span>\n </summary>\n <div class="results">\n <div id="after-all-results" class="result message"></div>\n </div>\n </details>\n <details id="required-after-any-details" class="hook">\n <summary id="required-after-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-after-any-result-icon" class="result-icon"></span>\n <span id="required-after-any-description" class="description hook-name">Required After Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-after-any-results" class="result message"></div>\n </div>\n </details>\n </div>\n \n <slot name="footer">\n <foooter id="footer">\n <span id="group-results">\n <span id="duration">\n <span id="duration-label">Duration</span>\n <span id="duration-value"></span>\n <span id="duration-unit">ms</span>\n </span>\n <span id="results-progress">\n <progress id="results-progress-value"></progress>\n </span>\n <span id="passed-total-pair">\n <span id="total-tests-passed-value"></span>\n <span id="passed-total-delimiter">of</span>\n <span id="total-tests-count-value"></span>\n <span id="total-tests-passed-label">Passed</span>\n </span>\n <span id="passed-total-percent">\n <span id="passed-total-percent-value"></span>\n <span id="passed-total-percent-label">%</span>\n </span>\n </span>\n </foooter>\n </slot>\n</details>\n<template id="prompt-template">\n <div class="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>\n<div id="icon-definitions" style="display: none;">\n <svg id="icon-definition_arrow" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path d="m3.26,6.81l-2.93,-4.69c-0.37,-0.58 0.05,-1.34 0.74,-1.34l5.87,0c0.69,0 1.11,0.76 0.74,1.34l-2.93,4.69c-0.35,0.55 -1.14,0.55 -1.49,0z" fill="var(--fill-color, currentcolor)" />\n </svg>\n <svg id="icon-definition_reset" class="icon reset" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M 5.484375 0.43359375 A 1.5224222 1.5224222 0 0 0 4.2558594 1.2011719 L 0.99804688 6.9453125 A 1.5224222 1.5224222 0 0 0 2.5488281 9.2011719 L 9.34375 8.171875 A 1.5224222 1.5224222 0 0 0 10.332031 5.7539062 L 9.4746094 4.6113281 C 11.949333 3.8016718 14.718209 4.258351 16.822266 5.9570312 C 19.510764 8.1275534 20.456787 11.785479 19.160156 14.988281 C 17.863527 18.191083 14.6405 20.15873 11.199219 19.847656 C 7.7579362 19.536584 4.9376009 17.022073 4.2363281 13.638672 A 1.5 1.5 0 0 0 2.4628906 12.474609 A 1.5 1.5 0 0 0 1.2988281 14.248047 C 2.2656928 18.912838 6.1831413 22.407052 10.927734 22.835938 C 15.672328 23.264824 20.153706 20.531029 21.941406 16.115234 C 23.729107 11.699441 22.413741 6.6156073 18.707031 3.6230469 C 16.853677 2.1267667 14.61485 1.3255701 12.347656 1.2324219 C 10.738216 1.1662975 9.1150542 1.4598646 7.6035156 2.1132812 L 6.7988281 1.0390625 A 1.5224222 1.5224222 0 0 0 5.484375 0.43359375 z " />\n </svg>\n <svg id="icon-definition_cancel" class="icon cancel" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M -7.063234 9.5244002 C -5.8135728 7.6769245 -5.0820528 5.453265 -5.0820528 3.0633809 C -5.0820529 -3.3096433 -10.278145 -8.5098163 -16.65117 -8.5098163 C -23.024193 -8.5098163 -28.22385 -3.3110105 -28.22385 3.0620137 C -28.22385 9.4350379 -23.025043 14.634694 -16.65202 14.634694 C -12.668879 14.634694 -9.1460028 12.603526 -7.063234 9.5244002 z M -9.5406311 7.8637601 C -11.076991 10.143147 -13.683157 11.63463 -16.652974 11.63463 C -19.960499 11.63463 -22.814085 9.782061 -24.244824 7.0543029 L -24.236684 7.0527515 L -8.1332524 3.983715 L -8.1305391 3.9831979 C -8.2815631 5.4121635 -8.7798709 6.7350751 -9.5406311 7.8637601 z M -9.0610781 -0.92890828 L -9.069218 -0.92735695 L -25.17265 2.1416796 L -25.175363 2.1421967 C -24.719122 -2.1725739 -21.093311 -5.5092358 -16.652928 -5.5092358 C -13.345403 -5.5092358 -10.491243 -3.6566663 -9.0610781 -0.92890828 z "\n transform="rotate(-124.20981)" />\n </svg>\n</div>';
380
+ const html = '<details id="component-details" class="details">\n <summary id="component-summary" class="summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <slot name="header">\n <header id="header">\n <span id="component-result-icon" class="result-icon"></span>\n <slot name="enabled-toggle">\n <input type="checkbox" name="enabled" id="enabled" title="Enabled?" checked />\n </slot>\n <span id="title"><slot name="title"><span id="title-text">Tests</span></slot></span>\n <slot name="reload-button">\n <button type="button" id="reload-button" title="Reload">\n <slot name="reload-button-content">\n <slot name="reload-button-icon"><svg class="icon reset-icon reload-button-icon"><use href="#icon-definition_reset"></use></svg></slot>\n <slot name="reload-button-label"><span class="reload-button-label button-label label icon">Reload</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="run-all-button">\n <button type="button" id="run-all-button" title="Run All Tests">\n <slot name="run-all-button-content">\n <slot name="run-all-button-icon"><svg class="icon arrow-icon run-button-icon run-all-button-icon"><use href="#icon-definition_arrow"></use></svg></slot>\n <slot name="run-all-button-label"><span class="run-all-button-label run-button-label button-label label icon">Run Tests</span></slot>\n </slot>\n </button>\n </slot>\n <slot name="header-details"></slot>\n </header>\n </slot>\n </summary>\n <div id="component-content" class="content">\n <details id="required-before-any-details" class="hook">\n <summary id="required-before-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-before-any-result-icon" class="result-icon"></span>\n <span id="required-before-any-description" class="description hook-name">Required Before Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-before-any-results" class="result message"></div>\n </div>\n </details>\n <details id="before-all-details" class="hook">\n <summary id="before-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="before-all-result-icon" class="result-icon"></span>\n <span id="before-all-description" class="description hook-name">Before All Hook</span>\n </summary>\n <div class="results">\n <div id="before-all-results" class="result message"></div>\n </div>\n </details>\n <div id="tests"></div>\n <details id="after-all-details" class="hook">\n <summary id="after-all-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="after-all-result-icon" class="result-icon"></span>\n <span id="after-all-description" class="description hook-name">After All Hook</span>\n </summary>\n <div class="results">\n <div id="after-all-results" class="result message"></div>\n </div>\n </details>\n <details id="required-after-any-details" class="hook">\n <summary id="required-after-any-summary">\n <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>\n <span id="required-after-any-result-icon" class="result-icon"></span>\n <span id="required-after-any-description" class="description hook-name">Required After Any Hook</span>\n </summary>\n <div class="results">\n <div id="required-after-any-results" class="result message"></div>\n </div>\n </details>\n </div>\n \n <slot name="footer">\n <foooter id="footer">\n <span id="group-results">\n <span id="duration">\n <span id="duration-label">Duration</span>\n <span id="duration-value">0</span>\n <span id="duration-unit">ms</span>\n </span>\n <span id="results-progress">\n <progress id="results-progress-value"></progress>\n </span>\n <span id="passed-total-pair">\n <span id="total-tests-passed-value"></span>\n <span id="passed-total-delimiter">of</span>\n <span id="total-tests-count-value"></span>\n <span id="total-tests-passed-label">Passed</span>\n </span>\n <span id="passed-total-percent">\n <span id="passed-total-percent-value">0</span>\n <span id="passed-total-percent-label">%</span>\n </span>\n </span>\n </foooter>\n </slot>\n</details>\n<template id="prompt-template">\n <div class="prompt">\n <div class="prompt-display">\n <span class="icon prompt-icon"></span>\n <span class="label prompt-label"></span>\n </div>\n <div class="prompt-actions">\n <button class="prompt-button accept" type="button">Accept</button>\n <button class="prompt-button reject" type="button">Reject</button>\n </div>\n </div>\n</template>\n<div id="icon-definitions" style="display: none;">\n <svg id="icon-definition_arrow" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path d="m3.26,6.81l-2.93,-4.69c-0.37,-0.58 0.05,-1.34 0.74,-1.34l5.87,0c0.69,0 1.11,0.76 0.74,1.34l-2.93,4.69c-0.35,0.55 -1.14,0.55 -1.49,0z" fill="var(--fill-color, currentcolor)" />\n </svg>\n <svg id="icon-definition_reset" class="icon reset" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M 5.484375 0.43359375 A 1.5224222 1.5224222 0 0 0 4.2558594 1.2011719 L 0.99804688 6.9453125 A 1.5224222 1.5224222 0 0 0 2.5488281 9.2011719 L 9.34375 8.171875 A 1.5224222 1.5224222 0 0 0 10.332031 5.7539062 L 9.4746094 4.6113281 C 11.949333 3.8016718 14.718209 4.258351 16.822266 5.9570312 C 19.510764 8.1275534 20.456787 11.785479 19.160156 14.988281 C 17.863527 18.191083 14.6405 20.15873 11.199219 19.847656 C 7.7579362 19.536584 4.9376009 17.022073 4.2363281 13.638672 A 1.5 1.5 0 0 0 2.4628906 12.474609 A 1.5 1.5 0 0 0 1.2988281 14.248047 C 2.2656928 18.912838 6.1831413 22.407052 10.927734 22.835938 C 15.672328 23.264824 20.153706 20.531029 21.941406 16.115234 C 23.729107 11.699441 22.413741 6.6156073 18.707031 3.6230469 C 16.853677 2.1267667 14.61485 1.3255701 12.347656 1.2324219 C 10.738216 1.1662975 9.1150542 1.4598646 7.6035156 2.1132812 L 6.7988281 1.0390625 A 1.5224222 1.5224222 0 0 0 5.484375 0.43359375 z " />\n </svg>\n <svg id="icon-definition_cancel" class="icon cancel" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">\n <path\n style="fill:var(--fill-color, currentcolor);stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"\n d="M -7.063234 9.5244002 C -5.8135728 7.6769245 -5.0820528 5.453265 -5.0820528 3.0633809 C -5.0820529 -3.3096433 -10.278145 -8.5098163 -16.65117 -8.5098163 C -23.024193 -8.5098163 -28.22385 -3.3110105 -28.22385 3.0620137 C -28.22385 9.4350379 -23.025043 14.634694 -16.65202 14.634694 C -12.668879 14.634694 -9.1460028 12.603526 -7.063234 9.5244002 z M -9.5406311 7.8637601 C -11.076991 10.143147 -13.683157 11.63463 -16.652974 11.63463 C -19.960499 11.63463 -22.814085 9.782061 -24.244824 7.0543029 L -24.236684 7.0527515 L -8.1332524 3.983715 L -8.1305391 3.9831979 C -8.2815631 5.4121635 -8.7798709 6.7350751 -9.5406311 7.8637601 z M -9.0610781 -0.92890828 L -9.069218 -0.92735695 L -25.17265 2.1416796 L -25.175363 2.1421967 C -24.719122 -2.1725739 -21.093311 -5.5092358 -16.652928 -5.5092358 C -13.345403 -5.5092358 -10.491243 -3.6566663 -9.0610781 -0.92890828 z "\n transform="rotate(-124.20981)" />\n </svg>\n</div>';
349
381
  const CodeTestEvent = {
350
382
  BeforeAll: "beforeall",
351
383
  AfterAll: "afterall",
@@ -355,7 +387,10 @@ code-test > details > summary > .description
355
387
  AfterHook: "afterhook",
356
388
  Cancel: "cancel",
357
389
  Context: "context",
358
- Reset: "reset"
390
+ Reset: "reset",
391
+ TestEnd: "testend",
392
+ Init: "init",
393
+ Enabled: "enabled"
359
394
  };
360
395
  const COMPONENT_TAG_NAME$1 = "code-test";
361
396
  class CodeTestElement extends HTMLElement {
@@ -445,7 +480,7 @@ code-test > details > summary > .description
445
480
  <summary class="test-summary" part="test-summary">
446
481
  <svg class="icon arrow-icon"><use href="#icon-definition_arrow"></use></svg>
447
482
  <div class="result-icon test-result-icon${this.state.testState?.resultCategory != "none" ? ` ${this.state.testState?.resultCategory}` : ""}" part="result-icon"></div>
448
- <span class="test-description description">${this.state.description}</span>
483
+ <span class="test-description description" title="${this.state.description}">${this.state.description}</span>
449
484
  ${this.state.testState?.duration != null && this.state.testState.duration > 0 ? `<span class="test-duration duration">
450
485
  <span class="test-duration-value">${this.state.testState.duration > 10 ? this.state.testState.duration.toFixed(0) : this.state.testState.duration.toFixed(2)}</span>
451
486
  <span class="test-duration-unit">ms</span>
@@ -598,7 +633,7 @@ code-test > details > summary > .description
598
633
  customElements.define(COMPONENT_TAG_NAME$1, CodeTestElement);
599
634
  }
600
635
  const NOTESTDEFINED = /* @__PURE__ */ Symbol("No Test Defined");
601
- class ContextManager {
636
+ class CodeTestsContext {
602
637
  codeTestsElement;
603
638
  // testContext?: TestContext;
604
639
  constructor(parent) {
@@ -822,6 +857,7 @@ code-test > details > summary > .description
822
857
  for (let i = 0; i < tests.length; i++) {
823
858
  tests[i].enable();
824
859
  }
860
+ this.codeTestsElement.dispatchEvent(new CustomEvent(CodeTestEvent.TestEnd, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
825
861
  }
826
862
  async runHook(testStateName, test, testContext) {
827
863
  const testState = this.codeTestsElement.state[testStateName];
@@ -1111,12 +1147,12 @@ Result:${objectResult.value}</pre>
1111
1147
  return "none";
1112
1148
  } else if (testCategory == "fail" || statesCategory == "fail") {
1113
1149
  return "fail";
1114
- } else if (testCategory == "success" && statesCategory == "success") {
1150
+ } else if (testCategory == "success" || statesCategory == "success") {
1115
1151
  return "success";
1116
1152
  }
1117
1153
  return "none";
1118
1154
  }
1119
- #contextManager;
1155
+ #context;
1120
1156
  constructor() {
1121
1157
  super();
1122
1158
  this.attachShadow({ mode: "open" });
@@ -1138,11 +1174,12 @@ Result:${objectResult.value}</pre>
1138
1174
  this.#isInitializing = true;
1139
1175
  assignClassAndIdToPart(this.shadowRoot);
1140
1176
  this.addEventListener("click", this.#boundClickHandler);
1177
+ this.findElement("#enabled").addEventListener("change", this.#boundEnabledHandler);
1141
1178
  await new Promise((resolve) => requestAnimationFrame(() => {
1142
- this.#contextManager = new ContextManager(this);
1179
+ this.#context = new CodeTestsContext(this);
1143
1180
  this.#isInitialized = true;
1144
1181
  this.#isInitializing = false;
1145
- const allowAutoLoad = this.dispatchEvent(new CustomEvent("init", { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
1182
+ const allowAutoLoad = this.dispatchEvent(new CustomEvent(CodeTestEvent.Init, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
1146
1183
  if (allowAutoLoad == false) {
1147
1184
  resolve();
1148
1185
  return;
@@ -1158,6 +1195,7 @@ Result:${objectResult.value}</pre>
1158
1195
  }
1159
1196
  #destroy() {
1160
1197
  this.removeEventListener("click", this.#boundClickHandler);
1198
+ this.findElement("#enabled").removeEventListener("change", this.#boundEnabledHandler);
1161
1199
  this.#isInitialized = false;
1162
1200
  this.#isInitializing = false;
1163
1201
  }
@@ -1183,7 +1221,17 @@ Result:${objectResult.value}</pre>
1183
1221
  return;
1184
1222
  }
1185
1223
  const test = runButton.closest("code-test") ?? void 0;
1186
- this.#contextManager.runTest(test, false);
1224
+ this.#context.runTest(test, false);
1225
+ }
1226
+ #boundEnabledHandler = this.#enabled_onChange.bind(this);
1227
+ #enabled_onChange(event) {
1228
+ const input = event.target;
1229
+ const allowToggle = this.dispatchEvent(new CustomEvent(CodeTestEvent.Enabled, { bubbles: true, composed: true, cancelable: true, detail: { target: this } }));
1230
+ if (allowToggle == false) {
1231
+ event.preventDefault();
1232
+ event.stopPropagation();
1233
+ input.checked = !input.checked;
1234
+ }
1187
1235
  }
1188
1236
  #getCurrentTestsPath() {
1189
1237
  return this.getAttribute("src") ?? this.getAttribute("test") ?? this.getAttribute("tests") ?? this.getAttribute("run") ?? this.getAttribute("path") ?? void 0;
@@ -1226,12 +1274,12 @@ Result:${objectResult.value}</pre>
1226
1274
  this.part.toggle("has-required-after-hook", hasRequiredAfterAnyState);
1227
1275
  const runAllButtonLabel = this.findElement(".run-all-button-label");
1228
1276
  if (runAllButtonLabel != null) {
1229
- runAllButtonLabel.textContent = isRunning == true ? "Cancel" : resultCategory == "fail" ? "Reset" : "Run Tests";
1230
- runAllButtonLabel.title = isRunning == true ? "Cancel the testing" : resultCategory == "fail" ? "Reset the tests so they can be run again" : "Run the tests";
1277
+ runAllButtonLabel.textContent = isRunning == true ? "Cancel" : resultCategory == "fail" || resultCategory == "success" ? "Reset" : "Run Tests";
1278
+ runAllButtonLabel.title = isRunning == true ? "Cancel the testing" : resultCategory == "fail" || resultCategory == "success" ? "Reset the tests so they can be run again" : "Run the tests";
1231
1279
  }
1232
1280
  const runAllIcon = this.findElement(".run-all-button-icon");
1233
1281
  if (runAllIcon != null) {
1234
- runAllIcon.innerHTML = isRunning == true ? '<use href="#icon-definition_cancel"></use>' : resultCategory == "fail" ? '<use href="#icon-definition_reset"></use>' : '<use href="#icon-definition_arrow"></use>';
1282
+ runAllIcon.innerHTML = isRunning == true ? '<use href="#icon-definition_cancel"></use>' : resultCategory == "fail" || resultCategory == "success" ? '<use href="#icon-definition_reset"></use>' : '<use href="#icon-definition_arrow"></use>';
1235
1283
  }
1236
1284
  this.#renderHook(this.state.beforeAllState, "#before-all-results");
1237
1285
  this.#renderHook(this.state.afterAllState, "#after-all-results");
@@ -1302,13 +1350,13 @@ Result:${objectResult.value}</pre>
1302
1350
  }
1303
1351
  async runTests() {
1304
1352
  const tests = this.findElements("code-test");
1305
- return this.#contextManager.runTests(tests);
1353
+ return this.#context.runTests(tests);
1306
1354
  }
1307
1355
  async reloadTests() {
1308
1356
  this.findElement("#tests").innerHTML = "";
1309
1357
  await this.reset();
1310
1358
  const testsPath = this.#getCurrentTestsPath();
1311
- this.#contextManager.loadTests(testsPath);
1359
+ this.#context.loadTests(testsPath);
1312
1360
  }
1313
1361
  async reset() {
1314
1362
  const tests = this.findElements("code-test");
@@ -1351,15 +1399,15 @@ Result:${objectResult.value}</pre>
1351
1399
  requiredAfterAnyState,
1352
1400
  requiredBeforeAnyState
1353
1401
  });
1354
- this.#contextManager.shouldContinueRunningTests = true;
1402
+ this.#context.shouldContinueRunningTests = true;
1355
1403
  if (this.state.resetHook != null) {
1356
- await this.state.resetHook(await this.#contextManager.createTestContext());
1404
+ await this.state.resetHook(await this.#context.createTestContext());
1357
1405
  }
1358
1406
  this.dispatchEvent(new CustomEvent(CodeTestEvent.Reset, { bubbles: true, composed: true }));
1359
1407
  }
1360
1408
  cancel() {
1361
1409
  this.state.isCanceled = true;
1362
- this.#contextManager.shouldContinueRunningTests = false;
1410
+ this.#context.shouldContinueRunningTests = false;
1363
1411
  this.classList.add("canceled");
1364
1412
  this.part.add("canceled");
1365
1413
  this.dispatchEvent(new CustomEvent(CodeTestEvent.Cancel, { bubbles: true, composed: true }));