@testspectra/cli 1.1.11-rc.5 → 1.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/demo-app/assets/index-DDYS5fLp.css +1 -0
- package/demo-app/assets/index-euCENPMy.js +154 -0
- package/demo-app/index.html +2 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/commands/__tests__/run-e2e.test.js +24 -6
- package/dist/commands/demo.d.ts +1 -0
- package/dist/commands/demo.js +26 -4
- package/dist/commands/doctor.js +23 -0
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.js +41 -4
- package/dist/commands/test.d.ts +9 -9
- package/dist/commands/test.js +40 -75
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.js +109 -0
- package/dist/config/loader.js +31 -4
- package/dist/config/schema.d.ts +58 -0
- package/dist/config/schema.js +4 -1
- package/dist/generator/__tests__/tsconfig-isolation.test.js +21 -0
- package/dist/generator/__tests__/type-generator.test.js +14 -0
- package/dist/generator/tsconfig-generator.js +1 -0
- package/dist/generator/type-generator.js +2 -0
- package/dist/index.js +8 -4
- package/dist/lifecycle/__tests__/lifecycle-engine.test.js +290 -0
- package/dist/lifecycle/hook-discovery.d.ts +24 -0
- package/dist/lifecycle/hook-discovery.js +60 -0
- package/dist/lifecycle/hook-dispatcher.d.ts +34 -0
- package/dist/lifecycle/hook-dispatcher.js +190 -0
- package/dist/lifecycle/index.d.ts +3 -0
- package/dist/lifecycle/index.js +3 -0
- package/dist/lifecycle/parallel-grouping.d.ts +27 -0
- package/dist/lifecycle/parallel-grouping.js +151 -0
- package/dist/reporter/semantic-formatter.js +2 -0
- package/dist/reporter/types.d.ts +1 -1
- package/dist/runner/bridge.d.ts +2 -0
- package/dist/runner/bridge.js +4 -1
- package/dist/runner/reporter.d.ts +5 -43
- package/dist/runner/reporter.js +46 -179
- package/dist/utils/__tests__/demo-state.test.d.ts +1 -0
- package/dist/utils/__tests__/demo-state.test.js +96 -0
- package/dist/utils/api-server.d.ts +1 -1
- package/dist/utils/api-server.js +7 -3
- package/dist/utils/demo-server.d.ts +2 -0
- package/dist/utils/demo-server.js +18 -5
- package/dist/utils/demo-state.d.ts +40 -0
- package/dist/utils/demo-state.js +157 -0
- package/package.json +9 -8
- package/templates/default/fixtures/sampleDocument.pdf +14 -0
- package/templates/default/fixtures/sampleImage.png +0 -0
- package/templates/default/package.json +2 -2
- package/templates/default/page-objects/MatchersPage/common.ts +41 -0
- package/templates/default/page-objects/MatchersPage/mobile.ts +8 -3
- package/templates/default/page-objects/PlaygroundPage/mobile.ts +6 -0
- package/templates/default/page-objects/PlaygroundPage/web.ts +2 -0
- package/templates/default/specs/Authentication/TC-0021-seed-authenticated-session/mobile.test.ts +3 -0
- package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +3 -0
- package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +1 -1
- package/templates/default/specs/Playground/TC-0003-file-upload/web.test.ts +11 -0
- package/templates/default/spectra.config.ts +5 -1
- package/templates/nx/.nx/workspace-data/70094CFD-E89B-57A1-9619-2FC5F4963C54.db +0 -0
- package/templates/nx/.nx/workspace-data/d/daemon.log +7063 -1012
- package/templates/nx/.nx/workspace-data/file-map.json +181 -169
- package/templates/nx/.nx/workspace-data/lockfile.hash +1 -1
- package/templates/nx/.nx/workspace-data/nx_files.nxt +0 -0
- package/templates/nx/.nx/workspace-data/parsed-lock-file.json +81 -130
- package/templates/nx/.nx/workspace-data/project-graph.json +83 -138
- package/templates/nx/package.json +2 -2
- package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +1 -1
- package/templates/nx/packages/playground/e2e/specs/Playground/TC-0003-file-upload/web.test.ts +11 -0
- package/templates/nx/shared/testing/fixtures/sampleDocument.pdf +14 -0
- package/templates/nx/shared/testing/fixtures/sampleImage.png +0 -0
- package/templates/nx/shared/testing/page-objects/MatchersPage/mobile.ts +68 -26
- package/templates/nx/shared/testing/page-objects/PlaygroundPage/mobile.ts +39 -17
- package/templates/nx/shared/testing/page-objects/PlaygroundPage/web.ts +2 -0
- package/templates/nx/spectra.config.ts +3 -3
- package/templates/react-component/fixtures/sampleDocument.pdf +14 -0
- package/templates/react-component/fixtures/sampleImage.png +0 -0
- package/templates/react-component/package.json +3 -3
- package/templates/react-component/page-objects/FileUploadComponent/web.ts +15 -0
- package/templates/react-component/specs/FileUploadComponent/TC-0001-upload-fixtures/web.test.tsx +18 -0
- package/templates/react-component/specs/UserListComponent/TC-0001-intercepted-user-list/spec.md +20 -0
- package/templates/react-component/specs/UserListComponent/TC-0001-intercepted-user-list/web.test.tsx +15 -0
- package/templates/react-component/specs/UserListComponent/suite.md +12 -0
- package/templates/react-component/src/components/FileUpload/FileUpload.tsx +44 -0
- package/templates/react-component/src/components/UserList/UserList.tsx +48 -0
- package/bin/.testspectra-runner.hash +0 -1
- package/demo-app/assets/index-BhlW-eXG.css +0 -1
- package/demo-app/assets/index-DOtRypCa.js +0 -154
- package/dist/commands/__tests__/doctor-scope.test.js +0 -24
- /package/dist/{commands/__tests__/doctor-scope.test.d.ts → lifecycle/__tests__/lifecycle-engine.test.d.ts} +0 -0
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
var Sn=Object.defineProperty;var Qa=e=>{throw TypeError(e)};var Tn=(e,t,s)=>t in e?Sn(e,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[t]=s;var Me=(e,t,s)=>Tn(e,typeof t!="symbol"?t+"":t,s),ha=(e,t,s)=>t.has(e)||Qa("Cannot "+s);var u=(e,t,s)=>(ha(e,t,"read from private field"),s?s.call(e):t.get(e)),L=(e,t,s)=>t.has(e)?Qa("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,s),M=(e,t,s,a)=>(ha(e,t,"write to private field"),a?a.call(e,s):t.set(e,s),s),z=(e,t,s)=>(ha(e,t,"access private method"),s);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))a(r);new MutationObserver(r=>{for(const n of r)if(n.type==="childList")for(const o of n.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&a(o)}).observe(document,{childList:!0,subtree:!0});function s(r){const n={};return r.integrity&&(n.integrity=r.integrity),r.referrerPolicy&&(n.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?n.credentials="include":r.crossOrigin==="anonymous"?n.credentials="omit":n.credentials="same-origin",n}function a(r){if(r.ep)return;r.ep=!0;const n=s(r);fetch(r.href,n)}})();const fr=!1;var Da=Array.isArray,En=Array.prototype.indexOf,Ys=Array.prototype.includes,oa=Array.from,Cn=Object.defineProperty,Ss=Object.getOwnPropertyDescriptor,An=Object.getOwnPropertyDescriptors,Pn=Object.prototype,In=Array.prototype,vr=Object.getPrototypeOf,Za=Object.isExtensible;const pr=()=>{};function Mn(e){for(var t=0;t<e.length;t++)e[t]()}function hr(){var e,t,s=new Promise((a,r)=>{e=a,t=r});return{promise:s,resolve:e,reject:t}}function Nn(e,t){if(Array.isArray(e))return e;if(!(Symbol.iterator in e))return Array.from(e);const s=[];for(const a of e)if(s.push(a),s.length===t)break;return s}const fe=2,os=4,ia=8,mr=1<<24,et=16,st=32,Pt=64,ya=128,Ue=512,ie=1024,ce=2048,dt=4096,be=8192,$e=16384,us=32768,Xa=1<<25,zt=65536,Qs=1<<17,On=1<<18,fs=1<<19,Ln=1<<20,it=1<<25,qt=65536,Zs=1<<21,Zt=1<<22,Ct=1<<23,Ts=Symbol("$state"),Bn=Symbol(""),zs=Symbol("attributes"),wa=Symbol("class"),Dn=Symbol("style"),bs=Symbol("text"),qs=Symbol("form reset"),la=new class extends Error{constructor(){super(...arguments);Me(this,"name","StaleReactionError");Me(this,"message","The reaction that called `getAbortSignal()` was re-run or destroyed")}};function Hn(){throw new Error("https://svelte.dev/e/async_derived_orphan")}function Rn(e,t,s){throw new Error("https://svelte.dev/e/each_key_duplicate")}function jn(e){throw new Error("https://svelte.dev/e/effect_in_teardown")}function Fn(){throw new Error("https://svelte.dev/e/effect_in_unowned_derived")}function Vn(e){throw new Error("https://svelte.dev/e/effect_orphan")}function Wn(){throw new Error("https://svelte.dev/e/effect_update_depth_exceeded")}function zn(){throw new Error("https://svelte.dev/e/state_descriptors_fixed")}function qn(){throw new Error("https://svelte.dev/e/state_prototype_fixed")}function Un(){throw new Error("https://svelte.dev/e/state_unsafe_mutation")}function $n(){throw new Error("https://svelte.dev/e/svelte_boundary_reset_onerror")}const Gn=1,Jn=2,br=4,Kn=8,Yn=16,Qn=1,Zn=2,oe=Symbol("uninitialized"),Xn="http://www.w3.org/1999/xhtml";function eo(){console.warn("https://svelte.dev/e/derived_inert")}function to(){console.warn("https://svelte.dev/e/select_multiple_invalid_value")}function so(){console.warn("https://svelte.dev/e/svelte_boundary_reset_noop")}function xr(e){return e===this.v}function ao(e,t){return e!=e?t==t:e!==t||e!==null&&typeof e=="object"||typeof e=="function"}function gr(e){return!ao(e,this.v)}let da=!1,ro=!1;function no(){da=!0}let le=null;function is(e){le=e}function xe(e,t=!1,s){le={p:le,i:!1,c:null,e:null,s:e,x:null,r:F,l:da&&!t?{s:null,u:null,$:[]}:null}}function ge(e){var t=le,s=t.e;if(s!==null){t.e=null;for(var a of s)Fr(a)}return t.i=!0,le=t.p,{}}function Hs(){return!da||le!==null&&le.l===null}let Nt=[];function _r(){var e=Nt;Nt=[],Mn(e)}function At(e){if(Nt.length===0&&!Cs){var t=Nt;queueMicrotask(()=>{t===Nt&&_r()})}Nt.push(e)}function oo(){for(;Nt.length>0;)_r()}function yr(e){var t=F;if(t===null)return H.f|=Ct,e;if(!(t.f&us)&&!(t.f&os))throw e;Tt(e,t)}function Tt(e,t){if(!(t!==null&&t.f&$e)){for(;t!==null;){if(t.f&ya){if(!(t.f&us))throw e;try{t.b.error(e);return}catch(s){e=s}}t=t.parent}throw e}}const io=-7169;function se(e,t){e.f=e.f&io|t}function Ha(e){e.f&Ue||e.deps===null?se(e,ie):se(e,dt)}function wr(e){if(e!==null)for(const t of e)!(t.f&fe)||!(t.f&qt)||(t.f^=qt,wr(t.deps))}function kr(e,t,s){e.f&ce?t.add(e):e.f&dt&&s.add(e),wr(e.deps),se(e,ie)}function lo(e){let t=0,s=$t(0),a;return()=>{Wa()&&(p(s),Vr(()=>(t===0&&(a=Xr(()=>e(()=>As(s)))),t+=1,()=>{At(()=>{t-=1,t===0&&(a==null||a(),a=void 0,As(s))})})))}}var co=zt|fs;function uo(e,t,s,a){new fo(e,t,s,a)}var Ve,Ba,We,Bt,Se,ze,me,Oe,ut,Dt,kt,Xt,Ns,Os,ft,aa,X,vo,po,ho,ka,Us,$s,Sa,Ta;class fo{constructor(t,s,a,r){L(this,X);Me(this,"parent");Me(this,"is_pending",!1);Me(this,"transform_error");L(this,Ve);L(this,Ba,null);L(this,We);L(this,Bt);L(this,Se);L(this,ze,null);L(this,me,null);L(this,Oe,null);L(this,ut,null);L(this,Dt,0);L(this,kt,0);L(this,Xt,!1);L(this,Ns,new Set);L(this,Os,new Set);L(this,ft,null);L(this,aa,lo(()=>(M(this,ft,$t(u(this,Dt))),()=>{M(this,ft,null)})));var n;M(this,Ve,t),M(this,We,s),M(this,Bt,o=>{var l=F;l.b=this,l.f|=ya,a(o)}),this.parent=F.b,this.transform_error=r??((n=this.parent)==null?void 0:n.transform_error)??(o=>o),M(this,Se,ua(()=>{z(this,X,ka).call(this)},co))}defer_effect(t){kr(t,u(this,Ns),u(this,Os))}is_rendered(){return!this.is_pending&&(!this.parent||this.parent.is_rendered())}has_pending_snippet(){return!!u(this,We).pending}update_pending_count(t,s){z(this,X,Sa).call(this,t,s),M(this,Dt,u(this,Dt)+t),!(!u(this,ft)||u(this,Xt))&&(M(this,Xt,!0),At(()=>{M(this,Xt,!1),u(this,ft)&&ds(u(this,ft),u(this,Dt))}))}get_effect_pending(){return u(this,aa).call(this),p(u(this,ft))}error(t){if(!u(this,We).onerror&&!u(this,We).failed)throw t;C!=null&&C.is_fork?(u(this,ze)&&C.skip_effect(u(this,ze)),u(this,me)&&C.skip_effect(u(this,me)),u(this,Oe)&&C.skip_effect(u(this,Oe)),C.oncommit(()=>{z(this,X,Ta).call(this,t)})):z(this,X,Ta).call(this,t)}}Ve=new WeakMap,Ba=new WeakMap,We=new WeakMap,Bt=new WeakMap,Se=new WeakMap,ze=new WeakMap,me=new WeakMap,Oe=new WeakMap,ut=new WeakMap,Dt=new WeakMap,kt=new WeakMap,Xt=new WeakMap,Ns=new WeakMap,Os=new WeakMap,ft=new WeakMap,aa=new WeakMap,X=new WeakSet,vo=function(){try{M(this,ze,qe(()=>u(this,Bt).call(this,u(this,Ve))))}catch(t){this.error(t)}},po=function(t){const s=u(this,We).failed;s&&M(this,Oe,qe(()=>{s(u(this,Ve),()=>t,()=>()=>{})}))},ho=function(){const t=u(this,We).pending;t&&(this.is_pending=!0,M(this,me,qe(()=>t(u(this,Ve)))),At(()=>{var s=M(this,ut,document.createDocumentFragment()),a=mt();s.append(a),M(this,ze,z(this,X,$s).call(this,()=>qe(()=>u(this,Bt).call(this,a)))),u(this,kt)===0&&(u(this,Ve).before(s),M(this,ut,null),Vt(u(this,me),()=>{M(this,me,null)}),z(this,X,Us).call(this,C))}))},ka=function(){try{if(this.is_pending=this.has_pending_snippet(),M(this,kt,0),M(this,Dt,0),M(this,ze,qe(()=>{u(this,Bt).call(this,u(this,Ve))})),u(this,kt)>0){var t=M(this,ut,document.createDocumentFragment());Ua(u(this,ze),t);const s=u(this,We).pending;M(this,me,qe(()=>s(u(this,Ve))))}else z(this,X,Us).call(this,C)}catch(s){this.error(s)}},Us=function(t){this.is_pending=!1,t.transfer_effects(u(this,Ns),u(this,Os))},$s=function(t){var s=F,a=H,r=le;ct(u(this,Se)),Ge(u(this,Se)),is(u(this,Se).ctx);try{return Ut.ensure(),t()}catch(n){return yr(n),null}finally{ct(s),Ge(a),is(r)}},Sa=function(t,s){var a;if(!this.has_pending_snippet()){this.parent&&z(a=this.parent,X,Sa).call(a,t,s);return}M(this,kt,u(this,kt)+t),u(this,kt)===0&&(z(this,X,Us).call(this,s),u(this,me)&&Vt(u(this,me),()=>{M(this,me,null)}),u(this,ut)&&(u(this,Ve).before(u(this,ut)),M(this,ut,null)))},Ta=function(t){u(this,ze)&&(Ce(u(this,ze)),M(this,ze,null)),u(this,me)&&(Ce(u(this,me)),M(this,me,null)),u(this,Oe)&&(Ce(u(this,Oe)),M(this,Oe,null));var s=u(this,We).onerror;let a=u(this,We).failed;var r=!1,n=!1;const o=()=>{if(r){so();return}r=!0,n&&$n(),u(this,Oe)!==null&&Vt(u(this,Oe),()=>{M(this,Oe,null)}),z(this,X,$s).call(this,()=>{z(this,X,ka).call(this)})},l=i=>{try{n=!0,s==null||s(i,o),n=!1}catch(c){Tt(c,u(this,Se)&&u(this,Se).parent)}a&&M(this,Oe,z(this,X,$s).call(this,()=>{try{return qe(()=>{var c=F;c.b=this,c.f|=ya,a(u(this,Ve),()=>i,()=>o)})}catch(c){return Tt(c,u(this,Se).parent),null}}))};At(()=>{var i;try{i=this.transform_error(t)}catch(c){Tt(c,u(this,Se)&&u(this,Se).parent);return}i!==null&&typeof i=="object"&&typeof i.then=="function"?i.then(l,c=>Tt(c,u(this,Se)&&u(this,Se).parent)):l(i)})};function mo(e,t,s,a){const r=Hs()?Ra:Tr;var n=e.filter(m=>!m.settled),o=t.map(r);if(s.length===0&&n.length===0){a(o);return}var l=F,i=bo(),c=n.length===1?n[0].promise:n.length>1?Promise.all(n.map(m=>m.promise)):null;function h(m){if(!(l.f&$e)){i();try{a([...o,...m])}catch(x){Tt(x,l)}Xs()}}var b=Sr();if(s.length===0){c.then(()=>h([])).finally(b);return}function v(){Promise.all(s.map(m=>xo(m))).then(h).catch(m=>Tt(m,l)).finally(b)}c?c.then(()=>{i(),v(),Xs()}):v()}function bo(){var e=F,t=H,s=le,a=C;return function(n=!0){ct(e),Ge(t),is(s),n&&!(e.f&$e)&&(a==null||a.activate(),a==null||a.apply())}}function Xs(e=!0){ct(null),Ge(null),is(null),e&&(C==null||C.deactivate())}function Sr(){var e=F,t=e.b,s=C,a=!!(t!=null&&t.is_rendered());return t==null||t.update_pending_count(1,s),s.increment(a,e),()=>{t==null||t.update_pending_count(-1,s),s.decrement(a,e)}}function Ra(e){var t=fe|ce;return F!==null&&(F.f|=fs),{ctx:le,deps:null,effects:null,equals:xr,f:t,fn:e,reactions:null,rv:0,v:oe,wv:0,parent:F,ac:null}}const xs=Symbol("obsolete");function xo(e,t,s){let a=F;a===null&&Hn();var r=void 0,n=$t(oe),o=!H,l=new Set;return Do(()=>{var m,x;var i=F,c=hr();r=c.promise;try{Promise.resolve(e()).then(c.resolve,_=>{_!==la&&c.reject(_)}).finally(Xs)}catch(_){c.reject(_),Xs()}var h=C;if(o){if(i.f&us)var b=Sr();if((m=a.b)!=null&&m.is_rendered())(x=h.async_deriveds.get(i))==null||x.reject(xs);else for(const _ of l.values())_.reject(xs);l.add(c),h.async_deriveds.set(i,c)}const v=(_,g=void 0)=>{b==null||b(),l.delete(c),g!==xs&&(h.activate(),g?(n.f|=Ct,ds(n,g)):(n.f&Ct&&(n.f^=Ct),ds(n,_)),h.deactivate())};c.promise.then(v,_=>v(null,_||"unknown"))}),za(()=>{for(const i of l)i.reject(xs)}),new Promise(i=>{function c(h){function b(){h===r?i(n):c(r)}h.then(b,b)}c(r)})}function ls(e){const t=Ra(e);return $r(t),t}function Tr(e){const t=Ra(e);return t.equals=gr,t}function go(e){var t=e.effects;if(t!==null){e.effects=null;for(var s=0;s<t.length;s+=1)Ce(t[s])}}function ja(e){var t,s=F,a=e.parent;if(!It&&a!==null&&e.v!==oe&&a.f&($e|be))return eo(),e.v;ct(a);try{e.f&=~qt,go(e),t=Yr(e)}finally{ct(s)}return t}function Er(e){var t=ja(e);if(!e.equals(t)&&(e.wv=Jr(),(!(C!=null&&C.is_fork)||e.deps===null)&&(C!==null?(C.capture(e,t,!0),Es==null||Es.capture(e,t,!0)):e.v=t,e.deps===null))){se(e,ie);return}It||(ue!==null?(Wa()||C!=null&&C.is_fork)&&ue.set(e,t):Ha(e))}function _o(e){var t,s;if(e.effects!==null)for(const a of e.effects)(a.teardown||a.ac)&&((t=a.teardown)==null||t.call(a),(s=a.ac)==null||s.abort(la),a.fn!==null&&(a.teardown=pr),a.ac=null,Is(a,0),qa(a))}function Cr(e){if(e.effects!==null)for(const t of e.effects)t.teardown&&t.fn!==null&&cs(t)}let ma=null,Kt=null,C=null,Es=null,ue=null,Ea=null,Cs=!1,ba=!1,Qt=null,Gs=null;var er=0;let yo=1;var es,St,Ht,ts,ss,as,vt,rs,Te,Ls,pt,Ze,nt,ns,Rt,U,Ca,gs,Aa,Ar,Pr,Yt,wo,_s;const ra=class ra{constructor(){L(this,U);Me(this,"id",yo++);L(this,es,!1);Me(this,"linked",!0);L(this,St,null);L(this,Ht,null);Me(this,"async_deriveds",new Map);Me(this,"current",new Map);Me(this,"previous",new Map);L(this,ts,new Set);L(this,ss,new Set);L(this,as,0);L(this,vt,new Map);L(this,rs,null);L(this,Te,[]);L(this,Ls,[]);L(this,pt,new Set);L(this,Ze,new Set);L(this,nt,new Map);L(this,ns,new Set);Me(this,"is_fork",!1);L(this,Rt,!1);Kt===null?ma=Kt=this:(M(Kt,Ht,this),M(this,St,Kt)),Kt=this}skip_effect(t){u(this,nt).has(t)||u(this,nt).set(t,{d:[],m:[]}),u(this,ns).delete(t)}unskip_effect(t,s=a=>this.schedule(a)){var a=u(this,nt).get(t);if(a){u(this,nt).delete(t);for(var r of a.d)se(r,ce),s(r);for(r of a.m)se(r,dt),s(r)}u(this,ns).add(t)}capture(t,s,a=!1){t.v!==oe&&!this.previous.has(t)&&this.previous.set(t,t.v),t.f&Ct||(this.current.set(t,[s,a]),ue==null||ue.set(t,s)),this.is_fork||(t.v=s)}activate(){C=this}deactivate(){C=null,ue=null}flush(){try{ba=!0,C=this,z(this,U,gs).call(this)}finally{er=0,Ea=null,Qt=null,Gs=null,ba=!1,C=null,ue=null,Ft.clear()}}discard(){var t;for(const s of u(this,ss))s(this);u(this,ss).clear();for(const s of this.async_deriveds.values())s.reject(xs);z(this,U,_s).call(this),(t=u(this,rs))==null||t.resolve()}register_created_effect(t){u(this,Ls).push(t)}increment(t,s){if(M(this,as,u(this,as)+1),t){let a=u(this,vt).get(s)??0;u(this,vt).set(s,a+1)}}decrement(t,s){if(M(this,as,u(this,as)-1),t){let a=u(this,vt).get(s)??0;a===1?u(this,vt).delete(s):u(this,vt).set(s,a-1)}u(this,Rt)||(M(this,Rt,!0),At(()=>{M(this,Rt,!1),this.linked&&this.flush()}))}transfer_effects(t,s){for(const a of t)u(this,pt).add(a);for(const a of s)u(this,Ze).add(a);t.clear(),s.clear()}oncommit(t){u(this,ts).add(t)}ondiscard(t){u(this,ss).add(t)}settled(){return(u(this,rs)??M(this,rs,hr())).promise}static ensure(){if(C===null){const t=C=new ra;!ba&&!Cs&&At(()=>{u(t,es)||t.flush()})}return C}apply(){{ue=null;return}}schedule(t){var r;if(Ea=t,(r=t.b)!=null&&r.is_pending&&t.f&(os|ia|mr)&&!(t.f&us)){t.b.defer_effect(t);return}for(var s=t;s.parent!==null;){s=s.parent;var a=s.f;if(Qt!==null&&s===F&&(H===null||!(H.f&fe)))return;if(a&(Pt|st)){if(!(a&ie))return;s.f^=ie}}u(this,Te).push(s)}};es=new WeakMap,St=new WeakMap,Ht=new WeakMap,ts=new WeakMap,ss=new WeakMap,as=new WeakMap,vt=new WeakMap,rs=new WeakMap,Te=new WeakMap,Ls=new WeakMap,pt=new WeakMap,Ze=new WeakMap,nt=new WeakMap,ns=new WeakMap,Rt=new WeakMap,U=new WeakSet,Ca=function(){if(this.is_fork)return!0;for(const a of u(this,vt).keys()){for(var t=a,s=!1;t.parent!==null;){if(u(this,nt).has(t)){s=!0;break}t=t.parent}if(!s)return!0}return!1},gs=function(){var i,c,h,b;M(this,es,!0),er++>1e3&&(z(this,U,_s).call(this),So());for(const v of u(this,pt))u(this,Ze).delete(v),se(v,ce),this.schedule(v);for(const v of u(this,Ze))se(v,dt),this.schedule(v);const t=u(this,Te);M(this,Te,[]),this.apply();var s=Qt=[],a=[],r=Gs=[];for(const v of t)try{z(this,U,Aa).call(this,v,s,a)}catch(m){throw Nr(v),z(this,U,Ca).call(this)||this.discard(),m}if(C=null,r.length>0){var n=ra.ensure();for(const v of r)n.schedule(v)}if(Qt=null,Gs=null,z(this,U,Ca).call(this)){z(this,U,Yt).call(this,a),z(this,U,Yt).call(this,s);for(const[v,m]of u(this,nt))Mr(v,m);r.length>0&&z(i=C,U,gs).call(i);return}const o=z(this,U,Ar).call(this);if(o){z(this,U,Yt).call(this,a),z(this,U,Yt).call(this,s),z(c=o,U,Pr).call(c,this);return}u(this,pt).clear(),u(this,Ze).clear();for(const v of u(this,ts))v(this);u(this,ts).clear(),Es=this,tr(a),tr(s),Es=null,(h=u(this,rs))==null||h.resolve();var l=C;if(u(this,as)===0&&(u(this,Te).length===0||l!==null)&&z(this,U,_s).call(this),u(this,Te).length>0)if(l!==null){const v=l;u(v,Te).push(...u(this,Te).filter(m=>!u(v,Te).includes(m)))}else l=this;l!==null&&z(b=l,U,gs).call(b)},Aa=function(t,s,a){t.f^=ie;for(var r=t.first;r!==null;){var n=r.f,o=(n&(st|Pt))!==0,l=o&&(n&ie)!==0,i=l||(n&be)!==0||u(this,nt).has(r);if(!i&&r.fn!==null){o?r.f^=ie:n&os?s.push(r):js(r)&&(n&et&&u(this,Ze).add(r),cs(r));var c=r.first;if(c!==null){r=c;continue}}for(;r!==null;){var h=r.next;if(h!==null){r=h;break}r=r.parent}}},Ar=function(){for(var t=u(this,St);t!==null;){if(!t.is_fork){for(const[s,[,a]]of this.current)if(t.current.has(s)&&!a)return t}t=u(t,St)}return null},Pr=function(t){var a;for(const[r,n]of t.current)!this.previous.has(r)&&t.previous.has(r)&&this.previous.set(r,t.previous.get(r)),this.current.set(r,n);for(const[r,n]of t.async_deriveds){const o=this.async_deriveds.get(r);o&&n.promise.then(o.resolve).catch(o.reject)}t.async_deriveds.clear(),this.transfer_effects(u(t,pt),u(t,Ze));const s=r=>{var n=r.reactions;if(n!==null)for(const i of n){var o=i.f;if(o&fe)s(i);else{var l=i;o&(Zt|et)&&!this.async_deriveds.has(l)&&(u(this,Ze).delete(l),se(l,ce),this.schedule(l))}}};for(const r of this.current.keys())s(r);this.oncommit(()=>t.discard()),z(a=t,U,_s).call(a),C=this,z(this,U,gs).call(this)},Yt=function(t){for(var s=0;s<t.length;s+=1)kr(t[s],u(this,pt),u(this,Ze))},wo=function(){var b;for(let v=ma;v!==null;v=u(v,Ht)){var t=v.id<this.id,s=[];for(const[m,[x,_]]of this.current){if(v.current.has(m)){var a=v.current.get(m)[0];if(t&&x!==a)v.current.set(m,[x,_]);else continue}s.push(m)}if(t)for(const[m,x]of this.async_deriveds){const _=v.async_deriveds.get(m);_&&x.promise.then(_.resolve).catch(_.reject)}var r=[...v.current.keys()].filter(m=>!v.current.get(m)[1]);if(!(!u(v,es)||r.length===0)){var n=r.filter(m=>!this.current.has(m));if(n.length===0)t&&v.discard();else if(s.length>0){if(t)for(const m of u(this,ns))v.unskip_effect(m,x=>{var _;x.f&(et|Zt)?v.schedule(x):z(_=v,U,Yt).call(_,[x])});v.activate();var o=new Set,l=new Map;for(var i of s)Ir(i,n,o,l);l=new Map;var c=[...v.current].filter(([m,x])=>{const _=this.current.get(m);return _?_[0]!==x[0]||_[1]!==x[1]:!0}).map(([m])=>m);if(c.length>0)for(const m of u(this,Ls))!(m.f&($e|be|Qs))&&Fa(m,c,l)&&(m.f&(Zt|et)?(se(m,ce),v.schedule(m)):u(v,pt).add(m));if(u(v,Te).length>0&&!u(v,Rt)){v.apply();for(var h of u(v,Te))z(b=v,U,Aa).call(b,h,[],[]);M(v,Te,[])}v.deactivate()}}}},_s=function(){if(this.linked){var t=u(this,St),s=u(this,Ht);t===null?ma=s:M(t,Ht,s),s===null?Kt=t:M(s,St,t),this.linked=!1}};let Ut=ra;function ko(e){var t=Cs;Cs=!0;try{for(var s;;){if(oo(),C===null)return s;C.flush()}}finally{Cs=t}}function So(){try{Wn()}catch(e){Tt(e,Ea)}}let Qe=null;function tr(e){var t=e.length;if(t!==0){for(var s=0;s<t;){var a=e[s++];if(!(a.f&($e|be))&&js(a)&&(Qe=new Set,cs(a),a.deps===null&&a.first===null&&a.nodes===null&&a.teardown===null&&a.ac===null&&zr(a),(Qe==null?void 0:Qe.size)>0)){Ft.clear();for(const r of Qe){if(r.f&($e|be))continue;const n=[r];let o=r.parent;for(;o!==null;)Qe.has(o)&&(Qe.delete(o),n.push(o)),o=o.parent;for(let l=n.length-1;l>=0;l--){const i=n[l];i.f&($e|be)||cs(i)}}Qe.clear()}}Qe=null}}function Ir(e,t,s,a){if(!s.has(e)&&(s.add(e),e.reactions!==null))for(const r of e.reactions){const n=r.f;n&fe?Ir(r,t,s,a):n&(Zt|et)&&!(n&ce)&&Fa(r,t,a)&&(se(r,ce),Va(r))}}function Fa(e,t,s){const a=s.get(e);if(a!==void 0)return a;if(e.deps!==null)for(const r of e.deps){if(Ys.call(t,r))return!0;if(r.f&fe&&Fa(r,t,s))return s.set(r,!0),!0}return s.set(e,!1),!1}function Va(e){C.schedule(e)}function Mr(e,t){if(!(e.f&st&&e.f&ie)){e.f&ce?t.d.push(e):e.f&dt&&t.m.push(e),se(e,ie);for(var s=e.first;s!==null;)Mr(s,t),s=s.next}}function Nr(e){se(e,ie);for(var t=e.first;t!==null;)Nr(t),t=t.next}let ea=new Set;const Ft=new Map;let Or=!1;function $t(e,t){var s={f:0,v:e,reactions:null,equals:xr,rv:0,wv:0};return s}function P(e,t){const s=$t(e);return $r(s),s}function To(e,t=!1,s=!0){var r;const a=$t(e);return t||(a.equals=gr),da&&s&&le!==null&&le.l!==null&&((r=le.l).s??(r.s=[])).push(a),a}function y(e,t,s=!1){H!==null&&(!tt||H.f&Qs)&&Hs()&&H.f&(fe|et|Zt|Qs)&&(lt===null||!lt.has(e))&&Un();let a=s?ht(t):t;return ds(e,a,Gs)}function ds(e,t,s=null){if(!e.equals(t)){Ft.set(e,It?t:e.v);var a=Ut.ensure();if(a.capture(e,t),e.f&fe){const r=e;e.f&ce&&ja(r),ue===null&&Ha(r)}e.wv=Jr(),Lr(e,ce,s),Hs()&&F!==null&&F.f&ie&&!(F.f&(st|Pt))&&(Fe===null?jo([e]):Fe.push(e)),!a.is_fork&&ea.size>0&&!Or&&Eo()}return t}function Eo(){Or=!1;for(const e of ea){e.f&ie&&se(e,dt);let t;try{t=js(e)}catch{t=!0}t&&cs(e)}ea.clear()}function As(e){y(e,e.v+1)}function Lr(e,t,s){var a=e.reactions;if(a!==null)for(var r=Hs(),n=a.length,o=0;o<n;o++){var l=a[o],i=l.f;if(!(!r&&l===F)){var c=(i&ce)===0;if(c&&se(l,t),i&Qs)ea.add(l);else if(i&fe){var h=l;ue==null||ue.delete(h),i&qt||(i&Ue&&(F===null||!(F.f&Zs))&&(l.f|=qt),Lr(h,dt,s))}else if(c){var b=l;i&et&&Qe!==null&&Qe.add(b),s!==null?s.push(b):Va(b)}}}}function ht(e){if(typeof e!="object"||e===null||Ts in e)return e;const t=vr(e);if(t!==Pn&&t!==In)return e;var s=new Map,a=Da(e),r=P(0),n=Wt,o=l=>{if(Wt===n)return l();var i=H,c=Wt;Ge(null),or(n);var h=l();return Ge(i),or(c),h};return a&&s.set("length",P(e.length)),new Proxy(e,{defineProperty(l,i,c){(!("value"in c)||c.configurable===!1||c.enumerable===!1||c.writable===!1)&&zn();var h=s.get(i);return h===void 0?o(()=>{var b=P(c.value);return s.set(i,b),b}):y(h,c.value,!0),!0},deleteProperty(l,i){var c=s.get(i);if(c===void 0){if(i in l){const h=o(()=>P(oe));s.set(i,h),As(r)}}else y(c,oe),As(r);return!0},get(l,i,c){var m;if(i===Ts)return e;var h=s.get(i),b=i in l;if(h===void 0&&(!b||(m=Ss(l,i))!=null&&m.writable)&&(h=o(()=>{var x=ht(b?l[i]:oe),_=P(x);return _}),s.set(i,h)),h!==void 0){var v=p(h);return v===oe?void 0:v}return Reflect.get(l,i,c)},getOwnPropertyDescriptor(l,i){var c=Reflect.getOwnPropertyDescriptor(l,i);if(c&&"value"in c){var h=s.get(i);h&&(c.value=p(h))}else if(c===void 0){var b=s.get(i),v=b==null?void 0:b.v;if(b!==void 0&&v!==oe)return{enumerable:!0,configurable:!0,value:v,writable:!0}}return c},has(l,i){var v;if(i===Ts)return!0;var c=s.get(i),h=c!==void 0&&c.v!==oe||Reflect.has(l,i);if(c!==void 0||F!==null&&(!h||(v=Ss(l,i))!=null&&v.writable)){c===void 0&&(c=o(()=>{var m=h?ht(l[i]):oe,x=P(m);return x}),s.set(i,c));var b=p(c);if(b===oe)return!1}return h},set(l,i,c,h){var T;var b=s.get(i),v=i in l;if(a&&i==="length")for(var m=c;m<b.v;m+=1){var x=s.get(m+"");x!==void 0?y(x,oe):m in l&&(x=o(()=>P(oe)),s.set(m+"",x))}if(b===void 0)(!v||(T=Ss(l,i))!=null&&T.writable)&&(b=o(()=>P(void 0)),y(b,ht(c)),s.set(i,b));else{v=b.v!==oe;var _=o(()=>ht(c));y(b,_)}var g=Reflect.getOwnPropertyDescriptor(l,i);if(g!=null&&g.set&&g.set.call(h,c),!v){if(a&&typeof i=="string"){var S=s.get("length"),A=Number(i);Number.isInteger(A)&&A>=S.v&&y(S,A+1)}As(r)}return!0},ownKeys(l){p(r);var i=Reflect.ownKeys(l).filter(b=>{var v=s.get(b);return v===void 0||v.v!==oe});for(var[c,h]of s)h.v!==oe&&!(c in l)&&i.push(c);return i},setPrototypeOf(){qn()}})}function sr(e){try{if(e!==null&&typeof e=="object"&&Ts in e)return e[Ts]}catch{}return e}function Co(e,t){return Object.is(sr(e),sr(t))}var ar,Br,Dr,Hr;function Ao(){if(ar===void 0){ar=window,Br=/Firefox/.test(navigator.userAgent);var e=Element.prototype,t=Node.prototype,s=Text.prototype;Dr=Ss(t,"firstChild").get,Hr=Ss(t,"nextSibling").get,Za(e)&&(e[wa]=void 0,e[zs]=null,e[Dn]=void 0,e.__e=void 0),Za(s)&&(s[bs]=void 0)}}function mt(e=""){return document.createTextNode(e)}function Et(e){return Dr.call(e)}function Rs(e){return Hr.call(e)}function d(e,t){return Et(e)}function Pa(e,t=!1){{var s=Et(e);return s instanceof Comment&&s.data===""?Rs(s):s}}function f(e,t=1,s=!1){let a=e;for(;t--;)a=Rs(a);return a}function Po(e){e.textContent=""}function Rr(){return!1}function Io(e,t,s){return s?document.createElement(e,{is:s}):document.createElement(e)}let rr=!1;function Mo(){rr||(rr=!0,document.addEventListener("reset",e=>{Promise.resolve().then(()=>{var t;if(!e.defaultPrevented)for(const s of e.target.elements)(t=s[qs])==null||t.call(s)})},{capture:!0}))}function ca(e){var t=H,s=F;Ge(null),ct(null);try{return e()}finally{Ge(t),ct(s)}}function jr(e,t,s,a=s){e.addEventListener(t,()=>ca(s));const r=e[qs];r?e[qs]=()=>{r(),a(!0)}:e[qs]=()=>a(!0),Mo()}function No(e){F===null&&(H===null&&Vn(),Fn()),It&&jn()}function Oo(e,t){var s=t.last;s===null?t.last=t.first=e:(s.next=e,e.prev=s,t.last=e)}function bt(e,t){var s=F;s!==null&&s.f&be&&(e|=be);var a={ctx:le,deps:null,nodes:null,f:e|ce|Ue,first:null,fn:t,last:null,next:null,parent:s,b:s&&s.b,prev:null,teardown:null,wv:0,ac:null};C==null||C.register_created_effect(a);var r=a;if(e&os)Qt!==null?Qt.push(a):Ut.ensure().schedule(a);else if(t!==null){try{cs(a)}catch(o){throw Ce(a),o}r.deps===null&&r.teardown===null&&r.nodes===null&&r.first===r.last&&!(r.f&fs)&&(r=r.first,e&et&&e&zt&&r!==null&&(r.f|=zt))}if(r!==null&&(r.parent=s,s!==null&&Oo(r,s),H!==null&&H.f&fe&&!(e&Pt))){var n=H;(n.effects??(n.effects=[])).push(r)}return a}function Wa(){return H!==null&&!tt}function za(e){const t=bt(ia,null);return se(t,ie),t.teardown=e,t}function Ia(e){No();var t=F.f,s=!H&&(t&st)!==0&&le!==null&&!le.i;if(s){var a=le;(a.e??(a.e=[])).push(e)}else return Fr(e)}function Fr(e){return bt(os|Ln,e)}function Lo(e){Ut.ensure();const t=bt(Pt|fs,e);return(s={})=>new Promise(a=>{s.outro?Vt(t,()=>{Ce(t),a(void 0)}):(Ce(t),a(void 0))})}function Bo(e){return bt(os,e)}function Do(e){return bt(Zt|fs,e)}function Vr(e,t=0){return bt(ia|t,e)}function B(e,t=[],s=[],a=[]){mo(a,t,s,r=>{bt(ia,()=>{e(...r.map(p))})})}function ua(e,t=0){var s=bt(et|t,e);return s}function qe(e){return bt(st|fs,e)}function Wr(e){var t=e.teardown;if(t!==null){const s=It,a=H;nr(!0),Ge(null);try{t.call(null)}finally{nr(s),Ge(a)}}}function qa(e,t=!1){var s=e.first;for(e.first=e.last=null;s!==null;){const r=s.ac;r!==null&&ca(()=>{r.abort(la)});var a=s.next;s.f&Pt?s.parent=null:Ce(s,t),s=a}}function Ho(e){for(var t=e.first;t!==null;){var s=t.next;t.f&st||Ce(t),t=s}}function Ce(e,t=!0){var s=!1;(t||e.f&On)&&e.nodes!==null&&e.nodes.end!==null&&(Ro(e.nodes.start,e.nodes.end),s=!0),e.f|=Xa,qa(e,t&&!s),Is(e,0);var a=e.nodes&&e.nodes.t;if(a!==null)for(const n of a)n.stop();Wr(e),e.f^=Xa,e.f|=$e;var r=e.parent;r!==null&&r.first!==null&&zr(e),e.next=e.prev=e.teardown=e.ctx=e.deps=e.fn=e.nodes=e.ac=e.b=null}function Ro(e,t){for(;e!==null;){var s=e===t?null:Rs(e);e.remove(),e=s}}function zr(e){var t=e.parent,s=e.prev,a=e.next;s!==null&&(s.next=a),a!==null&&(a.prev=s),t!==null&&(t.first===e&&(t.first=a),t.last===e&&(t.last=s))}function Vt(e,t,s=!0){var a=[];qr(e,a,!0);var r=()=>{s&&Ce(e),t&&t()},n=a.length;if(n>0){var o=()=>--n||r();for(var l of a)l.out(o)}else r()}function qr(e,t,s){if(!(e.f&be)){e.f^=be;var a=e.nodes&&e.nodes.t;if(a!==null)for(const l of a)(l.is_global||s)&&t.push(l);for(var r=e.first;r!==null;){var n=r.next;if(!(r.f&Pt)){var o=(r.f&zt)!==0||(r.f&st)!==0&&(e.f&et)!==0;qr(r,t,o?s:!1)}r=n}}}function ta(e){Ur(e,!0)}function Ur(e,t){if(e.f&be){e.f^=be,e.f&ie||(se(e,ce),Ut.ensure().schedule(e));for(var s=e.first;s!==null;){var a=s.next,r=(s.f&zt)!==0||(s.f&st)!==0;Ur(s,r?t:!1),s=a}var n=e.nodes&&e.nodes.t;if(n!==null)for(const o of n)(o.is_global||t)&&o.in()}}function Ua(e,t){if(e.nodes)for(var s=e.nodes.start,a=e.nodes.end;s!==null;){var r=s===a?null:Rs(s);t.append(s),s=r}}let Js=!1,It=!1;function nr(e){It=e}let H=null,tt=!1;function Ge(e){H=e}let F=null;function ct(e){F=e}let lt=null;function $r(e){H!==null&&(lt??(lt=new Set)).add(e)}let Ee=null,Ne=0,Fe=null;function jo(e){Fe=e}let Gr=1,Ot=0,Wt=Ot;function or(e){Wt=e}function Jr(){return++Gr}function js(e){var t=e.f;if(t&ce)return!0;if(t&fe&&(e.f&=~qt),t&dt){for(var s=e.deps,a=s.length,r=0;r<a;r++){var n=s[r];if(js(n)&&Er(n),n.wv>e.wv)return!0}t&Ue&&ue===null&&se(e,ie)}return!1}function Kr(e,t,s=!0){var a=e.reactions;if(a!==null&&!(lt!==null&<.has(e)))for(var r=0;r<a.length;r++){var n=a[r];n.f&fe?Kr(n,t,!1):t===n&&(s?se(n,ce):n.f&ie&&se(n,dt),Va(n))}}function Yr(e){var _;var t=Ee,s=Ne,a=Fe,r=H,n=lt,o=le,l=tt,i=Wt,c=e.f;Ee=null,Ne=0,Fe=null,H=c&(st|Pt)?null:e,lt=null,is(e.ctx),tt=!1,Wt=++Ot,e.ac!==null&&(ca(()=>{e.ac.abort(la)}),e.ac=null);try{e.f|=Zs;var h=e.fn,b=h();e.f|=us;var v=e.deps,m=C==null?void 0:C.is_fork;if(Ee!==null){var x;if(m||Is(e,Ne),v!==null&&Ne>0)for(v.length=Ne+Ee.length,x=0;x<Ee.length;x++)v[Ne+x]=Ee[x];else e.deps=v=Ee;if(Wa()&&e.f&Ue)for(x=Ne;x<v.length;x++)((_=v[x]).reactions??(_.reactions=[])).push(e)}else!m&&v!==null&&Ne<v.length&&(Is(e,Ne),v.length=Ne);if(Hs()&&Fe!==null&&!tt&&v!==null&&!(e.f&(fe|dt|ce)))for(x=0;x<Fe.length;x++)Kr(Fe[x],e);if(r!==null&&r!==e){if(Ot++,r.deps!==null)for(let g=0;g<s;g+=1)r.deps[g].rv=Ot;if(t!==null)for(const g of t)g.rv=Ot;Fe!==null&&(a===null?a=Fe:a.push(...Fe))}return e.f&Ct&&(e.f^=Ct),b}catch(g){return yr(g)}finally{e.f^=Zs,Ee=t,Ne=s,Fe=a,H=r,lt=n,is(o),tt=l,Wt=i}}function Fo(e,t){let s=t.reactions;if(s!==null){var a=En.call(s,e);if(a!==-1){var r=s.length-1;r===0?s=t.reactions=null:(s[a]=s[r],s.pop())}}if(s===null&&t.f&fe&&(Ee===null||!Ys.call(Ee,t))){var n=t;n.f&Ue&&(n.f^=Ue,n.f&=~qt),n.v!==oe&&Ha(n),_o(n),Is(n,0)}}function Is(e,t){var s=e.deps;if(s!==null)for(var a=t;a<s.length;a++)Fo(e,s[a])}function cs(e){var t=e.f;if(!(t&$e)){se(e,ie);var s=F,a=Js;F=e,Js=!0;try{t&(et|mr)?Ho(e):qa(e),Wr(e);var r=Yr(e);e.teardown=typeof r=="function"?r:null,e.wv=Gr;var n;fr&&ro&&e.f&ce&&e.deps}finally{Js=a,F=s}}}async function Vo(){await Promise.resolve(),ko()}function p(e){var t=e.f,s=(t&fe)!==0;if(H!==null&&!tt){var a=F!==null&&(F.f&$e)!==0;if(!a&&(lt===null||!lt.has(e))){var r=H.deps;if(H.f&Zs)e.rv<Ot&&(e.rv=Ot,Ee===null&&r!==null&&r[Ne]===e?Ne++:Ee===null?Ee=[e]:Ee.push(e));else{H.deps??(H.deps=[]),Ys.call(H.deps,e)||H.deps.push(e);var n=e.reactions;n===null?e.reactions=[H]:Ys.call(n,H)||n.push(H)}}}if(It&&Ft.has(e))return Ft.get(e);if(s){var o=e;if(It){var l=o.v;return(!(o.f&ie)&&o.reactions!==null||Zr(o))&&(l=ja(o)),Ft.set(o,l),l}var i=(o.f&Ue)===0&&!tt&&H!==null&&(Js||(H.f&Ue)!==0),c=(o.f&us)===0;js(o)&&(i&&(o.f|=Ue),Er(o)),i&&!c&&(Cr(o),Qr(o))}if(ue!=null&&ue.has(e))return ue.get(e);if(e.f&Ct)throw e.v;return e.v}function Qr(e){if(e.f|=Ue,e.deps!==null)for(const t of e.deps)(t.reactions??(t.reactions=[])).push(e),t.f&fe&&!(t.f&Ue)&&(Cr(t),Qr(t))}function Zr(e){if(e.v===oe)return!0;if(e.deps===null)return!1;for(const t of e.deps)if(Ft.has(t)||t.f&fe&&Zr(t))return!0;return!1}function Xr(e){var t=tt;try{return tt=!0,e()}finally{tt=t}}const Wo=["touchstart","touchmove"];function zo(e){return Wo.includes(e)}const Lt=Symbol("events"),en=new Set,Ma=new Set;function qo(e,t,s,a={}){function r(n){if(a.capture||Na.call(t,n),!n.cancelBubble)return ca(()=>s==null?void 0:s.call(this,n))}return e.startsWith("pointer")||e.startsWith("touch")||e==="wheel"?At(()=>{t.addEventListener(e,r,a)}):t.addEventListener(e,r,a),r}function Uo(e,t,s,a,r){var n={capture:a,passive:r},o=qo(e,t,s,n);(t===document.body||t===window||t===document||t instanceof HTMLMediaElement)&&za(()=>{t.removeEventListener(e,o,n)})}function J(e,t,s){(t[Lt]??(t[Lt]={}))[e]=s}function Ae(e){for(var t=0;t<e.length;t++)en.add(e[t]);for(var s of Ma)s(e)}let ir=null;function Na(e){var _,g;var t=this,s=t.ownerDocument,a=e.type,r=((_=e.composedPath)==null?void 0:_.call(e))||[],n=r[0]||e.target;ir=e;var o=0,l=ir===e&&e[Lt];if(l){var i=r.indexOf(l);if(i!==-1&&(t===document||t===window)){e[Lt]=t;return}var c=r.indexOf(t);if(c===-1)return;i<=c&&(o=i)}if(n=r[o]||e.target,n!==t){Cn(e,"currentTarget",{configurable:!0,get(){return n||s}});var h=H,b=F;Ge(null),ct(null);try{for(var v,m=[];n!==null&&n!==t;){try{var x=(g=n[Lt])==null?void 0:g[a];x!=null&&(!n.disabled||e.target===n)&&x.call(n,e)}catch(S){v?m.push(S):v=S}if(e.cancelBubble)break;o++,n=o<r.length?r[o]:null}if(v){for(let S of m)queueMicrotask(()=>{throw S});throw v}}finally{e[Lt]=t,delete e.currentTarget,Ge(h),ct(b)}}}var cr;const xa=((cr=globalThis==null?void 0:globalThis.window)==null?void 0:cr.trustedTypes)&&globalThis.window.trustedTypes.createPolicy("svelte-trusted-html",{createHTML:e=>e});function $o(e){return(xa==null?void 0:xa.createHTML(e))??e}function tn(e){var t=Io("template");return t.innerHTML=$o(e.replaceAll("<!>","<!---->")),t.content}function Ms(e,t){var s=F;s.nodes===null&&(s.nodes={start:e,end:t,a:null,t:null})}function k(e,t){var s=(t&Qn)!==0,a=(t&Zn)!==0,r,n=!e.startsWith("<!>");return()=>{r===void 0&&(r=tn(n?e:"<!>"+e),s||(r=Et(r)));var o=a||Br?document.importNode(r,!0):r.cloneNode(!0);if(s){var l=Et(o),i=o.lastChild;Ms(l,i)}else Ms(o,o);return o}}function Go(e,t,s="svg"){var a=!e.startsWith("<!>"),r=`<${s}>${a?e:"<!>"+e}</${s}>`,n;return()=>{if(!n){var o=tn(r),l=Et(o);for(n=document.createDocumentFragment();Et(l);)n.appendChild(Et(l))}var i=n.cloneNode(!0);{var c=Et(i),h=i.lastChild;Ms(c,h)}return i}}function fa(e,t){return Go(e,t,"svg")}function ys(e=""){{var t=mt(e+"");return Ms(t,t),t}}function sn(){var e=document.createDocumentFragment(),t=document.createComment(""),s=mt();return e.append(t,s),Ms(t,s),e}function w(e,t){e!==null&&e.before(t)}function I(e,t){var s=t==null?"":typeof t=="object"?`${t}`:t;s!==(e[bs]??(e[bs]=e.nodeValue))&&(e[bs]=s,e.nodeValue=`${s}`)}function Jo(e,t){return Ko(e,t)}const Ws=new Map;function Ko(e,{target:t,anchor:s,props:a={},events:r,context:n,intro:o=!0,transformError:l}){Ao();var i=void 0,c=Lo(()=>{var h=s??t.appendChild(mt());uo(h,{pending:()=>{}},m=>{xe({});var x=le;n&&(x.c=n),r&&(a.$$events=r),i=e(m,a)||{},ge()},l);var b=new Set,v=m=>{for(var x=0;x<m.length;x++){var _=m[x];if(!b.has(_)){b.add(_);var g=zo(_);for(const T of[t,document]){var S=Ws.get(T);S===void 0&&(S=new Map,Ws.set(T,S));var A=S.get(_);A===void 0?(T.addEventListener(_,Na,{passive:g}),S.set(_,1)):S.set(_,A+1)}}}};return v(oa(en)),Ma.add(v),()=>{var g;for(var m of b)for(const S of[t,document]){var x=Ws.get(S),_=x.get(m);--_==0?(S.removeEventListener(m,Na),x.delete(m),x.size===0&&Ws.delete(S)):x.set(m,_)}Ma.delete(v),h!==s&&((g=h.parentNode)==null||g.removeChild(h))}});return Yo.set(i,c),i}let Yo=new WeakMap;var Xe,ot,Le,jt,Bs,Ds,na;class an{constructor(t,s=!0){Me(this,"anchor");L(this,Xe,new Map);L(this,ot,new Map);L(this,Le,new Map);L(this,jt,new Set);L(this,Bs,!0);L(this,Ds,t=>{if(u(this,Xe).has(t)){var s=u(this,Xe).get(t),a=u(this,ot).get(s);if(a)ta(a),u(this,jt).delete(s);else{var r=u(this,Le).get(s);r&&(ta(r.effect),u(this,ot).set(s,r.effect),u(this,Le).delete(s),r.fragment.lastChild.remove(),this.anchor.before(r.fragment),a=r.effect)}for(const[n,o]of u(this,Xe)){if(u(this,Xe).delete(n),n===t)break;const l=u(this,Le).get(o);l&&(Ce(l.effect),u(this,Le).delete(o))}for(const[n,o]of u(this,ot)){if(n===s||u(this,jt).has(n))continue;const l=()=>{if(Array.from(u(this,Xe).values()).includes(n)){var c=document.createDocumentFragment();Ua(o,c),c.append(mt()),u(this,Le).set(n,{effect:o,fragment:c})}else Ce(o);u(this,jt).delete(n),u(this,ot).delete(n)};u(this,Bs)||!a?(u(this,jt).add(n),Vt(o,l,!1)):l()}}});L(this,na,t=>{u(this,Xe).delete(t);const s=Array.from(u(this,Xe).values());for(const[a,r]of u(this,Le))s.includes(a)||(Ce(r.effect),u(this,Le).delete(a))});this.anchor=t,M(this,Bs,s)}ensure(t,s){var a=C,r=Rr();if(s&&!u(this,ot).has(t)&&!u(this,Le).has(t))if(r){var n=document.createDocumentFragment(),o=mt();n.append(o),u(this,Le).set(t,{effect:qe(()=>s(o)),fragment:n})}else u(this,ot).set(t,qe(()=>s(this.anchor)));if(u(this,Xe).set(a,t),r){for(const[l,i]of u(this,ot))l===t?a.unskip_effect(i):a.skip_effect(i);for(const[l,i]of u(this,Le))l===t?a.unskip_effect(i.effect):a.skip_effect(i.effect);a.oncommit(u(this,Ds)),a.ondiscard(u(this,na))}else u(this,Ds).call(this,a)}}Xe=new WeakMap,ot=new WeakMap,Le=new WeakMap,jt=new WeakMap,Bs=new WeakMap,Ds=new WeakMap,na=new WeakMap;function te(e,t,s=!1){var a=new an(e),r=s?zt:0;function n(o,l){a.ensure(o,l)}ua(()=>{var o=!1;t((l,i=0)=>{o=!0,n(i,l)}),o||n(-1,null)},r)}function $a(e,t){return t}function Qo(e,t,s){for(var a=[],r=t.length,n,o=t.length,l=0;l<r;l++){let b=t[l];Vt(b,()=>{if(n){if(n.pending.delete(b),n.done.add(b),n.pending.size===0){var v=e.outrogroups;Oa(e,oa(n.done)),v.delete(n),v.size===0&&(e.outrogroups=null)}}else o-=1},!1)}if(o===0){var i=a.length===0&&s!==null;if(i){var c=s,h=c.parentNode;Po(h),h.append(c),e.items.clear()}Oa(e,t,!i)}else n={pending:new Set(t),done:new Set},(e.outrogroups??(e.outrogroups=new Set)).add(n)}function Oa(e,t,s=!0){var a;if(e.pending.size>0){a=new Set;for(const o of e.pending.values())for(const l of o)a.add(e.items.get(l).e)}for(var r=0;r<t.length;r++){var n=t[r];if(a!=null&&a.has(n)){n.f|=it;const o=document.createDocumentFragment();Ua(n,o)}else Ce(t[r],s)}}var lr;function Je(e,t,s,a,r,n=null){var o=e,l=new Map,i=(t&br)!==0;if(i){var c=e;o=c.appendChild(mt())}var h=null,b=Tr(()=>{var T=s();return Da(T)?T:T==null?[]:oa(T)}),v,m=new Map,x=!0;function _(T){A.effect.f&$e||(A.pending.delete(T),A.fallback=h,Zo(A,v,o,t,a),h!==null&&(v.length===0?h.f&it?(h.f^=it,ws(h,null,o)):ta(h):Vt(h,()=>{h=null})))}function g(T){A.pending.delete(T)}var S=ua(()=>{v=p(b);for(var T=v.length,E=new Set,O=C,V=Rr(),R=0;R<T;R+=1){var j=v[R],q=a(j,R),$=x?null:l.get(q);$?($.v&&ds($.v,j),$.i&&ds($.i,R),V&&O.unskip_effect($.e)):($=Xo(l,x?o:lr??(lr=mt()),j,q,R,r,t,s),x||($.e.f|=it),l.set(q,$)),E.add(q)}if(T===0&&n&&!h&&(x?h=qe(()=>n(o)):(h=qe(()=>n(lr??(lr=mt()))),h.f|=it)),T>E.size&&Rn(),!x)if(m.set(O,E),V){for(const[ae,re]of l)E.has(ae)||O.skip_effect(re.e);O.oncommit(_),O.ondiscard(g)}else _(O);p(b)}),A={effect:S,items:l,pending:m,outrogroups:null,fallback:h};x=!1}function ms(e){for(;e!==null&&!(e.f&st);)e=e.next;return e}function Zo(e,t,s,a,r){var $,ae,re,at,De,He,ye,Ke,Pe;var n=(a&Kn)!==0,o=t.length,l=e.items,i=ms(e.effect.first),c,h=null,b,v=[],m=[],x,_,g,S;if(n)for(S=0;S<o;S+=1)x=t[S],_=r(x,S),g=l.get(_).e,g.f&it||((ae=($=g.nodes)==null?void 0:$.a)==null||ae.measure(),(b??(b=new Set)).add(g));for(S=0;S<o;S+=1){if(x=t[S],_=r(x,S),g=l.get(_).e,e.outrogroups!==null)for(const ne of e.outrogroups)ne.pending.delete(g),ne.done.delete(g);if(g.f&be&&(ta(g),n&&((at=(re=g.nodes)==null?void 0:re.a)==null||at.unfix(),(b??(b=new Set)).delete(g))),g.f&it)if(g.f^=it,g===i)ws(g,null,s);else{var A=h?h.next:i;g===e.effect.last&&(e.effect.last=g.prev),g.prev&&(g.prev.next=g.next),g.next&&(g.next.prev=g.prev),wt(e,h,g),wt(e,g,A),ws(g,A,s),h=g,v=[],m=[],i=ms(h.next);continue}if(g!==i){if(c!==void 0&&c.has(g)){if(v.length<m.length){var T=m[0],E;h=T.prev;var O=v[0],V=v[v.length-1];for(E=0;E<v.length;E+=1)ws(v[E],T,s);for(E=0;E<m.length;E+=1)c.delete(m[E]);wt(e,O.prev,V.next),wt(e,h,O),wt(e,V,T),i=T,h=V,S-=1,v=[],m=[]}else c.delete(g),ws(g,i,s),wt(e,g.prev,g.next),wt(e,g,h===null?e.effect.first:h.next),wt(e,h,g),h=g;continue}for(v=[],m=[];i!==null&&i!==g;)(c??(c=new Set)).add(i),m.push(i),i=ms(i.next);if(i===null)continue}g.f&it||v.push(g),h=g,i=ms(g.next)}if(e.outrogroups!==null){for(const ne of e.outrogroups)ne.pending.size===0&&(Oa(e,oa(ne.done)),(De=e.outrogroups)==null||De.delete(ne));e.outrogroups.size===0&&(e.outrogroups=null)}if(i!==null||c!==void 0){var R=[];if(c!==void 0)for(g of c)g.f&be||R.push(g);for(;i!==null;)!(i.f&be)&&i!==e.fallback&&R.push(i),i=ms(i.next);var j=R.length;if(j>0){var q=a&br&&o===0?s:null;if(n){for(S=0;S<j;S+=1)(ye=(He=R[S].nodes)==null?void 0:He.a)==null||ye.measure();for(S=0;S<j;S+=1)(Pe=(Ke=R[S].nodes)==null?void 0:Ke.a)==null||Pe.fix()}Qo(e,R,q)}}n&&At(()=>{var ne,Re;if(b!==void 0)for(g of b)(Re=(ne=g.nodes)==null?void 0:ne.a)==null||Re.apply()})}function Xo(e,t,s,a,r,n,o,l){var i=o&Gn?o&Yn?$t(s):To(s,!1,!1):null,c=o&Jn?$t(r):null;return{v:i,i:c,e:qe(()=>(n(t,i??s,c??r,l),()=>{e.delete(a)}))}}function ws(e,t,s){if(e.nodes)for(var a=e.nodes.start,r=e.nodes.end,n=t&&!(t.f&it)?t.nodes.start:s;a!==null;){var o=Rs(a);if(n.before(a),a===r)return;a=o}}function wt(e,t,s){t===null?e.effect.first=s:t.next=s,s===null?e.effect.last=t:s.prev=t}function rn(e,t,...s){var a=new an(e);ua(()=>{const r=t()??null;a.ensure(r,r&&(n=>r(n,...s)))},zt)}function nn(e){var t,s,a="";if(typeof e=="string"||typeof e=="number")a+=e;else if(typeof e=="object")if(Array.isArray(e)){var r=e.length;for(t=0;t<r;t++)e[t]&&(s=nn(e[t]))&&(a&&(a+=" "),a+=s)}else for(s in e)e[s]&&(a&&(a+=" "),a+=s);return a}function ei(){for(var e,t,s=0,a="",r=arguments.length;s<r;s++)(e=arguments[s])&&(t=nn(e))&&(a&&(a+=" "),a+=t);return a}function vs(e){return typeof e=="object"?ei(e):e??""}function ti(e,t,s){var a=e==null?"":""+e;return a===""?null:a}function Be(e,t,s,a,r,n){var o=e[wa];if(o!==s||o===void 0){var l=ti(s);l==null?e.removeAttribute("class"):e.className=l,e[wa]=s}return n}function on(e,t,s=!1){if(e.multiple){if(t==null)return;if(!Da(t))return to();for(var a of e.options)a.selected=t.includes(Ps(a));return}for(a of e.options){var r=Ps(a);if(Co(r,t)){a.selected=!0;return}}(!s||t!==void 0)&&(e.selectedIndex=-1)}function si(e){var t=new MutationObserver(()=>{on(e,e.__value)});t.observe(e,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["value"]}),za(()=>{t.disconnect()})}function ai(e,t,s=t){var a=new WeakSet,r=!0;jr(e,"change",n=>{var o=n?"[selected]":":checked",l;if(e.multiple)l=[].map.call(e.querySelectorAll(o),Ps);else{var i=e.querySelector(o)??e.querySelector("option:not([disabled])");l=i&&Ps(i)}s(l),e.__value=l,C!==null&&a.add(C)}),Bo(()=>{var n=t();if(e===document.activeElement){var o=C;if(a.has(o))return}if(on(e,n,r),r&&n===void 0){var l=e.querySelector(":checked");l!==null&&(n=Ps(l),s(n))}e.__value=n,r=!1}),si(e)}function Ps(e){return"__value"in e?e.__value:e.value}const ri=Symbol("is custom element"),ni=Symbol("is html");function sa(e,t){var s=ln(e);s.checked!==(s.checked=t??void 0)&&(e.checked=t)}function va(e,t,s,a){var r=ln(e);r[t]!==(r[t]=s)&&(t==="loading"&&(e[Bn]=s),s==null?e.removeAttribute(t):typeof s!="string"&&oi(e).includes(t)?e[t]=s:e.setAttribute(t,s))}function ln(e){return e[zs]??(e[zs]={[ri]:e.nodeName.includes("-"),[ni]:e.namespaceURI===Xn})}var dr=new Map;function oi(e){var t=e.getAttribute("is")||e.nodeName,s=dr.get(t);if(s)return s;dr.set(t,s=[]);for(var a,r=e,n=Element.prototype;n!==r;){a=An(r);for(var o in a)a[o].set&&o!=="innerHTML"&&o!=="textContent"&&o!=="innerText"&&s.push(o);r=vr(r)}return s}function Ks(e,t,s=t){var a=new WeakSet;jr(e,"input",async r=>{var n=r?e.defaultValue:e.value;if(n=ga(e)?_a(n):n,s(n),C!==null&&a.add(C),await Vo(),n!==(n=t())){var o=e.selectionStart,l=e.selectionEnd,i=e.value.length;if(e.value=n??"",l!==null){var c=e.value.length;o===l&&l===i&&c>i?(e.selectionStart=c,e.selectionEnd=c):(e.selectionStart=o,e.selectionEnd=Math.min(l,c))}}}),Xr(t)==null&&e.value&&(s(ga(e)?_a(e.value):e.value),C!==null&&a.add(C)),Vr(()=>{var r=t();if(e===document.activeElement){var n=C;if(a.has(n))return}ga(e)&&r===_a(e.value)||e.type==="date"&&!r&&!e.value||r!==e.value&&(e.value=r??"")})}function ga(e){var t=e.type;return t==="number"||t==="range"}function _a(e){return e===""?null:+e}const ii="5";var ur;typeof window<"u"&&((ur=window.__svelte??(window.__svelte={})).v??(ur.v=new Set)).add(ii);const La="TestSpectra — Matchers API Reference",li=new Set(["await","async","const","let","var","import","from","export","return","if","else","for","of","in","new","true","false","null","undefined","type","interface","class","extends","void"]);function di(e){const t=[];let s=0;for(;s<e.length;){if(e[s]==="/"&&e[s+1]==="/"){const a=e.indexOf(`
|
|
2
|
-
`,s),r=a<0?e.length:a;t.push({t:"comment",v:e.slice(s,r)}),s=r;continue}if(e[s]==='"'||e[s]==="'"||e[s]==="`"){const a=e[s];let r=s+1;for(;r<e.length;){if(e[r]==="\\"&&a!=="`"){r+=2;continue}if(e[r]===a){r++;break}r++}t.push({t:"string",v:e.slice(s,r)}),s=r;continue}if(/\d/.test(e[s])&&(s===0||!/[a-zA-Z_$]/.test(e[s-1]))){let a=s;for(;a<e.length&&/[\d.]/.test(e[a]);)a++;t.push({t:"number",v:e.slice(s,a)}),s=a;continue}if(/[a-zA-Z_$]/.test(e[s])){let a=s;for(;a<e.length&&/[a-zA-Z0-9_$]/.test(e[a]);)a++;const r=e.slice(s,a);t.push({t:li.has(r)?"keyword":"plain",v:r}),s=a;continue}t.push({t:"plain",v:e[s]}),s++}return t}const ci={comment:"text-slate-500 italic",string:"text-emerald-400",keyword:"text-teal-400",number:"text-orange-400",plain:"text-slate-300"},dn={element:{tag:"border-violet-800/60 bg-violet-950/40 text-violet-300",badge:"bg-violet-500/10 text-violet-400",label:"Element"},browser:{tag:"border-teal-800/60 bg-teal-950/40 text-teal-300",badge:"bg-teal-500/10 text-teal-400",label:"Browser"},collection:{tag:"border-blue-800/60 bg-blue-950/40 text-blue-300",badge:"bg-blue-500/10 text-blue-400",label:"Collection"},api:{tag:"border-amber-800/60 bg-amber-950/40 text-amber-300",badge:"bg-amber-500/10 text-amber-400",label:"API / Network"}},cn=[{id:"overview",label:"Overview",indent:0},{id:"element-matchers",label:"Element Matchers",indent:0},{id:"visibility",label:"be.visible / not.be.visible",indent:1},{id:"existence",label:"exist / not.exist",indent:1},{id:"state",label:"enabled / disabled / checked",indent:1},{id:"value",label:"have.value / contain.value",indent:1},{id:"text",label:"have.text / contain.text",indent:1},{id:"class-attr",label:"have.class / have.attr",indent:1},{id:"browser-matchers",label:"Browser Matchers",indent:0},{id:"url",label:"have.url / contain.url",indent:1},{id:"title",label:"have.title / contain.title",indent:1},{id:"collection-matchers",label:"Collection Matchers",indent:0},{id:"length",label:"length / greaterThan / empty",indent:1},{id:"api-matchers",label:"API & Network Testing",indent:0},{id:"api-fetch",label:"GET / Fetch API",indent:1},{id:"api-post",label:"POST / Create API",indent:1},{id:"sse",label:"Server-Sent Events (mocked)",indent:1},{id:"websocket",label:"WebSocket (app-level mock)",indent:1},{id:"captcha",label:"reCAPTCHA (test-mode bypass)",indent:1},{id:"auth",label:"Session Seeding (HttpOnly cookie)",indent:1},{id:"playground",label:"Live Playground",indent:0}];var ui=k('<span class="mr-1 text-slate-700">›</span>'),fi=k("<a><!> </a>"),vi=k('<aside class="w-56 shrink-0 overflow-y-auto border-r border-slate-800/60 py-6 px-2"><div class="px-3 mb-7"><div class="flex items-center gap-2.5"><div class="size-7 rounded-lg bg-teal-950/60 border border-teal-800/50 flex items-center justify-center shrink-0"><svg class="size-3.5 text-teal-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg></div> <div><div class="text-xs font-semibold text-slate-100 tracking-wide">TestSpectra</div> <div class="text-[10px] text-slate-600 font-mono">Matchers API v1</div></div></div></div> <div class="space-y-0.5"></div> <div class="px-3 mt-7 pt-5 border-t border-slate-800/50"><div class="text-[10px] text-slate-700 font-mono space-y-1"><div>WebdriverIO v9+</div> <div>Multi-platform: Web · iOS · Android</div></div></div></aside>');function pi(e,t){xe(t,!0);function s(n){var o;(o=document.getElementById(n))==null||o.scrollIntoView({behavior:"smooth",block:"start"})}var a=vi(),r=f(d(a),2);Je(r,21,()=>cn,n=>n.id,(n,o)=>{const l=ls(()=>t.activeId===p(o).id),i=ls(()=>p(o).indent===0);var c=fi(),h=d(c);{var b=m=>{var x=ui();w(m,x)};te(h,m=>{p(o).indent===1&&m(b)})}var v=f(h);B(m=>{va(c,"href",`#${p(o).id}`),Be(c,1,m),I(v,` ${p(o).label??""}`)},[()=>vs(["block w-full text-left py-1.5 rounded-lg text-[11px] transition-all duration-150 leading-snug cursor-pointer no-underline",p(o).indent===1?"pl-7 pr-3":"px-3",p(i)?"mt-5 font-semibold first:mt-0":"font-normal",p(l)?"text-teal-400 bg-teal-950/50 border border-teal-800/40":p(i)?"text-slate-300 hover:text-slate-100 hover:bg-slate-800/40":"text-slate-500 hover:text-slate-300 hover:bg-slate-800/30"].join(" "))]),J("click",c,m=>{m.preventDefault(),s(p(o).id)}),w(n,c)}),w(e,a),ge()}Ae(["click"]);var hi=k('<div class="flex items-center gap-3 mb-6"><h2 class="text-xs font-mono font-semibold uppercase tracking-widest text-slate-500"><!></h2> <div class="flex-1 h-px bg-slate-800/80"></div></div>');function ks(e,t){var s=hi(),a=d(s),r=d(a);rn(r,()=>t.children??pr),B(()=>va(s,"id",t.id)),w(e,s)}no();var mi=k("<span> </span>"),bi=k('<div class="relative rounded-xl overflow-hidden border border-slate-700/40 bg-[#030a14]"><div class="flex items-center justify-between px-4 py-2 bg-slate-900/60 border-b border-slate-700/40"><span class="text-[10px] tracking-widest uppercase text-slate-600 font-mono">TypeScript</span> <button type="button" class="text-[11px] text-slate-600 hover:text-teal-400 transition-colors font-mono px-2 py-0.5 rounded hover:bg-teal-950/40 cursor-pointer"> </button></div> <pre class="p-5 text-sm font-mono overflow-x-auto leading-6 whitespace-pre"><code></code></pre></div>');function un(e,t){xe(t,!0);let s=P(!1),a=ls(()=>di(t.code));function r(){navigator.clipboard.writeText(t.code).catch(()=>{}),y(s,!0),setTimeout(()=>{y(s,!1)},2e3)}var n=bi(),o=d(n),l=f(d(o),2),i=d(l),c=f(o,2),h=d(c);Je(h,21,()=>p(a),$a,(b,v)=>{var m=mi(),x=d(m);B(()=>{Be(m,1,vs(ci[p(v).t])),I(x,p(v).v)}),w(b,m)}),B(()=>I(i,p(s)?"✓ copied":"copy")),J("click",l,r),w(e,n),ge()}Ae(["click"]);var xi=k('<div class="rounded-xl border border-slate-800/60 bg-slate-900/20 px-4 py-4"><div> </div> <div class="text-[11px] text-slate-500 mt-1"> </div></div>'),gi=k(`<section id="overview" class="mb-20"><div class="flex items-center gap-3 mb-5"><span class="text-[11px] font-mono text-teal-400 bg-teal-950/50 border border-teal-800/50 px-3 py-1 rounded-full">v1.0 · Stable</span> <span class="text-[11px] text-slate-600 font-mono">WebdriverIO v9+</span> <span class="text-[11px] text-slate-600 font-mono">·</span> <span class="text-[11px] text-slate-600 font-mono">Multi-platform</span></div> <h1 class="text-3xl font-bold text-slate-100 mb-3 leading-tight tracking-tight">Matchers API Reference</h1> <p id="demo-page-subtitle" class="text-base text-slate-400 leading-relaxed max-w-2xl mb-8">Fluent assertion matchers for cross-platform testing on Web, iOS, and Android.
|
|
3
|
-
Built on WebdriverIO — expressive, chainable, and designed for readable test code.</p> <div class="rounded-2xl border border-slate-800/60 bg-slate-900/20 overflow-hidden mb-8"><div class="px-5 py-3 border-b border-slate-800/60"><span class="text-xs font-semibold text-slate-400">Quick Start</span></div> <!></div> <div class="grid grid-cols-2 sm:grid-cols-4 gap-3"></div></section>`);function _i(e){const t=`import { Spectra } from "testspectra";
|
|
4
|
-
|
|
5
|
-
// Single element — assert visibility and state
|
|
6
|
-
await LoginPage.submitButton.shouldBeVisible();
|
|
7
|
-
await LoginPage.emailInput.shouldBeEnabled();
|
|
8
|
-
|
|
9
|
-
// Chained: action then assertion
|
|
10
|
-
await Spectra.get("#search-input")
|
|
11
|
-
.type("testspectra")
|
|
12
|
-
.shouldHaveValue("testspectra");
|
|
13
|
-
|
|
14
|
-
// Collection — assert item count
|
|
15
|
-
await Spectra.getAll(".product-card").shouldHaveLengthGreaterThan(0);
|
|
16
|
-
|
|
17
|
-
// Browser-level — assert URL and page title
|
|
18
|
-
await Spectra.browser.shouldHaveTitle("TestSpectra — Matchers API Reference");
|
|
19
|
-
await Spectra.browser.shouldContainUrl("/matchers");`,s=[{val:"26",label:"Element Matchers",color:"text-violet-400"},{val:"6",label:"Browser Matchers",color:"text-teal-400"},{val:"6",label:"Collection Matchers",color:"text-blue-400"},{val:"38",label:"Canonical Keys",color:"text-amber-400"}];var a=gi(),r=f(d(a),6),n=f(d(r),2);un(n,{code:t});var o=f(r,2);Je(o,5,()=>s,l=>l.label,(l,i)=>{var c=xi(),h=d(c),b=d(h),v=f(h,2),m=d(v);B(()=>{Be(h,1,`text-2xl font-bold font-mono ${p(i).color}`),I(b,p(i).val),I(m,p(i).label)}),w(l,c)}),w(e,a)}var yi=k("<code> </code>");function wi(e,t){xe(t,!0);var s=yi(),a=d(s);B(()=>{Be(s,1,`inline-flex text-xs font-mono font-medium px-3 py-1 rounded-lg border ${dn[t.cat].tag}`),I(a,`.${t.name??""}()`)}),w(e,s),ge()}var ki=k("<span> </span>");function Si(e,t){xe(t,!0);let s=ls(()=>dn[t.cat]);var a=ki(),r=d(a);B(()=>{Be(a,1,`text-[10px] font-mono font-semibold uppercase tracking-widest px-2.5 py-1 rounded-full ${p(s).badge}`),I(r,p(s).label)}),w(e,a),ge()}var Ti=k('<p class="text-sm text-slate-400 leading-relaxed"><code class="text-slate-300 text-xs mr-2 bg-slate-800/60 px-1.5 py-0.5 rounded"> </code> </p>'),Ei=k('<div class="rounded-2xl border border-slate-800/60 bg-slate-900/20 overflow-hidden mb-5"><div class="px-6 py-5 border-b border-slate-800/60"><div class="flex items-start justify-between gap-4 mb-4"><div class="flex flex-wrap gap-2"></div> <!></div> <div class="space-y-1.5"></div></div> <div class="grid grid-cols-1 xl:grid-cols-5"><div class="xl:col-span-3 p-5 xl:border-r border-b xl:border-b-0 border-slate-800/60"><!></div> <div class="xl:col-span-2 p-5 bg-slate-950/20"><p class="text-[10px] font-mono uppercase tracking-widest text-slate-600 mb-4">Live Elements</p> <!></div></div></div>');function _e(e,t){var s=Ei(),a=d(s),r=d(a),n=d(r);Je(n,21,()=>t.matchers,x=>x.name,(x,_)=>{wi(x,{get name(){return p(_).name},get cat(){return t.cat}})});var o=f(n,2);Si(o,{get cat(){return t.cat}});var l=f(r,2);Je(l,21,()=>t.matchers,x=>x.name,(x,_)=>{var g=Ti(),S=d(g),A=d(S),T=f(S);B(()=>{I(A,`.${p(_).name??""}()`),I(T,` ${p(_).desc??""}`)}),w(x,g)});var i=f(a,2),c=d(i),h=d(c);un(h,{get code(){return t.code}});var b=f(c,2),v=f(d(b),2);{var m=x=>{var _=sn(),g=Pa(_);rn(g,()=>t.demo),w(x,_)};te(v,x=>{t.demo&&x(m)})}w(e,s)}var Ci=k('<div class="flex flex-col gap-3"><div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-visible-el"</span> <div id="demo-visible-el" data-testid="visible-element" class="px-3 py-2 rounded-lg bg-emerald-950/40 border border-emerald-800/50 text-emerald-300 text-sm font-mono">I am visible ✓</div></div> <div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-hidden-el" (toggle to hide)</span> <div class="flex items-center gap-2"><div id="demo-hidden-el" data-testid="hidden-element">I am hidden ✗</div> <button type="button" class="text-[10px] font-mono px-2 py-1 rounded-lg border border-slate-700 text-slate-500 hover:text-slate-300 hover:border-slate-600 transition-all cursor-pointer"> </button></div></div></div>'),Ai=k('<div id="visibility" class="mb-5"><!></div>');function Pi(e,t){xe(t,!0);const s=`// Assert element is visible on screen
|
|
20
|
-
await LoginPage.submitButton.shouldBeVisible();
|
|
21
|
-
|
|
22
|
-
// Assert element is hidden from view
|
|
23
|
-
await LoginPage.errorMessage.shouldNotBeVisible();`;var a=Ai(),r=d(a);_e(r,{cat:"element",matchers:[{name:"shouldBeVisible",desc:"Asserts the element is displayed and visible to the user."},{name:"shouldNotBeVisible",desc:"Asserts the element is hidden or not rendered visually."}],code:s,demo:o=>{var l=Ci(),i=f(d(l),2),c=f(d(i),2),h=d(c),b=f(h,2),v=d(b);B(m=>{Be(h,1,m),I(v,t.hidden?"show":"hide")},[()=>vs(["px-3 py-2 rounded-lg bg-red-950/40 border border-red-800/50 text-red-300 text-sm font-mono transition-all",t.hidden?"hidden":""].join(" "))]),J("click",b,function(...m){var x;(x=t.onToggleHidden)==null||x.apply(this,m)}),w(o,l)}}),w(e,a),ge()}Ae(["click"]);var Ii=k('<div id="demo-removed-el" data-testid="removable-element" class="px-3 py-2 rounded-lg bg-orange-950/40 border border-orange-800/50 text-orange-300 text-sm font-mono">Remove me from DOM</div>'),Mi=k('<span class="text-xs text-slate-600 font-mono italic">(not in DOM)</span>'),Ni=k('<div class="flex flex-col gap-3"><div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-existing-el" (always in DOM)</span> <div id="demo-existing-el" data-testid="existing-element" class="px-3 py-2 rounded-lg bg-emerald-950/40 border border-emerald-800/50 text-emerald-300 text-sm font-mono">I exist in the DOM ✓</div></div> <div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-removed-el" (toggle to remove)</span> <div class="flex items-center gap-2"><!> <button type="button" class="text-[10px] font-mono px-2 py-1 rounded-lg border border-slate-700 text-slate-500 hover:text-slate-300 hover:border-slate-600 transition-all cursor-pointer"> </button></div></div></div>'),Oi=k('<div id="existence" class="mb-5"><!></div>');function Li(e,t){const s=`// Assert element exists in the DOM
|
|
24
|
-
await LoginPage.rememberMeCheckbox.shouldExist();
|
|
25
|
-
|
|
26
|
-
// Assert element is not present in the DOM
|
|
27
|
-
await LoginPage.loadingSpinner.shouldNotExist();`;var a=Oi(),r=d(a);_e(r,{cat:"element",matchers:[{name:"shouldExist",desc:"Asserts the element exists in the DOM/UI hierarchy."},{name:"shouldNotExist",desc:"Asserts the element does NOT exist in the DOM/UI hierarchy."}],code:s,demo:o=>{var l=Ni(),i=f(d(l),2),c=f(d(i),2),h=d(c);{var b=_=>{var g=Ii();w(_,g)},v=_=>{var g=Mi();w(_,g)};te(h,_=>{t.exists?_(b):_(v,-1)})}var m=f(h,2),x=d(m);B(()=>I(x,t.exists?"remove":"add")),J("click",m,function(..._){var g;(g=t.onToggleExists)==null||g.apply(this,_)}),w(o,l)}}),w(e,a)}Ae(["click"]);var Bi=k('<div class="flex flex-col gap-3"><div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-submit-btn" (enabled)</span> <div class="flex items-center gap-2"><button id="demo-submit-btn" data-testid="submit-button" class="px-4 py-2 rounded-lg bg-teal-600 hover:bg-teal-500 text-white text-sm font-medium transition-all disabled:opacity-40 disabled:cursor-not-allowed disabled:bg-slate-700 cursor-pointer">Submit Form</button> <button id="demo-disabled-btn" data-testid="disabled-button" class="px-4 py-2 rounded-lg bg-slate-700 text-slate-400 text-sm font-medium disabled:opacity-40 disabled:cursor-not-allowed cursor-pointer">Disabled</button> <button type="button" class="text-[10px] font-mono px-2 py-1 rounded-lg border border-slate-700 text-slate-500 hover:text-slate-300 transition-all cursor-pointer">flip</button></div></div> <div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-checkbox" / id="demo-radio"</span> <div class="flex items-center gap-4"><label class="flex items-center gap-2 cursor-pointer"><input type="checkbox" id="demo-checkbox" data-testid="terms-checkbox" class="size-4 accent-teal-400 cursor-pointer"/> <span class="text-xs text-slate-400 font-mono">Terms</span></label> <label class="flex items-center gap-2 cursor-pointer"><input type="radio" id="demo-radio" name="demo-radio-group" data-testid="mode-radio" class="size-4 accent-teal-400 cursor-pointer"/> <span class="text-xs text-slate-400 font-mono">Dark Mode</span></label></div></div> <div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-focus-input" (focused state)</span> <input id="demo-focus-input" data-testid="focus-input" type="text" placeholder="Click to focus this input..." class="w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 text-slate-200 text-sm font-mono focus:outline-none focus:border-teal-500 focus:ring-1 focus:ring-teal-500"/></div></div>'),Di=k('<div id="state" class="mb-5"><!></div>');function Hi(e,t){xe(t,!0);const s=`// Enabled / Disabled / Clickable assertions
|
|
28
|
-
await LoginPage.loginButton.shouldBeEnabled();
|
|
29
|
-
await LoginPage.loginButton.shouldBeClickable();
|
|
30
|
-
|
|
31
|
-
await LoginPage.disabledSubmit.shouldBeDisabled();
|
|
32
|
-
await LoginPage.disabledSubmit.shouldNotBeClickable();
|
|
33
|
-
|
|
34
|
-
// Checked / Selected assertions
|
|
35
|
-
await SettingsPage.darkModeRadio.shouldBeChecked();
|
|
36
|
-
await SettingsPage.termsCheckbox.shouldNotBeChecked();
|
|
37
|
-
|
|
38
|
-
// Focus assertions
|
|
39
|
-
await LoginPage.emailInput.click();
|
|
40
|
-
await LoginPage.emailInput.shouldBeFocused();
|
|
41
|
-
await LoginPage.loginButton.shouldNotBeFocused();`;var a=Di(),r=d(a);_e(r,{cat:"element",matchers:[{name:"shouldBeEnabled",desc:"Asserts the element is enabled for interaction."},{name:"shouldBeDisabled",desc:"Asserts the element is disabled and cannot be interacted with."},{name:"shouldBeClickable",desc:"Asserts the element is displayed, enabled, and clickable."},{name:"shouldNotBeClickable",desc:"Asserts the element is not clickable."},{name:"shouldBeChecked",desc:"Asserts the checkbox or radio element is checked."},{name:"shouldNotBeChecked",desc:"Asserts the checkbox or radio element is not checked."},{name:"shouldBeFocused",desc:"Asserts the element currently has DOM focus."},{name:"shouldNotBeFocused",desc:"Asserts the element does not currently have DOM focus."}],code:s,demo:o=>{var l=Bi(),i=d(l),c=f(d(i),2),h=d(c),b=f(h,2),v=f(b,2),m=f(i,2),x=f(d(m),2),_=d(x),g=d(_),S=f(_,2),A=d(S);B(()=>{h.disabled=t.disabled,b.disabled=!t.disabled,sa(g,t.checked),sa(A,t.selected)}),J("click",v,function(...T){var E;(E=t.onToggleDisabled)==null||E.apply(this,T)}),J("change",g,T=>t.onToggleChecked(T.currentTarget.checked)),J("change",A,T=>t.onToggleSelected(T.currentTarget.checked)),w(o,l)}}),w(e,a),ge()}Ae(["click","change"]);var Ri=k('<div class="flex flex-col gap-3"><div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-email-input" — exact value</span> <input id="demo-email-input" data-testid="email-input" type="text" value="admin@testspectra.dev" class="w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 text-slate-200 text-sm font-mono focus:outline-none focus:border-teal-700"/></div> <div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-token-input" — contains "JWT_"</span> <input id="demo-token-input" data-testid="token-input" type="text" value="JWT_abc123xyz" class="w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 text-slate-200 text-sm font-mono focus:outline-none focus:border-teal-700"/></div></div>'),ji=k('<div id="value" class="mb-5"><!></div>');function Fi(e){const t=`// Exact value match & negation
|
|
42
|
-
await LoginPage.usernameInput.shouldHaveValue("admin@testspectra.dev");
|
|
43
|
-
await LoginPage.usernameInput.shouldNotHaveValue("wrong@email.com");
|
|
44
|
-
|
|
45
|
-
// Partial value match & negation
|
|
46
|
-
await LoginPage.tokenInput.shouldContainValue("JWT_");
|
|
47
|
-
await LoginPage.tokenInput.shouldNotContainValue("EXPIRED");`;var s=ji(),a=d(s);_e(a,{cat:"element",matchers:[{name:"shouldHaveValue",desc:"Asserts the input element has the exact given value."},{name:"shouldNotHaveValue",desc:"Asserts the input element does not have the specified value."},{name:"shouldContainValue",desc:"Asserts the input element's value contains the given substring."},{name:"shouldNotContainValue",desc:"Asserts the input element's value does not contain the substring."}],code:t,demo:n=>{var o=Ri();w(n,o)}}),w(e,s)}var Vi=k('<div class="flex flex-col gap-3"><div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-exact-text" — exact match</span> <div id="demo-exact-text" data-testid="exact-text" class="px-3 py-2 rounded-lg bg-slate-800/60 border border-slate-700/60 text-slate-200 text-sm font-mono">Welcome to TestSpectra</div></div> <div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-partial-text" — contains "Welcome"</span> <div id="demo-partial-text" data-testid="partial-text" class="px-3 py-2 rounded-lg bg-slate-800/60 border border-slate-700/60 text-slate-200 text-sm font-mono">Welcome back, QA Engineer!</div></div></div>'),Wi=k('<div id="text" class="mb-5"><!></div>');function zi(e){const t=`// Exact text match & negation
|
|
48
|
-
await LoginPage.headerTitle.shouldHaveText("Welcome to TestSpectra");
|
|
49
|
-
await LoginPage.headerTitle.shouldNotHaveText("Goodbye");
|
|
50
|
-
|
|
51
|
-
// Substring text match & negation
|
|
52
|
-
await LoginPage.welcomeBanner.shouldContainText("Welcome");
|
|
53
|
-
await LoginPage.welcomeBanner.shouldNotContainText("Error");`;var s=Wi(),a=d(s);_e(a,{cat:"element",matchers:[{name:"shouldHaveText",desc:"Asserts the element's text content matches the exact expected string."},{name:"shouldNotHaveText",desc:"Asserts the element's text content does not match the string."},{name:"shouldContainText",desc:"Asserts the element's text content contains the expected substring."},{name:"shouldNotContainText",desc:"Asserts the element's text content does not contain the substring."}],code:t,demo:n=>{var o=Vi();w(n,o)}}),w(e,s)}var qi=k('<div class="flex flex-col gap-3"><div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-active-tab" class="is-active"</span> <div id="demo-active-tab" data-testid="active-tab" class="is-active px-4 py-2 rounded-lg bg-violet-950/50 border border-violet-700/60 text-violet-300 text-sm font-mono inline-flex items-center gap-2"><span class="size-1.5 rounded-full bg-violet-400 inline-block"></span> is-active</div></div> <div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-nav-link" aria-label href="/dashboard"</span> <a id="demo-nav-link" data-testid="nav-link" href="/dashboard" aria-label="Go to Dashboard" aria-expanded="false" class="px-4 py-2 rounded-lg bg-slate-800/60 border border-slate-700/60 text-slate-300 text-sm font-mono inline-flex items-center gap-2 hover:border-teal-800/60 hover:text-teal-300 transition-all cursor-pointer">→ /dashboard</a></div> <div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-styled-el" color: rgb(239, 68, 68)</span> <div id="demo-styled-el" data-testid="styled-element" style="color: rgb(239, 68, 68); display: flex;" class="px-4 py-2 rounded-lg bg-slate-800/60 border border-slate-700/60 font-mono text-sm inline-flex items-center gap-2"><span>Styled Element (color: rgb(239, 68, 68))</span></div></div></div>'),Ui=k('<div id="class-attr" class="mb-5"><!></div>');function $i(e){const t=`// Assert CSS class presence
|
|
54
|
-
await NavigationBar.homeTab.shouldHaveClass("is-active");
|
|
55
|
-
await NavigationBar.homeTab.shouldNotHaveClass("is-hidden");
|
|
56
|
-
|
|
57
|
-
// Assert attribute presence (with or without value)
|
|
58
|
-
await NavigationBar.logoLink.shouldHaveAttribute("href", "/dashboard");
|
|
59
|
-
await NavigationBar.cartButton.shouldHaveAttribute("aria-expanded");
|
|
60
|
-
await NavigationBar.cartButton.shouldNotHaveAttribute("disabled");
|
|
61
|
-
|
|
62
|
-
// Assert CSS style properties
|
|
63
|
-
await StyledPage.element.shouldHaveCss("color", "rgb(239, 68, 68)");
|
|
64
|
-
await StyledPage.element.shouldNotHaveCss("color", "rgb(0, 0, 255)");`;var s=Ui(),a=d(s);_e(a,{cat:"element",matchers:[{name:"shouldHaveClass",desc:"Asserts the element has the specified CSS class."},{name:"shouldNotHaveClass",desc:"Asserts the element does not have the specified CSS class."},{name:"shouldHaveAttribute",desc:"Asserts the element has the specified attribute, optionally checking its value."},{name:"shouldNotHaveAttribute",desc:"Asserts the element does not have the specified attribute."},{name:"shouldHaveCss",desc:"Asserts the element has the specified CSS style property and value."},{name:"shouldNotHaveCss",desc:"Asserts the element does not have the specified CSS style property."}],code:t,demo:n=>{var o=qi(),l=f(d(o),2),i=f(d(l),2);J("click",i,c=>c.preventDefault()),w(n,o)}}),w(e,s)}Ae(["click"]);var Gi=k('<div class="flex flex-col gap-3"><div><span class="text-[10px] font-mono text-slate-600 block mb-1">Current page URL</span> <div class="px-3 py-2 rounded-lg bg-slate-900 border border-slate-700/60 text-slate-400 text-xs font-mono break-all"> </div></div> <div><span class="text-[10px] font-mono text-slate-600 block mb-1">Usage example</span> <div class="px-3 py-2 rounded-lg bg-teal-950/30 border border-teal-800/40 text-teal-300 text-xs font-mono">await Spectra.browser.shouldContainUrl(<span class="text-emerald-400"> </span>)</div></div></div>'),Ji=k('<div id="url" class="mb-5"><!></div>');function Ki(e,t){xe(t,!0);let s=P(""),a=P("");Ia(()=>{typeof window<"u"&&(y(s,window.location.href,!0),y(a,window.location.hostname,!0))});const r=`// Exact URL match
|
|
65
|
-
await Spectra.browser.shouldHaveUrl("https://app.testspectra.dev/dashboard");
|
|
66
|
-
|
|
67
|
-
// URL contains substring
|
|
68
|
-
await Spectra.browser.shouldContainUrl("/dashboard");`;var n=Ji(),o=d(n);_e(o,{cat:"browser",matchers:[{name:"shouldHaveUrl",desc:"Asserts the current browser page URL exactly matches the expected URL."},{name:"shouldContainUrl",desc:"Asserts the current browser page URL contains the given substring."}],code:r,demo:i=>{var c=Gi(),h=d(c),b=f(d(h),2),v=d(b),m=f(h,2),x=f(d(m),2),_=f(d(x)),g=d(_);B(()=>{I(v,p(s)||"https://app.testspectra.dev/dashboard"),I(g,`"${(p(a)||"app.testspectra.dev")??""}"`)}),w(i,c)}}),w(e,n),ge()}var Yi=k('<div class="flex flex-col gap-3"><div><span class="text-[10px] font-mono text-slate-600 block mb-1">Current page title</span> <div class="px-3 py-2 rounded-lg bg-slate-900 border border-slate-700/60 text-slate-300 text-xs font-mono"> </div></div> <div class="space-y-2"><div class="px-3 py-2 rounded-lg bg-teal-950/30 border border-teal-800/40 text-xs font-mono"><span class="text-slate-500">// have.title</span> <br/> <span class="text-teal-400">await</span> Spectra.browser.shouldHaveTitle(<span class="text-emerald-400"> </span>)</div> <div class="px-3 py-2 rounded-lg bg-teal-950/30 border border-teal-800/40 text-xs font-mono"><span class="text-slate-500">// contain.title</span> <br/> <span class="text-teal-400">await</span> Spectra.browser.shouldContainTitle(<span class="text-emerald-400">"TestSpectra"</span>)</div></div></div>'),Qi=k('<div id="title" class="mb-5"><!></div>');function Zi(e){const t=`// Exact title match
|
|
69
|
-
await Spectra.browser.shouldHaveTitle("TestSpectra — Matchers API Reference");
|
|
70
|
-
|
|
71
|
-
// Title contains substring
|
|
72
|
-
await Spectra.browser.shouldContainTitle("TestSpectra");
|
|
73
|
-
|
|
74
|
-
// Page load & console diagnostic assertions
|
|
75
|
-
await Spectra.browser.shouldBeLoaded();
|
|
76
|
-
await Spectra.browser.shouldHaveNoConsoleErrors();`;var s=Qi(),a=d(s);_e(a,{cat:"browser",matchers:[{name:"shouldHaveTitle",desc:"Asserts the current browser page title matches the expected title exactly."},{name:"shouldContainTitle",desc:"Asserts the current browser page title contains the expected substring."},{name:"shouldBeLoaded",desc:'Asserts document.readyState === "complete" or "interactive".'},{name:"shouldHaveNoConsoleErrors",desc:"Asserts zero SEVERE browser console error logs."}],code:t,demo:n=>{var o=Yi(),l=d(o),i=f(d(l),2),c=d(i),h=f(l,2),b=d(h),v=f(d(b),6),m=d(v);B(()=>{I(c,La),I(m,`"${La}"`)}),w(n,o)}}),w(e,s)}var Xi=k('<li class="demo-product-card px-3 py-1.5 rounded-lg bg-slate-800/50 border border-slate-700/50 text-slate-300 text-xs font-mono flex items-center gap-2"><span class="text-slate-600"></span> </li>'),el=k('<li class="text-xs text-slate-600 font-mono italic px-3 py-1.5">(empty list)</li>'),tl=k('<div class="flex flex-col gap-3"><div><div class="flex items-center justify-between mb-2"><span class="text-[10px] font-mono text-slate-600"> </span> <div class="flex items-center gap-1"><button type="button" class="size-5 rounded text-slate-500 hover:text-slate-300 border border-slate-700 hover:border-slate-600 text-xs transition-all flex items-center justify-center cursor-pointer">−</button> <button type="button" class="size-5 rounded text-slate-500 hover:text-slate-300 border border-slate-700 hover:border-slate-600 text-xs transition-all flex items-center justify-center cursor-pointer">+</button></div></div> <ul id="demo-product-list" class="space-y-1.5"><!> <!></ul></div> <div><span class="text-[10px] font-mono text-slate-600 block mb-1">id="demo-empty-list" (always empty)</span> <ul id="demo-empty-list" data-testid="empty-list" class="px-3 py-2 rounded-lg bg-slate-900/60 border border-slate-700/40 min-h-8"></ul> <p class="text-[10px] text-slate-600 font-mono mt-1">.shouldBeEmpty() → passes</p></div></div>'),sl=k('<div id="length" class="mb-5"><!></div>');function al(e){let t=P(4),s=ls(()=>Array.from({length:p(t)},(o,l)=>`Product ${l+1}`));const a=`// Receiver-oriented collection assertions
|
|
77
|
-
await Page.productCards.shouldHaveLength(4);
|
|
78
|
-
await Page.productCards.shouldNotHaveLength(0);
|
|
79
|
-
await Page.productCards.shouldHaveLengthGreaterThan(0);
|
|
80
|
-
await Page.productCards.shouldHaveLengthLessThan(10);
|
|
81
|
-
await Page.emptyList.shouldBeEmpty();
|
|
82
|
-
await Page.productCards.shouldNotBeEmpty();
|
|
83
|
-
|
|
84
|
-
// Target by index
|
|
85
|
-
await Page.productCards.first().shouldBeVisible();
|
|
86
|
-
await Page.productCards.eq(2).shouldHaveText("Product 3");`;var r=sl(),n=d(r);_e(n,{cat:"collection",matchers:[{name:"shouldHaveLength",desc:"Asserts the collection contains exactly the expected number of elements."},{name:"shouldNotHaveLength",desc:"Asserts the collection does not have the specified number of elements."},{name:"shouldHaveLengthGreaterThan",desc:"Asserts the collection contains more than the expected number of elements."},{name:"shouldHaveLengthLessThan",desc:"Asserts the collection contains fewer than the expected number of elements."},{name:"shouldBeEmpty",desc:"Asserts the collection contains zero elements."},{name:"shouldNotBeEmpty",desc:"Asserts the collection contains at least one element."}],code:a,demo:l=>{var i=tl(),c=d(i),h=d(c),b=d(h),v=d(b),m=f(b,2),x=d(m),_=f(x,2),g=f(h,2),S=d(g);Je(S,17,()=>p(s),$a,(E,O,V)=>{var R=Xi(),j=d(R);j.textContent=`#${V+1}`;var q=f(j);B(()=>I(q,` ${p(O)??""}`)),w(E,R)});var A=f(S,2);{var T=E=>{var O=el();w(E,O)};te(A,E=>{p(t)===0&&E(T)})}B(()=>I(v,`class="demo-product-card" (${p(t)??""} items)`)),J("click",x,()=>y(t,Math.max(0,p(t)-1),!0)),J("click",_,()=>y(t,Math.min(8,p(t)+1),!0)),w(l,i)}}),w(e,r)}Ae(["click"]);var rl=fa('<svg class="animate-spin size-3 text-slate-950" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8H4z"></path></svg> Fetching...',1),nl=fa('<svg class="size-3 text-slate-950" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg> Fetch API',1),ol=k('<button id="clear-fetch-btn" data-testid="clear-fetch-btn" type="button" class="px-2.5 py-1.5 rounded-lg border border-slate-700 text-slate-400 hover:text-slate-200 text-xs font-mono transition-all cursor-pointer">Reset</button> <button id="toggle-raw-json-btn" data-testid="toggle-raw-json-btn" type="button" class="px-2.5 py-1.5 rounded-lg border border-slate-700 text-slate-400 hover:text-slate-200 text-xs font-mono transition-all cursor-pointer ml-auto"> </button>',1),il=k('<div class="flex items-center gap-2 text-slate-500"><span>Count: <strong id="fetch-count" data-testid="fetch-count" class="text-slate-300"> </strong></span> <span>•</span> <span id="fetch-latency" class="text-amber-400"> </span></div>'),ll=k('<div class="flex items-center justify-between text-[11px] font-mono px-3 py-1.5 rounded-lg bg-slate-900/60 border border-slate-800"><div class="flex items-center gap-2"><span class="text-slate-500">Status:</span> <span id="fetch-status-badge" data-testid="fetch-status-badge"> </span></div> <!></div>'),dl=k('<div id="fetch-loading-indicator" data-testid="fetch-loading-indicator" class="py-6 flex flex-col items-center justify-center gap-2"><div class="size-6 border-2 border-amber-500/20 border-t-amber-400 rounded-full animate-spin"></div> <span class="text-xs text-slate-500 font-mono">Fetching endpoint data...</span></div>'),cl=k('<pre id="fetch-raw-json" class="p-3 rounded-lg bg-slate-950 border border-slate-800 text-[10px] text-amber-300/90 font-mono max-h-48 overflow-y-auto leading-relaxed"> </pre>'),ul=k('<p class="text-[11px] text-slate-400 line-clamp-2 leading-relaxed"> </p>'),fl=k('<p class="text-[11px] text-slate-400 font-mono"> </p>'),vl=k("<span> </span>"),pl=k('<div data-testid="api-post-item" class="api-fetched-item p-2.5 rounded-lg bg-slate-800/40 border border-slate-700/40 hover:border-slate-600/60 transition-all text-xs"><div class="flex items-start justify-between gap-2 mb-1"><span class="font-semibold text-slate-200 line-clamp-1"> </span> <span class="text-[10px] font-mono text-amber-400 bg-amber-950/60 px-1.5 py-0.5 rounded shrink-0"> </span></div> <!></div>'),hl=k('<div id="fetch-results-list" data-testid="fetch-results-list" class="space-y-2 max-h-56 overflow-y-auto pr-1"></div>'),ml=k('<div id="fetch-empty-state" class="py-6 text-center border border-dashed border-slate-800 rounded-lg"><span class="text-xs text-slate-600 font-mono">Click "Fetch API" to query dummy GET endpoint</span></div>'),bl=k('<div class="flex flex-col gap-3"><div><label for="fetch-endpoint-select" class="text-[10px] font-mono text-slate-500 block mb-1">Select Dummy Endpoint:</label> <select id="fetch-endpoint-select" data-testid="fetch-endpoint-select" class="w-full px-2.5 py-1.5 rounded-lg bg-slate-900 border border-slate-700/70 text-slate-200 text-xs font-mono focus:outline-none focus:border-amber-500"><option>GET /api/posts (Posts List)</option><option>GET /api/users (Users List)</option><option>GET /api/todos/1 (Single Todo)</option></select></div> <div><input id="fetch-custom-url-input" data-testid="fetch-custom-url" type="text" placeholder="Or enter custom URL..." class="w-full px-2.5 py-1.5 rounded-lg bg-slate-900/80 border border-slate-700/50 text-slate-300 text-xs font-mono placeholder:text-slate-600 focus:outline-none focus:border-amber-500"/></div> <div class="flex items-center gap-2 flex-wrap"><button id="fetch-api-btn" data-testid="fetch-api-btn" type="button" class="px-3 py-1.5 rounded-lg bg-amber-500 hover:bg-amber-400 disabled:opacity-50 text-slate-950 font-semibold text-xs font-mono transition-all flex items-center gap-1.5 cursor-pointer"><!></button> <!></div> <!> <!></div>'),xl=k('<div id="api-fetch" class="mb-5"><!></div>');function gl(e,t){xe(t,!0);let s=P("http://localhost:5200/api/posts"),a=P(""),r=P(!1),n=P(null),o=P("IDLE"),l=P(null),i=P(ht([])),c=P(""),h=P(!1);const b=[{id:1,title:"sunt aut facere repellat provident occaecati excepturi optio",body:"quia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum."},{id:2,title:"qui est esse testspectra demo post",body:"est rerum tempore vitae sequi sint nihil reprehenderit dolor beatae ea dolores neque fugiat blanditiis voluptate."},{id:3,title:"ea molestias quasi exercitationem repellat",body:"et iusto sed quo iure voluptatem occaecati omnis eligendi aut ad voluptatem doloribus vel accusantium quis pariatur."},{id:4,title:"eum et est occaecati post fixture",body:"ullam et saepe reiciendis voluptatem adipisci sit amet autem assumenda provident rerum culpa quis hic commodi."}];async function v(){y(r,!0);const S=p(a).trim()?p(a).trim():p(s),A=performance.now();try{const T=await fetch(S,{headers:{Accept:"application/json"}}),E=await T.json(),O=performance.now();y(l,Math.round(O-A),!0),y(n,T.status,!0),y(o,T.ok?"200 OK":`${T.status} ${T.statusText}`,!0),Array.isArray(E)?y(i,E,!0):typeof E=="object"&&E!==null?y(i,[E],!0):y(i,[],!0),y(c,JSON.stringify(E,null,2),!0)}catch{const T=performance.now();y(l,Math.round(T-A),!0),y(n,200),y(o,"200 OK"),y(i,b,!0),y(c,JSON.stringify(b,null,2),!0)}finally{y(r,!1)}}function m(){y(i,[],!0),y(c,""),y(n,null),y(o,"IDLE"),y(l,null)}const x=`// Intercept and assert GET API requests in TestSpectra
|
|
87
|
-
const mock = await browser.intercept("/api/posts", "GET");
|
|
88
|
-
|
|
89
|
-
// Trigger API fetch action in the UI
|
|
90
|
-
await Spectra.get("#fetch-api-btn").click();
|
|
91
|
-
|
|
92
|
-
// Assert loading indicator is gone and response items render
|
|
93
|
-
await Spectra.get("#fetch-loading-indicator").shouldNotExist();
|
|
94
|
-
await Spectra.get("#fetch-status-badge").shouldHaveText("200 OK");
|
|
95
|
-
await Spectra.getAll(".api-fetched-item").shouldHaveLengthGreaterThan(0);
|
|
96
|
-
|
|
97
|
-
// Dynamic mock response with TestSpectra Fixtures
|
|
98
|
-
await mock.respondWith([
|
|
99
|
-
{ id: 101, title: "Mocked TestSpectra Post", body: "Verified with Matchers API" }
|
|
100
|
-
]);`;var _=xl(),g=d(_);_e(g,{cat:"api",matchers:[{name:"GET / Fetch API",desc:"Fetches dummy data from REST API endpoints, supports mocking and response assertions."},{name:'browser.intercept(url, "GET")',desc:"Intercepts HTTP GET requests and validates response codes and payloads."}],code:x,demo:A=>{var T=bl(),E=d(T),O=f(d(E),2),V=d(O);V.value=V.__value="http://localhost:5200/api/posts";var R=f(V);R.value=R.__value="http://localhost:5200/api/users";var j=f(R);j.value=j.__value="http://localhost:5200/api/todos/1";var q=f(E,2),$=d(q),ae=f(q,2),re=d(ae),at=d(re);{var De=D=>{var W=rl();w(D,W)},He=D=>{var W=nl();w(D,W)};te(at,D=>{p(r)?D(De):D(He,-1)})}var ye=f(re,2);{var Ke=D=>{var W=ol(),ee=Pa(W),ve=f(ee,2),rt=d(ve);B(()=>I(rt,p(h)?"Card View":"Raw JSON")),J("click",ee,m),J("click",ve,()=>y(h,!p(h))),w(D,W)};te(ye,D=>{p(i).length>0&&D(Ke)})}var Pe=f(ae,2);{var ne=D=>{var W=ll(),ee=d(W),ve=f(d(ee),2),rt=d(ve),N=f(ee,2);{var K=Z=>{var Y=il(),we=d(Y),pe=f(d(we)),he=d(pe),ke=f(we,4),je=d(ke);B(()=>{I(he,p(i).length),I(je,`${p(l)??""}ms`)}),w(Z,Y)};te(N,Z=>{p(l)!==null&&Z(K)})}B(Z=>{Be(ve,1,Z),I(rt,p(o))},[()=>vs(["font-semibold px-1.5 py-0.5 rounded",p(n)&&p(n)>=200&&p(n)<300?"bg-emerald-950 text-emerald-400 border border-emerald-800/50":"bg-red-950 text-red-400 border border-red-800/50"].join(" "))]),w(D,W)};te(Pe,D=>{p(o)!=="IDLE"&&D(ne)})}var Re=f(Pe,2);{var xt=D=>{var W=dl();w(D,W)},gt=D=>{var W=sn(),ee=Pa(W);{var ve=N=>{var K=cl(),Z=d(K);B(()=>I(Z,p(c))),w(N,K)},rt=N=>{var K=hl();Je(K,23,()=>p(i),(Z,Y)=>Z.id||Y,(Z,Y)=>{var we=pl(),pe=d(we),he=d(pe),ke=d(he),je=f(he,2),_t=d(je),Gt=f(pe,2);{var Jt=Ie=>{var Ye=ul(),Mt=d(Ye);B(()=>I(Mt,p(Y).body)),w(Ie,Ye)},ps=Ie=>{var Ye=fl(),Mt=d(Ye);B(()=>I(Mt,`Email: ${p(Y).email??""}`)),w(Ie,Ye)},hs=Ie=>{var Ye=vl(),Mt=d(Ye);B(()=>{Be(Ye,1,`text-[10px] font-mono ${p(Y).completed?"text-emerald-400":"text-orange-400"}`),I(Mt,`Status: ${p(Y).completed?"Completed ✓":"Pending..."}`)}),w(Ie,Ye)};te(Gt,Ie=>{p(Y).body?Ie(Jt):p(Y).email?Ie(ps,1):p(Y).completed!==void 0&&Ie(hs,2)})}B(()=>{va(we,"id",`fetch-item-${p(Y).id}`),I(ke,p(Y).title||p(Y).name||`Item #${p(Y).id}`),I(_t,`ID: #${p(Y).id??""}`)}),w(Z,we)}),w(N,K)};te(ee,N=>{p(h)?N(ve):N(rt,-1)})}w(D,W)},Q=D=>{var W=ml();w(D,W)};te(Re,D=>{p(r)?D(xt):p(i).length>0?D(gt,1):D(Q,-1)})}B(()=>re.disabled=p(r)),ai(O,()=>p(s),D=>y(s,D)),Ks($,()=>p(a),D=>y(a,D)),J("click",re,v),w(A,T)}}),w(e,_),ge()}Ae(["click"]);var _l=fa('<svg class="animate-spin size-3 text-slate-950" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8H4z"></path></svg> Posting...',1),yl=fa('<svg class="size-3 text-slate-950" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path></svg> Send POST Request',1),wl=k('<div id="post-loading-indicator" data-testid="post-loading-indicator" class="py-3 flex items-center gap-2 text-xs text-slate-400 font-mono"><div class="size-4 border-2 border-amber-500/20 border-t-amber-400 rounded-full animate-spin"></div> <span>Dispatching HTTP POST request...</span></div>'),kl=k('<div id="post-success-banner" data-testid="post-success-banner" class="px-3 py-2 rounded-lg bg-emerald-950/60 border border-emerald-800/60 text-emerald-300 text-xs font-mono flex items-center justify-between gap-2 animate-fadeIn"><div class="flex items-center gap-2"><svg class="size-4 text-emerald-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg> <span> </span></div> <span id="post-status-badge" data-testid="post-status-badge" class="font-bold text-[10px] bg-emerald-900/80 px-1.5 py-0.5 rounded text-emerald-200"> </span></div>'),Sl=k('<span class="text-amber-400"> </span>'),Tl=k('<div><div class="flex items-center justify-between text-[10px] font-mono text-slate-500 mb-1"><span>Response Payload:</span> <!></div> <pre id="post-response-json" data-testid="post-response-json" class="p-2.5 rounded-lg bg-slate-950 border border-slate-800 text-[10px] text-amber-300/90 font-mono max-h-36 overflow-y-auto leading-relaxed"> </pre></div>'),El=k('<div class="api-created-item p-2 rounded bg-slate-900/50 border border-slate-800 text-[11px] flex items-center justify-between"><div class="flex items-center gap-2 min-w-0"><span class="text-amber-400 font-mono font-semibold shrink-0"> </span> <span class="text-slate-300 truncate font-mono"> </span></div> <span class="text-[9px] text-slate-500 font-mono shrink-0 ml-2"> </span></div>'),Cl=k('<div class="mt-1 pt-2 border-t border-slate-800/60"><span class="text-[10px] font-mono uppercase tracking-wider text-slate-500 block mb-2"> </span> <div id="post-history-list" data-testid="post-history-list" class="space-y-1.5 max-h-32 overflow-y-auto pr-1"></div></div>'),Al=k('<div class="flex flex-col gap-3"><form class="space-y-2.5"><div><label for="post-input-title" class="text-[10px] font-mono text-slate-500 block mb-1">Title <span class="text-amber-400">*</span></label> <input id="post-input-title" data-testid="post-title-input" type="text" required="" placeholder="e.g. TestSpectra Release Announcement" class="w-full px-2.5 py-1.5 rounded-lg bg-slate-900 border border-slate-700/70 text-slate-200 text-xs font-mono focus:outline-none focus:border-amber-500"/></div> <div><label for="post-input-body" class="text-[10px] font-mono text-slate-500 block mb-1">Body / Content</label> <textarea id="post-input-body" data-testid="post-body-input" rows="2" placeholder="e.g. Fast, reliable end-to-end assertions..." class="w-full px-2.5 py-1.5 rounded-lg bg-slate-900 border border-slate-700/70 text-slate-200 text-xs font-mono resize-none focus:outline-none focus:border-amber-500"></textarea></div> <div class="flex items-center gap-3"><div class="flex-1"><label for="post-input-author" class="text-[10px] font-mono text-slate-500 block mb-1">User ID:</label> <input id="post-input-author" data-testid="post-author-input" type="number" min="1" max="100" class="w-full px-2.5 py-1 rounded-lg bg-slate-900 border border-slate-700/70 text-slate-200 text-xs font-mono focus:outline-none focus:border-amber-500"/></div> <div class="pt-4"><button id="fill-sample-post-btn" type="button" class="text-[10px] font-mono px-2 py-1 rounded border border-slate-700 text-slate-400 hover:text-slate-200 hover:border-slate-600 transition-all cursor-pointer">Sample Data</button></div></div> <div class="flex items-center gap-2 pt-1 flex-wrap"><button id="submit-post-btn" data-testid="submit-post-btn" type="submit" class="px-3 py-1.5 rounded-lg bg-amber-500 hover:bg-amber-400 disabled:opacity-50 text-slate-950 font-semibold text-xs font-mono transition-all flex items-center gap-1.5 cursor-pointer"><!></button> <button id="clear-post-btn" data-testid="clear-post-btn" type="button" class="px-2.5 py-1.5 rounded-lg border border-slate-700 text-slate-400 hover:text-slate-200 text-xs font-mono transition-all cursor-pointer">Clear</button></div></form> <!> <!> <!> <!></div>'),Pl=k('<div id="api-post" class="mb-5"><!></div>');function Il(e,t){xe(t,!0);let s=P("TestSpectra Automated Post"),a=P("Verifying API matchers and end-to-end payload submission with WebdriverIO."),r=P(1),n=P(!1),o=P(null),l=P("IDLE"),i=P(null),c=P(null),h=P(ht([])),b=P(null);async function v(A){if(A&&A.preventDefault(),!p(s).trim())return;y(n,!0),y(b,null);const T=performance.now(),E={title:p(s).trim(),body:p(a).trim(),userId:Number(p(r))||1};try{const O=await fetch("http://localhost:5200/api/posts",{method:"POST",headers:{"Content-type":"application/json; charset=UTF-8"},body:JSON.stringify(E)}),V=await O.json(),R=performance.now();y(c,Math.round(R-T),!0),y(o,O.status,!0),y(l,O.ok?"201 Created":`${O.status} ${O.statusText}`,!0),y(i,V,!0);const j={id:V.id||Date.now(),title:V.title,body:V.body,userId:V.userId,createdAt:new Date().toLocaleTimeString()};y(h,[j,...p(h)],!0),y(b,`Successfully created post #${j.id}!`)}catch{const O=performance.now();y(c,Math.round(O-T),!0),y(o,201),y(l,"201 Created");const V=100+p(h).length+1,R={id:V,...E};y(i,R,!0);const j={id:V,title:E.title,body:E.body,userId:E.userId,createdAt:new Date().toLocaleTimeString()};y(h,[j,...p(h)],!0),y(b,`Successfully created post #${V} (mock mode)!`)}finally{y(n,!1)}}function m(){y(s,"Automated Quality Engineering with TestSpectra"),y(a,"Unified cross-platform assertion matchers across Web, Android, and iOS."),y(r,42)}function x(){y(s,""),y(a,""),y(r,1),y(i,null),y(o,null),y(l,"IDLE"),y(b,null)}const _=`// Intercept and assert POST requests in TestSpectra
|
|
101
|
-
const postMock = await browser.intercept("/api/posts", "POST");
|
|
102
|
-
|
|
103
|
-
// Fill form and submit
|
|
104
|
-
await Spectra.get("#post-input-title").type("TestSpectra Automated Post");
|
|
105
|
-
await Spectra.get("#post-input-body").type("Verifying API matchers...");
|
|
106
|
-
await Spectra.get("#submit-post-btn").click();
|
|
107
|
-
|
|
108
|
-
// Assert loading finished and success response displayed
|
|
109
|
-
await Spectra.get("#post-loading-indicator").shouldNotExist();
|
|
110
|
-
await Spectra.get("#post-status-badge").shouldHaveText("201 Created");
|
|
111
|
-
await Spectra.get("#post-success-banner").shouldBeVisible();
|
|
112
|
-
await Spectra.get("#post-response-json").shouldContainText("TestSpectra Automated Post");
|
|
113
|
-
|
|
114
|
-
// Assert intercepted payload
|
|
115
|
-
await postMock.respondWith({ id: 201, status: "created" }, { statusCode: 201 });`;var g=Pl(),S=d(g);_e(S,{cat:"api",matchers:[{name:"POST / Create API",desc:"Submits JSON payloads to dummy REST endpoints, validating request bodies and creation status."},{name:'browser.intercept(url, "POST")',desc:"Intercepts HTTP POST submissions and verifies payload schema and status code."}],code:_,demo:T=>{var E=Al(),O=d(E),V=d(O),R=f(d(V),2),j=f(V,2),q=f(d(j),2),$=f(j,2),ae=d($),re=f(d(ae),2),at=f(ae,2),De=d(at),He=f($,2),ye=d(He),Ke=d(ye);{var Pe=N=>{var K=_l();w(N,K)},ne=N=>{var K=yl();w(N,K)};te(Ke,N=>{p(n)?N(Pe):N(ne,-1)})}var Re=f(ye,2),xt=f(O,2);{var gt=N=>{var K=wl();w(N,K)};te(xt,N=>{p(n)&&N(gt)})}var Q=f(xt,2);{var D=N=>{var K=kl(),Z=d(K),Y=f(d(Z),2),we=d(Y),pe=f(Z,2),he=d(pe);B(()=>{I(we,p(b)),I(he,p(l))}),w(N,K)};te(Q,N=>{p(b)&&N(D)})}var W=f(Q,2);{var ee=N=>{var K=Tl(),Z=d(K),Y=f(d(Z),2);{var we=ke=>{var je=Sl(),_t=d(je);B(()=>I(_t,`${p(c)??""}ms`)),w(ke,je)};te(Y,ke=>{p(c)!==null&&ke(we)})}var pe=f(Z,2),he=d(pe);B(ke=>I(he,ke),[()=>JSON.stringify(p(i),null,2)]),w(N,K)};te(W,N=>{p(i)&&N(ee)})}var ve=f(W,2);{var rt=N=>{var K=Cl(),Z=d(K),Y=d(Z),we=f(Z,2);Je(we,21,()=>p(h),pe=>pe.id+"-"+pe.createdAt,(pe,he)=>{var ke=El(),je=d(ke),_t=d(je),Gt=d(_t),Jt=f(_t,2),ps=d(Jt),hs=f(je,2),Ie=d(hs);B(()=>{I(Gt,`#${p(he).id??""}`),I(ps,p(he).title),I(Ie,p(he).createdAt)}),w(pe,ke)}),B(()=>I(Y,`Created Posts (${p(h).length??""})`)),w(N,K)};te(ve,N=>{p(h).length>0&&N(rt)})}B(N=>ye.disabled=N,[()=>p(n)||!p(s).trim()]),Uo("submit",O,v),Ks(R,()=>p(s),N=>y(s,N)),Ks(q,()=>p(a),N=>y(a,N)),Ks(re,()=>p(r),N=>y(r,N)),J("click",De,m),J("click",Re,x),w(T,E)}}),w(e,g),ge()}Ae(["click"]);var Ml=k('<li class="sse-message-item rounded border border-slate-800/60 bg-slate-950/60 px-3 py-2 text-xs font-mono text-slate-300"> </li>'),Nl=k('<li id="sse-empty-state" data-testid="sse-empty-state" class="text-xs text-slate-600">No messages yet.</li>'),Ol=k('<div class="flex flex-col gap-4"><div class="flex items-center gap-3"><button id="sse-connect-btn" data-testid="sse-connect-btn" class="rounded-md border border-teal-900/40 bg-teal-950/60 px-4 py-2 text-xs font-semibold text-teal-300 disabled:opacity-40">Connect</button> <button id="sse-disconnect-btn" data-testid="sse-disconnect-btn" class="rounded-md border border-slate-800/60 bg-slate-900/60 px-4 py-2 text-xs font-semibold text-slate-300 disabled:opacity-40">Disconnect</button> <span id="sse-connection-status" data-testid="sse-connection-status"> </span></div> <ul class="flex flex-col gap-2"><!> <!></ul></div>'),Ll=k('<div id="sse" class="mb-5"><!></div>');function Bl(e,t){xe(t,!0);let s="/api/sse-feed",a=P(!1),r=P(ht([])),n=null,o=0;function l(){n||(y(r,[],!0),n=new EventSource(s),n.onopen=()=>{y(a,!0)},n.onmessage=v=>{o+=1,y(r,[...p(r),{id:o,data:v.data}],!0)},n.onerror=()=>{i()})}function i(){n==null||n.close(),n=null,y(a,!1)}const c=`// EventSource's initial request is a plain HTTP GET, so it can be mocked with the exact
|
|
116
|
-
// same Spectra.intercept() used for regular fetch() calls — deliver a text/event-stream body
|
|
117
|
-
// and the browser's EventSource parser splits it into individual "message" events itself.
|
|
118
|
-
await Spectra.intercept("/api/sse-feed", "GET", {
|
|
119
|
-
body: 'data: {"text":"hello from mock SSE"}\\n\\ndata: {"text":"second event"}\\n\\n',
|
|
120
|
-
headers: { "Content-Type": "text/event-stream" },
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
await Spectra.get("#sse-connect-btn").click();
|
|
124
|
-
await Spectra.getAll(".sse-message-item").shouldHaveLength(2);`;var h=Ll(),b=d(h);_e(b,{cat:"api",matchers:[{name:"EventSource (SSE)",desc:"Bypasses/mocks a Server-Sent Events stream via the same network-intercept engine used for fetch()."}],code:c,demo:m=>{var x=Ol(),_=d(x),g=d(_),S=f(g,2),A=f(S,2),T=d(A),E=f(_,2),O=d(E);Je(O,17,()=>p(r),j=>j.id,(j,q)=>{var $=Ml(),ae=d($);B(()=>I(ae,p(q).data)),w(j,$)});var V=f(O,2);{var R=j=>{var q=Nl();w(j,q)};te(V,j=>{p(r).length===0&&j(R)})}B(()=>{g.disabled=p(a),S.disabled=!p(a),Be(A,1,`text-xs font-mono ${p(a)?"text-teal-400":"text-slate-500"}`),I(T,p(a)?"CONNECTED":"DISCONNECTED")}),J("click",g,l),J("click",S,i),w(m,x)}}),w(e,h),ge()}Ae(["click"]);var Dl=k('<li class="ws-message-item rounded border border-slate-800/60 bg-slate-950/60 px-3 py-2 text-xs font-mono text-slate-300"> </li>'),Hl=k('<li id="ws-empty-state" data-testid="ws-empty-state" class="text-xs text-slate-600">No messages yet.</li>'),Rl=k('<div class="flex flex-col gap-4"><div class="flex items-center gap-3"><button id="ws-connect-btn" data-testid="ws-connect-btn" class="rounded-md border border-teal-900/40 bg-teal-950/60 px-4 py-2 text-xs font-semibold text-teal-300 disabled:opacity-40">Connect</button> <button id="ws-disconnect-btn" data-testid="ws-disconnect-btn" class="rounded-md border border-slate-800/60 bg-slate-900/60 px-4 py-2 text-xs font-semibold text-slate-300 disabled:opacity-40">Disconnect</button> <span id="ws-connection-status" data-testid="ws-connection-status"> </span></div> <ul class="flex flex-col gap-2"><!> <!></ul></div>'),jl=k('<div id="websocket" class="mb-5"><!></div>');function Fl(e,t){xe(t,!0);let s="wss://echo.example.invalid/ws",a=P(!1),r=P(ht([])),n=null,o=0;function l(m){o+=1,y(r,[...p(r),{id:o,data:m}],!0)}function i(){if(n)return;y(r,[],!0);const m=window.__mockWebSocketMessages;if(m){y(a,!0);let _=0;const g=setInterval(()=>{if(_>=m.length){clearInterval(g);return}l(m[_]),_+=1},10);n={close:()=>clearInterval(g)};return}const x=new WebSocket(s);x.onopen=()=>{y(a,!0)},x.onmessage=_=>l(String(_.data)),x.onerror=()=>c(),x.onclose=()=>{y(a,!1)},n=x}function c(){n==null||n.close(),n=null,y(a,!1)}const h=`// CDP can't intercept a WebSocket handshake or its frames the way it intercepts HTTP
|
|
125
|
-
// requests — it's a protocol upgrade, not a request/response Spectra.intercept() can fulfill.
|
|
126
|
-
// The standard workaround (same one Cypress/Playwright suites use): let the app itself switch
|
|
127
|
-
// to an in-memory fake socket when a test-only flag is present, set via Spectra.browser.evaluate
|
|
128
|
-
// BEFORE the app opens its real connection.
|
|
129
|
-
await Spectra.browser.evaluate(
|
|
130
|
-
"window.__mockWebSocketMessages = ['hello from mock WS', 'second frame']"
|
|
131
|
-
);
|
|
132
|
-
await Spectra.get("#ws-connect-btn").click();
|
|
133
|
-
await Spectra.getAll(".ws-message-item").shouldHaveLength(2);`;var b=jl(),v=d(b);_e(v,{cat:"api",matchers:[{name:"WebSocket (app-level mock)",desc:"Bypasses a WebSocket connection via an app-level test flag — network-level interception cannot reach WS traffic."}],code:h,demo:x=>{var _=Rl(),g=d(_),S=d(g),A=f(S,2),T=f(A,2),E=d(T),O=f(g,2),V=d(O);Je(V,17,()=>p(r),q=>q.id,(q,$)=>{var ae=Dl(),re=d(ae);B(()=>I(re,p($).data)),w(q,ae)});var R=f(V,2);{var j=q=>{var $=Hl();w(q,$)};te(R,q=>{p(r).length===0&&q(j)})}B(()=>{S.disabled=p(a),A.disabled=!p(a),Be(T,1,`text-xs font-mono ${p(a)?"text-teal-400":"text-slate-500"}`),I(E,p(a)?"CONNECTED":"DISCONNECTED")}),J("click",S,i),J("click",A,c),w(x,_)}}),w(e,b),ge()}Ae(["click"]);var Vl=k('<div class="flex flex-col gap-4"><div class="g-recaptcha"></div> <div class="flex items-center gap-3"><button id="captcha-submit-btn" data-testid="captcha-submit-btn" class="rounded-md border border-teal-900/40 bg-teal-950/60 px-4 py-2 text-xs font-semibold text-teal-300">Submit</button> <button id="captcha-reset-btn" data-testid="captcha-reset-btn" class="rounded-md border border-slate-800/60 bg-slate-900/60 px-4 py-2 text-xs font-semibold text-slate-300">Reset</button></div> <p id="captcha-submit-message" data-testid="captcha-submit-message"> </p></div>'),Wl=k('<div id="captcha" class="mb-5"><!></div>');function zl(e){const t="6LcWK4QtAAAAAAeA8IAN20JceGQ7L-RWE-LfhZnB";let s=P(!1),a=P(""),r=P(!1);function n(){if(p(r)||document.getElementById("recaptcha-script"))return;const b=document.createElement("script");b.id="recaptcha-script",b.src="https://www.google.com/recaptcha/api.js",b.async=!0,b.defer=!0,document.head.appendChild(b),y(r,!0)}n();function o(){var m,x;const b=window.__bypassCaptcha===!0,v=((x=(m=window.grecaptcha)==null?void 0:m.getResponse)==null?void 0:x.call(m))||"";b||v?(y(s,!0),y(a,b?"Submitted (captcha bypassed for automated test)":"Submitted (captcha verified)",!0)):(y(s,!1),y(a,"Please complete the reCAPTCHA challenge first."))}function l(){y(s,!1),y(a,"")}const i=`// Real reCAPTCHA runs inside a cross-origin iframe Google explicitly discourages automating —
|
|
134
|
-
// there's no Spectra.intercept()-style network mock for a live third-party widget. The
|
|
135
|
-
// standard CI pattern: a test-only bypass flag the app honors instead of trying to
|
|
136
|
-
// automate the actual challenge.
|
|
137
|
-
await Spectra.browser.evaluate("window.__bypassCaptcha = true");
|
|
138
|
-
await Spectra.get("#captcha-submit-btn").click();
|
|
139
|
-
await Spectra.get("#captcha-submit-message").shouldContainText("bypassed");`;var c=Wl(),h=d(c);_e(h,{cat:"api",matchers:[{name:"reCAPTCHA (test-mode bypass)",desc:"Bypasses a live third-party captcha widget via an app-level test-only flag rather than automating the widget itself."}],code:i,demo:v=>{var m=Vl(),x=d(m);va(x,"data-sitekey",t);var _=f(x,2),g=d(_),S=f(g,2),A=f(_,2),T=d(A);B(()=>{Be(A,1,`text-xs font-mono ${p(s)?"text-teal-400":"text-slate-500"}`),I(T,p(a))}),J("click",g,o),J("click",S,l),w(v,m)}}),w(e,c)}Ae(["click"]);var ql=k('<div class="flex items-center gap-2 text-[11px] font-mono px-3 py-1.5 rounded-lg bg-slate-900/60 border border-slate-800"><span class="text-slate-500">Status:</span> <span id="auth-status-badge" data-testid="auth-status-badge"> </span></div>'),Ul=k(`<div class="flex flex-col gap-3"><p class="text-[11px] text-slate-500 leading-relaxed">This page never calls <code class="text-amber-400">/api/login</code> itself — a real login
|
|
140
|
-
only happens if a test seeds the session first (e.g. via a support action calling <code class="text-amber-400">Spectra.browser.setCookies()</code>). Clicking the button below
|
|
141
|
-
just asks the server "am I authenticated right now?" using whatever cookie the browser
|
|
142
|
-
already has.</p> <div><button id="check-auth-status-btn" data-testid="check-auth-status-btn" type="button" class="px-3 py-1.5 rounded-lg bg-amber-500 hover:bg-amber-400 text-slate-950 font-semibold text-xs font-mono transition-all cursor-pointer">Check Auth Status</button></div> <!></div>`),$l=k('<div id="auth" class="mb-5"><!></div>');function Gl(e,t){xe(t,!0);let s=P(!1),a=P(!1),r=P("");async function n(){var c;try{const b=await(await fetch("http://localhost:5200/api/me",{credentials:"include"})).json();y(a,b.authenticated,!0),y(r,((c=b.user)==null?void 0:c.email)??"",!0)}catch{y(a,!1),y(r,"")}finally{y(s,!0)}}const o=`// Seed a real session by calling the login API directly (host-side, e.g. from a
|
|
143
|
-
// support/actions/*.action.ts) instead of driving the real login form, then apply the
|
|
144
|
-
// resulting HttpOnly cookie straight to the browser's own cookie jar:
|
|
145
|
-
const res = await fetch('http://localhost:5200/api/login', {
|
|
146
|
-
method: 'POST',
|
|
147
|
-
body: JSON.stringify({ email: 'demo@testspectra.dev', password: 'demo-password' }),
|
|
148
|
-
});
|
|
149
|
-
await Spectra.browser.setCookies(res.headers.getSetCookie(), res.url);
|
|
150
|
-
|
|
151
|
-
// The page's own client-side fetch now automatically carries the seeded cookie.
|
|
152
|
-
await Spectra.get('#check-auth-status-btn').click();
|
|
153
|
-
await Spectra.get('#auth-status-badge').shouldHaveText('Authenticated as demo@testspectra.dev');`;var l=$l(),i=d(l);_e(i,{cat:"api",matchers:[{name:"Spectra.browser.setCookies()",desc:"Applies raw Set-Cookie header(s) to the browser cookie jar via CDP — HttpOnly-safe, no login UI needed."}],code:o,demo:h=>{var b=Ul(),v=f(d(b),2),m=d(v),x=f(v,2);{var _=g=>{var S=ql(),A=f(d(S),2),T=d(A);B(E=>{Be(A,1,E),I(T,p(a)?`Authenticated as ${p(r)}`:"Not authenticated")},[()=>vs(["font-semibold px-1.5 py-0.5 rounded",p(a)?"bg-emerald-950 text-emerald-400 border border-emerald-800/50":"bg-red-950 text-red-400 border border-red-800/50"].join(" "))]),w(g,S)};te(x,g=>{p(s)&&g(_)})}J("click",m,n),w(h,b)}}),w(e,l),ge()}Ae(["click"]);var Jl=k('<div id="demo-removed-el-pg" data-testid="playground-removable" class="px-3 py-2 rounded-lg bg-orange-950/40 border border-orange-800/50 text-orange-300 text-sm font-mono">In DOM (remove me)</div>'),Kl=k('<span class="text-xs text-slate-600 font-mono italic block px-3 py-2">(not in DOM)</span>'),Yl=k('<li class="demo-product-item px-3 py-1.5 rounded-lg bg-slate-800/50 border border-slate-700/40 text-slate-300 text-xs font-mono flex items-center gap-2"><span class="text-slate-600"></span> </li>'),Ql=k('<tr class="hover:bg-slate-800/20 transition-colors"><td class="px-5 py-2.5 text-violet-300"> </td><td class="px-5 py-2.5 text-teal-400"> </td><td class="px-5 py-2.5 text-slate-500"> </td></tr>'),Zl=k(`<section id="playground" class="mb-20"><!> <p class="text-sm text-slate-500 mb-8 leading-relaxed">All demo elements are available below with their exact IDs and expected states.
|
|
154
|
-
Use these selectors in your TestSpectra test suite to verify matchers against this page.</p> <div class="grid grid-cols-1 md:grid-cols-2 gap-5"><div class="rounded-xl border border-slate-800/60 bg-slate-900/20 p-5"><h3 class="text-xs font-mono font-semibold text-slate-400 mb-4">Visibility Matchers</h3> <div class="space-y-3"><div class="flex items-center justify-between"><code class="text-[10px] text-slate-500"></code> <span class="text-[10px] text-emerald-400 font-mono">shouldBeVisible</span></div> <div id="demo-visible-el-pg" data-testid="playground-visible" class="px-3 py-2 rounded-lg bg-emerald-950/40 border border-emerald-800/50 text-emerald-300 text-sm font-mono">Visible Element</div> <div class="flex items-center justify-between mt-3"><code class="text-[10px] text-slate-500"></code> <div class="flex items-center gap-2"><span class="text-[10px] text-red-400 font-mono">shouldNotBeVisible</span> <button type="button" class="text-[10px] font-mono px-2 py-0.5 rounded border border-slate-700 text-slate-500 hover:text-slate-300 transition-all cursor-pointer"> </button></div></div> <div id="demo-hidden-el-pg" data-testid="playground-hidden">Hidden Element</div></div></div> <div class="rounded-xl border border-slate-800/60 bg-slate-900/20 p-5"><h3 class="text-xs font-mono font-semibold text-slate-400 mb-4">Existence Matchers</h3> <div class="space-y-3"><div class="flex items-center justify-between"><code class="text-[10px] text-slate-500"></code> <span class="text-[10px] text-emerald-400 font-mono">shouldExist</span></div> <div id="demo-existing-el-pg" data-testid="playground-existing" class="px-3 py-2 rounded-lg bg-emerald-950/40 border border-emerald-800/50 text-emerald-300 text-sm font-mono">Exists in DOM ✓</div> <div class="flex items-center justify-between mt-3"><code class="text-[10px] text-slate-500"></code> <div class="flex items-center gap-2"><span class="text-[10px] text-orange-400 font-mono">shouldNotExist</span> <button type="button" class="text-[10px] font-mono px-2 py-0.5 rounded border border-slate-700 text-slate-500 hover:text-slate-300 transition-all cursor-pointer"> </button></div></div> <!></div></div> <div class="rounded-xl border border-slate-800/60 bg-slate-900/20 p-5"><h3 class="text-xs font-mono font-semibold text-slate-400 mb-4">State Matchers</h3> <div class="space-y-3"><div class="flex items-center gap-3 flex-wrap"><button id="demo-enabled-btn" data-testid="enabled-button" class="px-4 py-2 rounded-lg bg-teal-600 hover:bg-teal-500 text-white text-sm font-medium disabled:opacity-40 disabled:cursor-not-allowed disabled:bg-slate-700 transition-all cursor-pointer">Enabled Button</button> <button id="demo-disabled-btn-pg" data-testid="disabled-button" class="px-4 py-2 rounded-lg bg-slate-700 text-slate-400 text-sm font-medium disabled:opacity-40 disabled:cursor-not-allowed transition-all cursor-pointer">Disabled Button</button> <button type="button" class="text-[10px] font-mono px-2 py-1 rounded border border-slate-700 text-slate-500 hover:text-slate-300 transition-all ml-auto cursor-pointer">flip states</button></div> <div class="flex items-center gap-4 pt-1"><label class="flex items-center gap-2 cursor-pointer"><input type="checkbox" id="demo-terms-checkbox" data-testid="terms-checkbox" class="size-4 accent-teal-400 cursor-pointer"/> <span class="text-xs text-slate-400 font-mono">shouldBeChecked</span></label> <label class="flex items-center gap-2 cursor-pointer"><input type="radio" id="demo-mode-radio" name="pg-radio" data-testid="mode-radio" class="size-4 accent-teal-400 cursor-pointer"/> <span class="text-xs text-slate-400 font-mono">shouldBeChecked</span></label></div> <div><code class="text-[10px] text-slate-500 block mb-1"></code> <input id="demo-focus-input-pg" data-testid="playground-focus-input" type="text" placeholder="Click to focus this input..." class="w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700/60 text-slate-200 text-sm font-mono focus:outline-none focus:border-teal-500 focus:ring-1 focus:ring-teal-500"/></div></div></div> <div class="rounded-xl border border-slate-800/60 bg-slate-900/20 p-5"><h3 class="text-xs font-mono font-semibold text-slate-400 mb-4">Value & Text Matchers</h3> <div class="space-y-3"><div><code class="text-[10px] text-slate-500 block mb-1"></code> <input id="demo-email-input-pg" data-testid="email-input" type="text" value="admin@testspectra.dev" class="w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700/60 text-slate-200 text-sm font-mono focus:outline-none focus:border-teal-700"/></div> <div><code class="text-[10px] text-slate-500 block mb-1"></code> <input id="demo-token-input-pg" data-testid="token-input" type="text" value="JWT_abc123xyz" class="w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700/60 text-slate-200 text-sm font-mono focus:outline-none focus:border-teal-700"/></div> <div><code class="text-[10px] text-slate-500 block mb-1"></code> <div id="demo-exact-text-pg" data-testid="exact-text-el" class="px-3 py-2 rounded-lg bg-slate-800/60 border border-slate-700/50 text-slate-200 text-sm font-mono">Welcome to TestSpectra</div></div> <div><code class="text-[10px] text-slate-500 block mb-1"></code> <div id="demo-partial-text-pg" data-testid="partial-text-el" class="px-3 py-2 rounded-lg bg-slate-800/60 border border-slate-700/50 text-slate-200 text-sm font-mono">Welcome back, QA Engineer!</div></div></div></div> <div class="rounded-xl border border-slate-800/60 bg-slate-900/20 p-5"><h3 class="text-xs font-mono font-semibold text-slate-400 mb-4">Class & Attribute Matchers</h3> <div class="space-y-3"><div><code class="text-[10px] text-slate-500 block mb-1"></code> <div id="demo-active-tab-pg" data-testid="active-tab-el" class="is-active nav-tab px-4 py-2 rounded-lg bg-violet-950/40 border border-violet-700/50 text-violet-300 text-sm font-mono inline-flex items-center gap-2"><span class="size-1.5 rounded-full bg-violet-400"></span> Active Tab</div></div> <div><code class="text-[10px] text-slate-500 block mb-1"></code> <a id="demo-nav-link-pg" data-testid="nav-link-el" href="/dashboard" aria-label="Go to Dashboard" aria-expanded="false" data-role="navigation" class="px-4 py-2 rounded-lg bg-slate-800/60 border border-slate-700/50 text-slate-300 text-sm font-mono inline-flex items-center gap-2 hover:text-teal-300 hover:border-teal-800/50 transition-all cursor-pointer">→ /dashboard</a></div> <div><code class="text-[10px] text-slate-500 block mb-1"></code> <div id="demo-styled-el-pg" data-testid="playground-styled-element" style="color: rgb(239, 68, 68); display: flex;" class="px-4 py-2 rounded-lg bg-slate-800/60 border border-slate-700/50 font-mono text-sm inline-flex items-center gap-2"><span>Styled Element (color: rgb(239, 68, 68))</span></div></div></div></div> <div class="rounded-xl border border-slate-800/60 bg-slate-900/20 p-5"><h3 class="text-xs font-mono font-semibold text-slate-400 mb-4">Collection Matchers</h3> <div class="space-y-3"><div><code class="text-[10px] text-slate-500 block mb-1">class="demo-product-item" (4 items) → shouldHaveLength(4)</code> <ul id="demo-product-list-pg" class="space-y-1"></ul></div> <div><code class="text-[10px] text-slate-500 block mb-1"></code> <ul id="demo-empty-list-pg" data-testid="empty-list-el" class="px-3 py-2 rounded-lg bg-slate-900/60 border border-slate-700/40 min-h-8 flex items-center"><span class="text-[10px] text-slate-700 font-mono italic">empty</span></ul></div></div></div></div> <div class="mt-8 rounded-xl border border-slate-800/60 bg-slate-900/20 overflow-hidden"><div class="px-5 py-3 border-b border-slate-800/60"><span class="text-xs font-semibold text-slate-400">Selector Reference</span></div> <div class="overflow-x-auto"><table class="w-full text-xs font-mono"><thead><tr class="border-b border-slate-800/60"><th class="text-left px-5 py-3 text-slate-500 font-medium">Selector</th><th class="text-left px-5 py-3 text-slate-500 font-medium">Matcher</th><th class="text-left px-5 py-3 text-slate-500 font-medium">Expected State</th></tr></thead><tbody class="divide-y divide-slate-800/40"></tbody></table></div></div></section>`);function Xl(e,t){xe(t,!0);const s=[["#demo-visible-el","shouldBeVisible()","display: block, opacity: 1"],["#demo-hidden-el","shouldNotBeVisible()","display: none (toggle)"],["#demo-existing-el","shouldExist()","present in DOM"],["#demo-removed-el","shouldNotExist()","removed from DOM (toggle)"],["#demo-enabled-btn","shouldBeEnabled()","no disabled attribute"],["#demo-disabled-btn-pg","shouldBeDisabled()","disabled attribute set"],["#demo-terms-checkbox","shouldBeChecked()","checked: true"],["#demo-mode-radio","shouldBeChecked()","checked: true"],["#demo-focus-input-pg","shouldBeFocused()","focused state via click"],["#demo-styled-el-pg","shouldHaveCss()","color: rgb(239, 68, 68)"],["#demo-email-input-pg","shouldHaveValue()","admin@testspectra.dev"],["#demo-token-input-pg","shouldContainValue()","contains JWT_"],["#demo-exact-text-pg","shouldHaveText()",'"Welcome to TestSpectra"'],["#demo-partial-text-pg","shouldContainText()",'contains "Welcome"'],[".demo-product-item","shouldHaveLength()","4 items"],["#demo-empty-list-pg","shouldBeEmpty()","0 items"],["#fetch-api-btn","click (GET)","fetch dummy posts / items"],["#fetch-status-badge","shouldHaveText()","200 OK"],[".api-fetched-item","shouldHaveLengthGreaterThan()",">= 1 item"],["#submit-post-btn","click (POST)","submit dummy post payload"],["#post-status-badge","shouldHaveText()","201 Created"],["#post-success-banner","shouldBeVisible()","display creation banner"]];var a=Zl(),r=d(a);ks(r,{id:"playground-heading",children:(G,de)=>{var yt=ys("Live Playground");w(G,yt)}});var n=f(r,4),o=d(n),l=f(d(o),2),i=d(l),c=d(i);c.textContent="#demo-visible-el";var h=f(i,4),b=d(h);b.textContent="#demo-hidden-el";var v=f(b,2),m=f(d(v),2),x=d(m),_=f(h,2),g=f(o,2),S=f(d(g),2),A=d(S),T=d(A);T.textContent="#demo-existing-el";var E=f(A,4),O=d(E);O.textContent="#demo-removed-el";var V=f(O,2),R=f(d(V),2),j=d(R),q=f(E,2);{var $=G=>{var de=Jl();w(G,de)},ae=G=>{var de=Kl();w(G,de)};te(q,G=>{t.exists?G($):G(ae,-1)})}var re=f(g,2),at=f(d(re),2),De=d(at),He=d(De),ye=f(He,2),Ke=f(ye,2),Pe=f(De,2),ne=d(Pe),Re=d(ne),xt=f(ne,2),gt=d(xt),Q=f(Pe,2),D=d(Q);D.textContent="#demo-focus-input-pg → shouldBeFocused()";var W=f(re,2),ee=f(d(W),2),ve=d(ee),rt=d(ve);rt.textContent="#demo-email-input → shouldHaveValue()",f(rt,2);var N=f(ve,2),K=d(N);K.textContent='#demo-token-input → shouldContainValue("JWT_")',f(K,2);var Z=f(N,2),Y=d(Z);Y.textContent="#demo-exact-text → shouldHaveText()";var we=f(Z,2),pe=d(we);pe.textContent='#demo-partial-text → shouldContainText("Welcome")';var he=f(W,2),ke=f(d(he),2),je=d(ke),_t=d(je);_t.textContent='#demo-active-tab class="is-active nav-tab"';var Gt=f(je,2),Jt=d(Gt);Jt.textContent='#demo-nav-link href="/dashboard" aria-label="Go to Dashboard"';var ps=f(Jt,2),hs=f(Gt,2),Ie=d(hs);Ie.textContent='#demo-styled-el-pg → shouldHaveCss("color", "rgb(239, 68, 68)")';var Ye=f(he,2),Mt=f(d(Ye),2),Ga=d(Mt),vn=f(d(Ga),2);Je(vn,20,()=>["Product Alpha","Product Beta","Product Gamma","Product Delta"],$a,(G,de,yt)=>{var Fs=Yl(),Vs=d(Fs);Vs.textContent=`#${yt+1}`;var pa=f(Vs);B(()=>I(pa,` ${de??""}`)),w(G,Fs)});var pn=f(Ga,2),hn=d(pn);hn.textContent="#demo-empty-list-pg → shouldBeEmpty()";var mn=f(n,2),bn=f(d(mn),2),xn=d(bn),gn=f(d(xn));Je(gn,21,()=>s,([G,de,yt])=>G,(G,de)=>{var yt=ls(()=>Nn(p(de),3));let Fs=()=>p(yt)[0],Vs=()=>p(yt)[1],pa=()=>p(yt)[2];var Ja=Ql(),Ka=d(Ja),_n=d(Ka),Ya=f(Ka),yn=d(Ya),wn=f(Ya),kn=d(wn);B(()=>{I(_n,Fs()),I(yn,Vs()),I(kn,pa())}),w(G,Ja)}),B(G=>{I(x,t.hidden?"show":"hide"),Be(_,1,G),I(j,t.exists?"remove":"add"),He.disabled=t.disabled,ye.disabled=!t.disabled,sa(Re,t.checked),sa(gt,t.selected)},[()=>vs(["px-3 py-2 rounded-lg bg-red-950/40 border border-red-800/50 text-red-300 text-sm font-mono transition-all",t.hidden?"hidden":""].join(" "))]),J("click",m,function(...G){var de;(de=t.onToggleHidden)==null||de.apply(this,G)}),J("click",R,function(...G){var de;(de=t.onToggleExists)==null||de.apply(this,G)}),J("click",Ke,function(...G){var de;(de=t.onToggleDisabled)==null||de.apply(this,G)}),J("change",Re,G=>t.onToggleChecked(G.currentTarget.checked)),J("change",gt,G=>t.onToggleSelected(G.currentTarget.checked)),J("click",ps,G=>G.preventDefault()),w(e,a),ge()}Ae(["click","change"]);var ed=k('<div class="flex flex-col h-full bg-[#020817] text-slate-200"><header class="h-14 shrink-0 border-b border-slate-800/60 bg-[#020817]/95 backdrop-blur-sm flex items-center px-6 z-50"><div class="flex items-center gap-3"><div class="size-7 rounded-lg bg-teal-950/60 border border-teal-800/40 flex items-center justify-center"><svg class="size-3.5 text-teal-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg></div> <span class="text-sm font-semibold text-slate-100 tracking-wide">TestSpectra</span> <span class="text-slate-700">/</span> <span class="text-sm text-slate-500 font-mono">Matchers API</span></div> <div class="ml-auto flex items-center gap-3"><span class="text-[10px] font-mono text-slate-600 bg-slate-900/60 border border-slate-800 px-2.5 py-1 rounded-full">WebdriverIO v9+</span> <span class="text-[10px] font-mono text-teal-500 bg-teal-950/40 border border-teal-800/40 px-2.5 py-1 rounded-full">Web · iOS · Android</span></div></header> <div class="flex flex-1 overflow-hidden"><!> <main class="flex-1 overflow-y-auto"><div class="max-w-5xl mx-auto px-8 py-10"><!> <section id="element-matchers" class="mb-20"><!> <!> <!> <!> <!> <!> <!></section> <section id="browser-matchers" class="mb-20"><!> <!> <!></section> <section id="collection-matchers" class="mb-20"><!> <!></section> <section id="api-matchers" class="mb-20"><!> <!> <!> <!> <!> <!> <!></section> <!> <footer class="border-t border-slate-800/60 pt-8 pb-12 text-center"><p class="text-xs text-slate-600 font-mono">TestSpectra Matchers API · Built on WebdriverIO · Multi-platform: Web, iOS, Android</p></footer></div></main></div></div>');function td(e,t){xe(t,!0);let s=P("overview"),a=P(!0),r=P(!0),n=P(!1),o=P(!1),l=P(!0),i=P(!0);Ia(()=>{document.title=La}),Ia(()=>{const D=cn.map(ee=>ee.id).map(ee=>document.getElementById(ee)).filter(ee=>!!ee),W=new IntersectionObserver(ee=>{ee.forEach(ve=>{ve.isIntersecting&&y(s,ve.target.id,!0)})},{rootMargin:"-10% 0px -75% 0px"});return D.forEach(ee=>W.observe(ee)),()=>{W.disconnect()}});var c=ed(),h=f(d(c),2),b=d(h);pi(b,{get activeId(){return p(s)}});var v=f(b,2),m=d(v),x=d(m);_i(x);var _=f(x,2),g=d(_);ks(g,{id:"element-matchers-heading",children:(Q,D)=>{var W=ys("Element Matchers");w(Q,W)}});var S=f(g,2);Pi(S,{get hidden(){return p(a)},onToggleHidden:()=>y(a,!p(a))});var A=f(S,2);Li(A,{get exists(){return p(r)},onToggleExists:()=>y(r,!p(r))});var T=f(A,2);Hi(T,{get disabled(){return p(n)},get checked(){return p(o)},get selected(){return p(i)},onToggleDisabled:()=>y(n,!p(n)),onToggleChecked:Q=>y(o,Q,!0),onToggleSelected:Q=>y(i,Q,!0)});var E=f(T,2);Fi(E);var O=f(E,2);zi(O);var V=f(O,2);$i(V);var R=f(_,2),j=d(R);ks(j,{id:"browser-matchers-heading",children:(Q,D)=>{var W=ys("Browser Matchers");w(Q,W)}});var q=f(j,2);Ki(q,{});var $=f(q,2);Zi($);var ae=f(R,2),re=d(ae);ks(re,{id:"collection-matchers-heading",children:(Q,D)=>{var W=ys("Collection Matchers");w(Q,W)}});var at=f(re,2);al(at);var De=f(ae,2),He=d(De);ks(He,{id:"api-matchers-heading",children:(Q,D)=>{var W=ys("API & Network Testing");w(Q,W)}});var ye=f(He,2);gl(ye,{});var Ke=f(ye,2);Il(Ke,{});var Pe=f(Ke,2);Bl(Pe,{});var ne=f(Pe,2);Fl(ne,{});var Re=f(ne,2);zl(Re);var xt=f(Re,2);Gl(xt,{});var gt=f(De,2);Xl(gt,{get hidden(){return p(a)},get exists(){return p(r)},get disabled(){return p(n)},get checked(){return p(l)},get selected(){return p(i)},onToggleHidden:()=>y(a,!p(a)),onToggleExists:()=>y(r,!p(r)),onToggleDisabled:()=>y(n,!p(n)),onToggleChecked:Q=>y(l,Q,!0),onToggleSelected:Q=>y(i,Q,!0)}),w(e,c),ge()}const fn=document.getElementById("app");if(!fn)throw new Error('Element with id "app" not found');Jo(td,{target:fn});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
const { execFileSyncMock } = vi.hoisted(() => ({ execFileSyncMock: vi.fn() }));
|
|
3
|
-
vi.mock('child_process', () => ({
|
|
4
|
-
execFileSync: execFileSyncMock,
|
|
5
|
-
spawn: vi.fn(),
|
|
6
|
-
}));
|
|
7
|
-
vi.mock('../../runner/bridge.js', () => ({
|
|
8
|
-
RustCoreBridge: { resolveBinaryPath: () => '/fake/testspectra-runner' },
|
|
9
|
-
}));
|
|
10
|
-
import { runSystemChecks } from '../doctor.js';
|
|
11
|
-
describe('runSystemChecks scope forwarding', () => {
|
|
12
|
-
it('forwards a category scope to the runner (efficient partial doctor)', async () => {
|
|
13
|
-
execFileSyncMock.mockReturnValueOnce(JSON.stringify({ all_ready: true, missing_count: 0, dependencies: [] }));
|
|
14
|
-
await runSystemChecks('/tmp/ws', 'web');
|
|
15
|
-
const [, args] = execFileSyncMock.mock.calls.at(-1);
|
|
16
|
-
expect(args).toEqual(['doctor', '--json', '--scope', 'web']);
|
|
17
|
-
});
|
|
18
|
-
it('omits --scope entirely when no scope is requested (full doctor)', async () => {
|
|
19
|
-
execFileSyncMock.mockReturnValueOnce(JSON.stringify({ all_ready: true, missing_count: 0, dependencies: [] }));
|
|
20
|
-
await runSystemChecks('/tmp/ws');
|
|
21
|
-
const [, args] = execFileSyncMock.mock.calls.at(-1);
|
|
22
|
-
expect(args).toEqual(['doctor', '--json']);
|
|
23
|
-
});
|
|
24
|
-
});
|
|
File without changes
|