@vielzeug/assay 26.11.4 → 26.11.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/assay.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@vielzeug/arsenal");var walkFlatTree=(e,t)=>{let n=e instanceof HTMLSlotElement?e.assignedElements({flatten:!0}):e.children;for(let e of Array.from(n))e instanceof HTMLSlotElement||t(e),walkFlatTree(e,t)},AssayError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},AssayQueryError=class extends AssayError{},AssayTimeoutError=class extends AssayError{},dispatch=(e,t)=>e.dispatchEvent(t),fireBlur=(e,t={})=>dispatch(e,new FocusEvent(`blur`,t)),fireChange=(e,t={})=>dispatch(e,new Event(`change`,{bubbles:!0,...t})),fireClick=(e,t={})=>dispatch(e,new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...t})),fireCustom=(e,t,n={})=>dispatch(e,new CustomEvent(t,{bubbles:!0,cancelable:!0,composed:!1,...n})),fireFocus=(e,t={})=>dispatch(e,new FocusEvent(`focus`,t)),fireInput=(e,t={})=>dispatch(e,new InputEvent(`input`,{bubbles:!0,...t})),fireKeyDown=(e,t={})=>dispatch(e,new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...t})),fireKeyUp=(e,t={})=>dispatch(e,new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...t})),fireSubmit=(e,t={})=>dispatch(e,new SubmitEvent(`submit`,{bubbles:!0,cancelable:!0,...t})),installFormInternalsPolyfill=()=>{if(typeof ElementInternals>`u`)return()=>{};let e=Symbol.for(`vielzeug.assay.formInternalsPolyfillInstalled`),t=globalThis;if(t[e])return()=>{};t[e]=!0;let n=[],r=ElementInternals.prototype,i=new WeakMap,a=new WeakMap,o=new WeakMap,patchProto=(e,t)=>{e in r||(Object.defineProperty(r,e,t),n.push(()=>delete r[e]))},isValid=e=>{let t=i.get(e);return!t||!Object.values(t.flags).some(Boolean)};patchProto(`setFormValue`,{configurable:!0,value:function(e){let t=o.get(this);t&&a.set(t,e)},writable:!0}),patchProto(`setValidity`,{configurable:!0,value:function(e={},t=``){if(Object.values(e).some(Boolean)&&!t)throw TypeError(`Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if one or more flags in the first argument are true.`);i.set(this,{flags:e,message:t})},writable:!0}),patchProto(`checkValidity`,{configurable:!0,value:function(){return isValid(this)},writable:!0}),patchProto(`reportValidity`,{configurable:!0,value:function(){return isValid(this)},writable:!0}),patchProto(`validationMessage`,{configurable:!0,get(){return isValid(this)?``:i.get(this)?.message??``}}),patchProto(`validity`,{configurable:!0,get(){let e=i.get(this);return{badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valid:isValid(this),valueMissing:!1,...e?.flags??{}}}}),patchProto(`states`,{configurable:!0,get:function(){return this._states??=new Set,this._states}});let s=HTMLElement.prototype.attachInternals;HTMLElement.prototype.attachInternals=function(...e){let t=s.apply(this,e);return o.set(t,this),Object.defineProperties(this,{checkValidity:{configurable:!0,value:()=>t.checkValidity()},reportValidity:{configurable:!0,value:()=>t.reportValidity()},validationMessage:{configurable:!0,get:()=>t.validationMessage},validity:{configurable:!0,get:()=>t.validity}}),t},n.push(()=>{HTMLElement.prototype.attachInternals=s});let appendFormValue=(e,t,n)=>{if(n instanceof FormData)for(let[t,r]of n.entries())e.append(t,r);else e.append(t,n)},c=globalThis.FormData;globalThis.FormData=class FormDataWithFormAssociatedElements extends c{constructor(e,t){super(e,t),e instanceof HTMLFormElement&&walkFlatTree(e,e=>{let t=e.getAttribute(`name`),n=a.get(e);t&&n!=null&&!e.hasAttribute(`disabled`)&&appendFormValue(this,t,n)})}},n.push(()=>{globalThis.FormData=c});let l=HTMLFormElement.prototype.reset;return HTMLFormElement.prototype.reset=function(...e){l.apply(this,e),walkFlatTree(this,e=>{e.formResetCallback?.()})},n.push(()=>{HTMLFormElement.prototype.reset=l}),()=>{for(let e of n)e();n.length=0,t[e]=!1}},describeRoot=e=>e instanceof Element?e.outerHTML.slice(0,500):e instanceof ShadowRoot?`<shadow-root>${e.innerHTML.slice(0,500)}</shadow-root>`:e.nodeName,requireMatch=(e,t,n)=>{if(e)return e;throw new AssayQueryError(`Unable to find ${t} within ${describeRoot(n)}.`)},query=(e,t)=>e.querySelector(t),queryAll=(e,t)=>Array.from(e.querySelectorAll(t)),queryByTestId=(e,t)=>queryAll(e,`[data-testid]`).find(e=>e.getAttribute(`data-testid`)===t)??null,queryAllByTestId=(e,t)=>queryAll(e,`[data-testid]`).filter(e=>e.getAttribute(`data-testid`)===t),queryByText=(e,t,n=`*`)=>{for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null},queryAllByText=(e,t,n=`*`)=>queryAll(e,n).filter(e=>e.textContent?.trim()===t);function queryInShadow(e,t){return e.shadowRoot?query(e.shadowRoot,t):null}function queryAllInShadow(e,t){return e.shadowRoot?queryAll(e.shadowRoot,t):[]}function queryPart(e,t){return queryAllInShadow(e,`[part]`).find(e=>e.getAttribute(`part`)?.split(/\s+/).includes(t))??null}function getSlotted(e,t){return Array.from(e.children).filter(e=>t===void 0?!e.getAttribute(`slot`):e.getAttribute(`slot`)===t)}function within(e){return{get:t=>requireMatch(query(e,t),`"${t}"`,e),getByTestId:t=>requireMatch(queryByTestId(e,t),`data-testid "${t}"`,e),getByText:(t,n=`*`)=>requireMatch(queryByText(e,t,n),`text "${t}" matching "${n}"`,e),query:t=>query(e,t),queryAll:t=>queryAll(e,t),queryAllByTestId:t=>queryAllByTestId(e,t),queryAllByText:(t,n=`*`)=>queryAllByText(e,t,n),queryByTestId:t=>queryByTestId(e,t),queryByText:(t,n=`*`)=>queryByText(e,t,n)}}var t=Symbol(`assay.deadline`),n=2147483647,now=()=>performance.now(),validateDuration=(e,t,r)=>{if(!Number.isFinite(t)||t>n||(r?t<0:t<=0))throw RangeError(`${e} must be a ${r?`non-negative`:`positive`} finite number no greater than ${n}`)},validateWait=(e,t)=>{validateDuration(`interval`,e,!1),validateDuration(`timeout`,t,!0)},runBounded=(n,r,i)=>new Promise((a,o)=>{if(i?.aborted){o((0,e.abortError)(i,`The operation was aborted.`));return}let s=!1,cleanup=()=>!s&&(s=!0,clearTimeout(c),i?.removeEventListener(`abort`,abort),!0),resolveOnce=e=>{cleanup()&&a(e)},rejectOnce=e=>{cleanup()&&o(e)},c=setTimeout(()=>rejectOnce(t),Math.max(0,r-now())),abort=()=>rejectOnce((0,e.abortError)(i,`The operation was aborted.`));i?.addEventListener(`abort`,abort,{once:!0});try{Promise.resolve(n()).then(resolveOnce,rejectOnce)}catch(e){rejectOnce(e)}}),delay=(t=0,n={})=>(validateDuration(`ms`,t,!0),(0,e.sleep)(t,n.signal));async function waitUntil(n,{interval:r=50,signal:i,timeout:a=1e3}={}){validateWait(r,a);let o=now()+a,s=!0;for(;;){if(i?.aborted)throw(0,e.abortError)(i,`The operation was aborted.`);if(!s&&now()>=o)throw new AssayTimeoutError(`waitUntil timed out after ${a}ms`);s=!1;let c;try{c=await runBounded(n,o,i)}catch(e){throw e===t?new AssayTimeoutError(`waitUntil timed out after ${a}ms`):e}if(c)return;let l=o-now();if(l<=0)throw new AssayTimeoutError(`waitUntil timed out after ${a}ms`);await(0,e.sleep)(Math.min(r,l),i)}}async function eventually(n,{interval:r=50,message:i,signal:a,timeout:o=1e3}={}){validateWait(r,o);let s=now()+o,c=!0,l;for(;;){if(a?.aborted)throw(0,e.abortError)(a,`The operation was aborted.`);if(!c&&now()>=s)break;c=!1;try{await runBounded(n,s,a);return}catch(n){if(a?.aborted)throw(0,e.abortError)(a,`The operation was aborted.`);if(n===t)break;l=n}let i=s-now();if(i<=0)break;await(0,e.sleep)(Math.min(r,i),a)}let u=`eventually timed out after ${o}ms`,d=i?`${i} (${u})`:u,f=l instanceof Error?l.message:l==null?``:String(l);throw new AssayTimeoutError(f?`${d}\n${f}`:d,{cause:l})}function waitForEvent(t,n,{signal:r,timeout:i=1e3}={}){return validateDuration(`timeout`,i,!0),new Promise((a,o)=>{if(r?.aborted){o((0,e.abortError)(r,`The operation was aborted.`));return}let dispose=()=>{clearTimeout(s),r?.removeEventListener(`abort`,onAbort),t.removeEventListener(n,onEvent)},onEvent=e=>{dispose(),a(e)},s=setTimeout(()=>{dispose(),o(new AssayTimeoutError(`waitForEvent: "${n}" timed out after ${i}ms`))},i),onAbort=()=>{dispose(),o((0,e.abortError)(r,`The operation was aborted.`))};t.addEventListener(n,onEvent,{once:!0}),r?.addEventListener(`abort`,onAbort,{once:!0})})}exports.AssayError=AssayError,exports.AssayQueryError=AssayQueryError,exports.AssayTimeoutError=AssayTimeoutError,exports.delay=delay,exports.dispatch=dispatch,exports.eventually=eventually,exports.fireBlur=fireBlur,exports.fireChange=fireChange,exports.fireClick=fireClick,exports.fireCustom=fireCustom,exports.fireFocus=fireFocus,exports.fireInput=fireInput,exports.fireKeyDown=fireKeyDown,exports.fireKeyUp=fireKeyUp,exports.fireSubmit=fireSubmit,exports.getSlotted=getSlotted,exports.installFormInternalsPolyfill=installFormInternalsPolyfill,exports.queryAllInShadow=queryAllInShadow,exports.queryInShadow=queryInShadow,exports.queryPart=queryPart,exports.waitForEvent=waitForEvent,exports.waitUntil=waitUntil,exports.walkFlatTree=walkFlatTree,exports.within=within;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@vielzeug/arsenal");var walkFlatTree=(e,t)=>{let n=e instanceof HTMLSlotElement?e.assignedElements({flatten:!0}):e.children;for(let e of Array.from(n))e instanceof HTMLSlotElement||t(e),walkFlatTree(e,t)},AssayError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},AssayQueryError=class extends AssayError{},AssayTimeoutError=class extends AssayError{},dispatch=(e,t)=>e.dispatchEvent(t),fireBlur=(e,t={})=>dispatch(e,new FocusEvent(`blur`,t)),fireChange=(e,t={})=>dispatch(e,new Event(`change`,{bubbles:!0,...t})),fireClick=(e,t={})=>dispatch(e,new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...t})),fireCustom=(e,t,n={})=>dispatch(e,new CustomEvent(t,{bubbles:!0,cancelable:!0,composed:!1,...n})),fireFocus=(e,t={})=>dispatch(e,new FocusEvent(`focus`,t)),fireInput=(e,t={})=>dispatch(e,new InputEvent(`input`,{bubbles:!0,...t})),fireKeyDown=(e,t={})=>dispatch(e,new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...t})),fireKeyUp=(e,t={})=>dispatch(e,new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...t})),fireSubmit=(e,t={})=>dispatch(e,new SubmitEvent(`submit`,{bubbles:!0,cancelable:!0,...t})),installFormInternalsPolyfill=()=>{if(typeof ElementInternals>`u`)return()=>{};let e=Symbol.for(`vielzeug.assay.formInternalsPolyfillInstalled`),t=globalThis;if(t[e])return()=>{};t[e]=!0;let n=[],r=ElementInternals.prototype,i=new WeakMap,a=new WeakMap,o=new WeakMap,patchProto=(e,t)=>{e in r||(Object.defineProperty(r,e,t),n.push(()=>delete r[e]))},isValid=e=>{let t=i.get(e);return!t||!Object.values(t.flags).some(Boolean)};patchProto(`setFormValue`,{configurable:!0,value:function(e){let t=o.get(this);t&&a.set(t,e)},writable:!0}),patchProto(`setValidity`,{configurable:!0,value:function(e={},t=``){if(Object.values(e).some(Boolean)&&!t)throw TypeError(`Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if one or more flags in the first argument are true.`);i.set(this,{flags:e,message:t})},writable:!0}),patchProto(`checkValidity`,{configurable:!0,value:function(){return isValid(this)},writable:!0}),patchProto(`reportValidity`,{configurable:!0,value:function(){return isValid(this)},writable:!0}),patchProto(`validationMessage`,{configurable:!0,get(){return isValid(this)?``:i.get(this)?.message??``}}),patchProto(`validity`,{configurable:!0,get(){let e=i.get(this);return{badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valid:isValid(this),valueMissing:!1,...e?.flags??{}}}}),patchProto(`states`,{configurable:!0,get:function(){return this._states??=new Set,this._states}});let s=HTMLElement.prototype.attachInternals;HTMLElement.prototype.attachInternals=function(...e){let t=s.apply(this,e);return o.set(t,this),Object.defineProperties(this,{checkValidity:{configurable:!0,value:()=>t.checkValidity()},reportValidity:{configurable:!0,value:()=>t.reportValidity()},validationMessage:{configurable:!0,get:()=>t.validationMessage},validity:{configurable:!0,get:()=>t.validity}}),t},n.push(()=>{HTMLElement.prototype.attachInternals=s});let appendFormValue=(e,t,n)=>{if(n instanceof FormData)for(let[t,r]of n.entries())e.append(t,r);else e.append(t,n)},c=globalThis.FormData;globalThis.FormData=class FormDataWithFormAssociatedElements extends c{constructor(e,t){super(e,t),e instanceof HTMLFormElement&&walkFlatTree(e,e=>{let t=e.getAttribute(`name`),n=a.get(e);t&&n!=null&&!e.hasAttribute(`disabled`)&&appendFormValue(this,t,n)})}},n.push(()=>{globalThis.FormData=c});let l=HTMLFormElement.prototype.reset;return HTMLFormElement.prototype.reset=function(...e){l.apply(this,e),walkFlatTree(this,e=>{e.formResetCallback?.()})},n.push(()=>{HTMLFormElement.prototype.reset=l}),()=>{for(let e of n)e();n.length=0,t[e]=!1}},installPopoverPolyfill=()=>{if(typeof HTMLElement>`u`)return()=>{};let e=Symbol.for(`vielzeug.assay.popoverPolyfillInstalled`),t=globalThis;if(t[e])return()=>{};t[e]=!0;let n=[],r=`popover-open`,isOpen=e=>e.hasAttribute(r),i=new WeakMap,reveal=e=>{let t=e.ownerDocument?.defaultView;t&&t.getComputedStyle(e).display===`none`&&(i.has(e)||i.set(e,e.style.getPropertyValue(`display`)),e.style.setProperty(`display`,`block`))},conceal=e=>{if(!i.has(e))return;let t=i.get(e);i.delete(e),t?e.style.setProperty(`display`,t):e.style.removeProperty(`display`)},requirePopoverAttribute=(e,t)=>{if(!e.hasAttribute(`popover`))throw new DOMException(`Failed to execute '${t}' on 'HTMLElement': the element does not have a popover attribute.`,`InvalidStateError`)},a=HTMLElement.prototype,patchProto=(e,t)=>{e in a||(Object.defineProperty(a,e,t),n.push(()=>delete a[e]))};patchProto(`showPopover`,{configurable:!0,value:function(e){requirePopoverAttribute(this,`showPopover`),(!isOpen(this)||e?.force)&&(reveal(this),this.setAttribute(r,``))}}),patchProto(`hidePopover`,{configurable:!0,value:function(){requirePopoverAttribute(this,`hidePopover`),isOpen(this)&&(this.removeAttribute(r),conceal(this))}}),patchProto(`togglePopover`,{configurable:!0,value:function(e){requirePopoverAttribute(this,`togglePopover`);let t=e??!isOpen(this);return t?reveal(this):conceal(this),t?this.setAttribute(r,``):this.removeAttribute(r),isOpen(this)}});let o=Element.prototype.matches;return Element.prototype.matches=function(e){return e===`:popover-open`?this.hasAttribute(r):o.call(this,e)},n.push(()=>{Element.prototype.matches=o}),()=>{for(let e of n)e();n.length=0,t[e]=!1}},describeRoot=e=>e instanceof Element?e.outerHTML.slice(0,500):e instanceof ShadowRoot?`<shadow-root>${e.innerHTML.slice(0,500)}</shadow-root>`:e.nodeName,requireMatch=(e,t,n)=>{if(e)return e;throw new AssayQueryError(`Unable to find ${t} within ${describeRoot(n)}.`)},query=(e,t)=>e.querySelector(t),queryAll=(e,t)=>Array.from(e.querySelectorAll(t)),queryByTestId=(e,t)=>queryAll(e,`[data-testid]`).find(e=>e.getAttribute(`data-testid`)===t)??null,queryAllByTestId=(e,t)=>queryAll(e,`[data-testid]`).filter(e=>e.getAttribute(`data-testid`)===t),queryByText=(e,t,n=`*`)=>{for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null},queryAllByText=(e,t,n=`*`)=>queryAll(e,n).filter(e=>e.textContent?.trim()===t);function queryInShadow(e,t){return e.shadowRoot?query(e.shadowRoot,t):null}function queryAllInShadow(e,t){return e.shadowRoot?queryAll(e.shadowRoot,t):[]}function queryPart(e,t){return queryAllInShadow(e,`[part]`).find(e=>e.getAttribute(`part`)?.split(/\s+/).includes(t))??null}function getSlotted(e,t){return Array.from(e.children).filter(e=>t===void 0?!e.getAttribute(`slot`):e.getAttribute(`slot`)===t)}function within(e){return{get:t=>requireMatch(query(e,t),`"${t}"`,e),getByTestId:t=>requireMatch(queryByTestId(e,t),`data-testid "${t}"`,e),getByText:(t,n=`*`)=>requireMatch(queryByText(e,t,n),`text "${t}" matching "${n}"`,e),query:t=>query(e,t),queryAll:t=>queryAll(e,t),queryAllByTestId:t=>queryAllByTestId(e,t),queryAllByText:(t,n=`*`)=>queryAllByText(e,t,n),queryByTestId:t=>queryByTestId(e,t),queryByText:(t,n=`*`)=>queryByText(e,t,n)}}var t=Symbol(`assay.deadline`),n=2147483647,now=()=>performance.now(),validateDuration=(e,t,r)=>{if(!Number.isFinite(t)||t>n||(r?t<0:t<=0))throw RangeError(`${e} must be a ${r?`non-negative`:`positive`} finite number no greater than ${n}`)},validateWait=(e,t)=>{validateDuration(`interval`,e,!1),validateDuration(`timeout`,t,!0)},runBounded=(n,r,i)=>new Promise((a,o)=>{if(i?.aborted){o((0,e.abortError)(i,`The operation was aborted.`));return}let s=!1,cleanup=()=>!s&&(s=!0,clearTimeout(c),i?.removeEventListener(`abort`,abort),!0),resolveOnce=e=>{cleanup()&&a(e)},rejectOnce=e=>{cleanup()&&o(e)},c=setTimeout(()=>rejectOnce(t),Math.max(0,r-now())),abort=()=>rejectOnce((0,e.abortError)(i,`The operation was aborted.`));i?.addEventListener(`abort`,abort,{once:!0});try{Promise.resolve(n()).then(resolveOnce,rejectOnce)}catch(e){rejectOnce(e)}}),delay=(t=0,n={})=>(validateDuration(`ms`,t,!0),(0,e.sleep)(t,n.signal));async function waitUntil(n,{interval:r=50,signal:i,timeout:a=1e3}={}){validateWait(r,a);let o=now()+a,s=!0;for(;;){if(i?.aborted)throw(0,e.abortError)(i,`The operation was aborted.`);if(!s&&now()>=o)throw new AssayTimeoutError(`waitUntil timed out after ${a}ms`);s=!1;let c;try{c=await runBounded(n,o,i)}catch(e){throw e===t?new AssayTimeoutError(`waitUntil timed out after ${a}ms`):e}if(c)return;let l=o-now();if(l<=0)throw new AssayTimeoutError(`waitUntil timed out after ${a}ms`);await(0,e.sleep)(Math.min(r,l),i)}}async function eventually(n,{interval:r=50,message:i,signal:a,timeout:o=1e3}={}){validateWait(r,o);let s=now()+o,c=!0,l;for(;;){if(a?.aborted)throw(0,e.abortError)(a,`The operation was aborted.`);if(!c&&now()>=s)break;c=!1;try{await runBounded(n,s,a);return}catch(n){if(a?.aborted)throw(0,e.abortError)(a,`The operation was aborted.`);if(n===t)break;l=n}let i=s-now();if(i<=0)break;await(0,e.sleep)(Math.min(r,i),a)}let u=`eventually timed out after ${o}ms`,d=i?`${i} (${u})`:u,f=l instanceof Error?l.message:l==null?``:String(l);throw new AssayTimeoutError(f?`${d}\n${f}`:d,{cause:l})}function waitForEvent(t,n,{signal:r,timeout:i=1e3}={}){return validateDuration(`timeout`,i,!0),new Promise((a,o)=>{if(r?.aborted){o((0,e.abortError)(r,`The operation was aborted.`));return}let dispose=()=>{clearTimeout(s),r?.removeEventListener(`abort`,onAbort),t.removeEventListener(n,onEvent)},onEvent=e=>{dispose(),a(e)},s=setTimeout(()=>{dispose(),o(new AssayTimeoutError(`waitForEvent: "${n}" timed out after ${i}ms`))},i),onAbort=()=>{dispose(),o((0,e.abortError)(r,`The operation was aborted.`))};t.addEventListener(n,onEvent,{once:!0}),r?.addEventListener(`abort`,onAbort,{once:!0})})}exports.AssayError=AssayError,exports.AssayQueryError=AssayQueryError,exports.AssayTimeoutError=AssayTimeoutError,exports.delay=delay,exports.dispatch=dispatch,exports.eventually=eventually,exports.fireBlur=fireBlur,exports.fireChange=fireChange,exports.fireClick=fireClick,exports.fireCustom=fireCustom,exports.fireFocus=fireFocus,exports.fireInput=fireInput,exports.fireKeyDown=fireKeyDown,exports.fireKeyUp=fireKeyUp,exports.fireSubmit=fireSubmit,exports.getSlotted=getSlotted,exports.installFormInternalsPolyfill=installFormInternalsPolyfill,exports.installPopoverPolyfill=installPopoverPolyfill,exports.queryAllInShadow=queryAllInShadow,exports.queryInShadow=queryInShadow,exports.queryPart=queryPart,exports.waitForEvent=waitForEvent,exports.waitUntil=waitUntil,exports.walkFlatTree=walkFlatTree,exports.within=within;
2
2
  //# sourceMappingURL=assay.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"assay.cjs","names":["abortError","sleep","_vielzeug_arsenal","children","root","child","visit","message","opts","target","event","init","type","INSTALLED_FLAG","flagHost","restorers","proto","validityState","formValueByHost","hostByInternals","name","descriptor","state","internals","host","value","flags","originalAttachInternals","args","entryName","entryValue","formData","NativeFormData","form","submitter","element","originalReset","restore","description","selector","testId","text","part","slotName","DEADLINE","MAX_TIMER_MS","allowZero","interval","timeout","signal","reject","settled","timer","resolve","error","deadline","run","ms","options","first","matched","predicate","remaining","lastError","assertion","timing","context","detail"],"sources":["../src/dom.ts","../src/errors.ts","../src/events.ts","../src/form-internals.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/**\n * DOM traversal helpers for tests running under jsdom, which only implements the *light* DOM\n * tree: `Element.children`/`querySelectorAll()` never cross a `<slot>` into its assigned\n * elements. Real browsers use the *flat tree* (light DOM with each `<slot>` transparently\n * replaced by what's actually assigned to it) for this: it's what \"form owner\" resolution,\n * `:has()`, and plenty of other DOM algorithms are specified against.\n */\n\n/**\n * Walks the flat tree starting at `root`, calling `visit` for every element encountered :\n * expanding each `<slot>` via `assignedElements()` instead of descending into its (always\n * empty, in jsdom) literal children.\n *\n * @example\n * ```ts\n * // Find every form-associated element slotted (possibly through nested slots) under `form`,\n * // something `form.querySelectorAll('[name]')` can't do once a shadow boundary is involved.\n * const named: HTMLElement[] = [];\n * walkFlatTree(form, (el) => { if (el.hasAttribute('name')) named.push(el); });\n * ```\n */\nexport const walkFlatTree = (root: Element, visit: (element: HTMLElement) => void): void => {\n const children = root instanceof HTMLSlotElement ? root.assignedElements({ flatten: true }) : root.children;\n\n for (const child of Array.from(children)) {\n if (!(child instanceof HTMLSlotElement)) visit(child as HTMLElement);\n\n walkFlatTree(child, visit);\n }\n};\n","/** Base class for all Assay errors. Use `instanceof AssayError` to catch any Assay-originated error. */\nexport class AssayError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a required query has no match. */\nexport class AssayQueryError extends AssayError {}\n\n/** Thrown when an Assay wait reaches its timeout. */\nexport class AssayTimeoutError extends AssayError {}\n","/**\n * # Confidence boundary: read first\n *\n * `dispatch` is a **low-level synthetic-event dispatch API**. It fires a caller-\n * supplied DOM `Event` synchronously and returns the `dispatchEvent`\n * result. It does **not** model real user interaction: there is no focus/blur\n * sequencing, no input-event coordination, no keyboard layout, no pointer\n * hit-testing, and no trust flag (`event.isTrusted` is always `false`).\n *\n * Use it to drive event handlers in unit/integration tests where you control\n * the exact event shape. For **behavioral confidence**, that a real click\n * actually activates a control, that focus management works end-to-end, that\n * keyboard shortcuts fire under a real input device: write Playwright tests.\n * Assay deliberately stops at the dispatch boundary; anything that depends on\n * the browser's interaction semantics belongs in a browser-driven suite.\n */\n\n/** Dispatch a pre-built `Event` instance unchanged. Returns the `dispatchEvent` result. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\n/** Synthetic convenience dispatchers. They share the same confidence boundary as `dispatch()`. */\nexport const fireBlur = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('blur', init));\n\nexport const fireChange = (target: EventTarget, init: EventInit = {}): boolean =>\n dispatch(target, new Event('change', { bubbles: true, ...init }));\n\nexport const fireClick = (target: EventTarget, init: MouseEventInit = {}): boolean =>\n dispatch(target, new MouseEvent('click', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireCustom = <T>(target: EventTarget, type: string, init: CustomEventInit<T> = {}): boolean =>\n dispatch(target, new CustomEvent(type, { bubbles: true, cancelable: true, composed: false, ...init }));\n\nexport const fireFocus = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('focus', init));\n\nexport const fireInput = (target: EventTarget, init: InputEventInit = {}): boolean =>\n dispatch(target, new InputEvent('input', { bubbles: true, ...init }));\n\nexport const fireKeyDown = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireKeyUp = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireSubmit = (target: EventTarget, init: SubmitEventInit = {}): boolean =>\n dispatch(target, new SubmitEvent('submit', { bubbles: true, cancelable: true, ...init }));\n","import { walkFlatTree } from './dom';\n\n/**\n * jsdom implements none of the `ElementInternals` form-association API: not `setFormValue`,\n * not `setValidity`, not the `checkValidity`/`reportValidity`/`validity`/`validationMessage`\n * mixin real browsers put on every `formAssociated: true` element, not even `FormData`\n * collecting a form-associated element's set value, or `<form>.reset()` invoking\n * `formResetCallback()`. Every one of those gaps is exercised by `useField()` (`@vielzeug/ore`),\n * so any package testing a form-associated component needs all of them, not just one.\n *\n * Call this directly from a test setup when the suite tests form-associated components:\n * the patches are global monkey-patches, so suites without them shouldn't pay for them.\n * Returns an `uninstall()` that restores every patched global.\n *\n * Lives in Assay because it patches the DOM environment itself: the gap is in jsdom, not in\n * any package's feature, and Assay is the repo's home for DOM test-environment helpers.\n * `walkFlatTree` handles form-associated custom elements across shadow boundaries, so\n * consumer packages do not need package-local copies of this polyfill.\n */\nexport const installFormInternalsPolyfill = (): (() => void) => {\n // Checked *before* consuming the flag below: an environment without `ElementInternals`\n // installs nothing and should stay eligible to install for real later (e.g. a differently\n // configured environment in the same process), not get marked \"already installed\" for having\n // done nothing.\n if (typeof ElementInternals === 'undefined') return () => {};\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.assay.formInternalsPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return () => {};\n\n flagHost[INSTALLED_FLAG] = true;\n\n // Every patch pushes its inverse here, so uninstall() restores the environment exactly.\n const restorers: Array<() => void> = [];\n\n const proto = ElementInternals.prototype as unknown as Record<string, unknown>;\n const validityState = new WeakMap<ElementInternals, { flags: ValidityStateFlags; message: string }>();\n const formValueByHost = new WeakMap<HTMLElement, File | FormData | string | null>();\n const hostByInternals = new WeakMap<ElementInternals, HTMLElement>();\n\n const patchProto = (name: string, descriptor: PropertyDescriptor): void => {\n if (name in proto) return;\n\n Object.defineProperty(proto, name, descriptor);\n restorers.push(() => delete proto[name]);\n };\n\n const isValid = (internals: ElementInternals): boolean => {\n const state = validityState.get(internals);\n\n return !state || !Object.values(state.flags).some(Boolean);\n };\n\n patchProto('setFormValue', {\n configurable: true,\n value: function (this: ElementInternals, value: File | FormData | string | null) {\n const host = hostByInternals.get(this);\n\n if (host) formValueByHost.set(host, value);\n },\n writable: true,\n });\n\n patchProto('setValidity', {\n configurable: true,\n // Matches the real platform contract: throws if any flag is true and message is empty.\n // `useField()` itself already guards against triggering this: see forms/field.ts, but\n // the polyfill enforcing it too means a test would still catch a *different* caller doing\n // the same thing wrong, instead of that bug only surfacing in a real browser.\n value: function (this: ElementInternals, flags: ValidityStateFlags = {}, message = '') {\n if (Object.values(flags).some(Boolean) && !message) {\n throw new TypeError(\n \"Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if \" +\n 'one or more flags in the first argument are true.',\n );\n }\n\n validityState.set(this, { flags, message });\n },\n writable: true,\n });\n\n patchProto('checkValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('reportValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('validationMessage', {\n configurable: true,\n get(this: ElementInternals) {\n return isValid(this) ? '' : (validityState.get(this)?.message ?? '');\n },\n });\n\n // A ValidityState-shaped view of the flags passed to setValidity: every known\n // flag defaults to false, `valid` reflects whether any flag is set.\n patchProto('validity', {\n configurable: true,\n get(this: ElementInternals): ValidityState {\n const state = validityState.get(this);\n\n return {\n badInput: false,\n customError: false,\n patternMismatch: false,\n rangeOverflow: false,\n rangeUnderflow: false,\n stepMismatch: false,\n tooLong: false,\n tooShort: false,\n typeMismatch: false,\n valid: isValid(this),\n valueMissing: false,\n ...(state?.flags ?? {}),\n } as ValidityState;\n },\n });\n\n patchProto('states', {\n configurable: true,\n get: function (this: ElementInternals & { _states?: Set<string> }) {\n this._states ??= new Set();\n\n return this._states;\n },\n });\n\n // Real browsers mix `checkValidity`/`reportValidity`/`validity`/`validationMessage` onto any\n // `formAssociated: true` custom element itself (delegating to its internals): not just onto\n // `ElementInternals`. jsdom does neither; mirror it here so a component's own\n // `checkValidity()`/`reportValidity()`, and a test asserting against the element directly,\n // behave the same as they would in a real browser.\n const originalAttachInternals = HTMLElement.prototype.attachInternals;\n\n HTMLElement.prototype.attachInternals = function (this: HTMLElement, ...args: []): ElementInternals {\n const internals = originalAttachInternals.apply(this, args);\n\n hostByInternals.set(internals, this);\n\n Object.defineProperties(this, {\n checkValidity: { configurable: true, value: () => internals.checkValidity() },\n reportValidity: { configurable: true, value: () => internals.reportValidity() },\n validationMessage: { configurable: true, get: () => internals.validationMessage },\n validity: { configurable: true, get: () => internals.validity },\n });\n\n return internals;\n };\n restorers.push(() => {\n HTMLElement.prototype.attachInternals = originalAttachInternals;\n });\n\n const appendFormValue = (formData: FormData, name: string, value: File | FormData | string): void => {\n if (value instanceof FormData) {\n for (const [entryName, entryValue] of value.entries()) formData.append(entryName, entryValue);\n\n return;\n }\n\n formData.append(name, value);\n };\n\n // jsdom's `FormData` constructor never collects a form-associated custom element's set form\n // value: real browsers walk the flat tree for every form-associated element with a `name`.\n const NativeFormData = globalThis.FormData;\n\n globalThis.FormData = class FormDataWithFormAssociatedElements extends NativeFormData {\n constructor(form?: HTMLFormElement, submitter?: HTMLElement | null) {\n super(form as HTMLFormElement | undefined, submitter as HTMLElement | null | undefined);\n\n if (!(form instanceof HTMLFormElement)) return;\n\n walkFlatTree(form, (element) => {\n const name = element.getAttribute('name');\n const value = formValueByHost.get(element);\n\n if (!name || value == null || element.hasAttribute('disabled')) return;\n\n appendFormValue(this, name, value);\n });\n }\n };\n restorers.push(() => {\n globalThis.FormData = NativeFormData;\n });\n\n // jsdom never invokes the native `formResetCallback` lifecycle method on form-associated\n // custom elements when their form resets: patch `reset()` to do it (via the same flat-tree\n // walk, since a reset field can be nested behind a shadow boundary too), so `onFormReset()`\n // (see `@vielzeug/ore`'s runtime.ts) is testable against a real `<form>.reset()` call instead\n // of only by calling `element.formResetCallback()` directly.\n const originalReset = HTMLFormElement.prototype.reset;\n\n HTMLFormElement.prototype.reset = function (this: HTMLFormElement, ...args: []) {\n originalReset.apply(this, args);\n\n walkFlatTree(this, (element) => {\n (element as Partial<{ formResetCallback: () => void }>).formResetCallback?.();\n });\n };\n restorers.push(() => {\n HTMLFormElement.prototype.reset = originalReset;\n });\n\n return () => {\n for (const restore of restorers) restore();\n\n restorers.length = 0;\n flagHost[INSTALLED_FLAG] = false;\n };\n};\n","import { AssayQueryError } from './errors';\n\n/** DOM query helpers for test environments. */\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Scoped query helpers for any queryable DOM root: see {@link within}. */\nexport interface QueryScope {\n get<E extends Element = Element>(selector: string): E;\n getByTestId<E extends Element = Element>(testId: string): E;\n getByText<E extends Element = Element>(text: string, selector?: string): E;\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\ntype QueryRoot = ParentNode;\n\nconst describeRoot = (root: QueryRoot): string => {\n if (root instanceof Element) return root.outerHTML.slice(0, 500);\n\n if (root instanceof ShadowRoot) return `<shadow-root>${root.innerHTML.slice(0, 500)}</shadow-root>`;\n\n return root.nodeName;\n};\n\nconst requireMatch = <E extends Element>(element: E | null, description: string, root: QueryRoot): E => {\n if (element) return element;\n\n throw new AssayQueryError(`Unable to find ${description} within ${describeRoot(root)}.`);\n};\n\nconst query = <E extends Element = Element>(root: QueryRoot, selector: string): E | null =>\n root.querySelector<E>(selector);\n\nconst queryAll = <E extends Element = Element>(root: QueryRoot, selector: string): E[] => {\n return Array.from(root.querySelectorAll<E>(selector));\n};\n\nconst queryByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E | null =>\n queryAll<E>(root, '[data-testid]').find((element) => element.getAttribute('data-testid') === testId) ?? null;\n\nconst queryAllByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E[] =>\n queryAll<E>(root, '[data-testid]').filter((element) => element.getAttribute('data-testid') === testId);\n\nconst queryByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E | null => {\n for (const element of root.querySelectorAll<E>(selector)) {\n if (element.textContent?.trim() === text) return element;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] =>\n queryAll<E>(root, selector).filter((element) => element.textContent?.trim() === text);\n\n/**\n * Queries the shadow root of a custom element for a matching CSS selector.\n * Returns `null` if the element has no shadow root or no match is found: safe to call on\n * both open-shadow custom elements and plain elements without checking `shadowRoot` first.\n */\nexport function queryInShadow<E extends Element = Element>(host: Element, selector: string): E | null {\n return host.shadowRoot ? query<E>(host.shadowRoot, selector) : null;\n}\n\n/** Queries all matching elements inside the shadow root of a custom element. */\nexport function queryAllInShadow<E extends Element = Element>(host: Element, selector: string): E[] {\n return host.shadowRoot ? queryAll<E>(host.shadowRoot, selector) : [];\n}\n\n/**\n * Queries a shadow DOM element by its CSS `part` attribute: shorthand for\n * `queryInShadow(host, '[part=\"name\"]')`.\n *\n * @example\n * const btn = queryPart(carousel, 'prev-btn');\n * expect(btn).not.toBeNull();\n */\nexport function queryPart<E extends Element = Element>(host: Element, part: string): E | null {\n return (\n queryAllInShadow<E>(host, '[part]').find((element) => element.getAttribute('part')?.split(/\\s+/).includes(part)) ??\n null\n );\n}\n\n/**\n * Returns the light-DOM children assigned to a named slot, or every child assigned to the\n * default slot when no name is given.\n *\n * @example\n * const slides = getSlotted(carousel);\n * expect(slides).toHaveLength(3);\n */\nexport function getSlotted<E extends Element = Element>(host: Element, slotName?: string): E[] {\n return Array.from(host.children).filter((element) =>\n slotName === undefined ? !element.getAttribute('slot') : element.getAttribute('slot') === slotName,\n ) as E[];\n}\n\n// ─── API ─────────────────────────────────────────────────────────────────────\n\n/**\n * Create query helpers scoped to a DOM root: useful for light DOM and shadow roots.\n *\n * @example\n * const view = within(fixture.shadow!);\n * expect(view.get('.title').textContent).toBe('Hello');\n */\nexport function within(root: QueryRoot): QueryScope {\n return {\n get: <E extends Element = Element>(selector: string) =>\n requireMatch(query<E>(root, selector), `\"${selector}\"`, root),\n getByTestId: <E extends Element = Element>(testId: string) =>\n requireMatch(queryByTestId<E>(root, testId), `data-testid \"${testId}\"`, root),\n getByText: <E extends Element = Element>(text: string, selector = '*') =>\n requireMatch(queryByText<E>(root, text, selector), `text \"${text}\" matching \"${selector}\"`, root),\n query: <E extends Element = Element>(selector: string) => query<E>(root, selector),\n queryAll: <E extends Element = Element>(selector: string) => queryAll<E>(root, selector),\n queryAllByTestId: <E extends Element = Element>(testId: string) => queryAllByTestId<E>(root, testId),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(root, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) => queryByTestId<E>(root, testId),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(root, text, selector),\n };\n}\n","import { abortError, sleep } from '@vielzeug/arsenal';\n\nimport { AssayTimeoutError } from './errors';\n\nexport interface DelayOptions {\n signal?: AbortSignal;\n}\n\nexport interface WaitOptions {\n /** Polling interval in ms (default: 50). */\n interval?: number;\n /** Cancel the pending wait. */\n signal?: AbortSignal;\n /** Maximum wait time in ms (default: 1000). */\n timeout?: number;\n}\n\nexport interface EventuallyOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nconst DEADLINE = Symbol('assay.deadline');\nconst MAX_TIMER_MS = 2_147_483_647;\nconst now = (): number => performance.now();\n\nconst validateDuration = (name: string, value: number, allowZero: boolean): void => {\n if (!Number.isFinite(value) || value > MAX_TIMER_MS || (allowZero ? value < 0 : value <= 0)) {\n throw new RangeError(\n `${name} must be a ${allowZero ? 'non-negative' : 'positive'} finite number no greater than ${MAX_TIMER_MS}`,\n );\n }\n};\n\nconst validateWait = (interval: number, timeout: number): void => {\n validateDuration('interval', interval, false);\n validateDuration('timeout', timeout, true);\n};\n\nconst runBounded = <T>(run: () => T | Promise<T>, deadline: number, signal?: AbortSignal): Promise<T> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n let settled = false;\n const cleanup = (): boolean => {\n if (settled) return false;\n settled = true;\n clearTimeout(timer);\n signal?.removeEventListener('abort', abort);\n return true;\n };\n const resolveOnce = (value: T): void => {\n if (cleanup()) resolve(value);\n };\n const rejectOnce = (error: unknown): void => {\n if (cleanup()) reject(error);\n };\n const timer = setTimeout(() => rejectOnce(DEADLINE), Math.max(0, deadline - now()));\n const abort = () => rejectOnce(abortError(signal, 'The operation was aborted.'));\n\n signal?.addEventListener('abort', abort, { once: true });\n\n try {\n Promise.resolve(run()).then(resolveOnce, rejectOnce);\n } catch (error) {\n rejectOnce(error);\n }\n });\n\nexport const delay = (ms = 0, options: DelayOptions = {}): Promise<void> => {\n validateDuration('ms', ms, true);\n return sleep(ms, options.signal);\n};\n\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n first = false;\n\n let matched: boolean;\n try {\n matched = await runBounded(predicate, deadline, signal);\n } catch (error) {\n if (error === DEADLINE) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n throw error;\n }\n if (matched) return;\n\n const remaining = deadline - now();\n if (remaining <= 0) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n await sleep(Math.min(interval, remaining), signal);\n }\n}\n\n/**\n * Retry an assertion until it stops throwing or the timeout elapses.\n *\n * Polls the assertion on a fixed interval and preserves the last failure as the\n * timeout cause. Pending asynchronous assertions remain bounded by the same\n * deadline. Use `waitUntil()` for boolean conditions, `delay()` for explicit\n * timer dependencies, and `nextTick()` for one queued microtask boundary.\n *\n * @example\n * await eventually(() => expect(region.textContent).toBe('Saved'));\n */\nexport async function eventually(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: EventuallyOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) break;\n first = false;\n\n try {\n await runBounded(assertion, deadline, signal);\n return;\n } catch (error) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (error === DEADLINE) break;\n lastError = error;\n }\n\n const remaining = deadline - now();\n if (remaining <= 0) break;\n await sleep(Math.min(interval, remaining), signal);\n }\n\n const timing = `eventually timed out after ${timeout}ms`;\n const context = message ? `${message} (${timing})` : timing;\n const detail = lastError instanceof Error ? lastError.message : lastError == null ? '' : String(lastError);\n\n throw new AssayTimeoutError(detail ? `${context}\\n${detail}` : context, { cause: lastError });\n}\n\n/** Resolve with the next event of `type`, or reject when it times out or is aborted. */\nexport function waitForEvent<T extends Event = Event>(\n target: EventTarget,\n type: string,\n { signal, timeout = 1000 }: Omit<WaitOptions, 'interval'> = {},\n): Promise<T> {\n validateDuration('timeout', timeout, true);\n\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (event: Event): void => {\n dispose();\n resolve(event as T);\n };\n const timer = setTimeout(() => {\n dispose();\n reject(new AssayTimeoutError(`waitForEvent: \"${type}\" timed out after ${timeout}ms`));\n }, timeout);\n const onAbort = () => {\n dispose();\n reject(abortError(signal, 'The operation was aborted.'));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"assay.cjs","names":["abortError","sleep","_vielzeug_arsenal","children","root","child","visit","message","opts","target","event","init","type","INSTALLED_FLAG","flagHost","restorers","proto","validityState","formValueByHost","hostByInternals","name","descriptor","state","internals","host","value","flags","originalAttachInternals","args","entryName","entryValue","formData","NativeFormData","form","submitter","element","originalReset","restore","OPEN_ATTRIBUTE","displayBeforeOpen","view","before","method","options","shouldOpen","force","originalMatches","selectors","description","selector","testId","text","part","slotName","DEADLINE","MAX_TIMER_MS","allowZero","interval","timeout","signal","reject","settled","timer","resolve","error","deadline","run","ms","first","matched","predicate","remaining","lastError","assertion","timing","context","detail"],"sources":["../src/dom.ts","../src/errors.ts","../src/events.ts","../src/form-internals.ts","../src/popover.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/**\n * DOM traversal helpers for tests running under jsdom, which only implements the *light* DOM\n * tree: `Element.children`/`querySelectorAll()` never cross a `<slot>` into its assigned\n * elements. Real browsers use the *flat tree* (light DOM with each `<slot>` transparently\n * replaced by what's actually assigned to it) for this: it's what \"form owner\" resolution,\n * `:has()`, and plenty of other DOM algorithms are specified against.\n */\n\n/**\n * Walks the flat tree starting at `root`, calling `visit` for every element encountered :\n * expanding each `<slot>` via `assignedElements()` instead of descending into its (always\n * empty, in jsdom) literal children.\n *\n * @example\n * ```ts\n * // Find every form-associated element slotted (possibly through nested slots) under `form`,\n * // something `form.querySelectorAll('[name]')` can't do once a shadow boundary is involved.\n * const named: HTMLElement[] = [];\n * walkFlatTree(form, (el) => { if (el.hasAttribute('name')) named.push(el); });\n * ```\n */\nexport const walkFlatTree = (root: Element, visit: (element: HTMLElement) => void): void => {\n const children = root instanceof HTMLSlotElement ? root.assignedElements({ flatten: true }) : root.children;\n\n for (const child of Array.from(children)) {\n if (!(child instanceof HTMLSlotElement)) visit(child as HTMLElement);\n\n walkFlatTree(child, visit);\n }\n};\n","/** Base class for all Assay errors. Use `instanceof AssayError` to catch any Assay-originated error. */\nexport class AssayError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a required query has no match. */\nexport class AssayQueryError extends AssayError {}\n\n/** Thrown when an Assay wait reaches its timeout. */\nexport class AssayTimeoutError extends AssayError {}\n","/**\n * # Confidence boundary: read first\n *\n * `dispatch` is a **low-level synthetic-event dispatch API**. It fires a caller-\n * supplied DOM `Event` synchronously and returns the `dispatchEvent`\n * result. It does **not** model real user interaction: there is no focus/blur\n * sequencing, no input-event coordination, no keyboard layout, no pointer\n * hit-testing, and no trust flag (`event.isTrusted` is always `false`).\n *\n * Use it to drive event handlers in unit/integration tests where you control\n * the exact event shape. For **behavioral confidence**, that a real click\n * actually activates a control, that focus management works end-to-end, that\n * keyboard shortcuts fire under a real input device: write Playwright tests.\n * Assay deliberately stops at the dispatch boundary; anything that depends on\n * the browser's interaction semantics belongs in a browser-driven suite.\n */\n\n/** Dispatch a pre-built `Event` instance unchanged. Returns the `dispatchEvent` result. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\n/** Synthetic convenience dispatchers. They share the same confidence boundary as `dispatch()`. */\nexport const fireBlur = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('blur', init));\n\nexport const fireChange = (target: EventTarget, init: EventInit = {}): boolean =>\n dispatch(target, new Event('change', { bubbles: true, ...init }));\n\nexport const fireClick = (target: EventTarget, init: MouseEventInit = {}): boolean =>\n dispatch(target, new MouseEvent('click', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireCustom = <T>(target: EventTarget, type: string, init: CustomEventInit<T> = {}): boolean =>\n dispatch(target, new CustomEvent(type, { bubbles: true, cancelable: true, composed: false, ...init }));\n\nexport const fireFocus = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('focus', init));\n\nexport const fireInput = (target: EventTarget, init: InputEventInit = {}): boolean =>\n dispatch(target, new InputEvent('input', { bubbles: true, ...init }));\n\nexport const fireKeyDown = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireKeyUp = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireSubmit = (target: EventTarget, init: SubmitEventInit = {}): boolean =>\n dispatch(target, new SubmitEvent('submit', { bubbles: true, cancelable: true, ...init }));\n","import { walkFlatTree } from './dom';\n\n/**\n * jsdom implements none of the `ElementInternals` form-association API: not `setFormValue`,\n * not `setValidity`, not the `checkValidity`/`reportValidity`/`validity`/`validationMessage`\n * mixin real browsers put on every `formAssociated: true` element, not even `FormData`\n * collecting a form-associated element's set value, or `<form>.reset()` invoking\n * `formResetCallback()`. Every one of those gaps is exercised by `useField()` (`@vielzeug/ore`),\n * so any package testing a form-associated component needs all of them, not just one.\n *\n * Call this directly from a test setup when the suite tests form-associated components:\n * the patches are global monkey-patches, so suites without them shouldn't pay for them.\n * Returns an `uninstall()` that restores every patched global.\n *\n * Lives in Assay because it patches the DOM environment itself: the gap is in jsdom, not in\n * any package's feature, and Assay is the repo's home for DOM test-environment helpers.\n * `walkFlatTree` handles form-associated custom elements across shadow boundaries, so\n * consumer packages do not need package-local copies of this polyfill.\n */\nexport const installFormInternalsPolyfill = (): (() => void) => {\n // Checked *before* consuming the flag below: an environment without `ElementInternals`\n // installs nothing and should stay eligible to install for real later (e.g. a differently\n // configured environment in the same process), not get marked \"already installed\" for having\n // done nothing.\n if (typeof ElementInternals === 'undefined') return () => {};\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.assay.formInternalsPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return () => {};\n\n flagHost[INSTALLED_FLAG] = true;\n\n // Every patch pushes its inverse here, so uninstall() restores the environment exactly.\n const restorers: Array<() => void> = [];\n\n const proto = ElementInternals.prototype as unknown as Record<string, unknown>;\n const validityState = new WeakMap<ElementInternals, { flags: ValidityStateFlags; message: string }>();\n const formValueByHost = new WeakMap<HTMLElement, File | FormData | string | null>();\n const hostByInternals = new WeakMap<ElementInternals, HTMLElement>();\n\n const patchProto = (name: string, descriptor: PropertyDescriptor): void => {\n if (name in proto) return;\n\n Object.defineProperty(proto, name, descriptor);\n restorers.push(() => delete proto[name]);\n };\n\n const isValid = (internals: ElementInternals): boolean => {\n const state = validityState.get(internals);\n\n return !state || !Object.values(state.flags).some(Boolean);\n };\n\n patchProto('setFormValue', {\n configurable: true,\n value: function (this: ElementInternals, value: File | FormData | string | null) {\n const host = hostByInternals.get(this);\n\n if (host) formValueByHost.set(host, value);\n },\n writable: true,\n });\n\n patchProto('setValidity', {\n configurable: true,\n // Matches the real platform contract: throws if any flag is true and message is empty.\n // `useField()` itself already guards against triggering this: see forms/field.ts, but\n // the polyfill enforcing it too means a test would still catch a *different* caller doing\n // the same thing wrong, instead of that bug only surfacing in a real browser.\n value: function (this: ElementInternals, flags: ValidityStateFlags = {}, message = '') {\n if (Object.values(flags).some(Boolean) && !message) {\n throw new TypeError(\n \"Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if \" +\n 'one or more flags in the first argument are true.',\n );\n }\n\n validityState.set(this, { flags, message });\n },\n writable: true,\n });\n\n patchProto('checkValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('reportValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('validationMessage', {\n configurable: true,\n get(this: ElementInternals) {\n return isValid(this) ? '' : (validityState.get(this)?.message ?? '');\n },\n });\n\n // A ValidityState-shaped view of the flags passed to setValidity: every known\n // flag defaults to false, `valid` reflects whether any flag is set.\n patchProto('validity', {\n configurable: true,\n get(this: ElementInternals): ValidityState {\n const state = validityState.get(this);\n\n return {\n badInput: false,\n customError: false,\n patternMismatch: false,\n rangeOverflow: false,\n rangeUnderflow: false,\n stepMismatch: false,\n tooLong: false,\n tooShort: false,\n typeMismatch: false,\n valid: isValid(this),\n valueMissing: false,\n ...(state?.flags ?? {}),\n } as ValidityState;\n },\n });\n\n patchProto('states', {\n configurable: true,\n get: function (this: ElementInternals & { _states?: Set<string> }) {\n this._states ??= new Set();\n\n return this._states;\n },\n });\n\n // Real browsers mix `checkValidity`/`reportValidity`/`validity`/`validationMessage` onto any\n // `formAssociated: true` custom element itself (delegating to its internals): not just onto\n // `ElementInternals`. jsdom does neither; mirror it here so a component's own\n // `checkValidity()`/`reportValidity()`, and a test asserting against the element directly,\n // behave the same as they would in a real browser.\n const originalAttachInternals = HTMLElement.prototype.attachInternals;\n\n HTMLElement.prototype.attachInternals = function (this: HTMLElement, ...args: []): ElementInternals {\n const internals = originalAttachInternals.apply(this, args);\n\n hostByInternals.set(internals, this);\n\n Object.defineProperties(this, {\n checkValidity: { configurable: true, value: () => internals.checkValidity() },\n reportValidity: { configurable: true, value: () => internals.reportValidity() },\n validationMessage: { configurable: true, get: () => internals.validationMessage },\n validity: { configurable: true, get: () => internals.validity },\n });\n\n return internals;\n };\n restorers.push(() => {\n HTMLElement.prototype.attachInternals = originalAttachInternals;\n });\n\n const appendFormValue = (formData: FormData, name: string, value: File | FormData | string): void => {\n if (value instanceof FormData) {\n for (const [entryName, entryValue] of value.entries()) formData.append(entryName, entryValue);\n\n return;\n }\n\n formData.append(name, value);\n };\n\n // jsdom's `FormData` constructor never collects a form-associated custom element's set form\n // value: real browsers walk the flat tree for every form-associated element with a `name`.\n const NativeFormData = globalThis.FormData;\n\n globalThis.FormData = class FormDataWithFormAssociatedElements extends NativeFormData {\n constructor(form?: HTMLFormElement, submitter?: HTMLElement | null) {\n super(form as HTMLFormElement | undefined, submitter as HTMLElement | null | undefined);\n\n if (!(form instanceof HTMLFormElement)) return;\n\n walkFlatTree(form, (element) => {\n const name = element.getAttribute('name');\n const value = formValueByHost.get(element);\n\n if (!name || value == null || element.hasAttribute('disabled')) return;\n\n appendFormValue(this, name, value);\n });\n }\n };\n restorers.push(() => {\n globalThis.FormData = NativeFormData;\n });\n\n // jsdom never invokes the native `formResetCallback` lifecycle method on form-associated\n // custom elements when their form resets: patch `reset()` to do it (via the same flat-tree\n // walk, since a reset field can be nested behind a shadow boundary too), so `onFormReset()`\n // (see `@vielzeug/ore`'s runtime.ts) is testable against a real `<form>.reset()` call instead\n // of only by calling `element.formResetCallback()` directly.\n const originalReset = HTMLFormElement.prototype.reset;\n\n HTMLFormElement.prototype.reset = function (this: HTMLFormElement, ...args: []) {\n originalReset.apply(this, args);\n\n walkFlatTree(this, (element) => {\n (element as Partial<{ formResetCallback: () => void }>).formResetCallback?.();\n });\n };\n restorers.push(() => {\n HTMLFormElement.prototype.reset = originalReset;\n });\n\n return () => {\n for (const restore of restorers) restore();\n\n restorers.length = 0;\n flagHost[INSTALLED_FLAG] = false;\n };\n};\n","/**\n * jsdom implements none of the Popover API (`jsdom#3721`): no `showPopover`/`hidePopover`/\n * `togglePopover`, no `popover` IDL attribute, and — the part that silently breaks suites — its\n * selector engine treats `:popover-open` as a documented no-op that never matches.\n *\n * A partial shim (just setting the `popover-open` attribute) is worse than no shim, because every\n * component in the repo guards its calls the idiomatic way:\n *\n * ```ts\n * if (!panel.matches(':popover-open')) panel.showPopover();\n * if (panel.matches(':popover-open')) panel.hidePopover();\n * ```\n *\n * With `:popover-open` permanently false, `showPopover` runs twice and `hidePopover` never runs at\n * all: overlays open and can never close, and the failure looks like a component bug rather than an\n * environment gap. jsdom's UA stylesheet also keeps every `[popover]` element at\n * `display: none` (nothing matches `:popover-open` to lift it), and jsdom's focus algorithm refuses\n * to focus anything with a `display: none` flat-tree ancestor — so focusing an item inside an open\n * panel silently does nothing.\n *\n * This shim closes all three gaps: it tracks open state in the `popover-open` attribute (the same\n * attribute real browsers reflect, so tests can still assert on it), makes `matches(':popover-open')`\n * answer from that state, and holds the element visible with an inline `display` while open —\n * inline styles are the only author-level declaration that beats jsdom's UA rule, since component\n * styles live in adopted style sheets that jsdom does not cascade at all.\n *\n * Known simplifications, deliberate because nothing in the repo depends on them: no light-dismiss\n * behavior (`manual` is the only mode any component uses, and it has none), no top-layer ordering,\n * and no `beforetoggle`/`toggle` events. A suite that starts listening for those needs them added\n * here, not worked around per test.\n *\n * Call this from a test setup when the suite mounts popover-based components: the patches are global\n * monkey-patches, so suites without them shouldn't pay for them. Returns an `uninstall()` restoring\n * every patched global.\n *\n * Lives in Assay because the gap is in jsdom, not in any package's feature, and Assay is the repo's\n * home for DOM test-environment helpers (see `installFormInternalsPolyfill`). Consumer packages get\n * it from here instead of keeping per-file copies that drift out of sync with the API.\n */\nexport const installPopoverPolyfill = (): (() => void) => {\n if (typeof HTMLElement === 'undefined') return () => {};\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.assay.popoverPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return () => {};\n\n flagHost[INSTALLED_FLAG] = true;\n\n // Every patch pushes its inverse here, so uninstall() restores the environment exactly.\n const restorers: Array<() => void> = [];\n\n const OPEN_ATTRIBUTE = 'popover-open';\n\n const isOpen = (element: HTMLElement): boolean => element.hasAttribute(OPEN_ATTRIBUTE);\n\n // The inline `display` each element had before it was first shown, so hiding restores exactly\n // what was there rather than guessing. WeakMap: nothing outlives the element.\n const displayBeforeOpen = new WeakMap<HTMLElement, string>();\n\n const reveal = (element: HTMLElement): void => {\n const view = element.ownerDocument?.defaultView;\n\n // Only lift a `display: none` that is actually blocking the element. Overwriting an author-chosen\n // display (`grid` on a menu panel, `flex` on a card) would change layout the test is measuring.\n if (!view || view.getComputedStyle(element).display !== 'none') return;\n\n if (!displayBeforeOpen.has(element)) {\n displayBeforeOpen.set(element, element.style.getPropertyValue('display'));\n }\n\n element.style.setProperty('display', 'block');\n };\n\n const conceal = (element: HTMLElement): void => {\n if (!displayBeforeOpen.has(element)) return;\n\n const before = displayBeforeOpen.get(element) as string;\n\n displayBeforeOpen.delete(element);\n\n if (before) element.style.setProperty('display', before);\n else element.style.removeProperty('display');\n };\n\n const requirePopoverAttribute = (element: HTMLElement, method: string): void => {\n if (element.hasAttribute('popover')) return;\n\n // Matches the platform contract: showing or hiding an element that is not a popover is a\n // misuse bug, and throwing here surfaces it instead of letting the test pass quietly.\n throw new DOMException(\n `Failed to execute '${method}' on 'HTMLElement': the element does not have a popover attribute.`,\n 'InvalidStateError',\n );\n };\n\n // Same shape as `installFormInternalsPolyfill`: the prototype is patched through a plain record,\n // because these members are declared as always-present in lib.dom and this file's whole job is to\n // add them where they are absent.\n const proto = HTMLElement.prototype as unknown as Record<string, unknown>;\n\n const patchProto = (name: string, descriptor: PropertyDescriptor): void => {\n if (name in proto) return;\n\n Object.defineProperty(proto, name, descriptor);\n restorers.push(() => delete proto[name]);\n };\n\n patchProto('showPopover', {\n configurable: true,\n value: function (this: HTMLElement, options?: { source?: HTMLElement | null; force?: boolean }) {\n requirePopoverAttribute(this, 'showPopover');\n\n if (isOpen(this) && !options?.force) return;\n\n reveal(this);\n this.setAttribute(OPEN_ATTRIBUTE, '');\n },\n });\n\n patchProto('hidePopover', {\n configurable: true,\n value: function (this: HTMLElement) {\n requirePopoverAttribute(this, 'hidePopover');\n\n if (!isOpen(this)) return;\n\n this.removeAttribute(OPEN_ATTRIBUTE);\n conceal(this);\n },\n });\n\n patchProto('togglePopover', {\n configurable: true,\n value: function (this: HTMLElement, force?: boolean): boolean {\n requirePopoverAttribute(this, 'togglePopover');\n\n const shouldOpen = force ?? !isOpen(this);\n\n if (shouldOpen) reveal(this);\n else conceal(this);\n\n if (shouldOpen) this.setAttribute(OPEN_ATTRIBUTE, '');\n else this.removeAttribute(OPEN_ATTRIBUTE);\n\n return isOpen(this);\n },\n });\n\n // The guard every component wraps its calls in. dom-selector (jsdom's engine) stubs `:popover-open`\n // out as a permanent false, so without this `hidePopover` is unreachable from component code.\n // Intercepted by exact selector string: anything else, including `:not(:popover-open)` inside a\n // stylesheet, still goes through jsdom's own engine untouched.\n const originalMatches = Element.prototype.matches;\n\n Element.prototype.matches = function (this: Element, selectors: string): boolean {\n if (selectors === ':popover-open') return this.hasAttribute(OPEN_ATTRIBUTE);\n\n return originalMatches.call(this, selectors);\n // Cast: the interception only ever answers for one exact selector string, but the declared\n // member carries element-tag type predicates that a plain predicate cannot structurally satisfy.\n } as unknown as typeof Element.prototype.matches;\n restorers.push(() => {\n Element.prototype.matches = originalMatches;\n });\n\n return () => {\n for (const restore of restorers) restore();\n\n restorers.length = 0;\n flagHost[INSTALLED_FLAG] = false;\n };\n};\n","import { AssayQueryError } from './errors';\n\n/** DOM query helpers for test environments. */\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Scoped query helpers for any queryable DOM root: see {@link within}. */\nexport interface QueryScope {\n get<E extends Element = Element>(selector: string): E;\n getByTestId<E extends Element = Element>(testId: string): E;\n getByText<E extends Element = Element>(text: string, selector?: string): E;\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\ntype QueryRoot = ParentNode;\n\nconst describeRoot = (root: QueryRoot): string => {\n if (root instanceof Element) return root.outerHTML.slice(0, 500);\n\n if (root instanceof ShadowRoot) return `<shadow-root>${root.innerHTML.slice(0, 500)}</shadow-root>`;\n\n return root.nodeName;\n};\n\nconst requireMatch = <E extends Element>(element: E | null, description: string, root: QueryRoot): E => {\n if (element) return element;\n\n throw new AssayQueryError(`Unable to find ${description} within ${describeRoot(root)}.`);\n};\n\nconst query = <E extends Element = Element>(root: QueryRoot, selector: string): E | null =>\n root.querySelector<E>(selector);\n\nconst queryAll = <E extends Element = Element>(root: QueryRoot, selector: string): E[] => {\n return Array.from(root.querySelectorAll<E>(selector));\n};\n\nconst queryByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E | null =>\n queryAll<E>(root, '[data-testid]').find((element) => element.getAttribute('data-testid') === testId) ?? null;\n\nconst queryAllByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E[] =>\n queryAll<E>(root, '[data-testid]').filter((element) => element.getAttribute('data-testid') === testId);\n\nconst queryByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E | null => {\n for (const element of root.querySelectorAll<E>(selector)) {\n if (element.textContent?.trim() === text) return element;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] =>\n queryAll<E>(root, selector).filter((element) => element.textContent?.trim() === text);\n\n/**\n * Queries the shadow root of a custom element for a matching CSS selector.\n * Returns `null` if the element has no shadow root or no match is found: safe to call on\n * both open-shadow custom elements and plain elements without checking `shadowRoot` first.\n */\nexport function queryInShadow<E extends Element = Element>(host: Element, selector: string): E | null {\n return host.shadowRoot ? query<E>(host.shadowRoot, selector) : null;\n}\n\n/** Queries all matching elements inside the shadow root of a custom element. */\nexport function queryAllInShadow<E extends Element = Element>(host: Element, selector: string): E[] {\n return host.shadowRoot ? queryAll<E>(host.shadowRoot, selector) : [];\n}\n\n/**\n * Queries a shadow DOM element by its CSS `part` attribute: shorthand for\n * `queryInShadow(host, '[part=\"name\"]')`.\n *\n * @example\n * const btn = queryPart(carousel, 'prev-btn');\n * expect(btn).not.toBeNull();\n */\nexport function queryPart<E extends Element = Element>(host: Element, part: string): E | null {\n return (\n queryAllInShadow<E>(host, '[part]').find((element) => element.getAttribute('part')?.split(/\\s+/).includes(part)) ??\n null\n );\n}\n\n/**\n * Returns the light-DOM children assigned to a named slot, or every child assigned to the\n * default slot when no name is given.\n *\n * @example\n * const slides = getSlotted(carousel);\n * expect(slides).toHaveLength(3);\n */\nexport function getSlotted<E extends Element = Element>(host: Element, slotName?: string): E[] {\n return Array.from(host.children).filter((element) =>\n slotName === undefined ? !element.getAttribute('slot') : element.getAttribute('slot') === slotName,\n ) as E[];\n}\n\n// ─── API ─────────────────────────────────────────────────────────────────────\n\n/**\n * Create query helpers scoped to a DOM root: useful for light DOM and shadow roots.\n *\n * @example\n * const view = within(fixture.shadow!);\n * expect(view.get('.title').textContent).toBe('Hello');\n */\nexport function within(root: QueryRoot): QueryScope {\n return {\n get: <E extends Element = Element>(selector: string) =>\n requireMatch(query<E>(root, selector), `\"${selector}\"`, root),\n getByTestId: <E extends Element = Element>(testId: string) =>\n requireMatch(queryByTestId<E>(root, testId), `data-testid \"${testId}\"`, root),\n getByText: <E extends Element = Element>(text: string, selector = '*') =>\n requireMatch(queryByText<E>(root, text, selector), `text \"${text}\" matching \"${selector}\"`, root),\n query: <E extends Element = Element>(selector: string) => query<E>(root, selector),\n queryAll: <E extends Element = Element>(selector: string) => queryAll<E>(root, selector),\n queryAllByTestId: <E extends Element = Element>(testId: string) => queryAllByTestId<E>(root, testId),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(root, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) => queryByTestId<E>(root, testId),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(root, text, selector),\n };\n}\n","import { abortError, sleep } from '@vielzeug/arsenal';\n\nimport { AssayTimeoutError } from './errors';\n\nexport interface DelayOptions {\n signal?: AbortSignal;\n}\n\nexport interface WaitOptions {\n /** Polling interval in ms (default: 50). */\n interval?: number;\n /** Cancel the pending wait. */\n signal?: AbortSignal;\n /** Maximum wait time in ms (default: 1000). */\n timeout?: number;\n}\n\nexport interface EventuallyOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nconst DEADLINE = Symbol('assay.deadline');\nconst MAX_TIMER_MS = 2_147_483_647;\nconst now = (): number => performance.now();\n\nconst validateDuration = (name: string, value: number, allowZero: boolean): void => {\n if (!Number.isFinite(value) || value > MAX_TIMER_MS || (allowZero ? value < 0 : value <= 0)) {\n throw new RangeError(\n `${name} must be a ${allowZero ? 'non-negative' : 'positive'} finite number no greater than ${MAX_TIMER_MS}`,\n );\n }\n};\n\nconst validateWait = (interval: number, timeout: number): void => {\n validateDuration('interval', interval, false);\n validateDuration('timeout', timeout, true);\n};\n\nconst runBounded = <T>(run: () => T | Promise<T>, deadline: number, signal?: AbortSignal): Promise<T> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n let settled = false;\n const cleanup = (): boolean => {\n if (settled) return false;\n settled = true;\n clearTimeout(timer);\n signal?.removeEventListener('abort', abort);\n return true;\n };\n const resolveOnce = (value: T): void => {\n if (cleanup()) resolve(value);\n };\n const rejectOnce = (error: unknown): void => {\n if (cleanup()) reject(error);\n };\n const timer = setTimeout(() => rejectOnce(DEADLINE), Math.max(0, deadline - now()));\n const abort = () => rejectOnce(abortError(signal, 'The operation was aborted.'));\n\n signal?.addEventListener('abort', abort, { once: true });\n\n try {\n Promise.resolve(run()).then(resolveOnce, rejectOnce);\n } catch (error) {\n rejectOnce(error);\n }\n });\n\nexport const delay = (ms = 0, options: DelayOptions = {}): Promise<void> => {\n validateDuration('ms', ms, true);\n return sleep(ms, options.signal);\n};\n\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n first = false;\n\n let matched: boolean;\n try {\n matched = await runBounded(predicate, deadline, signal);\n } catch (error) {\n if (error === DEADLINE) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n throw error;\n }\n if (matched) return;\n\n const remaining = deadline - now();\n if (remaining <= 0) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n await sleep(Math.min(interval, remaining), signal);\n }\n}\n\n/**\n * Retry an assertion until it stops throwing or the timeout elapses.\n *\n * Polls the assertion on a fixed interval and preserves the last failure as the\n * timeout cause. Pending asynchronous assertions remain bounded by the same\n * deadline. Use `waitUntil()` for boolean conditions, `delay()` for explicit\n * timer dependencies, and `nextTick()` for one queued microtask boundary.\n *\n * @example\n * await eventually(() => expect(region.textContent).toBe('Saved'));\n */\nexport async function eventually(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: EventuallyOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) break;\n first = false;\n\n try {\n await runBounded(assertion, deadline, signal);\n return;\n } catch (error) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (error === DEADLINE) break;\n lastError = error;\n }\n\n const remaining = deadline - now();\n if (remaining <= 0) break;\n await sleep(Math.min(interval, remaining), signal);\n }\n\n const timing = `eventually timed out after ${timeout}ms`;\n const context = message ? `${message} (${timing})` : timing;\n const detail = lastError instanceof Error ? lastError.message : lastError == null ? '' : String(lastError);\n\n throw new AssayTimeoutError(detail ? `${context}\\n${detail}` : context, { cause: lastError });\n}\n\n/** Resolve with the next event of `type`, or reject when it times out or is aborted. */\nexport function waitForEvent<T extends Event = Event>(\n target: EventTarget,\n type: string,\n { signal, timeout = 1000 }: Omit<WaitOptions, 'interval'> = {},\n): Promise<T> {\n validateDuration('timeout', timeout, true);\n\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (event: Event): void => {\n dispose();\n resolve(event as T);\n };\n const timer = setTimeout(() => {\n dispose();\n reject(new AssayTimeoutError(`waitForEvent: \"${type}\" timed out after ${timeout}ms`));\n }, timeout);\n const onAbort = () => {\n dispose();\n reject(abortError(signal, 'The operation was aborted.'));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var Assay=(function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var walkFlatTree=(e,t)=>{let n=e instanceof HTMLSlotElement?e.assignedElements({flatten:!0}):e.children;for(let e of Array.from(n))e instanceof HTMLSlotElement||t(e),walkFlatTree(e,t)},AssayError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},AssayQueryError=class extends AssayError{},AssayTimeoutError=class extends AssayError{},dispatch=(e,t)=>e.dispatchEvent(t),fireBlur=(e,t={})=>dispatch(e,new FocusEvent(`blur`,t)),fireChange=(e,t={})=>dispatch(e,new Event(`change`,{bubbles:!0,...t})),fireClick=(e,t={})=>dispatch(e,new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...t})),fireCustom=(e,t,n={})=>dispatch(e,new CustomEvent(t,{bubbles:!0,cancelable:!0,composed:!1,...n})),fireFocus=(e,t={})=>dispatch(e,new FocusEvent(`focus`,t)),fireInput=(e,t={})=>dispatch(e,new InputEvent(`input`,{bubbles:!0,...t})),fireKeyDown=(e,t={})=>dispatch(e,new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...t})),fireKeyUp=(e,t={})=>dispatch(e,new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...t})),fireSubmit=(e,t={})=>dispatch(e,new SubmitEvent(`submit`,{bubbles:!0,cancelable:!0,...t})),installFormInternalsPolyfill=()=>{if(typeof ElementInternals>`u`)return()=>{};let e=Symbol.for(`vielzeug.assay.formInternalsPolyfillInstalled`),t=globalThis;if(t[e])return()=>{};t[e]=!0;let n=[],r=ElementInternals.prototype,i=new WeakMap,a=new WeakMap,o=new WeakMap,patchProto=(e,t)=>{e in r||(Object.defineProperty(r,e,t),n.push(()=>delete r[e]))},isValid=e=>{let t=i.get(e);return!t||!Object.values(t.flags).some(Boolean)};patchProto(`setFormValue`,{configurable:!0,value:function(e){let t=o.get(this);t&&a.set(t,e)},writable:!0}),patchProto(`setValidity`,{configurable:!0,value:function(e={},t=``){if(Object.values(e).some(Boolean)&&!t)throw TypeError(`Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if one or more flags in the first argument are true.`);i.set(this,{flags:e,message:t})},writable:!0}),patchProto(`checkValidity`,{configurable:!0,value:function(){return isValid(this)},writable:!0}),patchProto(`reportValidity`,{configurable:!0,value:function(){return isValid(this)},writable:!0}),patchProto(`validationMessage`,{configurable:!0,get(){return isValid(this)?``:i.get(this)?.message??``}}),patchProto(`validity`,{configurable:!0,get(){let e=i.get(this);return{badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valid:isValid(this),valueMissing:!1,...e?.flags??{}}}}),patchProto(`states`,{configurable:!0,get:function(){return this._states??=new Set,this._states}});let s=HTMLElement.prototype.attachInternals;HTMLElement.prototype.attachInternals=function(...e){let t=s.apply(this,e);return o.set(t,this),Object.defineProperties(this,{checkValidity:{configurable:!0,value:()=>t.checkValidity()},reportValidity:{configurable:!0,value:()=>t.reportValidity()},validationMessage:{configurable:!0,get:()=>t.validationMessage},validity:{configurable:!0,get:()=>t.validity}}),t},n.push(()=>{HTMLElement.prototype.attachInternals=s});let appendFormValue=(e,t,n)=>{if(n instanceof FormData)for(let[t,r]of n.entries())e.append(t,r);else e.append(t,n)},c=globalThis.FormData;globalThis.FormData=class FormDataWithFormAssociatedElements extends c{constructor(e,t){super(e,t),e instanceof HTMLFormElement&&walkFlatTree(e,e=>{let t=e.getAttribute(`name`),n=a.get(e);t&&n!=null&&!e.hasAttribute(`disabled`)&&appendFormValue(this,t,n)})}},n.push(()=>{globalThis.FormData=c});let l=HTMLFormElement.prototype.reset;return HTMLFormElement.prototype.reset=function(...e){l.apply(this,e),walkFlatTree(this,e=>{e.formResetCallback?.()})},n.push(()=>{HTMLFormElement.prototype.reset=l}),()=>{for(let e of n)e();n.length=0,t[e]=!1}},describeRoot=e=>e instanceof Element?e.outerHTML.slice(0,500):e instanceof ShadowRoot?`<shadow-root>${e.innerHTML.slice(0,500)}</shadow-root>`:e.nodeName,requireMatch=(e,t,n)=>{if(e)return e;throw new AssayQueryError(`Unable to find ${t} within ${describeRoot(n)}.`)},query=(e,t)=>e.querySelector(t),queryAll=(e,t)=>Array.from(e.querySelectorAll(t)),queryByTestId=(e,t)=>queryAll(e,`[data-testid]`).find(e=>e.getAttribute(`data-testid`)===t)??null,queryAllByTestId=(e,t)=>queryAll(e,`[data-testid]`).filter(e=>e.getAttribute(`data-testid`)===t),queryByText=(e,t,n=`*`)=>{for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null},queryAllByText=(e,t,n=`*`)=>queryAll(e,n).filter(e=>e.textContent?.trim()===t);function queryInShadow(e,t){return e.shadowRoot?query(e.shadowRoot,t):null}function queryAllInShadow(e,t){return e.shadowRoot?queryAll(e.shadowRoot,t):[]}function queryPart(e,t){return queryAllInShadow(e,`[part]`).find(e=>e.getAttribute(`part`)?.split(/\s+/).includes(t))??null}function getSlotted(e,t){return Array.from(e.children).filter(e=>t===void 0?!e.getAttribute(`slot`):e.getAttribute(`slot`)===t)}function within(e){return{get:t=>requireMatch(query(e,t),`"${t}"`,e),getByTestId:t=>requireMatch(queryByTestId(e,t),`data-testid "${t}"`,e),getByText:(t,n=`*`)=>requireMatch(queryByText(e,t,n),`text "${t}" matching "${n}"`,e),query:t=>query(e,t),queryAll:t=>queryAll(e,t),queryAllByTestId:t=>queryAllByTestId(e,t),queryAllByText:(t,n=`*`)=>queryAllByText(e,t,n),queryByTestId:t=>queryByTestId(e,t),queryByText:(t,n=`*`)=>queryByText(e,t,n)}}var n=Symbol(`assay.deadline`),r=2147483647,now=()=>performance.now(),validateDuration=(e,t,n)=>{if(!Number.isFinite(t)||t>r||(n?t<0:t<=0))throw RangeError(`${e} must be a ${n?`non-negative`:`positive`} finite number no greater than ${r}`)},validateWait=(e,t)=>{validateDuration(`interval`,e,!1),validateDuration(`timeout`,t,!0)},runBounded=(e,r,i)=>new Promise((a,o)=>{if(i?.aborted){o((0,t.abortError)(i,`The operation was aborted.`));return}let s=!1,cleanup=()=>!s&&(s=!0,clearTimeout(c),i?.removeEventListener(`abort`,abort),!0),resolveOnce=e=>{cleanup()&&a(e)},rejectOnce=e=>{cleanup()&&o(e)},c=setTimeout(()=>rejectOnce(n),Math.max(0,r-now())),abort=()=>rejectOnce((0,t.abortError)(i,`The operation was aborted.`));i?.addEventListener(`abort`,abort,{once:!0});try{Promise.resolve(e()).then(resolveOnce,rejectOnce)}catch(e){rejectOnce(e)}}),delay=(e=0,n={})=>(validateDuration(`ms`,e,!0),(0,t.sleep)(e,n.signal));async function waitUntil(e,{interval:r=50,signal:i,timeout:a=1e3}={}){validateWait(r,a);let o=now()+a,s=!0;for(;;){if(i?.aborted)throw(0,t.abortError)(i,`The operation was aborted.`);if(!s&&now()>=o)throw new AssayTimeoutError(`waitUntil timed out after ${a}ms`);s=!1;let c;try{c=await runBounded(e,o,i)}catch(e){throw e===n?new AssayTimeoutError(`waitUntil timed out after ${a}ms`):e}if(c)return;let l=o-now();if(l<=0)throw new AssayTimeoutError(`waitUntil timed out after ${a}ms`);await(0,t.sleep)(Math.min(r,l),i)}}async function eventually(e,{interval:r=50,message:i,signal:a,timeout:o=1e3}={}){validateWait(r,o);let s=now()+o,c=!0,l;for(;;){if(a?.aborted)throw(0,t.abortError)(a,`The operation was aborted.`);if(!c&&now()>=s)break;c=!1;try{await runBounded(e,s,a);return}catch(e){if(a?.aborted)throw(0,t.abortError)(a,`The operation was aborted.`);if(e===n)break;l=e}let i=s-now();if(i<=0)break;await(0,t.sleep)(Math.min(r,i),a)}let u=`eventually timed out after ${o}ms`,d=i?`${i} (${u})`:u,f=l instanceof Error?l.message:l==null?``:String(l);throw new AssayTimeoutError(f?`${d}\n${f}`:d,{cause:l})}function waitForEvent(e,n,{signal:r,timeout:i=1e3}={}){return validateDuration(`timeout`,i,!0),new Promise((a,o)=>{if(r?.aborted){o((0,t.abortError)(r,`The operation was aborted.`));return}let dispose=()=>{clearTimeout(s),r?.removeEventListener(`abort`,onAbort),e.removeEventListener(n,onEvent)},onEvent=e=>{dispose(),a(e)},s=setTimeout(()=>{dispose(),o(new AssayTimeoutError(`waitForEvent: "${n}" timed out after ${i}ms`))},i),onAbort=()=>{dispose(),o((0,t.abortError)(r,`The operation was aborted.`))};e.addEventListener(n,onEvent,{once:!0}),r?.addEventListener(`abort`,onAbort,{once:!0})})}return e.AssayError=AssayError,e.AssayQueryError=AssayQueryError,e.AssayTimeoutError=AssayTimeoutError,e.delay=delay,e.dispatch=dispatch,e.eventually=eventually,e.fireBlur=fireBlur,e.fireChange=fireChange,e.fireClick=fireClick,e.fireCustom=fireCustom,e.fireFocus=fireFocus,e.fireInput=fireInput,e.fireKeyDown=fireKeyDown,e.fireKeyUp=fireKeyUp,e.fireSubmit=fireSubmit,e.getSlotted=getSlotted,e.installFormInternalsPolyfill=installFormInternalsPolyfill,e.queryAllInShadow=queryAllInShadow,e.queryInShadow=queryInShadow,e.queryPart=queryPart,e.waitForEvent=waitForEvent,e.waitUntil=waitUntil,e.walkFlatTree=walkFlatTree,e.within=within,e})({},Arsenal);
1
+ var Assay=(function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var walkFlatTree=(e,t)=>{let n=e instanceof HTMLSlotElement?e.assignedElements({flatten:!0}):e.children;for(let e of Array.from(n))e instanceof HTMLSlotElement||t(e),walkFlatTree(e,t)},AssayError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},AssayQueryError=class extends AssayError{},AssayTimeoutError=class extends AssayError{},dispatch=(e,t)=>e.dispatchEvent(t),fireBlur=(e,t={})=>dispatch(e,new FocusEvent(`blur`,t)),fireChange=(e,t={})=>dispatch(e,new Event(`change`,{bubbles:!0,...t})),fireClick=(e,t={})=>dispatch(e,new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...t})),fireCustom=(e,t,n={})=>dispatch(e,new CustomEvent(t,{bubbles:!0,cancelable:!0,composed:!1,...n})),fireFocus=(e,t={})=>dispatch(e,new FocusEvent(`focus`,t)),fireInput=(e,t={})=>dispatch(e,new InputEvent(`input`,{bubbles:!0,...t})),fireKeyDown=(e,t={})=>dispatch(e,new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...t})),fireKeyUp=(e,t={})=>dispatch(e,new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...t})),fireSubmit=(e,t={})=>dispatch(e,new SubmitEvent(`submit`,{bubbles:!0,cancelable:!0,...t})),installFormInternalsPolyfill=()=>{if(typeof ElementInternals>`u`)return()=>{};let e=Symbol.for(`vielzeug.assay.formInternalsPolyfillInstalled`),t=globalThis;if(t[e])return()=>{};t[e]=!0;let n=[],r=ElementInternals.prototype,i=new WeakMap,a=new WeakMap,o=new WeakMap,patchProto=(e,t)=>{e in r||(Object.defineProperty(r,e,t),n.push(()=>delete r[e]))},isValid=e=>{let t=i.get(e);return!t||!Object.values(t.flags).some(Boolean)};patchProto(`setFormValue`,{configurable:!0,value:function(e){let t=o.get(this);t&&a.set(t,e)},writable:!0}),patchProto(`setValidity`,{configurable:!0,value:function(e={},t=``){if(Object.values(e).some(Boolean)&&!t)throw TypeError(`Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if one or more flags in the first argument are true.`);i.set(this,{flags:e,message:t})},writable:!0}),patchProto(`checkValidity`,{configurable:!0,value:function(){return isValid(this)},writable:!0}),patchProto(`reportValidity`,{configurable:!0,value:function(){return isValid(this)},writable:!0}),patchProto(`validationMessage`,{configurable:!0,get(){return isValid(this)?``:i.get(this)?.message??``}}),patchProto(`validity`,{configurable:!0,get(){let e=i.get(this);return{badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valid:isValid(this),valueMissing:!1,...e?.flags??{}}}}),patchProto(`states`,{configurable:!0,get:function(){return this._states??=new Set,this._states}});let s=HTMLElement.prototype.attachInternals;HTMLElement.prototype.attachInternals=function(...e){let t=s.apply(this,e);return o.set(t,this),Object.defineProperties(this,{checkValidity:{configurable:!0,value:()=>t.checkValidity()},reportValidity:{configurable:!0,value:()=>t.reportValidity()},validationMessage:{configurable:!0,get:()=>t.validationMessage},validity:{configurable:!0,get:()=>t.validity}}),t},n.push(()=>{HTMLElement.prototype.attachInternals=s});let appendFormValue=(e,t,n)=>{if(n instanceof FormData)for(let[t,r]of n.entries())e.append(t,r);else e.append(t,n)},c=globalThis.FormData;globalThis.FormData=class FormDataWithFormAssociatedElements extends c{constructor(e,t){super(e,t),e instanceof HTMLFormElement&&walkFlatTree(e,e=>{let t=e.getAttribute(`name`),n=a.get(e);t&&n!=null&&!e.hasAttribute(`disabled`)&&appendFormValue(this,t,n)})}},n.push(()=>{globalThis.FormData=c});let l=HTMLFormElement.prototype.reset;return HTMLFormElement.prototype.reset=function(...e){l.apply(this,e),walkFlatTree(this,e=>{e.formResetCallback?.()})},n.push(()=>{HTMLFormElement.prototype.reset=l}),()=>{for(let e of n)e();n.length=0,t[e]=!1}},installPopoverPolyfill=()=>{if(typeof HTMLElement>`u`)return()=>{};let e=Symbol.for(`vielzeug.assay.popoverPolyfillInstalled`),t=globalThis;if(t[e])return()=>{};t[e]=!0;let n=[],r=`popover-open`,isOpen=e=>e.hasAttribute(r),i=new WeakMap,reveal=e=>{let t=e.ownerDocument?.defaultView;t&&t.getComputedStyle(e).display===`none`&&(i.has(e)||i.set(e,e.style.getPropertyValue(`display`)),e.style.setProperty(`display`,`block`))},conceal=e=>{if(!i.has(e))return;let t=i.get(e);i.delete(e),t?e.style.setProperty(`display`,t):e.style.removeProperty(`display`)},requirePopoverAttribute=(e,t)=>{if(!e.hasAttribute(`popover`))throw new DOMException(`Failed to execute '${t}' on 'HTMLElement': the element does not have a popover attribute.`,`InvalidStateError`)},a=HTMLElement.prototype,patchProto=(e,t)=>{e in a||(Object.defineProperty(a,e,t),n.push(()=>delete a[e]))};patchProto(`showPopover`,{configurable:!0,value:function(e){requirePopoverAttribute(this,`showPopover`),(!isOpen(this)||e?.force)&&(reveal(this),this.setAttribute(r,``))}}),patchProto(`hidePopover`,{configurable:!0,value:function(){requirePopoverAttribute(this,`hidePopover`),isOpen(this)&&(this.removeAttribute(r),conceal(this))}}),patchProto(`togglePopover`,{configurable:!0,value:function(e){requirePopoverAttribute(this,`togglePopover`);let t=e??!isOpen(this);return t?reveal(this):conceal(this),t?this.setAttribute(r,``):this.removeAttribute(r),isOpen(this)}});let o=Element.prototype.matches;return Element.prototype.matches=function(e){return e===`:popover-open`?this.hasAttribute(r):o.call(this,e)},n.push(()=>{Element.prototype.matches=o}),()=>{for(let e of n)e();n.length=0,t[e]=!1}},describeRoot=e=>e instanceof Element?e.outerHTML.slice(0,500):e instanceof ShadowRoot?`<shadow-root>${e.innerHTML.slice(0,500)}</shadow-root>`:e.nodeName,requireMatch=(e,t,n)=>{if(e)return e;throw new AssayQueryError(`Unable to find ${t} within ${describeRoot(n)}.`)},query=(e,t)=>e.querySelector(t),queryAll=(e,t)=>Array.from(e.querySelectorAll(t)),queryByTestId=(e,t)=>queryAll(e,`[data-testid]`).find(e=>e.getAttribute(`data-testid`)===t)??null,queryAllByTestId=(e,t)=>queryAll(e,`[data-testid]`).filter(e=>e.getAttribute(`data-testid`)===t),queryByText=(e,t,n=`*`)=>{for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null},queryAllByText=(e,t,n=`*`)=>queryAll(e,n).filter(e=>e.textContent?.trim()===t);function queryInShadow(e,t){return e.shadowRoot?query(e.shadowRoot,t):null}function queryAllInShadow(e,t){return e.shadowRoot?queryAll(e.shadowRoot,t):[]}function queryPart(e,t){return queryAllInShadow(e,`[part]`).find(e=>e.getAttribute(`part`)?.split(/\s+/).includes(t))??null}function getSlotted(e,t){return Array.from(e.children).filter(e=>t===void 0?!e.getAttribute(`slot`):e.getAttribute(`slot`)===t)}function within(e){return{get:t=>requireMatch(query(e,t),`"${t}"`,e),getByTestId:t=>requireMatch(queryByTestId(e,t),`data-testid "${t}"`,e),getByText:(t,n=`*`)=>requireMatch(queryByText(e,t,n),`text "${t}" matching "${n}"`,e),query:t=>query(e,t),queryAll:t=>queryAll(e,t),queryAllByTestId:t=>queryAllByTestId(e,t),queryAllByText:(t,n=`*`)=>queryAllByText(e,t,n),queryByTestId:t=>queryByTestId(e,t),queryByText:(t,n=`*`)=>queryByText(e,t,n)}}var n=Symbol(`assay.deadline`),r=2147483647,now=()=>performance.now(),validateDuration=(e,t,n)=>{if(!Number.isFinite(t)||t>r||(n?t<0:t<=0))throw RangeError(`${e} must be a ${n?`non-negative`:`positive`} finite number no greater than ${r}`)},validateWait=(e,t)=>{validateDuration(`interval`,e,!1),validateDuration(`timeout`,t,!0)},runBounded=(e,r,i)=>new Promise((a,o)=>{if(i?.aborted){o((0,t.abortError)(i,`The operation was aborted.`));return}let s=!1,cleanup=()=>!s&&(s=!0,clearTimeout(c),i?.removeEventListener(`abort`,abort),!0),resolveOnce=e=>{cleanup()&&a(e)},rejectOnce=e=>{cleanup()&&o(e)},c=setTimeout(()=>rejectOnce(n),Math.max(0,r-now())),abort=()=>rejectOnce((0,t.abortError)(i,`The operation was aborted.`));i?.addEventListener(`abort`,abort,{once:!0});try{Promise.resolve(e()).then(resolveOnce,rejectOnce)}catch(e){rejectOnce(e)}}),delay=(e=0,n={})=>(validateDuration(`ms`,e,!0),(0,t.sleep)(e,n.signal));async function waitUntil(e,{interval:r=50,signal:i,timeout:a=1e3}={}){validateWait(r,a);let o=now()+a,s=!0;for(;;){if(i?.aborted)throw(0,t.abortError)(i,`The operation was aborted.`);if(!s&&now()>=o)throw new AssayTimeoutError(`waitUntil timed out after ${a}ms`);s=!1;let c;try{c=await runBounded(e,o,i)}catch(e){throw e===n?new AssayTimeoutError(`waitUntil timed out after ${a}ms`):e}if(c)return;let l=o-now();if(l<=0)throw new AssayTimeoutError(`waitUntil timed out after ${a}ms`);await(0,t.sleep)(Math.min(r,l),i)}}async function eventually(e,{interval:r=50,message:i,signal:a,timeout:o=1e3}={}){validateWait(r,o);let s=now()+o,c=!0,l;for(;;){if(a?.aborted)throw(0,t.abortError)(a,`The operation was aborted.`);if(!c&&now()>=s)break;c=!1;try{await runBounded(e,s,a);return}catch(e){if(a?.aborted)throw(0,t.abortError)(a,`The operation was aborted.`);if(e===n)break;l=e}let i=s-now();if(i<=0)break;await(0,t.sleep)(Math.min(r,i),a)}let u=`eventually timed out after ${o}ms`,d=i?`${i} (${u})`:u,f=l instanceof Error?l.message:l==null?``:String(l);throw new AssayTimeoutError(f?`${d}\n${f}`:d,{cause:l})}function waitForEvent(e,n,{signal:r,timeout:i=1e3}={}){return validateDuration(`timeout`,i,!0),new Promise((a,o)=>{if(r?.aborted){o((0,t.abortError)(r,`The operation was aborted.`));return}let dispose=()=>{clearTimeout(s),r?.removeEventListener(`abort`,onAbort),e.removeEventListener(n,onEvent)},onEvent=e=>{dispose(),a(e)},s=setTimeout(()=>{dispose(),o(new AssayTimeoutError(`waitForEvent: "${n}" timed out after ${i}ms`))},i),onAbort=()=>{dispose(),o((0,t.abortError)(r,`The operation was aborted.`))};e.addEventListener(n,onEvent,{once:!0}),r?.addEventListener(`abort`,onAbort,{once:!0})})}return e.AssayError=AssayError,e.AssayQueryError=AssayQueryError,e.AssayTimeoutError=AssayTimeoutError,e.delay=delay,e.dispatch=dispatch,e.eventually=eventually,e.fireBlur=fireBlur,e.fireChange=fireChange,e.fireClick=fireClick,e.fireCustom=fireCustom,e.fireFocus=fireFocus,e.fireInput=fireInput,e.fireKeyDown=fireKeyDown,e.fireKeyUp=fireKeyUp,e.fireSubmit=fireSubmit,e.getSlotted=getSlotted,e.installFormInternalsPolyfill=installFormInternalsPolyfill,e.installPopoverPolyfill=installPopoverPolyfill,e.queryAllInShadow=queryAllInShadow,e.queryInShadow=queryInShadow,e.queryPart=queryPart,e.waitForEvent=waitForEvent,e.waitUntil=waitUntil,e.walkFlatTree=walkFlatTree,e.within=within,e})({},Arsenal);
2
2
  //# sourceMappingURL=assay.iife.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"assay.iife.js","names":["abortError","sleep","exports","children","root","child","visit","message","opts","target","event","init","type","INSTALLED_FLAG","flagHost","restorers","proto","validityState","formValueByHost","hostByInternals","name","descriptor","state","internals","host","value","flags","originalAttachInternals","args","entryName","entryValue","formData","NativeFormData","form","submitter","element","originalReset","restore","description","selector","testId","text","part","slotName","DEADLINE","MAX_TIMER_MS","allowZero","interval","timeout","signal","reject","_vielzeug_arsenal","settled","timer","resolve","error","deadline","run","ms","options","first","matched","predicate","remaining","lastError","assertion","timing","context","detail"],"sources":["../src/dom.ts","../src/errors.ts","../src/events.ts","../src/form-internals.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/**\n * DOM traversal helpers for tests running under jsdom, which only implements the *light* DOM\n * tree: `Element.children`/`querySelectorAll()` never cross a `<slot>` into its assigned\n * elements. Real browsers use the *flat tree* (light DOM with each `<slot>` transparently\n * replaced by what's actually assigned to it) for this: it's what \"form owner\" resolution,\n * `:has()`, and plenty of other DOM algorithms are specified against.\n */\n\n/**\n * Walks the flat tree starting at `root`, calling `visit` for every element encountered :\n * expanding each `<slot>` via `assignedElements()` instead of descending into its (always\n * empty, in jsdom) literal children.\n *\n * @example\n * ```ts\n * // Find every form-associated element slotted (possibly through nested slots) under `form`,\n * // something `form.querySelectorAll('[name]')` can't do once a shadow boundary is involved.\n * const named: HTMLElement[] = [];\n * walkFlatTree(form, (el) => { if (el.hasAttribute('name')) named.push(el); });\n * ```\n */\nexport const walkFlatTree = (root: Element, visit: (element: HTMLElement) => void): void => {\n const children = root instanceof HTMLSlotElement ? root.assignedElements({ flatten: true }) : root.children;\n\n for (const child of Array.from(children)) {\n if (!(child instanceof HTMLSlotElement)) visit(child as HTMLElement);\n\n walkFlatTree(child, visit);\n }\n};\n","/** Base class for all Assay errors. Use `instanceof AssayError` to catch any Assay-originated error. */\nexport class AssayError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a required query has no match. */\nexport class AssayQueryError extends AssayError {}\n\n/** Thrown when an Assay wait reaches its timeout. */\nexport class AssayTimeoutError extends AssayError {}\n","/**\n * # Confidence boundary: read first\n *\n * `dispatch` is a **low-level synthetic-event dispatch API**. It fires a caller-\n * supplied DOM `Event` synchronously and returns the `dispatchEvent`\n * result. It does **not** model real user interaction: there is no focus/blur\n * sequencing, no input-event coordination, no keyboard layout, no pointer\n * hit-testing, and no trust flag (`event.isTrusted` is always `false`).\n *\n * Use it to drive event handlers in unit/integration tests where you control\n * the exact event shape. For **behavioral confidence**, that a real click\n * actually activates a control, that focus management works end-to-end, that\n * keyboard shortcuts fire under a real input device: write Playwright tests.\n * Assay deliberately stops at the dispatch boundary; anything that depends on\n * the browser's interaction semantics belongs in a browser-driven suite.\n */\n\n/** Dispatch a pre-built `Event` instance unchanged. Returns the `dispatchEvent` result. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\n/** Synthetic convenience dispatchers. They share the same confidence boundary as `dispatch()`. */\nexport const fireBlur = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('blur', init));\n\nexport const fireChange = (target: EventTarget, init: EventInit = {}): boolean =>\n dispatch(target, new Event('change', { bubbles: true, ...init }));\n\nexport const fireClick = (target: EventTarget, init: MouseEventInit = {}): boolean =>\n dispatch(target, new MouseEvent('click', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireCustom = <T>(target: EventTarget, type: string, init: CustomEventInit<T> = {}): boolean =>\n dispatch(target, new CustomEvent(type, { bubbles: true, cancelable: true, composed: false, ...init }));\n\nexport const fireFocus = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('focus', init));\n\nexport const fireInput = (target: EventTarget, init: InputEventInit = {}): boolean =>\n dispatch(target, new InputEvent('input', { bubbles: true, ...init }));\n\nexport const fireKeyDown = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireKeyUp = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireSubmit = (target: EventTarget, init: SubmitEventInit = {}): boolean =>\n dispatch(target, new SubmitEvent('submit', { bubbles: true, cancelable: true, ...init }));\n","import { walkFlatTree } from './dom';\n\n/**\n * jsdom implements none of the `ElementInternals` form-association API: not `setFormValue`,\n * not `setValidity`, not the `checkValidity`/`reportValidity`/`validity`/`validationMessage`\n * mixin real browsers put on every `formAssociated: true` element, not even `FormData`\n * collecting a form-associated element's set value, or `<form>.reset()` invoking\n * `formResetCallback()`. Every one of those gaps is exercised by `useField()` (`@vielzeug/ore`),\n * so any package testing a form-associated component needs all of them, not just one.\n *\n * Call this directly from a test setup when the suite tests form-associated components:\n * the patches are global monkey-patches, so suites without them shouldn't pay for them.\n * Returns an `uninstall()` that restores every patched global.\n *\n * Lives in Assay because it patches the DOM environment itself: the gap is in jsdom, not in\n * any package's feature, and Assay is the repo's home for DOM test-environment helpers.\n * `walkFlatTree` handles form-associated custom elements across shadow boundaries, so\n * consumer packages do not need package-local copies of this polyfill.\n */\nexport const installFormInternalsPolyfill = (): (() => void) => {\n // Checked *before* consuming the flag below: an environment without `ElementInternals`\n // installs nothing and should stay eligible to install for real later (e.g. a differently\n // configured environment in the same process), not get marked \"already installed\" for having\n // done nothing.\n if (typeof ElementInternals === 'undefined') return () => {};\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.assay.formInternalsPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return () => {};\n\n flagHost[INSTALLED_FLAG] = true;\n\n // Every patch pushes its inverse here, so uninstall() restores the environment exactly.\n const restorers: Array<() => void> = [];\n\n const proto = ElementInternals.prototype as unknown as Record<string, unknown>;\n const validityState = new WeakMap<ElementInternals, { flags: ValidityStateFlags; message: string }>();\n const formValueByHost = new WeakMap<HTMLElement, File | FormData | string | null>();\n const hostByInternals = new WeakMap<ElementInternals, HTMLElement>();\n\n const patchProto = (name: string, descriptor: PropertyDescriptor): void => {\n if (name in proto) return;\n\n Object.defineProperty(proto, name, descriptor);\n restorers.push(() => delete proto[name]);\n };\n\n const isValid = (internals: ElementInternals): boolean => {\n const state = validityState.get(internals);\n\n return !state || !Object.values(state.flags).some(Boolean);\n };\n\n patchProto('setFormValue', {\n configurable: true,\n value: function (this: ElementInternals, value: File | FormData | string | null) {\n const host = hostByInternals.get(this);\n\n if (host) formValueByHost.set(host, value);\n },\n writable: true,\n });\n\n patchProto('setValidity', {\n configurable: true,\n // Matches the real platform contract: throws if any flag is true and message is empty.\n // `useField()` itself already guards against triggering this: see forms/field.ts, but\n // the polyfill enforcing it too means a test would still catch a *different* caller doing\n // the same thing wrong, instead of that bug only surfacing in a real browser.\n value: function (this: ElementInternals, flags: ValidityStateFlags = {}, message = '') {\n if (Object.values(flags).some(Boolean) && !message) {\n throw new TypeError(\n \"Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if \" +\n 'one or more flags in the first argument are true.',\n );\n }\n\n validityState.set(this, { flags, message });\n },\n writable: true,\n });\n\n patchProto('checkValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('reportValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('validationMessage', {\n configurable: true,\n get(this: ElementInternals) {\n return isValid(this) ? '' : (validityState.get(this)?.message ?? '');\n },\n });\n\n // A ValidityState-shaped view of the flags passed to setValidity: every known\n // flag defaults to false, `valid` reflects whether any flag is set.\n patchProto('validity', {\n configurable: true,\n get(this: ElementInternals): ValidityState {\n const state = validityState.get(this);\n\n return {\n badInput: false,\n customError: false,\n patternMismatch: false,\n rangeOverflow: false,\n rangeUnderflow: false,\n stepMismatch: false,\n tooLong: false,\n tooShort: false,\n typeMismatch: false,\n valid: isValid(this),\n valueMissing: false,\n ...(state?.flags ?? {}),\n } as ValidityState;\n },\n });\n\n patchProto('states', {\n configurable: true,\n get: function (this: ElementInternals & { _states?: Set<string> }) {\n this._states ??= new Set();\n\n return this._states;\n },\n });\n\n // Real browsers mix `checkValidity`/`reportValidity`/`validity`/`validationMessage` onto any\n // `formAssociated: true` custom element itself (delegating to its internals): not just onto\n // `ElementInternals`. jsdom does neither; mirror it here so a component's own\n // `checkValidity()`/`reportValidity()`, and a test asserting against the element directly,\n // behave the same as they would in a real browser.\n const originalAttachInternals = HTMLElement.prototype.attachInternals;\n\n HTMLElement.prototype.attachInternals = function (this: HTMLElement, ...args: []): ElementInternals {\n const internals = originalAttachInternals.apply(this, args);\n\n hostByInternals.set(internals, this);\n\n Object.defineProperties(this, {\n checkValidity: { configurable: true, value: () => internals.checkValidity() },\n reportValidity: { configurable: true, value: () => internals.reportValidity() },\n validationMessage: { configurable: true, get: () => internals.validationMessage },\n validity: { configurable: true, get: () => internals.validity },\n });\n\n return internals;\n };\n restorers.push(() => {\n HTMLElement.prototype.attachInternals = originalAttachInternals;\n });\n\n const appendFormValue = (formData: FormData, name: string, value: File | FormData | string): void => {\n if (value instanceof FormData) {\n for (const [entryName, entryValue] of value.entries()) formData.append(entryName, entryValue);\n\n return;\n }\n\n formData.append(name, value);\n };\n\n // jsdom's `FormData` constructor never collects a form-associated custom element's set form\n // value: real browsers walk the flat tree for every form-associated element with a `name`.\n const NativeFormData = globalThis.FormData;\n\n globalThis.FormData = class FormDataWithFormAssociatedElements extends NativeFormData {\n constructor(form?: HTMLFormElement, submitter?: HTMLElement | null) {\n super(form as HTMLFormElement | undefined, submitter as HTMLElement | null | undefined);\n\n if (!(form instanceof HTMLFormElement)) return;\n\n walkFlatTree(form, (element) => {\n const name = element.getAttribute('name');\n const value = formValueByHost.get(element);\n\n if (!name || value == null || element.hasAttribute('disabled')) return;\n\n appendFormValue(this, name, value);\n });\n }\n };\n restorers.push(() => {\n globalThis.FormData = NativeFormData;\n });\n\n // jsdom never invokes the native `formResetCallback` lifecycle method on form-associated\n // custom elements when their form resets: patch `reset()` to do it (via the same flat-tree\n // walk, since a reset field can be nested behind a shadow boundary too), so `onFormReset()`\n // (see `@vielzeug/ore`'s runtime.ts) is testable against a real `<form>.reset()` call instead\n // of only by calling `element.formResetCallback()` directly.\n const originalReset = HTMLFormElement.prototype.reset;\n\n HTMLFormElement.prototype.reset = function (this: HTMLFormElement, ...args: []) {\n originalReset.apply(this, args);\n\n walkFlatTree(this, (element) => {\n (element as Partial<{ formResetCallback: () => void }>).formResetCallback?.();\n });\n };\n restorers.push(() => {\n HTMLFormElement.prototype.reset = originalReset;\n });\n\n return () => {\n for (const restore of restorers) restore();\n\n restorers.length = 0;\n flagHost[INSTALLED_FLAG] = false;\n };\n};\n","import { AssayQueryError } from './errors';\n\n/** DOM query helpers for test environments. */\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Scoped query helpers for any queryable DOM root: see {@link within}. */\nexport interface QueryScope {\n get<E extends Element = Element>(selector: string): E;\n getByTestId<E extends Element = Element>(testId: string): E;\n getByText<E extends Element = Element>(text: string, selector?: string): E;\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\ntype QueryRoot = ParentNode;\n\nconst describeRoot = (root: QueryRoot): string => {\n if (root instanceof Element) return root.outerHTML.slice(0, 500);\n\n if (root instanceof ShadowRoot) return `<shadow-root>${root.innerHTML.slice(0, 500)}</shadow-root>`;\n\n return root.nodeName;\n};\n\nconst requireMatch = <E extends Element>(element: E | null, description: string, root: QueryRoot): E => {\n if (element) return element;\n\n throw new AssayQueryError(`Unable to find ${description} within ${describeRoot(root)}.`);\n};\n\nconst query = <E extends Element = Element>(root: QueryRoot, selector: string): E | null =>\n root.querySelector<E>(selector);\n\nconst queryAll = <E extends Element = Element>(root: QueryRoot, selector: string): E[] => {\n return Array.from(root.querySelectorAll<E>(selector));\n};\n\nconst queryByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E | null =>\n queryAll<E>(root, '[data-testid]').find((element) => element.getAttribute('data-testid') === testId) ?? null;\n\nconst queryAllByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E[] =>\n queryAll<E>(root, '[data-testid]').filter((element) => element.getAttribute('data-testid') === testId);\n\nconst queryByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E | null => {\n for (const element of root.querySelectorAll<E>(selector)) {\n if (element.textContent?.trim() === text) return element;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] =>\n queryAll<E>(root, selector).filter((element) => element.textContent?.trim() === text);\n\n/**\n * Queries the shadow root of a custom element for a matching CSS selector.\n * Returns `null` if the element has no shadow root or no match is found: safe to call on\n * both open-shadow custom elements and plain elements without checking `shadowRoot` first.\n */\nexport function queryInShadow<E extends Element = Element>(host: Element, selector: string): E | null {\n return host.shadowRoot ? query<E>(host.shadowRoot, selector) : null;\n}\n\n/** Queries all matching elements inside the shadow root of a custom element. */\nexport function queryAllInShadow<E extends Element = Element>(host: Element, selector: string): E[] {\n return host.shadowRoot ? queryAll<E>(host.shadowRoot, selector) : [];\n}\n\n/**\n * Queries a shadow DOM element by its CSS `part` attribute: shorthand for\n * `queryInShadow(host, '[part=\"name\"]')`.\n *\n * @example\n * const btn = queryPart(carousel, 'prev-btn');\n * expect(btn).not.toBeNull();\n */\nexport function queryPart<E extends Element = Element>(host: Element, part: string): E | null {\n return (\n queryAllInShadow<E>(host, '[part]').find((element) => element.getAttribute('part')?.split(/\\s+/).includes(part)) ??\n null\n );\n}\n\n/**\n * Returns the light-DOM children assigned to a named slot, or every child assigned to the\n * default slot when no name is given.\n *\n * @example\n * const slides = getSlotted(carousel);\n * expect(slides).toHaveLength(3);\n */\nexport function getSlotted<E extends Element = Element>(host: Element, slotName?: string): E[] {\n return Array.from(host.children).filter((element) =>\n slotName === undefined ? !element.getAttribute('slot') : element.getAttribute('slot') === slotName,\n ) as E[];\n}\n\n// ─── API ─────────────────────────────────────────────────────────────────────\n\n/**\n * Create query helpers scoped to a DOM root: useful for light DOM and shadow roots.\n *\n * @example\n * const view = within(fixture.shadow!);\n * expect(view.get('.title').textContent).toBe('Hello');\n */\nexport function within(root: QueryRoot): QueryScope {\n return {\n get: <E extends Element = Element>(selector: string) =>\n requireMatch(query<E>(root, selector), `\"${selector}\"`, root),\n getByTestId: <E extends Element = Element>(testId: string) =>\n requireMatch(queryByTestId<E>(root, testId), `data-testid \"${testId}\"`, root),\n getByText: <E extends Element = Element>(text: string, selector = '*') =>\n requireMatch(queryByText<E>(root, text, selector), `text \"${text}\" matching \"${selector}\"`, root),\n query: <E extends Element = Element>(selector: string) => query<E>(root, selector),\n queryAll: <E extends Element = Element>(selector: string) => queryAll<E>(root, selector),\n queryAllByTestId: <E extends Element = Element>(testId: string) => queryAllByTestId<E>(root, testId),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(root, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) => queryByTestId<E>(root, testId),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(root, text, selector),\n };\n}\n","import { abortError, sleep } from '@vielzeug/arsenal';\n\nimport { AssayTimeoutError } from './errors';\n\nexport interface DelayOptions {\n signal?: AbortSignal;\n}\n\nexport interface WaitOptions {\n /** Polling interval in ms (default: 50). */\n interval?: number;\n /** Cancel the pending wait. */\n signal?: AbortSignal;\n /** Maximum wait time in ms (default: 1000). */\n timeout?: number;\n}\n\nexport interface EventuallyOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nconst DEADLINE = Symbol('assay.deadline');\nconst MAX_TIMER_MS = 2_147_483_647;\nconst now = (): number => performance.now();\n\nconst validateDuration = (name: string, value: number, allowZero: boolean): void => {\n if (!Number.isFinite(value) || value > MAX_TIMER_MS || (allowZero ? value < 0 : value <= 0)) {\n throw new RangeError(\n `${name} must be a ${allowZero ? 'non-negative' : 'positive'} finite number no greater than ${MAX_TIMER_MS}`,\n );\n }\n};\n\nconst validateWait = (interval: number, timeout: number): void => {\n validateDuration('interval', interval, false);\n validateDuration('timeout', timeout, true);\n};\n\nconst runBounded = <T>(run: () => T | Promise<T>, deadline: number, signal?: AbortSignal): Promise<T> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n let settled = false;\n const cleanup = (): boolean => {\n if (settled) return false;\n settled = true;\n clearTimeout(timer);\n signal?.removeEventListener('abort', abort);\n return true;\n };\n const resolveOnce = (value: T): void => {\n if (cleanup()) resolve(value);\n };\n const rejectOnce = (error: unknown): void => {\n if (cleanup()) reject(error);\n };\n const timer = setTimeout(() => rejectOnce(DEADLINE), Math.max(0, deadline - now()));\n const abort = () => rejectOnce(abortError(signal, 'The operation was aborted.'));\n\n signal?.addEventListener('abort', abort, { once: true });\n\n try {\n Promise.resolve(run()).then(resolveOnce, rejectOnce);\n } catch (error) {\n rejectOnce(error);\n }\n });\n\nexport const delay = (ms = 0, options: DelayOptions = {}): Promise<void> => {\n validateDuration('ms', ms, true);\n return sleep(ms, options.signal);\n};\n\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n first = false;\n\n let matched: boolean;\n try {\n matched = await runBounded(predicate, deadline, signal);\n } catch (error) {\n if (error === DEADLINE) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n throw error;\n }\n if (matched) return;\n\n const remaining = deadline - now();\n if (remaining <= 0) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n await sleep(Math.min(interval, remaining), signal);\n }\n}\n\n/**\n * Retry an assertion until it stops throwing or the timeout elapses.\n *\n * Polls the assertion on a fixed interval and preserves the last failure as the\n * timeout cause. Pending asynchronous assertions remain bounded by the same\n * deadline. Use `waitUntil()` for boolean conditions, `delay()` for explicit\n * timer dependencies, and `nextTick()` for one queued microtask boundary.\n *\n * @example\n * await eventually(() => expect(region.textContent).toBe('Saved'));\n */\nexport async function eventually(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: EventuallyOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) break;\n first = false;\n\n try {\n await runBounded(assertion, deadline, signal);\n return;\n } catch (error) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (error === DEADLINE) break;\n lastError = error;\n }\n\n const remaining = deadline - now();\n if (remaining <= 0) break;\n await sleep(Math.min(interval, remaining), signal);\n }\n\n const timing = `eventually timed out after ${timeout}ms`;\n const context = message ? `${message} (${timing})` : timing;\n const detail = lastError instanceof Error ? lastError.message : lastError == null ? '' : String(lastError);\n\n throw new AssayTimeoutError(detail ? `${context}\\n${detail}` : context, { cause: lastError });\n}\n\n/** Resolve with the next event of `type`, or reject when it times out or is aborted. */\nexport function waitForEvent<T extends Event = Event>(\n target: EventTarget,\n type: string,\n { signal, timeout = 1000 }: Omit<WaitOptions, 'interval'> = {},\n): Promise<T> {\n validateDuration('timeout', timeout, true);\n\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (event: Event): void => {\n dispose();\n resolve(event as T);\n };\n const timer = setTimeout(() => {\n dispose();\n reject(new AssayTimeoutError(`waitForEvent: \"${type}\" timed out after ${timeout}ms`));\n }, timeout);\n const onAbort = () => {\n dispose();\n reject(abortError(signal, 'The operation was aborted.'));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"assay.iife.js","names":["abortError","sleep","exports","children","root","child","visit","message","opts","target","event","init","type","INSTALLED_FLAG","flagHost","restorers","proto","validityState","formValueByHost","hostByInternals","name","descriptor","state","internals","host","value","flags","originalAttachInternals","args","entryName","entryValue","formData","NativeFormData","form","submitter","element","originalReset","restore","OPEN_ATTRIBUTE","displayBeforeOpen","view","before","method","options","shouldOpen","force","originalMatches","selectors","description","selector","testId","text","part","slotName","DEADLINE","MAX_TIMER_MS","allowZero","interval","timeout","signal","reject","_vielzeug_arsenal","settled","timer","resolve","error","deadline","run","ms","first","matched","predicate","remaining","lastError","assertion","timing","context","detail"],"sources":["../src/dom.ts","../src/errors.ts","../src/events.ts","../src/form-internals.ts","../src/popover.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/**\n * DOM traversal helpers for tests running under jsdom, which only implements the *light* DOM\n * tree: `Element.children`/`querySelectorAll()` never cross a `<slot>` into its assigned\n * elements. Real browsers use the *flat tree* (light DOM with each `<slot>` transparently\n * replaced by what's actually assigned to it) for this: it's what \"form owner\" resolution,\n * `:has()`, and plenty of other DOM algorithms are specified against.\n */\n\n/**\n * Walks the flat tree starting at `root`, calling `visit` for every element encountered :\n * expanding each `<slot>` via `assignedElements()` instead of descending into its (always\n * empty, in jsdom) literal children.\n *\n * @example\n * ```ts\n * // Find every form-associated element slotted (possibly through nested slots) under `form`,\n * // something `form.querySelectorAll('[name]')` can't do once a shadow boundary is involved.\n * const named: HTMLElement[] = [];\n * walkFlatTree(form, (el) => { if (el.hasAttribute('name')) named.push(el); });\n * ```\n */\nexport const walkFlatTree = (root: Element, visit: (element: HTMLElement) => void): void => {\n const children = root instanceof HTMLSlotElement ? root.assignedElements({ flatten: true }) : root.children;\n\n for (const child of Array.from(children)) {\n if (!(child instanceof HTMLSlotElement)) visit(child as HTMLElement);\n\n walkFlatTree(child, visit);\n }\n};\n","/** Base class for all Assay errors. Use `instanceof AssayError` to catch any Assay-originated error. */\nexport class AssayError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a required query has no match. */\nexport class AssayQueryError extends AssayError {}\n\n/** Thrown when an Assay wait reaches its timeout. */\nexport class AssayTimeoutError extends AssayError {}\n","/**\n * # Confidence boundary: read first\n *\n * `dispatch` is a **low-level synthetic-event dispatch API**. It fires a caller-\n * supplied DOM `Event` synchronously and returns the `dispatchEvent`\n * result. It does **not** model real user interaction: there is no focus/blur\n * sequencing, no input-event coordination, no keyboard layout, no pointer\n * hit-testing, and no trust flag (`event.isTrusted` is always `false`).\n *\n * Use it to drive event handlers in unit/integration tests where you control\n * the exact event shape. For **behavioral confidence**, that a real click\n * actually activates a control, that focus management works end-to-end, that\n * keyboard shortcuts fire under a real input device: write Playwright tests.\n * Assay deliberately stops at the dispatch boundary; anything that depends on\n * the browser's interaction semantics belongs in a browser-driven suite.\n */\n\n/** Dispatch a pre-built `Event` instance unchanged. Returns the `dispatchEvent` result. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\n/** Synthetic convenience dispatchers. They share the same confidence boundary as `dispatch()`. */\nexport const fireBlur = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('blur', init));\n\nexport const fireChange = (target: EventTarget, init: EventInit = {}): boolean =>\n dispatch(target, new Event('change', { bubbles: true, ...init }));\n\nexport const fireClick = (target: EventTarget, init: MouseEventInit = {}): boolean =>\n dispatch(target, new MouseEvent('click', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireCustom = <T>(target: EventTarget, type: string, init: CustomEventInit<T> = {}): boolean =>\n dispatch(target, new CustomEvent(type, { bubbles: true, cancelable: true, composed: false, ...init }));\n\nexport const fireFocus = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('focus', init));\n\nexport const fireInput = (target: EventTarget, init: InputEventInit = {}): boolean =>\n dispatch(target, new InputEvent('input', { bubbles: true, ...init }));\n\nexport const fireKeyDown = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireKeyUp = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireSubmit = (target: EventTarget, init: SubmitEventInit = {}): boolean =>\n dispatch(target, new SubmitEvent('submit', { bubbles: true, cancelable: true, ...init }));\n","import { walkFlatTree } from './dom';\n\n/**\n * jsdom implements none of the `ElementInternals` form-association API: not `setFormValue`,\n * not `setValidity`, not the `checkValidity`/`reportValidity`/`validity`/`validationMessage`\n * mixin real browsers put on every `formAssociated: true` element, not even `FormData`\n * collecting a form-associated element's set value, or `<form>.reset()` invoking\n * `formResetCallback()`. Every one of those gaps is exercised by `useField()` (`@vielzeug/ore`),\n * so any package testing a form-associated component needs all of them, not just one.\n *\n * Call this directly from a test setup when the suite tests form-associated components:\n * the patches are global monkey-patches, so suites without them shouldn't pay for them.\n * Returns an `uninstall()` that restores every patched global.\n *\n * Lives in Assay because it patches the DOM environment itself: the gap is in jsdom, not in\n * any package's feature, and Assay is the repo's home for DOM test-environment helpers.\n * `walkFlatTree` handles form-associated custom elements across shadow boundaries, so\n * consumer packages do not need package-local copies of this polyfill.\n */\nexport const installFormInternalsPolyfill = (): (() => void) => {\n // Checked *before* consuming the flag below: an environment without `ElementInternals`\n // installs nothing and should stay eligible to install for real later (e.g. a differently\n // configured environment in the same process), not get marked \"already installed\" for having\n // done nothing.\n if (typeof ElementInternals === 'undefined') return () => {};\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.assay.formInternalsPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return () => {};\n\n flagHost[INSTALLED_FLAG] = true;\n\n // Every patch pushes its inverse here, so uninstall() restores the environment exactly.\n const restorers: Array<() => void> = [];\n\n const proto = ElementInternals.prototype as unknown as Record<string, unknown>;\n const validityState = new WeakMap<ElementInternals, { flags: ValidityStateFlags; message: string }>();\n const formValueByHost = new WeakMap<HTMLElement, File | FormData | string | null>();\n const hostByInternals = new WeakMap<ElementInternals, HTMLElement>();\n\n const patchProto = (name: string, descriptor: PropertyDescriptor): void => {\n if (name in proto) return;\n\n Object.defineProperty(proto, name, descriptor);\n restorers.push(() => delete proto[name]);\n };\n\n const isValid = (internals: ElementInternals): boolean => {\n const state = validityState.get(internals);\n\n return !state || !Object.values(state.flags).some(Boolean);\n };\n\n patchProto('setFormValue', {\n configurable: true,\n value: function (this: ElementInternals, value: File | FormData | string | null) {\n const host = hostByInternals.get(this);\n\n if (host) formValueByHost.set(host, value);\n },\n writable: true,\n });\n\n patchProto('setValidity', {\n configurable: true,\n // Matches the real platform contract: throws if any flag is true and message is empty.\n // `useField()` itself already guards against triggering this: see forms/field.ts, but\n // the polyfill enforcing it too means a test would still catch a *different* caller doing\n // the same thing wrong, instead of that bug only surfacing in a real browser.\n value: function (this: ElementInternals, flags: ValidityStateFlags = {}, message = '') {\n if (Object.values(flags).some(Boolean) && !message) {\n throw new TypeError(\n \"Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if \" +\n 'one or more flags in the first argument are true.',\n );\n }\n\n validityState.set(this, { flags, message });\n },\n writable: true,\n });\n\n patchProto('checkValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('reportValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('validationMessage', {\n configurable: true,\n get(this: ElementInternals) {\n return isValid(this) ? '' : (validityState.get(this)?.message ?? '');\n },\n });\n\n // A ValidityState-shaped view of the flags passed to setValidity: every known\n // flag defaults to false, `valid` reflects whether any flag is set.\n patchProto('validity', {\n configurable: true,\n get(this: ElementInternals): ValidityState {\n const state = validityState.get(this);\n\n return {\n badInput: false,\n customError: false,\n patternMismatch: false,\n rangeOverflow: false,\n rangeUnderflow: false,\n stepMismatch: false,\n tooLong: false,\n tooShort: false,\n typeMismatch: false,\n valid: isValid(this),\n valueMissing: false,\n ...(state?.flags ?? {}),\n } as ValidityState;\n },\n });\n\n patchProto('states', {\n configurable: true,\n get: function (this: ElementInternals & { _states?: Set<string> }) {\n this._states ??= new Set();\n\n return this._states;\n },\n });\n\n // Real browsers mix `checkValidity`/`reportValidity`/`validity`/`validationMessage` onto any\n // `formAssociated: true` custom element itself (delegating to its internals): not just onto\n // `ElementInternals`. jsdom does neither; mirror it here so a component's own\n // `checkValidity()`/`reportValidity()`, and a test asserting against the element directly,\n // behave the same as they would in a real browser.\n const originalAttachInternals = HTMLElement.prototype.attachInternals;\n\n HTMLElement.prototype.attachInternals = function (this: HTMLElement, ...args: []): ElementInternals {\n const internals = originalAttachInternals.apply(this, args);\n\n hostByInternals.set(internals, this);\n\n Object.defineProperties(this, {\n checkValidity: { configurable: true, value: () => internals.checkValidity() },\n reportValidity: { configurable: true, value: () => internals.reportValidity() },\n validationMessage: { configurable: true, get: () => internals.validationMessage },\n validity: { configurable: true, get: () => internals.validity },\n });\n\n return internals;\n };\n restorers.push(() => {\n HTMLElement.prototype.attachInternals = originalAttachInternals;\n });\n\n const appendFormValue = (formData: FormData, name: string, value: File | FormData | string): void => {\n if (value instanceof FormData) {\n for (const [entryName, entryValue] of value.entries()) formData.append(entryName, entryValue);\n\n return;\n }\n\n formData.append(name, value);\n };\n\n // jsdom's `FormData` constructor never collects a form-associated custom element's set form\n // value: real browsers walk the flat tree for every form-associated element with a `name`.\n const NativeFormData = globalThis.FormData;\n\n globalThis.FormData = class FormDataWithFormAssociatedElements extends NativeFormData {\n constructor(form?: HTMLFormElement, submitter?: HTMLElement | null) {\n super(form as HTMLFormElement | undefined, submitter as HTMLElement | null | undefined);\n\n if (!(form instanceof HTMLFormElement)) return;\n\n walkFlatTree(form, (element) => {\n const name = element.getAttribute('name');\n const value = formValueByHost.get(element);\n\n if (!name || value == null || element.hasAttribute('disabled')) return;\n\n appendFormValue(this, name, value);\n });\n }\n };\n restorers.push(() => {\n globalThis.FormData = NativeFormData;\n });\n\n // jsdom never invokes the native `formResetCallback` lifecycle method on form-associated\n // custom elements when their form resets: patch `reset()` to do it (via the same flat-tree\n // walk, since a reset field can be nested behind a shadow boundary too), so `onFormReset()`\n // (see `@vielzeug/ore`'s runtime.ts) is testable against a real `<form>.reset()` call instead\n // of only by calling `element.formResetCallback()` directly.\n const originalReset = HTMLFormElement.prototype.reset;\n\n HTMLFormElement.prototype.reset = function (this: HTMLFormElement, ...args: []) {\n originalReset.apply(this, args);\n\n walkFlatTree(this, (element) => {\n (element as Partial<{ formResetCallback: () => void }>).formResetCallback?.();\n });\n };\n restorers.push(() => {\n HTMLFormElement.prototype.reset = originalReset;\n });\n\n return () => {\n for (const restore of restorers) restore();\n\n restorers.length = 0;\n flagHost[INSTALLED_FLAG] = false;\n };\n};\n","/**\n * jsdom implements none of the Popover API (`jsdom#3721`): no `showPopover`/`hidePopover`/\n * `togglePopover`, no `popover` IDL attribute, and — the part that silently breaks suites — its\n * selector engine treats `:popover-open` as a documented no-op that never matches.\n *\n * A partial shim (just setting the `popover-open` attribute) is worse than no shim, because every\n * component in the repo guards its calls the idiomatic way:\n *\n * ```ts\n * if (!panel.matches(':popover-open')) panel.showPopover();\n * if (panel.matches(':popover-open')) panel.hidePopover();\n * ```\n *\n * With `:popover-open` permanently false, `showPopover` runs twice and `hidePopover` never runs at\n * all: overlays open and can never close, and the failure looks like a component bug rather than an\n * environment gap. jsdom's UA stylesheet also keeps every `[popover]` element at\n * `display: none` (nothing matches `:popover-open` to lift it), and jsdom's focus algorithm refuses\n * to focus anything with a `display: none` flat-tree ancestor — so focusing an item inside an open\n * panel silently does nothing.\n *\n * This shim closes all three gaps: it tracks open state in the `popover-open` attribute (the same\n * attribute real browsers reflect, so tests can still assert on it), makes `matches(':popover-open')`\n * answer from that state, and holds the element visible with an inline `display` while open —\n * inline styles are the only author-level declaration that beats jsdom's UA rule, since component\n * styles live in adopted style sheets that jsdom does not cascade at all.\n *\n * Known simplifications, deliberate because nothing in the repo depends on them: no light-dismiss\n * behavior (`manual` is the only mode any component uses, and it has none), no top-layer ordering,\n * and no `beforetoggle`/`toggle` events. A suite that starts listening for those needs them added\n * here, not worked around per test.\n *\n * Call this from a test setup when the suite mounts popover-based components: the patches are global\n * monkey-patches, so suites without them shouldn't pay for them. Returns an `uninstall()` restoring\n * every patched global.\n *\n * Lives in Assay because the gap is in jsdom, not in any package's feature, and Assay is the repo's\n * home for DOM test-environment helpers (see `installFormInternalsPolyfill`). Consumer packages get\n * it from here instead of keeping per-file copies that drift out of sync with the API.\n */\nexport const installPopoverPolyfill = (): (() => void) => {\n if (typeof HTMLElement === 'undefined') return () => {};\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.assay.popoverPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return () => {};\n\n flagHost[INSTALLED_FLAG] = true;\n\n // Every patch pushes its inverse here, so uninstall() restores the environment exactly.\n const restorers: Array<() => void> = [];\n\n const OPEN_ATTRIBUTE = 'popover-open';\n\n const isOpen = (element: HTMLElement): boolean => element.hasAttribute(OPEN_ATTRIBUTE);\n\n // The inline `display` each element had before it was first shown, so hiding restores exactly\n // what was there rather than guessing. WeakMap: nothing outlives the element.\n const displayBeforeOpen = new WeakMap<HTMLElement, string>();\n\n const reveal = (element: HTMLElement): void => {\n const view = element.ownerDocument?.defaultView;\n\n // Only lift a `display: none` that is actually blocking the element. Overwriting an author-chosen\n // display (`grid` on a menu panel, `flex` on a card) would change layout the test is measuring.\n if (!view || view.getComputedStyle(element).display !== 'none') return;\n\n if (!displayBeforeOpen.has(element)) {\n displayBeforeOpen.set(element, element.style.getPropertyValue('display'));\n }\n\n element.style.setProperty('display', 'block');\n };\n\n const conceal = (element: HTMLElement): void => {\n if (!displayBeforeOpen.has(element)) return;\n\n const before = displayBeforeOpen.get(element) as string;\n\n displayBeforeOpen.delete(element);\n\n if (before) element.style.setProperty('display', before);\n else element.style.removeProperty('display');\n };\n\n const requirePopoverAttribute = (element: HTMLElement, method: string): void => {\n if (element.hasAttribute('popover')) return;\n\n // Matches the platform contract: showing or hiding an element that is not a popover is a\n // misuse bug, and throwing here surfaces it instead of letting the test pass quietly.\n throw new DOMException(\n `Failed to execute '${method}' on 'HTMLElement': the element does not have a popover attribute.`,\n 'InvalidStateError',\n );\n };\n\n // Same shape as `installFormInternalsPolyfill`: the prototype is patched through a plain record,\n // because these members are declared as always-present in lib.dom and this file's whole job is to\n // add them where they are absent.\n const proto = HTMLElement.prototype as unknown as Record<string, unknown>;\n\n const patchProto = (name: string, descriptor: PropertyDescriptor): void => {\n if (name in proto) return;\n\n Object.defineProperty(proto, name, descriptor);\n restorers.push(() => delete proto[name]);\n };\n\n patchProto('showPopover', {\n configurable: true,\n value: function (this: HTMLElement, options?: { source?: HTMLElement | null; force?: boolean }) {\n requirePopoverAttribute(this, 'showPopover');\n\n if (isOpen(this) && !options?.force) return;\n\n reveal(this);\n this.setAttribute(OPEN_ATTRIBUTE, '');\n },\n });\n\n patchProto('hidePopover', {\n configurable: true,\n value: function (this: HTMLElement) {\n requirePopoverAttribute(this, 'hidePopover');\n\n if (!isOpen(this)) return;\n\n this.removeAttribute(OPEN_ATTRIBUTE);\n conceal(this);\n },\n });\n\n patchProto('togglePopover', {\n configurable: true,\n value: function (this: HTMLElement, force?: boolean): boolean {\n requirePopoverAttribute(this, 'togglePopover');\n\n const shouldOpen = force ?? !isOpen(this);\n\n if (shouldOpen) reveal(this);\n else conceal(this);\n\n if (shouldOpen) this.setAttribute(OPEN_ATTRIBUTE, '');\n else this.removeAttribute(OPEN_ATTRIBUTE);\n\n return isOpen(this);\n },\n });\n\n // The guard every component wraps its calls in. dom-selector (jsdom's engine) stubs `:popover-open`\n // out as a permanent false, so without this `hidePopover` is unreachable from component code.\n // Intercepted by exact selector string: anything else, including `:not(:popover-open)` inside a\n // stylesheet, still goes through jsdom's own engine untouched.\n const originalMatches = Element.prototype.matches;\n\n Element.prototype.matches = function (this: Element, selectors: string): boolean {\n if (selectors === ':popover-open') return this.hasAttribute(OPEN_ATTRIBUTE);\n\n return originalMatches.call(this, selectors);\n // Cast: the interception only ever answers for one exact selector string, but the declared\n // member carries element-tag type predicates that a plain predicate cannot structurally satisfy.\n } as unknown as typeof Element.prototype.matches;\n restorers.push(() => {\n Element.prototype.matches = originalMatches;\n });\n\n return () => {\n for (const restore of restorers) restore();\n\n restorers.length = 0;\n flagHost[INSTALLED_FLAG] = false;\n };\n};\n","import { AssayQueryError } from './errors';\n\n/** DOM query helpers for test environments. */\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Scoped query helpers for any queryable DOM root: see {@link within}. */\nexport interface QueryScope {\n get<E extends Element = Element>(selector: string): E;\n getByTestId<E extends Element = Element>(testId: string): E;\n getByText<E extends Element = Element>(text: string, selector?: string): E;\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\ntype QueryRoot = ParentNode;\n\nconst describeRoot = (root: QueryRoot): string => {\n if (root instanceof Element) return root.outerHTML.slice(0, 500);\n\n if (root instanceof ShadowRoot) return `<shadow-root>${root.innerHTML.slice(0, 500)}</shadow-root>`;\n\n return root.nodeName;\n};\n\nconst requireMatch = <E extends Element>(element: E | null, description: string, root: QueryRoot): E => {\n if (element) return element;\n\n throw new AssayQueryError(`Unable to find ${description} within ${describeRoot(root)}.`);\n};\n\nconst query = <E extends Element = Element>(root: QueryRoot, selector: string): E | null =>\n root.querySelector<E>(selector);\n\nconst queryAll = <E extends Element = Element>(root: QueryRoot, selector: string): E[] => {\n return Array.from(root.querySelectorAll<E>(selector));\n};\n\nconst queryByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E | null =>\n queryAll<E>(root, '[data-testid]').find((element) => element.getAttribute('data-testid') === testId) ?? null;\n\nconst queryAllByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E[] =>\n queryAll<E>(root, '[data-testid]').filter((element) => element.getAttribute('data-testid') === testId);\n\nconst queryByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E | null => {\n for (const element of root.querySelectorAll<E>(selector)) {\n if (element.textContent?.trim() === text) return element;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] =>\n queryAll<E>(root, selector).filter((element) => element.textContent?.trim() === text);\n\n/**\n * Queries the shadow root of a custom element for a matching CSS selector.\n * Returns `null` if the element has no shadow root or no match is found: safe to call on\n * both open-shadow custom elements and plain elements without checking `shadowRoot` first.\n */\nexport function queryInShadow<E extends Element = Element>(host: Element, selector: string): E | null {\n return host.shadowRoot ? query<E>(host.shadowRoot, selector) : null;\n}\n\n/** Queries all matching elements inside the shadow root of a custom element. */\nexport function queryAllInShadow<E extends Element = Element>(host: Element, selector: string): E[] {\n return host.shadowRoot ? queryAll<E>(host.shadowRoot, selector) : [];\n}\n\n/**\n * Queries a shadow DOM element by its CSS `part` attribute: shorthand for\n * `queryInShadow(host, '[part=\"name\"]')`.\n *\n * @example\n * const btn = queryPart(carousel, 'prev-btn');\n * expect(btn).not.toBeNull();\n */\nexport function queryPart<E extends Element = Element>(host: Element, part: string): E | null {\n return (\n queryAllInShadow<E>(host, '[part]').find((element) => element.getAttribute('part')?.split(/\\s+/).includes(part)) ??\n null\n );\n}\n\n/**\n * Returns the light-DOM children assigned to a named slot, or every child assigned to the\n * default slot when no name is given.\n *\n * @example\n * const slides = getSlotted(carousel);\n * expect(slides).toHaveLength(3);\n */\nexport function getSlotted<E extends Element = Element>(host: Element, slotName?: string): E[] {\n return Array.from(host.children).filter((element) =>\n slotName === undefined ? !element.getAttribute('slot') : element.getAttribute('slot') === slotName,\n ) as E[];\n}\n\n// ─── API ─────────────────────────────────────────────────────────────────────\n\n/**\n * Create query helpers scoped to a DOM root: useful for light DOM and shadow roots.\n *\n * @example\n * const view = within(fixture.shadow!);\n * expect(view.get('.title').textContent).toBe('Hello');\n */\nexport function within(root: QueryRoot): QueryScope {\n return {\n get: <E extends Element = Element>(selector: string) =>\n requireMatch(query<E>(root, selector), `\"${selector}\"`, root),\n getByTestId: <E extends Element = Element>(testId: string) =>\n requireMatch(queryByTestId<E>(root, testId), `data-testid \"${testId}\"`, root),\n getByText: <E extends Element = Element>(text: string, selector = '*') =>\n requireMatch(queryByText<E>(root, text, selector), `text \"${text}\" matching \"${selector}\"`, root),\n query: <E extends Element = Element>(selector: string) => query<E>(root, selector),\n queryAll: <E extends Element = Element>(selector: string) => queryAll<E>(root, selector),\n queryAllByTestId: <E extends Element = Element>(testId: string) => queryAllByTestId<E>(root, testId),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(root, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) => queryByTestId<E>(root, testId),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(root, text, selector),\n };\n}\n","import { abortError, sleep } from '@vielzeug/arsenal';\n\nimport { AssayTimeoutError } from './errors';\n\nexport interface DelayOptions {\n signal?: AbortSignal;\n}\n\nexport interface WaitOptions {\n /** Polling interval in ms (default: 50). */\n interval?: number;\n /** Cancel the pending wait. */\n signal?: AbortSignal;\n /** Maximum wait time in ms (default: 1000). */\n timeout?: number;\n}\n\nexport interface EventuallyOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nconst DEADLINE = Symbol('assay.deadline');\nconst MAX_TIMER_MS = 2_147_483_647;\nconst now = (): number => performance.now();\n\nconst validateDuration = (name: string, value: number, allowZero: boolean): void => {\n if (!Number.isFinite(value) || value > MAX_TIMER_MS || (allowZero ? value < 0 : value <= 0)) {\n throw new RangeError(\n `${name} must be a ${allowZero ? 'non-negative' : 'positive'} finite number no greater than ${MAX_TIMER_MS}`,\n );\n }\n};\n\nconst validateWait = (interval: number, timeout: number): void => {\n validateDuration('interval', interval, false);\n validateDuration('timeout', timeout, true);\n};\n\nconst runBounded = <T>(run: () => T | Promise<T>, deadline: number, signal?: AbortSignal): Promise<T> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n let settled = false;\n const cleanup = (): boolean => {\n if (settled) return false;\n settled = true;\n clearTimeout(timer);\n signal?.removeEventListener('abort', abort);\n return true;\n };\n const resolveOnce = (value: T): void => {\n if (cleanup()) resolve(value);\n };\n const rejectOnce = (error: unknown): void => {\n if (cleanup()) reject(error);\n };\n const timer = setTimeout(() => rejectOnce(DEADLINE), Math.max(0, deadline - now()));\n const abort = () => rejectOnce(abortError(signal, 'The operation was aborted.'));\n\n signal?.addEventListener('abort', abort, { once: true });\n\n try {\n Promise.resolve(run()).then(resolveOnce, rejectOnce);\n } catch (error) {\n rejectOnce(error);\n }\n });\n\nexport const delay = (ms = 0, options: DelayOptions = {}): Promise<void> => {\n validateDuration('ms', ms, true);\n return sleep(ms, options.signal);\n};\n\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n first = false;\n\n let matched: boolean;\n try {\n matched = await runBounded(predicate, deadline, signal);\n } catch (error) {\n if (error === DEADLINE) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n throw error;\n }\n if (matched) return;\n\n const remaining = deadline - now();\n if (remaining <= 0) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n await sleep(Math.min(interval, remaining), signal);\n }\n}\n\n/**\n * Retry an assertion until it stops throwing or the timeout elapses.\n *\n * Polls the assertion on a fixed interval and preserves the last failure as the\n * timeout cause. Pending asynchronous assertions remain bounded by the same\n * deadline. Use `waitUntil()` for boolean conditions, `delay()` for explicit\n * timer dependencies, and `nextTick()` for one queued microtask boundary.\n *\n * @example\n * await eventually(() => expect(region.textContent).toBe('Saved'));\n */\nexport async function eventually(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: EventuallyOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) break;\n first = false;\n\n try {\n await runBounded(assertion, deadline, signal);\n return;\n } catch (error) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (error === DEADLINE) break;\n lastError = error;\n }\n\n const remaining = deadline - now();\n if (remaining <= 0) break;\n await sleep(Math.min(interval, remaining), signal);\n }\n\n const timing = `eventually timed out after ${timeout}ms`;\n const context = message ? `${message} (${timing})` : timing;\n const detail = lastError instanceof Error ? lastError.message : lastError == null ? '' : String(lastError);\n\n throw new AssayTimeoutError(detail ? `${context}\\n${detail}` : context, { cause: lastError });\n}\n\n/** Resolve with the next event of `type`, or reject when it times out or is aborted. */\nexport function waitForEvent<T extends Event = Event>(\n target: EventTarget,\n type: string,\n { signal, timeout = 1000 }: Omit<WaitOptions, 'interval'> = {},\n): Promise<T> {\n validateDuration('timeout', timeout, true);\n\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (event: Event): void => {\n dispose();\n resolve(event as T);\n };\n const timer = setTimeout(() => {\n dispose();\n reject(new AssayTimeoutError(`waitForEvent: \"${type}\" timed out after ${timeout}ms`));\n }, timeout);\n const onAbort = () => {\n dispose();\n reject(abortError(signal, 'The operation was aborted.'));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n"],"mappings":"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"}
package/dist/assay.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { abortError as e, sleep as t } from "@vielzeug/arsenal";
2
- //#region src/dom.ts
2
+ // src/dom.ts
3
3
  var walkFlatTree = (e, t) => {
4
4
  let n = e instanceof HTMLSlotElement ? e.assignedElements({ flatten: !0 }) : e.children;
5
5
  for (let e of Array.from(n)) e instanceof HTMLSlotElement || t(e), walkFlatTree(e, t);
@@ -153,6 +153,50 @@ var walkFlatTree = (e, t) => {
153
153
  for (let e of n) e();
154
154
  n.length = 0, t[e] = !1;
155
155
  };
156
+ }, installPopoverPolyfill = () => {
157
+ if (typeof HTMLElement > "u") return () => {};
158
+ let e = Symbol.for("vielzeug.assay.popoverPolyfillInstalled"), t = globalThis;
159
+ if (t[e]) return () => {};
160
+ t[e] = !0;
161
+ let n = [], r = "popover-open", isOpen = (e) => e.hasAttribute(r), i = /* @__PURE__ */ new WeakMap(), reveal = (e) => {
162
+ let t = e.ownerDocument?.defaultView;
163
+ t && t.getComputedStyle(e).display === "none" && (i.has(e) || i.set(e, e.style.getPropertyValue("display")), e.style.setProperty("display", "block"));
164
+ }, conceal = (e) => {
165
+ if (!i.has(e)) return;
166
+ let t = i.get(e);
167
+ i.delete(e), t ? e.style.setProperty("display", t) : e.style.removeProperty("display");
168
+ }, requirePopoverAttribute = (e, t) => {
169
+ if (!e.hasAttribute("popover")) throw new DOMException(`Failed to execute '${t}' on 'HTMLElement': the element does not have a popover attribute.`, "InvalidStateError");
170
+ }, a = HTMLElement.prototype, patchProto = (e, t) => {
171
+ e in a || (Object.defineProperty(a, e, t), n.push(() => delete a[e]));
172
+ };
173
+ patchProto("showPopover", {
174
+ configurable: !0,
175
+ value: function(e) {
176
+ requirePopoverAttribute(this, "showPopover"), (!isOpen(this) || e?.force) && (reveal(this), this.setAttribute(r, ""));
177
+ }
178
+ }), patchProto("hidePopover", {
179
+ configurable: !0,
180
+ value: function() {
181
+ requirePopoverAttribute(this, "hidePopover"), isOpen(this) && (this.removeAttribute(r), conceal(this));
182
+ }
183
+ }), patchProto("togglePopover", {
184
+ configurable: !0,
185
+ value: function(e) {
186
+ requirePopoverAttribute(this, "togglePopover");
187
+ let t = e ?? !isOpen(this);
188
+ return t ? reveal(this) : conceal(this), t ? this.setAttribute(r, "") : this.removeAttribute(r), isOpen(this);
189
+ }
190
+ });
191
+ let o = Element.prototype.matches;
192
+ return Element.prototype.matches = function(e) {
193
+ return e === ":popover-open" ? this.hasAttribute(r) : o.call(this, e);
194
+ }, n.push(() => {
195
+ Element.prototype.matches = o;
196
+ }), () => {
197
+ for (let e of n) e();
198
+ n.length = 0, t[e] = !1;
199
+ };
156
200
  }, describeRoot = (e) => e instanceof Element ? e.outerHTML.slice(0, 500) : e instanceof ShadowRoot ? `<shadow-root>${e.innerHTML.slice(0, 500)}</shadow-root>` : e.nodeName, requireMatch = (e, t, n) => {
157
201
  if (e) return e;
158
202
  throw new AssayQueryError(`Unable to find ${t} within ${describeRoot(n)}.`);
@@ -185,8 +229,7 @@ function within(e) {
185
229
  queryByText: (t, n = "*") => queryByText(e, t, n)
186
230
  };
187
231
  }
188
- //#endregion
189
- //#region src/wait.ts
232
+ // src/wait.ts
190
233
  var n = Symbol("assay.deadline"), r = 2147483647, now = () => performance.now(), validateDuration = (e, t, n) => {
191
234
  if (!Number.isFinite(t) || t > r || (n ? t < 0 : t <= 0)) throw RangeError(`${e} must be a ${n ? "non-negative" : "positive"} finite number no greater than ${r}`);
192
235
  }, validateWait = (e, t) => {
@@ -267,7 +310,6 @@ function waitForEvent(t, n, { signal: r, timeout: i = 1e3 } = {}) {
267
310
  t.addEventListener(n, onEvent, { once: !0 }), r?.addEventListener("abort", onAbort, { once: !0 });
268
311
  });
269
312
  }
270
- //#endregion
271
- export { AssayError, AssayQueryError, AssayTimeoutError, delay, dispatch, eventually, fireBlur, fireChange, fireClick, fireCustom, fireFocus, fireInput, fireKeyDown, fireKeyUp, fireSubmit, getSlotted, installFormInternalsPolyfill, queryAllInShadow, queryInShadow, queryPart, waitForEvent, waitUntil, walkFlatTree, within };
313
+ export { AssayError, AssayQueryError, AssayTimeoutError, delay, dispatch, eventually, fireBlur, fireChange, fireClick, fireCustom, fireFocus, fireInput, fireKeyDown, fireKeyUp, fireSubmit, getSlotted, installFormInternalsPolyfill, installPopoverPolyfill, queryAllInShadow, queryInShadow, queryPart, waitForEvent, waitUntil, walkFlatTree, within };
272
314
 
273
315
  //# sourceMappingURL=assay.js.map
package/dist/assay.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"assay.js","names":["children","root","child","visit","message","opts","target","event","init","type","INSTALLED_FLAG","flagHost","restorers","proto","validityState","formValueByHost","hostByInternals","name","descriptor","state","internals","host","value","flags","originalAttachInternals","args","entryName","entryValue","NativeFormData","form","submitter","element","originalReset","restore","description","selector","testId","text","part","slotName","DEADLINE","MAX_TIMER_MS","allowZero","interval","timeout","signal","abortError","settled","timer","resolve","reject","error","deadline","run","ms","sleep","options","first","matched","predicate","remaining","lastError","assertion","timing","context","detail"],"sources":["../src/dom.ts","../src/errors.ts","../src/events.ts","../src/form-internals.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/**\n * DOM traversal helpers for tests running under jsdom, which only implements the *light* DOM\n * tree: `Element.children`/`querySelectorAll()` never cross a `<slot>` into its assigned\n * elements. Real browsers use the *flat tree* (light DOM with each `<slot>` transparently\n * replaced by what's actually assigned to it) for this: it's what \"form owner\" resolution,\n * `:has()`, and plenty of other DOM algorithms are specified against.\n */\n\n/**\n * Walks the flat tree starting at `root`, calling `visit` for every element encountered :\n * expanding each `<slot>` via `assignedElements()` instead of descending into its (always\n * empty, in jsdom) literal children.\n *\n * @example\n * ```ts\n * // Find every form-associated element slotted (possibly through nested slots) under `form`,\n * // something `form.querySelectorAll('[name]')` can't do once a shadow boundary is involved.\n * const named: HTMLElement[] = [];\n * walkFlatTree(form, (el) => { if (el.hasAttribute('name')) named.push(el); });\n * ```\n */\nexport const walkFlatTree = (root: Element, visit: (element: HTMLElement) => void): void => {\n const children = root instanceof HTMLSlotElement ? root.assignedElements({ flatten: true }) : root.children;\n\n for (const child of Array.from(children)) {\n if (!(child instanceof HTMLSlotElement)) visit(child as HTMLElement);\n\n walkFlatTree(child, visit);\n }\n};\n","/** Base class for all Assay errors. Use `instanceof AssayError` to catch any Assay-originated error. */\nexport class AssayError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a required query has no match. */\nexport class AssayQueryError extends AssayError {}\n\n/** Thrown when an Assay wait reaches its timeout. */\nexport class AssayTimeoutError extends AssayError {}\n","/**\n * # Confidence boundary: read first\n *\n * `dispatch` is a **low-level synthetic-event dispatch API**. It fires a caller-\n * supplied DOM `Event` synchronously and returns the `dispatchEvent`\n * result. It does **not** model real user interaction: there is no focus/blur\n * sequencing, no input-event coordination, no keyboard layout, no pointer\n * hit-testing, and no trust flag (`event.isTrusted` is always `false`).\n *\n * Use it to drive event handlers in unit/integration tests where you control\n * the exact event shape. For **behavioral confidence**, that a real click\n * actually activates a control, that focus management works end-to-end, that\n * keyboard shortcuts fire under a real input device: write Playwright tests.\n * Assay deliberately stops at the dispatch boundary; anything that depends on\n * the browser's interaction semantics belongs in a browser-driven suite.\n */\n\n/** Dispatch a pre-built `Event` instance unchanged. Returns the `dispatchEvent` result. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\n/** Synthetic convenience dispatchers. They share the same confidence boundary as `dispatch()`. */\nexport const fireBlur = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('blur', init));\n\nexport const fireChange = (target: EventTarget, init: EventInit = {}): boolean =>\n dispatch(target, new Event('change', { bubbles: true, ...init }));\n\nexport const fireClick = (target: EventTarget, init: MouseEventInit = {}): boolean =>\n dispatch(target, new MouseEvent('click', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireCustom = <T>(target: EventTarget, type: string, init: CustomEventInit<T> = {}): boolean =>\n dispatch(target, new CustomEvent(type, { bubbles: true, cancelable: true, composed: false, ...init }));\n\nexport const fireFocus = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('focus', init));\n\nexport const fireInput = (target: EventTarget, init: InputEventInit = {}): boolean =>\n dispatch(target, new InputEvent('input', { bubbles: true, ...init }));\n\nexport const fireKeyDown = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireKeyUp = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireSubmit = (target: EventTarget, init: SubmitEventInit = {}): boolean =>\n dispatch(target, new SubmitEvent('submit', { bubbles: true, cancelable: true, ...init }));\n","import { walkFlatTree } from './dom';\n\n/**\n * jsdom implements none of the `ElementInternals` form-association API: not `setFormValue`,\n * not `setValidity`, not the `checkValidity`/`reportValidity`/`validity`/`validationMessage`\n * mixin real browsers put on every `formAssociated: true` element, not even `FormData`\n * collecting a form-associated element's set value, or `<form>.reset()` invoking\n * `formResetCallback()`. Every one of those gaps is exercised by `useField()` (`@vielzeug/ore`),\n * so any package testing a form-associated component needs all of them, not just one.\n *\n * Call this directly from a test setup when the suite tests form-associated components:\n * the patches are global monkey-patches, so suites without them shouldn't pay for them.\n * Returns an `uninstall()` that restores every patched global.\n *\n * Lives in Assay because it patches the DOM environment itself: the gap is in jsdom, not in\n * any package's feature, and Assay is the repo's home for DOM test-environment helpers.\n * `walkFlatTree` handles form-associated custom elements across shadow boundaries, so\n * consumer packages do not need package-local copies of this polyfill.\n */\nexport const installFormInternalsPolyfill = (): (() => void) => {\n // Checked *before* consuming the flag below: an environment without `ElementInternals`\n // installs nothing and should stay eligible to install for real later (e.g. a differently\n // configured environment in the same process), not get marked \"already installed\" for having\n // done nothing.\n if (typeof ElementInternals === 'undefined') return () => {};\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.assay.formInternalsPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return () => {};\n\n flagHost[INSTALLED_FLAG] = true;\n\n // Every patch pushes its inverse here, so uninstall() restores the environment exactly.\n const restorers: Array<() => void> = [];\n\n const proto = ElementInternals.prototype as unknown as Record<string, unknown>;\n const validityState = new WeakMap<ElementInternals, { flags: ValidityStateFlags; message: string }>();\n const formValueByHost = new WeakMap<HTMLElement, File | FormData | string | null>();\n const hostByInternals = new WeakMap<ElementInternals, HTMLElement>();\n\n const patchProto = (name: string, descriptor: PropertyDescriptor): void => {\n if (name in proto) return;\n\n Object.defineProperty(proto, name, descriptor);\n restorers.push(() => delete proto[name]);\n };\n\n const isValid = (internals: ElementInternals): boolean => {\n const state = validityState.get(internals);\n\n return !state || !Object.values(state.flags).some(Boolean);\n };\n\n patchProto('setFormValue', {\n configurable: true,\n value: function (this: ElementInternals, value: File | FormData | string | null) {\n const host = hostByInternals.get(this);\n\n if (host) formValueByHost.set(host, value);\n },\n writable: true,\n });\n\n patchProto('setValidity', {\n configurable: true,\n // Matches the real platform contract: throws if any flag is true and message is empty.\n // `useField()` itself already guards against triggering this: see forms/field.ts, but\n // the polyfill enforcing it too means a test would still catch a *different* caller doing\n // the same thing wrong, instead of that bug only surfacing in a real browser.\n value: function (this: ElementInternals, flags: ValidityStateFlags = {}, message = '') {\n if (Object.values(flags).some(Boolean) && !message) {\n throw new TypeError(\n \"Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if \" +\n 'one or more flags in the first argument are true.',\n );\n }\n\n validityState.set(this, { flags, message });\n },\n writable: true,\n });\n\n patchProto('checkValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('reportValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('validationMessage', {\n configurable: true,\n get(this: ElementInternals) {\n return isValid(this) ? '' : (validityState.get(this)?.message ?? '');\n },\n });\n\n // A ValidityState-shaped view of the flags passed to setValidity: every known\n // flag defaults to false, `valid` reflects whether any flag is set.\n patchProto('validity', {\n configurable: true,\n get(this: ElementInternals): ValidityState {\n const state = validityState.get(this);\n\n return {\n badInput: false,\n customError: false,\n patternMismatch: false,\n rangeOverflow: false,\n rangeUnderflow: false,\n stepMismatch: false,\n tooLong: false,\n tooShort: false,\n typeMismatch: false,\n valid: isValid(this),\n valueMissing: false,\n ...(state?.flags ?? {}),\n } as ValidityState;\n },\n });\n\n patchProto('states', {\n configurable: true,\n get: function (this: ElementInternals & { _states?: Set<string> }) {\n this._states ??= new Set();\n\n return this._states;\n },\n });\n\n // Real browsers mix `checkValidity`/`reportValidity`/`validity`/`validationMessage` onto any\n // `formAssociated: true` custom element itself (delegating to its internals): not just onto\n // `ElementInternals`. jsdom does neither; mirror it here so a component's own\n // `checkValidity()`/`reportValidity()`, and a test asserting against the element directly,\n // behave the same as they would in a real browser.\n const originalAttachInternals = HTMLElement.prototype.attachInternals;\n\n HTMLElement.prototype.attachInternals = function (this: HTMLElement, ...args: []): ElementInternals {\n const internals = originalAttachInternals.apply(this, args);\n\n hostByInternals.set(internals, this);\n\n Object.defineProperties(this, {\n checkValidity: { configurable: true, value: () => internals.checkValidity() },\n reportValidity: { configurable: true, value: () => internals.reportValidity() },\n validationMessage: { configurable: true, get: () => internals.validationMessage },\n validity: { configurable: true, get: () => internals.validity },\n });\n\n return internals;\n };\n restorers.push(() => {\n HTMLElement.prototype.attachInternals = originalAttachInternals;\n });\n\n const appendFormValue = (formData: FormData, name: string, value: File | FormData | string): void => {\n if (value instanceof FormData) {\n for (const [entryName, entryValue] of value.entries()) formData.append(entryName, entryValue);\n\n return;\n }\n\n formData.append(name, value);\n };\n\n // jsdom's `FormData` constructor never collects a form-associated custom element's set form\n // value: real browsers walk the flat tree for every form-associated element with a `name`.\n const NativeFormData = globalThis.FormData;\n\n globalThis.FormData = class FormDataWithFormAssociatedElements extends NativeFormData {\n constructor(form?: HTMLFormElement, submitter?: HTMLElement | null) {\n super(form as HTMLFormElement | undefined, submitter as HTMLElement | null | undefined);\n\n if (!(form instanceof HTMLFormElement)) return;\n\n walkFlatTree(form, (element) => {\n const name = element.getAttribute('name');\n const value = formValueByHost.get(element);\n\n if (!name || value == null || element.hasAttribute('disabled')) return;\n\n appendFormValue(this, name, value);\n });\n }\n };\n restorers.push(() => {\n globalThis.FormData = NativeFormData;\n });\n\n // jsdom never invokes the native `formResetCallback` lifecycle method on form-associated\n // custom elements when their form resets: patch `reset()` to do it (via the same flat-tree\n // walk, since a reset field can be nested behind a shadow boundary too), so `onFormReset()`\n // (see `@vielzeug/ore`'s runtime.ts) is testable against a real `<form>.reset()` call instead\n // of only by calling `element.formResetCallback()` directly.\n const originalReset = HTMLFormElement.prototype.reset;\n\n HTMLFormElement.prototype.reset = function (this: HTMLFormElement, ...args: []) {\n originalReset.apply(this, args);\n\n walkFlatTree(this, (element) => {\n (element as Partial<{ formResetCallback: () => void }>).formResetCallback?.();\n });\n };\n restorers.push(() => {\n HTMLFormElement.prototype.reset = originalReset;\n });\n\n return () => {\n for (const restore of restorers) restore();\n\n restorers.length = 0;\n flagHost[INSTALLED_FLAG] = false;\n };\n};\n","import { AssayQueryError } from './errors';\n\n/** DOM query helpers for test environments. */\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Scoped query helpers for any queryable DOM root: see {@link within}. */\nexport interface QueryScope {\n get<E extends Element = Element>(selector: string): E;\n getByTestId<E extends Element = Element>(testId: string): E;\n getByText<E extends Element = Element>(text: string, selector?: string): E;\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\ntype QueryRoot = ParentNode;\n\nconst describeRoot = (root: QueryRoot): string => {\n if (root instanceof Element) return root.outerHTML.slice(0, 500);\n\n if (root instanceof ShadowRoot) return `<shadow-root>${root.innerHTML.slice(0, 500)}</shadow-root>`;\n\n return root.nodeName;\n};\n\nconst requireMatch = <E extends Element>(element: E | null, description: string, root: QueryRoot): E => {\n if (element) return element;\n\n throw new AssayQueryError(`Unable to find ${description} within ${describeRoot(root)}.`);\n};\n\nconst query = <E extends Element = Element>(root: QueryRoot, selector: string): E | null =>\n root.querySelector<E>(selector);\n\nconst queryAll = <E extends Element = Element>(root: QueryRoot, selector: string): E[] => {\n return Array.from(root.querySelectorAll<E>(selector));\n};\n\nconst queryByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E | null =>\n queryAll<E>(root, '[data-testid]').find((element) => element.getAttribute('data-testid') === testId) ?? null;\n\nconst queryAllByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E[] =>\n queryAll<E>(root, '[data-testid]').filter((element) => element.getAttribute('data-testid') === testId);\n\nconst queryByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E | null => {\n for (const element of root.querySelectorAll<E>(selector)) {\n if (element.textContent?.trim() === text) return element;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] =>\n queryAll<E>(root, selector).filter((element) => element.textContent?.trim() === text);\n\n/**\n * Queries the shadow root of a custom element for a matching CSS selector.\n * Returns `null` if the element has no shadow root or no match is found: safe to call on\n * both open-shadow custom elements and plain elements without checking `shadowRoot` first.\n */\nexport function queryInShadow<E extends Element = Element>(host: Element, selector: string): E | null {\n return host.shadowRoot ? query<E>(host.shadowRoot, selector) : null;\n}\n\n/** Queries all matching elements inside the shadow root of a custom element. */\nexport function queryAllInShadow<E extends Element = Element>(host: Element, selector: string): E[] {\n return host.shadowRoot ? queryAll<E>(host.shadowRoot, selector) : [];\n}\n\n/**\n * Queries a shadow DOM element by its CSS `part` attribute: shorthand for\n * `queryInShadow(host, '[part=\"name\"]')`.\n *\n * @example\n * const btn = queryPart(carousel, 'prev-btn');\n * expect(btn).not.toBeNull();\n */\nexport function queryPart<E extends Element = Element>(host: Element, part: string): E | null {\n return (\n queryAllInShadow<E>(host, '[part]').find((element) => element.getAttribute('part')?.split(/\\s+/).includes(part)) ??\n null\n );\n}\n\n/**\n * Returns the light-DOM children assigned to a named slot, or every child assigned to the\n * default slot when no name is given.\n *\n * @example\n * const slides = getSlotted(carousel);\n * expect(slides).toHaveLength(3);\n */\nexport function getSlotted<E extends Element = Element>(host: Element, slotName?: string): E[] {\n return Array.from(host.children).filter((element) =>\n slotName === undefined ? !element.getAttribute('slot') : element.getAttribute('slot') === slotName,\n ) as E[];\n}\n\n// ─── API ─────────────────────────────────────────────────────────────────────\n\n/**\n * Create query helpers scoped to a DOM root: useful for light DOM and shadow roots.\n *\n * @example\n * const view = within(fixture.shadow!);\n * expect(view.get('.title').textContent).toBe('Hello');\n */\nexport function within(root: QueryRoot): QueryScope {\n return {\n get: <E extends Element = Element>(selector: string) =>\n requireMatch(query<E>(root, selector), `\"${selector}\"`, root),\n getByTestId: <E extends Element = Element>(testId: string) =>\n requireMatch(queryByTestId<E>(root, testId), `data-testid \"${testId}\"`, root),\n getByText: <E extends Element = Element>(text: string, selector = '*') =>\n requireMatch(queryByText<E>(root, text, selector), `text \"${text}\" matching \"${selector}\"`, root),\n query: <E extends Element = Element>(selector: string) => query<E>(root, selector),\n queryAll: <E extends Element = Element>(selector: string) => queryAll<E>(root, selector),\n queryAllByTestId: <E extends Element = Element>(testId: string) => queryAllByTestId<E>(root, testId),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(root, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) => queryByTestId<E>(root, testId),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(root, text, selector),\n };\n}\n","import { abortError, sleep } from '@vielzeug/arsenal';\n\nimport { AssayTimeoutError } from './errors';\n\nexport interface DelayOptions {\n signal?: AbortSignal;\n}\n\nexport interface WaitOptions {\n /** Polling interval in ms (default: 50). */\n interval?: number;\n /** Cancel the pending wait. */\n signal?: AbortSignal;\n /** Maximum wait time in ms (default: 1000). */\n timeout?: number;\n}\n\nexport interface EventuallyOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nconst DEADLINE = Symbol('assay.deadline');\nconst MAX_TIMER_MS = 2_147_483_647;\nconst now = (): number => performance.now();\n\nconst validateDuration = (name: string, value: number, allowZero: boolean): void => {\n if (!Number.isFinite(value) || value > MAX_TIMER_MS || (allowZero ? value < 0 : value <= 0)) {\n throw new RangeError(\n `${name} must be a ${allowZero ? 'non-negative' : 'positive'} finite number no greater than ${MAX_TIMER_MS}`,\n );\n }\n};\n\nconst validateWait = (interval: number, timeout: number): void => {\n validateDuration('interval', interval, false);\n validateDuration('timeout', timeout, true);\n};\n\nconst runBounded = <T>(run: () => T | Promise<T>, deadline: number, signal?: AbortSignal): Promise<T> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n let settled = false;\n const cleanup = (): boolean => {\n if (settled) return false;\n settled = true;\n clearTimeout(timer);\n signal?.removeEventListener('abort', abort);\n return true;\n };\n const resolveOnce = (value: T): void => {\n if (cleanup()) resolve(value);\n };\n const rejectOnce = (error: unknown): void => {\n if (cleanup()) reject(error);\n };\n const timer = setTimeout(() => rejectOnce(DEADLINE), Math.max(0, deadline - now()));\n const abort = () => rejectOnce(abortError(signal, 'The operation was aborted.'));\n\n signal?.addEventListener('abort', abort, { once: true });\n\n try {\n Promise.resolve(run()).then(resolveOnce, rejectOnce);\n } catch (error) {\n rejectOnce(error);\n }\n });\n\nexport const delay = (ms = 0, options: DelayOptions = {}): Promise<void> => {\n validateDuration('ms', ms, true);\n return sleep(ms, options.signal);\n};\n\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n first = false;\n\n let matched: boolean;\n try {\n matched = await runBounded(predicate, deadline, signal);\n } catch (error) {\n if (error === DEADLINE) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n throw error;\n }\n if (matched) return;\n\n const remaining = deadline - now();\n if (remaining <= 0) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n await sleep(Math.min(interval, remaining), signal);\n }\n}\n\n/**\n * Retry an assertion until it stops throwing or the timeout elapses.\n *\n * Polls the assertion on a fixed interval and preserves the last failure as the\n * timeout cause. Pending asynchronous assertions remain bounded by the same\n * deadline. Use `waitUntil()` for boolean conditions, `delay()` for explicit\n * timer dependencies, and `nextTick()` for one queued microtask boundary.\n *\n * @example\n * await eventually(() => expect(region.textContent).toBe('Saved'));\n */\nexport async function eventually(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: EventuallyOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) break;\n first = false;\n\n try {\n await runBounded(assertion, deadline, signal);\n return;\n } catch (error) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (error === DEADLINE) break;\n lastError = error;\n }\n\n const remaining = deadline - now();\n if (remaining <= 0) break;\n await sleep(Math.min(interval, remaining), signal);\n }\n\n const timing = `eventually timed out after ${timeout}ms`;\n const context = message ? `${message} (${timing})` : timing;\n const detail = lastError instanceof Error ? lastError.message : lastError == null ? '' : String(lastError);\n\n throw new AssayTimeoutError(detail ? `${context}\\n${detail}` : context, { cause: lastError });\n}\n\n/** Resolve with the next event of `type`, or reject when it times out or is aborted. */\nexport function waitForEvent<T extends Event = Event>(\n target: EventTarget,\n type: string,\n { signal, timeout = 1000 }: Omit<WaitOptions, 'interval'> = {},\n): Promise<T> {\n validateDuration('timeout', timeout, true);\n\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (event: Event): void => {\n dispose();\n resolve(event as T);\n };\n const timer = setTimeout(() => {\n dispose();\n reject(new AssayTimeoutError(`waitForEvent: \"${type}\" timed out after ${timeout}ms`));\n }, timeout);\n const onAbort = () => {\n dispose();\n reject(abortError(signal, 'The operation was aborted.'));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"assay.js","names":["children","root","child","visit","message","opts","target","event","init","type","INSTALLED_FLAG","flagHost","restorers","proto","validityState","formValueByHost","hostByInternals","name","descriptor","state","internals","host","value","flags","originalAttachInternals","args","entryName","entryValue","NativeFormData","form","submitter","element","originalReset","restore","OPEN_ATTRIBUTE","displayBeforeOpen","view","before","method","options","shouldOpen","force","originalMatches","selectors","description","selector","testId","text","part","slotName","DEADLINE","MAX_TIMER_MS","allowZero","interval","timeout","signal","abortError","settled","timer","resolve","reject","error","deadline","run","ms","sleep","first","matched","predicate","remaining","lastError","assertion","timing","context","detail"],"sources":["../src/dom.ts","../src/errors.ts","../src/events.ts","../src/form-internals.ts","../src/popover.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/**\n * DOM traversal helpers for tests running under jsdom, which only implements the *light* DOM\n * tree: `Element.children`/`querySelectorAll()` never cross a `<slot>` into its assigned\n * elements. Real browsers use the *flat tree* (light DOM with each `<slot>` transparently\n * replaced by what's actually assigned to it) for this: it's what \"form owner\" resolution,\n * `:has()`, and plenty of other DOM algorithms are specified against.\n */\n\n/**\n * Walks the flat tree starting at `root`, calling `visit` for every element encountered :\n * expanding each `<slot>` via `assignedElements()` instead of descending into its (always\n * empty, in jsdom) literal children.\n *\n * @example\n * ```ts\n * // Find every form-associated element slotted (possibly through nested slots) under `form`,\n * // something `form.querySelectorAll('[name]')` can't do once a shadow boundary is involved.\n * const named: HTMLElement[] = [];\n * walkFlatTree(form, (el) => { if (el.hasAttribute('name')) named.push(el); });\n * ```\n */\nexport const walkFlatTree = (root: Element, visit: (element: HTMLElement) => void): void => {\n const children = root instanceof HTMLSlotElement ? root.assignedElements({ flatten: true }) : root.children;\n\n for (const child of Array.from(children)) {\n if (!(child instanceof HTMLSlotElement)) visit(child as HTMLElement);\n\n walkFlatTree(child, visit);\n }\n};\n","/** Base class for all Assay errors. Use `instanceof AssayError` to catch any Assay-originated error. */\nexport class AssayError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a required query has no match. */\nexport class AssayQueryError extends AssayError {}\n\n/** Thrown when an Assay wait reaches its timeout. */\nexport class AssayTimeoutError extends AssayError {}\n","/**\n * # Confidence boundary: read first\n *\n * `dispatch` is a **low-level synthetic-event dispatch API**. It fires a caller-\n * supplied DOM `Event` synchronously and returns the `dispatchEvent`\n * result. It does **not** model real user interaction: there is no focus/blur\n * sequencing, no input-event coordination, no keyboard layout, no pointer\n * hit-testing, and no trust flag (`event.isTrusted` is always `false`).\n *\n * Use it to drive event handlers in unit/integration tests where you control\n * the exact event shape. For **behavioral confidence**, that a real click\n * actually activates a control, that focus management works end-to-end, that\n * keyboard shortcuts fire under a real input device: write Playwright tests.\n * Assay deliberately stops at the dispatch boundary; anything that depends on\n * the browser's interaction semantics belongs in a browser-driven suite.\n */\n\n/** Dispatch a pre-built `Event` instance unchanged. Returns the `dispatchEvent` result. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\n/** Synthetic convenience dispatchers. They share the same confidence boundary as `dispatch()`. */\nexport const fireBlur = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('blur', init));\n\nexport const fireChange = (target: EventTarget, init: EventInit = {}): boolean =>\n dispatch(target, new Event('change', { bubbles: true, ...init }));\n\nexport const fireClick = (target: EventTarget, init: MouseEventInit = {}): boolean =>\n dispatch(target, new MouseEvent('click', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireCustom = <T>(target: EventTarget, type: string, init: CustomEventInit<T> = {}): boolean =>\n dispatch(target, new CustomEvent(type, { bubbles: true, cancelable: true, composed: false, ...init }));\n\nexport const fireFocus = (target: EventTarget, init: FocusEventInit = {}): boolean =>\n dispatch(target, new FocusEvent('focus', init));\n\nexport const fireInput = (target: EventTarget, init: InputEventInit = {}): boolean =>\n dispatch(target, new InputEvent('input', { bubbles: true, ...init }));\n\nexport const fireKeyDown = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireKeyUp = (target: EventTarget, init: KeyboardEventInit = {}): boolean =>\n dispatch(target, new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...init }));\n\nexport const fireSubmit = (target: EventTarget, init: SubmitEventInit = {}): boolean =>\n dispatch(target, new SubmitEvent('submit', { bubbles: true, cancelable: true, ...init }));\n","import { walkFlatTree } from './dom';\n\n/**\n * jsdom implements none of the `ElementInternals` form-association API: not `setFormValue`,\n * not `setValidity`, not the `checkValidity`/`reportValidity`/`validity`/`validationMessage`\n * mixin real browsers put on every `formAssociated: true` element, not even `FormData`\n * collecting a form-associated element's set value, or `<form>.reset()` invoking\n * `formResetCallback()`. Every one of those gaps is exercised by `useField()` (`@vielzeug/ore`),\n * so any package testing a form-associated component needs all of them, not just one.\n *\n * Call this directly from a test setup when the suite tests form-associated components:\n * the patches are global monkey-patches, so suites without them shouldn't pay for them.\n * Returns an `uninstall()` that restores every patched global.\n *\n * Lives in Assay because it patches the DOM environment itself: the gap is in jsdom, not in\n * any package's feature, and Assay is the repo's home for DOM test-environment helpers.\n * `walkFlatTree` handles form-associated custom elements across shadow boundaries, so\n * consumer packages do not need package-local copies of this polyfill.\n */\nexport const installFormInternalsPolyfill = (): (() => void) => {\n // Checked *before* consuming the flag below: an environment without `ElementInternals`\n // installs nothing and should stay eligible to install for real later (e.g. a differently\n // configured environment in the same process), not get marked \"already installed\" for having\n // done nothing.\n if (typeof ElementInternals === 'undefined') return () => {};\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.assay.formInternalsPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return () => {};\n\n flagHost[INSTALLED_FLAG] = true;\n\n // Every patch pushes its inverse here, so uninstall() restores the environment exactly.\n const restorers: Array<() => void> = [];\n\n const proto = ElementInternals.prototype as unknown as Record<string, unknown>;\n const validityState = new WeakMap<ElementInternals, { flags: ValidityStateFlags; message: string }>();\n const formValueByHost = new WeakMap<HTMLElement, File | FormData | string | null>();\n const hostByInternals = new WeakMap<ElementInternals, HTMLElement>();\n\n const patchProto = (name: string, descriptor: PropertyDescriptor): void => {\n if (name in proto) return;\n\n Object.defineProperty(proto, name, descriptor);\n restorers.push(() => delete proto[name]);\n };\n\n const isValid = (internals: ElementInternals): boolean => {\n const state = validityState.get(internals);\n\n return !state || !Object.values(state.flags).some(Boolean);\n };\n\n patchProto('setFormValue', {\n configurable: true,\n value: function (this: ElementInternals, value: File | FormData | string | null) {\n const host = hostByInternals.get(this);\n\n if (host) formValueByHost.set(host, value);\n },\n writable: true,\n });\n\n patchProto('setValidity', {\n configurable: true,\n // Matches the real platform contract: throws if any flag is true and message is empty.\n // `useField()` itself already guards against triggering this: see forms/field.ts, but\n // the polyfill enforcing it too means a test would still catch a *different* caller doing\n // the same thing wrong, instead of that bug only surfacing in a real browser.\n value: function (this: ElementInternals, flags: ValidityStateFlags = {}, message = '') {\n if (Object.values(flags).some(Boolean) && !message) {\n throw new TypeError(\n \"Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if \" +\n 'one or more flags in the first argument are true.',\n );\n }\n\n validityState.set(this, { flags, message });\n },\n writable: true,\n });\n\n patchProto('checkValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('reportValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n\n patchProto('validationMessage', {\n configurable: true,\n get(this: ElementInternals) {\n return isValid(this) ? '' : (validityState.get(this)?.message ?? '');\n },\n });\n\n // A ValidityState-shaped view of the flags passed to setValidity: every known\n // flag defaults to false, `valid` reflects whether any flag is set.\n patchProto('validity', {\n configurable: true,\n get(this: ElementInternals): ValidityState {\n const state = validityState.get(this);\n\n return {\n badInput: false,\n customError: false,\n patternMismatch: false,\n rangeOverflow: false,\n rangeUnderflow: false,\n stepMismatch: false,\n tooLong: false,\n tooShort: false,\n typeMismatch: false,\n valid: isValid(this),\n valueMissing: false,\n ...(state?.flags ?? {}),\n } as ValidityState;\n },\n });\n\n patchProto('states', {\n configurable: true,\n get: function (this: ElementInternals & { _states?: Set<string> }) {\n this._states ??= new Set();\n\n return this._states;\n },\n });\n\n // Real browsers mix `checkValidity`/`reportValidity`/`validity`/`validationMessage` onto any\n // `formAssociated: true` custom element itself (delegating to its internals): not just onto\n // `ElementInternals`. jsdom does neither; mirror it here so a component's own\n // `checkValidity()`/`reportValidity()`, and a test asserting against the element directly,\n // behave the same as they would in a real browser.\n const originalAttachInternals = HTMLElement.prototype.attachInternals;\n\n HTMLElement.prototype.attachInternals = function (this: HTMLElement, ...args: []): ElementInternals {\n const internals = originalAttachInternals.apply(this, args);\n\n hostByInternals.set(internals, this);\n\n Object.defineProperties(this, {\n checkValidity: { configurable: true, value: () => internals.checkValidity() },\n reportValidity: { configurable: true, value: () => internals.reportValidity() },\n validationMessage: { configurable: true, get: () => internals.validationMessage },\n validity: { configurable: true, get: () => internals.validity },\n });\n\n return internals;\n };\n restorers.push(() => {\n HTMLElement.prototype.attachInternals = originalAttachInternals;\n });\n\n const appendFormValue = (formData: FormData, name: string, value: File | FormData | string): void => {\n if (value instanceof FormData) {\n for (const [entryName, entryValue] of value.entries()) formData.append(entryName, entryValue);\n\n return;\n }\n\n formData.append(name, value);\n };\n\n // jsdom's `FormData` constructor never collects a form-associated custom element's set form\n // value: real browsers walk the flat tree for every form-associated element with a `name`.\n const NativeFormData = globalThis.FormData;\n\n globalThis.FormData = class FormDataWithFormAssociatedElements extends NativeFormData {\n constructor(form?: HTMLFormElement, submitter?: HTMLElement | null) {\n super(form as HTMLFormElement | undefined, submitter as HTMLElement | null | undefined);\n\n if (!(form instanceof HTMLFormElement)) return;\n\n walkFlatTree(form, (element) => {\n const name = element.getAttribute('name');\n const value = formValueByHost.get(element);\n\n if (!name || value == null || element.hasAttribute('disabled')) return;\n\n appendFormValue(this, name, value);\n });\n }\n };\n restorers.push(() => {\n globalThis.FormData = NativeFormData;\n });\n\n // jsdom never invokes the native `formResetCallback` lifecycle method on form-associated\n // custom elements when their form resets: patch `reset()` to do it (via the same flat-tree\n // walk, since a reset field can be nested behind a shadow boundary too), so `onFormReset()`\n // (see `@vielzeug/ore`'s runtime.ts) is testable against a real `<form>.reset()` call instead\n // of only by calling `element.formResetCallback()` directly.\n const originalReset = HTMLFormElement.prototype.reset;\n\n HTMLFormElement.prototype.reset = function (this: HTMLFormElement, ...args: []) {\n originalReset.apply(this, args);\n\n walkFlatTree(this, (element) => {\n (element as Partial<{ formResetCallback: () => void }>).formResetCallback?.();\n });\n };\n restorers.push(() => {\n HTMLFormElement.prototype.reset = originalReset;\n });\n\n return () => {\n for (const restore of restorers) restore();\n\n restorers.length = 0;\n flagHost[INSTALLED_FLAG] = false;\n };\n};\n","/**\n * jsdom implements none of the Popover API (`jsdom#3721`): no `showPopover`/`hidePopover`/\n * `togglePopover`, no `popover` IDL attribute, and — the part that silently breaks suites — its\n * selector engine treats `:popover-open` as a documented no-op that never matches.\n *\n * A partial shim (just setting the `popover-open` attribute) is worse than no shim, because every\n * component in the repo guards its calls the idiomatic way:\n *\n * ```ts\n * if (!panel.matches(':popover-open')) panel.showPopover();\n * if (panel.matches(':popover-open')) panel.hidePopover();\n * ```\n *\n * With `:popover-open` permanently false, `showPopover` runs twice and `hidePopover` never runs at\n * all: overlays open and can never close, and the failure looks like a component bug rather than an\n * environment gap. jsdom's UA stylesheet also keeps every `[popover]` element at\n * `display: none` (nothing matches `:popover-open` to lift it), and jsdom's focus algorithm refuses\n * to focus anything with a `display: none` flat-tree ancestor — so focusing an item inside an open\n * panel silently does nothing.\n *\n * This shim closes all three gaps: it tracks open state in the `popover-open` attribute (the same\n * attribute real browsers reflect, so tests can still assert on it), makes `matches(':popover-open')`\n * answer from that state, and holds the element visible with an inline `display` while open —\n * inline styles are the only author-level declaration that beats jsdom's UA rule, since component\n * styles live in adopted style sheets that jsdom does not cascade at all.\n *\n * Known simplifications, deliberate because nothing in the repo depends on them: no light-dismiss\n * behavior (`manual` is the only mode any component uses, and it has none), no top-layer ordering,\n * and no `beforetoggle`/`toggle` events. A suite that starts listening for those needs them added\n * here, not worked around per test.\n *\n * Call this from a test setup when the suite mounts popover-based components: the patches are global\n * monkey-patches, so suites without them shouldn't pay for them. Returns an `uninstall()` restoring\n * every patched global.\n *\n * Lives in Assay because the gap is in jsdom, not in any package's feature, and Assay is the repo's\n * home for DOM test-environment helpers (see `installFormInternalsPolyfill`). Consumer packages get\n * it from here instead of keeping per-file copies that drift out of sync with the API.\n */\nexport const installPopoverPolyfill = (): (() => void) => {\n if (typeof HTMLElement === 'undefined') return () => {};\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.assay.popoverPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return () => {};\n\n flagHost[INSTALLED_FLAG] = true;\n\n // Every patch pushes its inverse here, so uninstall() restores the environment exactly.\n const restorers: Array<() => void> = [];\n\n const OPEN_ATTRIBUTE = 'popover-open';\n\n const isOpen = (element: HTMLElement): boolean => element.hasAttribute(OPEN_ATTRIBUTE);\n\n // The inline `display` each element had before it was first shown, so hiding restores exactly\n // what was there rather than guessing. WeakMap: nothing outlives the element.\n const displayBeforeOpen = new WeakMap<HTMLElement, string>();\n\n const reveal = (element: HTMLElement): void => {\n const view = element.ownerDocument?.defaultView;\n\n // Only lift a `display: none` that is actually blocking the element. Overwriting an author-chosen\n // display (`grid` on a menu panel, `flex` on a card) would change layout the test is measuring.\n if (!view || view.getComputedStyle(element).display !== 'none') return;\n\n if (!displayBeforeOpen.has(element)) {\n displayBeforeOpen.set(element, element.style.getPropertyValue('display'));\n }\n\n element.style.setProperty('display', 'block');\n };\n\n const conceal = (element: HTMLElement): void => {\n if (!displayBeforeOpen.has(element)) return;\n\n const before = displayBeforeOpen.get(element) as string;\n\n displayBeforeOpen.delete(element);\n\n if (before) element.style.setProperty('display', before);\n else element.style.removeProperty('display');\n };\n\n const requirePopoverAttribute = (element: HTMLElement, method: string): void => {\n if (element.hasAttribute('popover')) return;\n\n // Matches the platform contract: showing or hiding an element that is not a popover is a\n // misuse bug, and throwing here surfaces it instead of letting the test pass quietly.\n throw new DOMException(\n `Failed to execute '${method}' on 'HTMLElement': the element does not have a popover attribute.`,\n 'InvalidStateError',\n );\n };\n\n // Same shape as `installFormInternalsPolyfill`: the prototype is patched through a plain record,\n // because these members are declared as always-present in lib.dom and this file's whole job is to\n // add them where they are absent.\n const proto = HTMLElement.prototype as unknown as Record<string, unknown>;\n\n const patchProto = (name: string, descriptor: PropertyDescriptor): void => {\n if (name in proto) return;\n\n Object.defineProperty(proto, name, descriptor);\n restorers.push(() => delete proto[name]);\n };\n\n patchProto('showPopover', {\n configurable: true,\n value: function (this: HTMLElement, options?: { source?: HTMLElement | null; force?: boolean }) {\n requirePopoverAttribute(this, 'showPopover');\n\n if (isOpen(this) && !options?.force) return;\n\n reveal(this);\n this.setAttribute(OPEN_ATTRIBUTE, '');\n },\n });\n\n patchProto('hidePopover', {\n configurable: true,\n value: function (this: HTMLElement) {\n requirePopoverAttribute(this, 'hidePopover');\n\n if (!isOpen(this)) return;\n\n this.removeAttribute(OPEN_ATTRIBUTE);\n conceal(this);\n },\n });\n\n patchProto('togglePopover', {\n configurable: true,\n value: function (this: HTMLElement, force?: boolean): boolean {\n requirePopoverAttribute(this, 'togglePopover');\n\n const shouldOpen = force ?? !isOpen(this);\n\n if (shouldOpen) reveal(this);\n else conceal(this);\n\n if (shouldOpen) this.setAttribute(OPEN_ATTRIBUTE, '');\n else this.removeAttribute(OPEN_ATTRIBUTE);\n\n return isOpen(this);\n },\n });\n\n // The guard every component wraps its calls in. dom-selector (jsdom's engine) stubs `:popover-open`\n // out as a permanent false, so without this `hidePopover` is unreachable from component code.\n // Intercepted by exact selector string: anything else, including `:not(:popover-open)` inside a\n // stylesheet, still goes through jsdom's own engine untouched.\n const originalMatches = Element.prototype.matches;\n\n Element.prototype.matches = function (this: Element, selectors: string): boolean {\n if (selectors === ':popover-open') return this.hasAttribute(OPEN_ATTRIBUTE);\n\n return originalMatches.call(this, selectors);\n // Cast: the interception only ever answers for one exact selector string, but the declared\n // member carries element-tag type predicates that a plain predicate cannot structurally satisfy.\n } as unknown as typeof Element.prototype.matches;\n restorers.push(() => {\n Element.prototype.matches = originalMatches;\n });\n\n return () => {\n for (const restore of restorers) restore();\n\n restorers.length = 0;\n flagHost[INSTALLED_FLAG] = false;\n };\n};\n","import { AssayQueryError } from './errors';\n\n/** DOM query helpers for test environments. */\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Scoped query helpers for any queryable DOM root: see {@link within}. */\nexport interface QueryScope {\n get<E extends Element = Element>(selector: string): E;\n getByTestId<E extends Element = Element>(testId: string): E;\n getByText<E extends Element = Element>(text: string, selector?: string): E;\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\ntype QueryRoot = ParentNode;\n\nconst describeRoot = (root: QueryRoot): string => {\n if (root instanceof Element) return root.outerHTML.slice(0, 500);\n\n if (root instanceof ShadowRoot) return `<shadow-root>${root.innerHTML.slice(0, 500)}</shadow-root>`;\n\n return root.nodeName;\n};\n\nconst requireMatch = <E extends Element>(element: E | null, description: string, root: QueryRoot): E => {\n if (element) return element;\n\n throw new AssayQueryError(`Unable to find ${description} within ${describeRoot(root)}.`);\n};\n\nconst query = <E extends Element = Element>(root: QueryRoot, selector: string): E | null =>\n root.querySelector<E>(selector);\n\nconst queryAll = <E extends Element = Element>(root: QueryRoot, selector: string): E[] => {\n return Array.from(root.querySelectorAll<E>(selector));\n};\n\nconst queryByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E | null =>\n queryAll<E>(root, '[data-testid]').find((element) => element.getAttribute('data-testid') === testId) ?? null;\n\nconst queryAllByTestId = <E extends Element = Element>(root: QueryRoot, testId: string): E[] =>\n queryAll<E>(root, '[data-testid]').filter((element) => element.getAttribute('data-testid') === testId);\n\nconst queryByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E | null => {\n for (const element of root.querySelectorAll<E>(selector)) {\n if (element.textContent?.trim() === text) return element;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] =>\n queryAll<E>(root, selector).filter((element) => element.textContent?.trim() === text);\n\n/**\n * Queries the shadow root of a custom element for a matching CSS selector.\n * Returns `null` if the element has no shadow root or no match is found: safe to call on\n * both open-shadow custom elements and plain elements without checking `shadowRoot` first.\n */\nexport function queryInShadow<E extends Element = Element>(host: Element, selector: string): E | null {\n return host.shadowRoot ? query<E>(host.shadowRoot, selector) : null;\n}\n\n/** Queries all matching elements inside the shadow root of a custom element. */\nexport function queryAllInShadow<E extends Element = Element>(host: Element, selector: string): E[] {\n return host.shadowRoot ? queryAll<E>(host.shadowRoot, selector) : [];\n}\n\n/**\n * Queries a shadow DOM element by its CSS `part` attribute: shorthand for\n * `queryInShadow(host, '[part=\"name\"]')`.\n *\n * @example\n * const btn = queryPart(carousel, 'prev-btn');\n * expect(btn).not.toBeNull();\n */\nexport function queryPart<E extends Element = Element>(host: Element, part: string): E | null {\n return (\n queryAllInShadow<E>(host, '[part]').find((element) => element.getAttribute('part')?.split(/\\s+/).includes(part)) ??\n null\n );\n}\n\n/**\n * Returns the light-DOM children assigned to a named slot, or every child assigned to the\n * default slot when no name is given.\n *\n * @example\n * const slides = getSlotted(carousel);\n * expect(slides).toHaveLength(3);\n */\nexport function getSlotted<E extends Element = Element>(host: Element, slotName?: string): E[] {\n return Array.from(host.children).filter((element) =>\n slotName === undefined ? !element.getAttribute('slot') : element.getAttribute('slot') === slotName,\n ) as E[];\n}\n\n// ─── API ─────────────────────────────────────────────────────────────────────\n\n/**\n * Create query helpers scoped to a DOM root: useful for light DOM and shadow roots.\n *\n * @example\n * const view = within(fixture.shadow!);\n * expect(view.get('.title').textContent).toBe('Hello');\n */\nexport function within(root: QueryRoot): QueryScope {\n return {\n get: <E extends Element = Element>(selector: string) =>\n requireMatch(query<E>(root, selector), `\"${selector}\"`, root),\n getByTestId: <E extends Element = Element>(testId: string) =>\n requireMatch(queryByTestId<E>(root, testId), `data-testid \"${testId}\"`, root),\n getByText: <E extends Element = Element>(text: string, selector = '*') =>\n requireMatch(queryByText<E>(root, text, selector), `text \"${text}\" matching \"${selector}\"`, root),\n query: <E extends Element = Element>(selector: string) => query<E>(root, selector),\n queryAll: <E extends Element = Element>(selector: string) => queryAll<E>(root, selector),\n queryAllByTestId: <E extends Element = Element>(testId: string) => queryAllByTestId<E>(root, testId),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(root, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) => queryByTestId<E>(root, testId),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(root, text, selector),\n };\n}\n","import { abortError, sleep } from '@vielzeug/arsenal';\n\nimport { AssayTimeoutError } from './errors';\n\nexport interface DelayOptions {\n signal?: AbortSignal;\n}\n\nexport interface WaitOptions {\n /** Polling interval in ms (default: 50). */\n interval?: number;\n /** Cancel the pending wait. */\n signal?: AbortSignal;\n /** Maximum wait time in ms (default: 1000). */\n timeout?: number;\n}\n\nexport interface EventuallyOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nconst DEADLINE = Symbol('assay.deadline');\nconst MAX_TIMER_MS = 2_147_483_647;\nconst now = (): number => performance.now();\n\nconst validateDuration = (name: string, value: number, allowZero: boolean): void => {\n if (!Number.isFinite(value) || value > MAX_TIMER_MS || (allowZero ? value < 0 : value <= 0)) {\n throw new RangeError(\n `${name} must be a ${allowZero ? 'non-negative' : 'positive'} finite number no greater than ${MAX_TIMER_MS}`,\n );\n }\n};\n\nconst validateWait = (interval: number, timeout: number): void => {\n validateDuration('interval', interval, false);\n validateDuration('timeout', timeout, true);\n};\n\nconst runBounded = <T>(run: () => T | Promise<T>, deadline: number, signal?: AbortSignal): Promise<T> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n let settled = false;\n const cleanup = (): boolean => {\n if (settled) return false;\n settled = true;\n clearTimeout(timer);\n signal?.removeEventListener('abort', abort);\n return true;\n };\n const resolveOnce = (value: T): void => {\n if (cleanup()) resolve(value);\n };\n const rejectOnce = (error: unknown): void => {\n if (cleanup()) reject(error);\n };\n const timer = setTimeout(() => rejectOnce(DEADLINE), Math.max(0, deadline - now()));\n const abort = () => rejectOnce(abortError(signal, 'The operation was aborted.'));\n\n signal?.addEventListener('abort', abort, { once: true });\n\n try {\n Promise.resolve(run()).then(resolveOnce, rejectOnce);\n } catch (error) {\n rejectOnce(error);\n }\n });\n\nexport const delay = (ms = 0, options: DelayOptions = {}): Promise<void> => {\n validateDuration('ms', ms, true);\n return sleep(ms, options.signal);\n};\n\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n first = false;\n\n let matched: boolean;\n try {\n matched = await runBounded(predicate, deadline, signal);\n } catch (error) {\n if (error === DEADLINE) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n throw error;\n }\n if (matched) return;\n\n const remaining = deadline - now();\n if (remaining <= 0) throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n await sleep(Math.min(interval, remaining), signal);\n }\n}\n\n/**\n * Retry an assertion until it stops throwing or the timeout elapses.\n *\n * Polls the assertion on a fixed interval and preserves the last failure as the\n * timeout cause. Pending asynchronous assertions remain bounded by the same\n * deadline. Use `waitUntil()` for boolean conditions, `delay()` for explicit\n * timer dependencies, and `nextTick()` for one queued microtask boundary.\n *\n * @example\n * await eventually(() => expect(region.textContent).toBe('Saved'));\n */\nexport async function eventually(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: EventuallyOptions = {},\n): Promise<void> {\n validateWait(interval, timeout);\n const deadline = now() + timeout;\n let first = true;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (!first && now() >= deadline) break;\n first = false;\n\n try {\n await runBounded(assertion, deadline, signal);\n return;\n } catch (error) {\n if (signal?.aborted) throw abortError(signal, 'The operation was aborted.');\n if (error === DEADLINE) break;\n lastError = error;\n }\n\n const remaining = deadline - now();\n if (remaining <= 0) break;\n await sleep(Math.min(interval, remaining), signal);\n }\n\n const timing = `eventually timed out after ${timeout}ms`;\n const context = message ? `${message} (${timing})` : timing;\n const detail = lastError instanceof Error ? lastError.message : lastError == null ? '' : String(lastError);\n\n throw new AssayTimeoutError(detail ? `${context}\\n${detail}` : context, { cause: lastError });\n}\n\n/** Resolve with the next event of `type`, or reject when it times out or is aborted. */\nexport function waitForEvent<T extends Event = Event>(\n target: EventTarget,\n type: string,\n { signal, timeout = 1000 }: Omit<WaitOptions, 'interval'> = {},\n): Promise<T> {\n validateDuration('timeout', timeout, true);\n\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal, 'The operation was aborted.'));\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (event: Event): void => {\n dispose();\n resolve(event as T);\n };\n const timer = setTimeout(() => {\n dispose();\n reject(new AssayTimeoutError(`waitForEvent: \"${type}\" timed out after ${timeout}ms`));\n }, timeout);\n const onAbort = () => {\n dispose();\n reject(abortError(signal, 'The operation was aborted.'));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n"],"mappings":"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"}
package/dist/dom.js CHANGED
@@ -1,9 +1,8 @@
1
- //#region src/dom.ts
1
+ // src/dom.ts
2
2
  var walkFlatTree = (e, t) => {
3
3
  let n = e instanceof HTMLSlotElement ? e.assignedElements({ flatten: !0 }) : e.children;
4
4
  for (let e of Array.from(n)) e instanceof HTMLSlotElement || t(e), walkFlatTree(e, t);
5
5
  };
6
- //#endregion
7
6
  export { walkFlatTree };
8
7
 
9
8
  //# sourceMappingURL=dom.js.map
package/dist/errors.js CHANGED
@@ -1,10 +1,9 @@
1
- //#region src/errors.ts
1
+ // src/errors.ts
2
2
  var AssayError = class extends Error {
3
3
  constructor(e, t) {
4
4
  super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
5
5
  }
6
6
  }, AssayQueryError = class extends AssayError {}, AssayTimeoutError = class extends AssayError {};
7
- //#endregion
8
7
  export { AssayError, AssayQueryError, AssayTimeoutError };
9
8
 
10
9
  //# sourceMappingURL=errors.js.map
package/dist/events.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/events.ts
1
+ // src/events.ts
2
2
  var dispatch = (e, t) => e.dispatchEvent(t), fireBlur = (e, t = {}) => dispatch(e, new FocusEvent("blur", t)), fireChange = (e, t = {}) => dispatch(e, new Event("change", {
3
3
  bubbles: !0,
4
4
  ...t
@@ -27,7 +27,6 @@ var dispatch = (e, t) => e.dispatchEvent(t), fireBlur = (e, t = {}) => dispatch(
27
27
  cancelable: !0,
28
28
  ...t
29
29
  }));
30
- //#endregion
31
30
  export { dispatch, fireBlur, fireChange, fireClick, fireCustom, fireFocus, fireInput, fireKeyDown, fireKeyUp, fireSubmit };
32
31
 
33
32
  //# sourceMappingURL=events.js.map
@@ -1,5 +1,5 @@
1
1
  import { walkFlatTree as e } from "./dom.js";
2
- //#region src/form-internals.ts
2
+ // src/form-internals.ts
3
3
  var installFormInternalsPolyfill = () => {
4
4
  if (typeof ElementInternals > "u") return () => {};
5
5
  let t = Symbol.for("vielzeug.assay.formInternalsPolyfillInstalled"), n = globalThis;
@@ -120,7 +120,6 @@ var installFormInternalsPolyfill = () => {
120
120
  r.length = 0, n[t] = !1;
121
121
  };
122
122
  };
123
- //#endregion
124
123
  export { installFormInternalsPolyfill };
125
124
 
126
125
  //# sourceMappingURL=form-internals.js.map
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./dom.cjs"),t=require("./errors.cjs"),n=require("./events.cjs"),r=require("./form-internals.cjs"),i=require("./query.cjs"),a=require("./wait.cjs");exports.AssayError=t.AssayError,exports.AssayQueryError=t.AssayQueryError,exports.AssayTimeoutError=t.AssayTimeoutError,exports.delay=a.delay,exports.dispatch=n.dispatch,exports.eventually=a.eventually,exports.fireBlur=n.fireBlur,exports.fireChange=n.fireChange,exports.fireClick=n.fireClick,exports.fireCustom=n.fireCustom,exports.fireFocus=n.fireFocus,exports.fireInput=n.fireInput,exports.fireKeyDown=n.fireKeyDown,exports.fireKeyUp=n.fireKeyUp,exports.fireSubmit=n.fireSubmit,exports.getSlotted=i.getSlotted,exports.installFormInternalsPolyfill=r.installFormInternalsPolyfill,exports.queryAllInShadow=i.queryAllInShadow,exports.queryInShadow=i.queryInShadow,exports.queryPart=i.queryPart,exports.waitForEvent=a.waitForEvent,exports.waitUntil=a.waitUntil,exports.walkFlatTree=e.walkFlatTree,exports.within=i.within;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./dom.cjs"),t=require("./errors.cjs"),n=require("./events.cjs"),r=require("./form-internals.cjs"),i=require("./popover.cjs"),a=require("./query.cjs"),o=require("./wait.cjs");exports.AssayError=t.AssayError,exports.AssayQueryError=t.AssayQueryError,exports.AssayTimeoutError=t.AssayTimeoutError,exports.delay=o.delay,exports.dispatch=n.dispatch,exports.eventually=o.eventually,exports.fireBlur=n.fireBlur,exports.fireChange=n.fireChange,exports.fireClick=n.fireClick,exports.fireCustom=n.fireCustom,exports.fireFocus=n.fireFocus,exports.fireInput=n.fireInput,exports.fireKeyDown=n.fireKeyDown,exports.fireKeyUp=n.fireKeyUp,exports.fireSubmit=n.fireSubmit,exports.getSlotted=a.getSlotted,exports.installFormInternalsPolyfill=r.installFormInternalsPolyfill,exports.installPopoverPolyfill=i.installPopoverPolyfill,exports.queryAllInShadow=a.queryAllInShadow,exports.queryInShadow=a.queryInShadow,exports.queryPart=a.queryPart,exports.waitForEvent=o.waitForEvent,exports.waitUntil=o.waitUntil,exports.walkFlatTree=e.walkFlatTree,exports.within=a.within;
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { walkFlatTree } from './dom';
2
2
  export { AssayError, AssayQueryError, AssayTimeoutError } from './errors';
3
3
  export { dispatch, fireBlur, fireChange, fireClick, fireCustom, fireFocus, fireInput, fireKeyDown, fireKeyUp, fireSubmit, } from './events';
4
4
  export { installFormInternalsPolyfill } from './form-internals';
5
+ export { installPopoverPolyfill } from './popover';
5
6
  export { getSlotted, type QueryScope, queryAllInShadow, queryInShadow, queryPart, within } from './query';
6
7
  export { type DelayOptions, delay, type EventuallyOptions, eventually, type WaitOptions, waitForEvent, waitUntil, } from './wait';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC1E,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,WAAW,EACX,SAAS,EACT,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1G,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,EACL,KAAK,iBAAiB,EACtB,UAAU,EACV,KAAK,WAAW,EAChB,YAAY,EACZ,SAAS,GACV,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC1E,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,WAAW,EACX,SAAS,EACT,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1G,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,EACL,KAAK,iBAAiB,EACtB,UAAU,EACV,KAAK,WAAW,EAChB,YAAY,EACZ,SAAS,GACV,MAAM,QAAQ,CAAC"}
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { walkFlatTree as e } from "./dom.js";
2
2
  import { AssayError as t, AssayQueryError as n, AssayTimeoutError as r } from "./errors.js";
3
3
  import { dispatch as i, fireBlur as a, fireChange as o, fireClick as s, fireCustom as c, fireFocus as l, fireInput as u, fireKeyDown as d, fireKeyUp as f, fireSubmit as p } from "./events.js";
4
4
  import { installFormInternalsPolyfill as m } from "./form-internals.js";
5
- import { getSlotted as h, queryAllInShadow as g, queryInShadow as _, queryPart as v, within as y } from "./query.js";
6
- import { delay as b, eventually as x, waitForEvent as S, waitUntil as C } from "./wait.js";
7
- export { t as AssayError, n as AssayQueryError, r as AssayTimeoutError, b as delay, i as dispatch, x as eventually, a as fireBlur, o as fireChange, s as fireClick, c as fireCustom, l as fireFocus, u as fireInput, d as fireKeyDown, f as fireKeyUp, p as fireSubmit, h as getSlotted, m as installFormInternalsPolyfill, g as queryAllInShadow, _ as queryInShadow, v as queryPart, S as waitForEvent, C as waitUntil, e as walkFlatTree, y as within };
5
+ import { installPopoverPolyfill as h } from "./popover.js";
6
+ import { getSlotted as g, queryAllInShadow as _, queryInShadow as v, queryPart as y, within as b } from "./query.js";
7
+ import { delay as x, eventually as S, waitForEvent as C, waitUntil as w } from "./wait.js";
8
+ export { t as AssayError, n as AssayQueryError, r as AssayTimeoutError, x as delay, i as dispatch, S as eventually, a as fireBlur, o as fireChange, s as fireClick, c as fireCustom, l as fireFocus, u as fireInput, d as fireKeyDown, f as fireKeyUp, p as fireSubmit, g as getSlotted, m as installFormInternalsPolyfill, h as installPopoverPolyfill, _ as queryAllInShadow, v as queryInShadow, y as queryPart, C as waitForEvent, w as waitUntil, e as walkFlatTree, b as within };
@@ -0,0 +1,2 @@
1
+ var installPopoverPolyfill=()=>{if(typeof HTMLElement>`u`)return()=>{};let e=Symbol.for(`vielzeug.assay.popoverPolyfillInstalled`),t=globalThis;if(t[e])return()=>{};t[e]=!0;let n=[],r=`popover-open`,isOpen=e=>e.hasAttribute(r),i=new WeakMap,reveal=e=>{let t=e.ownerDocument?.defaultView;t&&t.getComputedStyle(e).display===`none`&&(i.has(e)||i.set(e,e.style.getPropertyValue(`display`)),e.style.setProperty(`display`,`block`))},conceal=e=>{if(!i.has(e))return;let t=i.get(e);i.delete(e),t?e.style.setProperty(`display`,t):e.style.removeProperty(`display`)},requirePopoverAttribute=(e,t)=>{if(!e.hasAttribute(`popover`))throw new DOMException(`Failed to execute '${t}' on 'HTMLElement': the element does not have a popover attribute.`,`InvalidStateError`)},a=HTMLElement.prototype,patchProto=(e,t)=>{e in a||(Object.defineProperty(a,e,t),n.push(()=>delete a[e]))};patchProto(`showPopover`,{configurable:!0,value:function(e){requirePopoverAttribute(this,`showPopover`),(!isOpen(this)||e?.force)&&(reveal(this),this.setAttribute(r,``))}}),patchProto(`hidePopover`,{configurable:!0,value:function(){requirePopoverAttribute(this,`hidePopover`),isOpen(this)&&(this.removeAttribute(r),conceal(this))}}),patchProto(`togglePopover`,{configurable:!0,value:function(e){requirePopoverAttribute(this,`togglePopover`);let t=e??!isOpen(this);return t?reveal(this):conceal(this),t?this.setAttribute(r,``):this.removeAttribute(r),isOpen(this)}});let o=Element.prototype.matches;return Element.prototype.matches=function(e){return e===`:popover-open`?this.hasAttribute(r):o.call(this,e)},n.push(()=>{Element.prototype.matches=o}),()=>{for(let e of n)e();n.length=0,t[e]=!1}};exports.installPopoverPolyfill=installPopoverPolyfill;
2
+ //# sourceMappingURL=popover.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popover.cjs","names":["INSTALLED_FLAG","flagHost","restorers","OPEN_ATTRIBUTE","element","displayBeforeOpen","view","before","method","proto","name","descriptor","options","shouldOpen","force","originalMatches","selectors","restore"],"sources":["../src/popover.ts"],"sourcesContent":["/**\n * jsdom implements none of the Popover API (`jsdom#3721`): no `showPopover`/`hidePopover`/\n * `togglePopover`, no `popover` IDL attribute, and — the part that silently breaks suites — its\n * selector engine treats `:popover-open` as a documented no-op that never matches.\n *\n * A partial shim (just setting the `popover-open` attribute) is worse than no shim, because every\n * component in the repo guards its calls the idiomatic way:\n *\n * ```ts\n * if (!panel.matches(':popover-open')) panel.showPopover();\n * if (panel.matches(':popover-open')) panel.hidePopover();\n * ```\n *\n * With `:popover-open` permanently false, `showPopover` runs twice and `hidePopover` never runs at\n * all: overlays open and can never close, and the failure looks like a component bug rather than an\n * environment gap. jsdom's UA stylesheet also keeps every `[popover]` element at\n * `display: none` (nothing matches `:popover-open` to lift it), and jsdom's focus algorithm refuses\n * to focus anything with a `display: none` flat-tree ancestor — so focusing an item inside an open\n * panel silently does nothing.\n *\n * This shim closes all three gaps: it tracks open state in the `popover-open` attribute (the same\n * attribute real browsers reflect, so tests can still assert on it), makes `matches(':popover-open')`\n * answer from that state, and holds the element visible with an inline `display` while open —\n * inline styles are the only author-level declaration that beats jsdom's UA rule, since component\n * styles live in adopted style sheets that jsdom does not cascade at all.\n *\n * Known simplifications, deliberate because nothing in the repo depends on them: no light-dismiss\n * behavior (`manual` is the only mode any component uses, and it has none), no top-layer ordering,\n * and no `beforetoggle`/`toggle` events. A suite that starts listening for those needs them added\n * here, not worked around per test.\n *\n * Call this from a test setup when the suite mounts popover-based components: the patches are global\n * monkey-patches, so suites without them shouldn't pay for them. Returns an `uninstall()` restoring\n * every patched global.\n *\n * Lives in Assay because the gap is in jsdom, not in any package's feature, and Assay is the repo's\n * home for DOM test-environment helpers (see `installFormInternalsPolyfill`). Consumer packages get\n * it from here instead of keeping per-file copies that drift out of sync with the API.\n */\nexport const installPopoverPolyfill = (): (() => void) => {\n if (typeof HTMLElement === 'undefined') return () => {};\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.assay.popoverPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return () => {};\n\n flagHost[INSTALLED_FLAG] = true;\n\n // Every patch pushes its inverse here, so uninstall() restores the environment exactly.\n const restorers: Array<() => void> = [];\n\n const OPEN_ATTRIBUTE = 'popover-open';\n\n const isOpen = (element: HTMLElement): boolean => element.hasAttribute(OPEN_ATTRIBUTE);\n\n // The inline `display` each element had before it was first shown, so hiding restores exactly\n // what was there rather than guessing. WeakMap: nothing outlives the element.\n const displayBeforeOpen = new WeakMap<HTMLElement, string>();\n\n const reveal = (element: HTMLElement): void => {\n const view = element.ownerDocument?.defaultView;\n\n // Only lift a `display: none` that is actually blocking the element. Overwriting an author-chosen\n // display (`grid` on a menu panel, `flex` on a card) would change layout the test is measuring.\n if (!view || view.getComputedStyle(element).display !== 'none') return;\n\n if (!displayBeforeOpen.has(element)) {\n displayBeforeOpen.set(element, element.style.getPropertyValue('display'));\n }\n\n element.style.setProperty('display', 'block');\n };\n\n const conceal = (element: HTMLElement): void => {\n if (!displayBeforeOpen.has(element)) return;\n\n const before = displayBeforeOpen.get(element) as string;\n\n displayBeforeOpen.delete(element);\n\n if (before) element.style.setProperty('display', before);\n else element.style.removeProperty('display');\n };\n\n const requirePopoverAttribute = (element: HTMLElement, method: string): void => {\n if (element.hasAttribute('popover')) return;\n\n // Matches the platform contract: showing or hiding an element that is not a popover is a\n // misuse bug, and throwing here surfaces it instead of letting the test pass quietly.\n throw new DOMException(\n `Failed to execute '${method}' on 'HTMLElement': the element does not have a popover attribute.`,\n 'InvalidStateError',\n );\n };\n\n // Same shape as `installFormInternalsPolyfill`: the prototype is patched through a plain record,\n // because these members are declared as always-present in lib.dom and this file's whole job is to\n // add them where they are absent.\n const proto = HTMLElement.prototype as unknown as Record<string, unknown>;\n\n const patchProto = (name: string, descriptor: PropertyDescriptor): void => {\n if (name in proto) return;\n\n Object.defineProperty(proto, name, descriptor);\n restorers.push(() => delete proto[name]);\n };\n\n patchProto('showPopover', {\n configurable: true,\n value: function (this: HTMLElement, options?: { source?: HTMLElement | null; force?: boolean }) {\n requirePopoverAttribute(this, 'showPopover');\n\n if (isOpen(this) && !options?.force) return;\n\n reveal(this);\n this.setAttribute(OPEN_ATTRIBUTE, '');\n },\n });\n\n patchProto('hidePopover', {\n configurable: true,\n value: function (this: HTMLElement) {\n requirePopoverAttribute(this, 'hidePopover');\n\n if (!isOpen(this)) return;\n\n this.removeAttribute(OPEN_ATTRIBUTE);\n conceal(this);\n },\n });\n\n patchProto('togglePopover', {\n configurable: true,\n value: function (this: HTMLElement, force?: boolean): boolean {\n requirePopoverAttribute(this, 'togglePopover');\n\n const shouldOpen = force ?? !isOpen(this);\n\n if (shouldOpen) reveal(this);\n else conceal(this);\n\n if (shouldOpen) this.setAttribute(OPEN_ATTRIBUTE, '');\n else this.removeAttribute(OPEN_ATTRIBUTE);\n\n return isOpen(this);\n },\n });\n\n // The guard every component wraps its calls in. dom-selector (jsdom's engine) stubs `:popover-open`\n // out as a permanent false, so without this `hidePopover` is unreachable from component code.\n // Intercepted by exact selector string: anything else, including `:not(:popover-open)` inside a\n // stylesheet, still goes through jsdom's own engine untouched.\n const originalMatches = Element.prototype.matches;\n\n Element.prototype.matches = function (this: Element, selectors: string): boolean {\n if (selectors === ':popover-open') return this.hasAttribute(OPEN_ATTRIBUTE);\n\n return originalMatches.call(this, selectors);\n // Cast: the interception only ever answers for one exact selector string, but the declared\n // member carries element-tag type predicates that a plain predicate cannot structurally satisfy.\n } as unknown as typeof Element.prototype.matches;\n restorers.push(() => {\n Element.prototype.matches = originalMatches;\n });\n\n return () => {\n for (const restore of restorers) restore();\n\n restorers.length = 0;\n flagHost[INSTALLED_FLAG] = false;\n };\n};\n"],"mappings":"AAuCA,IAAa,2BAA6C,CACxD,GAAI,OAAO,YAAgB,IAAa,UAAa,CAAC,EAEtD,IAAMA,EAAiB,OAAO,IAAI,yCAAyC,EACrEC,EAAW,WAEjB,GAAIA,EAASD,GAAiB,UAAa,CAAC,EAE5C,EAASA,GAAkB,GAG3B,IAAME,EAA+B,CAAC,EAEhCC,EAAiB,eAEjB,OAAU,GAAkCC,EAAQ,aAAaD,CAAc,EAI/EE,EAAoB,IAAI,QAExB,OAAU,GAA+B,CAC7C,IAAMC,EAAOF,EAAQ,eAAe,YAI/BE,GAAQA,EAAK,iBAAiBF,CAAO,CAAC,CAAC,UAAY,SAEnDC,EAAkB,IAAID,CAAO,GAChCC,EAAkB,IAAID,EAASA,EAAQ,MAAM,iBAAiB,SAAS,CAAC,EAG1EA,EAAQ,MAAM,YAAY,UAAW,OAAO,EAC9C,EAEM,QAAW,GAA+B,CAC9C,GAAI,CAACC,EAAkB,IAAID,CAAO,EAAG,OAErC,IAAMG,EAASF,EAAkB,IAAID,CAAO,EAE5CC,EAAkB,OAAOD,CAAO,EAE5BG,EAAQH,EAAQ,MAAM,YAAY,UAAWG,CAAM,EAClDH,EAAQ,MAAM,eAAe,SAAS,CAC7C,EAEM,yBAA2B,EAAsB,IAAyB,CAC9E,GAAI,GAAQ,aAAa,SAAS,EAIlC,MAAM,IAAI,aACR,sBAAsBI,EAAO,oEAC7B,mBACF,CACF,EAKMC,EAAQ,YAAY,UAEpB,YAAc,EAAc,IAAyC,CACrEC,KAAQD,IAEZ,OAAO,eAAeA,EAAOC,EAAMC,CAAU,EAC7CT,EAAU,SAAW,OAAOO,EAAMC,EAAK,EACzC,EAEA,WAAW,cAAe,CACxB,aAAc,GACd,MAAO,SAA6B,EAA4D,CAC9F,wBAAwB,KAAM,aAAa,GAEvC,QAAO,IAAI,GAAME,GAAS,SAE9B,OAAO,IAAI,EACX,KAAK,aAAaT,EAAgB,EAAE,EACtC,CACF,CAAC,EAED,WAAW,cAAe,CACxB,aAAc,GACd,MAAO,UAA6B,CAClC,wBAAwB,KAAM,aAAa,EAEtC,OAAO,IAAI,IAEhB,KAAK,gBAAgBA,CAAc,EACnC,QAAQ,IAAI,EACd,CACF,CAAC,EAED,WAAW,gBAAiB,CAC1B,aAAc,GACd,MAAO,SAA6B,EAA0B,CAC5D,wBAAwB,KAAM,eAAe,EAE7C,IAAMU,EAAaC,GAAS,CAAC,OAAO,IAAI,EAQxC,OANID,EAAY,OAAO,IAAI,EACtB,QAAQ,IAAI,EAEbA,EAAY,KAAK,aAAaV,EAAgB,EAAE,EAC/C,KAAK,gBAAgBA,CAAc,EAEjC,OAAO,IAAI,CACpB,CACF,CAAC,EAMD,IAAMY,EAAkB,QAAQ,UAAU,QAa1C,MAXA,SAAQ,UAAU,QAAU,SAAyB,EAA4B,CAG/E,OAFIC,IAAc,gBAAwB,KAAK,aAAab,CAAc,EAEnEY,EAAgB,KAAK,KAAMC,CAAS,CAG7C,EACAd,EAAU,SAAW,CACnB,QAAQ,UAAU,QAAUa,CAC9B,CAAC,MAEY,CACX,IAAK,IAAME,KAAWf,EAAWe,EAAQ,EAEzC,EAAU,OAAS,EACnB,EAASjB,GAAkB,EAC7B,CACF,E"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * jsdom implements none of the Popover API (`jsdom#3721`): no `showPopover`/`hidePopover`/
3
+ * `togglePopover`, no `popover` IDL attribute, and — the part that silently breaks suites — its
4
+ * selector engine treats `:popover-open` as a documented no-op that never matches.
5
+ *
6
+ * A partial shim (just setting the `popover-open` attribute) is worse than no shim, because every
7
+ * component in the repo guards its calls the idiomatic way:
8
+ *
9
+ * ```ts
10
+ * if (!panel.matches(':popover-open')) panel.showPopover();
11
+ * if (panel.matches(':popover-open')) panel.hidePopover();
12
+ * ```
13
+ *
14
+ * With `:popover-open` permanently false, `showPopover` runs twice and `hidePopover` never runs at
15
+ * all: overlays open and can never close, and the failure looks like a component bug rather than an
16
+ * environment gap. jsdom's UA stylesheet also keeps every `[popover]` element at
17
+ * `display: none` (nothing matches `:popover-open` to lift it), and jsdom's focus algorithm refuses
18
+ * to focus anything with a `display: none` flat-tree ancestor — so focusing an item inside an open
19
+ * panel silently does nothing.
20
+ *
21
+ * This shim closes all three gaps: it tracks open state in the `popover-open` attribute (the same
22
+ * attribute real browsers reflect, so tests can still assert on it), makes `matches(':popover-open')`
23
+ * answer from that state, and holds the element visible with an inline `display` while open —
24
+ * inline styles are the only author-level declaration that beats jsdom's UA rule, since component
25
+ * styles live in adopted style sheets that jsdom does not cascade at all.
26
+ *
27
+ * Known simplifications, deliberate because nothing in the repo depends on them: no light-dismiss
28
+ * behavior (`manual` is the only mode any component uses, and it has none), no top-layer ordering,
29
+ * and no `beforetoggle`/`toggle` events. A suite that starts listening for those needs them added
30
+ * here, not worked around per test.
31
+ *
32
+ * Call this from a test setup when the suite mounts popover-based components: the patches are global
33
+ * monkey-patches, so suites without them shouldn't pay for them. Returns an `uninstall()` restoring
34
+ * every patched global.
35
+ *
36
+ * Lives in Assay because the gap is in jsdom, not in any package's feature, and Assay is the repo's
37
+ * home for DOM test-environment helpers (see `installFormInternalsPolyfill`). Consumer packages get
38
+ * it from here instead of keeping per-file copies that drift out of sync with the API.
39
+ */
40
+ export declare const installPopoverPolyfill: () => (() => void);
41
+ //# sourceMappingURL=popover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popover.d.ts","sourceRoot":"","sources":["../src/popover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,sBAAsB,QAAO,CAAC,MAAM,IAAI,CAqIpD,CAAC"}
@@ -0,0 +1,49 @@
1
+ // src/popover.ts
2
+ var installPopoverPolyfill = () => {
3
+ if (typeof HTMLElement > "u") return () => {};
4
+ let e = Symbol.for("vielzeug.assay.popoverPolyfillInstalled"), t = globalThis;
5
+ if (t[e]) return () => {};
6
+ t[e] = !0;
7
+ let n = [], r = "popover-open", isOpen = (e) => e.hasAttribute(r), i = /* @__PURE__ */ new WeakMap(), reveal = (e) => {
8
+ let t = e.ownerDocument?.defaultView;
9
+ t && t.getComputedStyle(e).display === "none" && (i.has(e) || i.set(e, e.style.getPropertyValue("display")), e.style.setProperty("display", "block"));
10
+ }, conceal = (e) => {
11
+ if (!i.has(e)) return;
12
+ let t = i.get(e);
13
+ i.delete(e), t ? e.style.setProperty("display", t) : e.style.removeProperty("display");
14
+ }, requirePopoverAttribute = (e, t) => {
15
+ if (!e.hasAttribute("popover")) throw new DOMException(`Failed to execute '${t}' on 'HTMLElement': the element does not have a popover attribute.`, "InvalidStateError");
16
+ }, a = HTMLElement.prototype, patchProto = (e, t) => {
17
+ e in a || (Object.defineProperty(a, e, t), n.push(() => delete a[e]));
18
+ };
19
+ patchProto("showPopover", {
20
+ configurable: !0,
21
+ value: function(e) {
22
+ requirePopoverAttribute(this, "showPopover"), (!isOpen(this) || e?.force) && (reveal(this), this.setAttribute(r, ""));
23
+ }
24
+ }), patchProto("hidePopover", {
25
+ configurable: !0,
26
+ value: function() {
27
+ requirePopoverAttribute(this, "hidePopover"), isOpen(this) && (this.removeAttribute(r), conceal(this));
28
+ }
29
+ }), patchProto("togglePopover", {
30
+ configurable: !0,
31
+ value: function(e) {
32
+ requirePopoverAttribute(this, "togglePopover");
33
+ let t = e ?? !isOpen(this);
34
+ return t ? reveal(this) : conceal(this), t ? this.setAttribute(r, "") : this.removeAttribute(r), isOpen(this);
35
+ }
36
+ });
37
+ let o = Element.prototype.matches;
38
+ return Element.prototype.matches = function(e) {
39
+ return e === ":popover-open" ? this.hasAttribute(r) : o.call(this, e);
40
+ }, n.push(() => {
41
+ Element.prototype.matches = o;
42
+ }), () => {
43
+ for (let e of n) e();
44
+ n.length = 0, t[e] = !1;
45
+ };
46
+ };
47
+ export { installPopoverPolyfill };
48
+
49
+ //# sourceMappingURL=popover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popover.js","names":["INSTALLED_FLAG","flagHost","restorers","OPEN_ATTRIBUTE","element","displayBeforeOpen","view","before","method","proto","name","descriptor","options","shouldOpen","force","originalMatches","selectors","restore"],"sources":["../src/popover.ts"],"sourcesContent":["/**\n * jsdom implements none of the Popover API (`jsdom#3721`): no `showPopover`/`hidePopover`/\n * `togglePopover`, no `popover` IDL attribute, and — the part that silently breaks suites — its\n * selector engine treats `:popover-open` as a documented no-op that never matches.\n *\n * A partial shim (just setting the `popover-open` attribute) is worse than no shim, because every\n * component in the repo guards its calls the idiomatic way:\n *\n * ```ts\n * if (!panel.matches(':popover-open')) panel.showPopover();\n * if (panel.matches(':popover-open')) panel.hidePopover();\n * ```\n *\n * With `:popover-open` permanently false, `showPopover` runs twice and `hidePopover` never runs at\n * all: overlays open and can never close, and the failure looks like a component bug rather than an\n * environment gap. jsdom's UA stylesheet also keeps every `[popover]` element at\n * `display: none` (nothing matches `:popover-open` to lift it), and jsdom's focus algorithm refuses\n * to focus anything with a `display: none` flat-tree ancestor — so focusing an item inside an open\n * panel silently does nothing.\n *\n * This shim closes all three gaps: it tracks open state in the `popover-open` attribute (the same\n * attribute real browsers reflect, so tests can still assert on it), makes `matches(':popover-open')`\n * answer from that state, and holds the element visible with an inline `display` while open —\n * inline styles are the only author-level declaration that beats jsdom's UA rule, since component\n * styles live in adopted style sheets that jsdom does not cascade at all.\n *\n * Known simplifications, deliberate because nothing in the repo depends on them: no light-dismiss\n * behavior (`manual` is the only mode any component uses, and it has none), no top-layer ordering,\n * and no `beforetoggle`/`toggle` events. A suite that starts listening for those needs them added\n * here, not worked around per test.\n *\n * Call this from a test setup when the suite mounts popover-based components: the patches are global\n * monkey-patches, so suites without them shouldn't pay for them. Returns an `uninstall()` restoring\n * every patched global.\n *\n * Lives in Assay because the gap is in jsdom, not in any package's feature, and Assay is the repo's\n * home for DOM test-environment helpers (see `installFormInternalsPolyfill`). Consumer packages get\n * it from here instead of keeping per-file copies that drift out of sync with the API.\n */\nexport const installPopoverPolyfill = (): (() => void) => {\n if (typeof HTMLElement === 'undefined') return () => {};\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.assay.popoverPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return () => {};\n\n flagHost[INSTALLED_FLAG] = true;\n\n // Every patch pushes its inverse here, so uninstall() restores the environment exactly.\n const restorers: Array<() => void> = [];\n\n const OPEN_ATTRIBUTE = 'popover-open';\n\n const isOpen = (element: HTMLElement): boolean => element.hasAttribute(OPEN_ATTRIBUTE);\n\n // The inline `display` each element had before it was first shown, so hiding restores exactly\n // what was there rather than guessing. WeakMap: nothing outlives the element.\n const displayBeforeOpen = new WeakMap<HTMLElement, string>();\n\n const reveal = (element: HTMLElement): void => {\n const view = element.ownerDocument?.defaultView;\n\n // Only lift a `display: none` that is actually blocking the element. Overwriting an author-chosen\n // display (`grid` on a menu panel, `flex` on a card) would change layout the test is measuring.\n if (!view || view.getComputedStyle(element).display !== 'none') return;\n\n if (!displayBeforeOpen.has(element)) {\n displayBeforeOpen.set(element, element.style.getPropertyValue('display'));\n }\n\n element.style.setProperty('display', 'block');\n };\n\n const conceal = (element: HTMLElement): void => {\n if (!displayBeforeOpen.has(element)) return;\n\n const before = displayBeforeOpen.get(element) as string;\n\n displayBeforeOpen.delete(element);\n\n if (before) element.style.setProperty('display', before);\n else element.style.removeProperty('display');\n };\n\n const requirePopoverAttribute = (element: HTMLElement, method: string): void => {\n if (element.hasAttribute('popover')) return;\n\n // Matches the platform contract: showing or hiding an element that is not a popover is a\n // misuse bug, and throwing here surfaces it instead of letting the test pass quietly.\n throw new DOMException(\n `Failed to execute '${method}' on 'HTMLElement': the element does not have a popover attribute.`,\n 'InvalidStateError',\n );\n };\n\n // Same shape as `installFormInternalsPolyfill`: the prototype is patched through a plain record,\n // because these members are declared as always-present in lib.dom and this file's whole job is to\n // add them where they are absent.\n const proto = HTMLElement.prototype as unknown as Record<string, unknown>;\n\n const patchProto = (name: string, descriptor: PropertyDescriptor): void => {\n if (name in proto) return;\n\n Object.defineProperty(proto, name, descriptor);\n restorers.push(() => delete proto[name]);\n };\n\n patchProto('showPopover', {\n configurable: true,\n value: function (this: HTMLElement, options?: { source?: HTMLElement | null; force?: boolean }) {\n requirePopoverAttribute(this, 'showPopover');\n\n if (isOpen(this) && !options?.force) return;\n\n reveal(this);\n this.setAttribute(OPEN_ATTRIBUTE, '');\n },\n });\n\n patchProto('hidePopover', {\n configurable: true,\n value: function (this: HTMLElement) {\n requirePopoverAttribute(this, 'hidePopover');\n\n if (!isOpen(this)) return;\n\n this.removeAttribute(OPEN_ATTRIBUTE);\n conceal(this);\n },\n });\n\n patchProto('togglePopover', {\n configurable: true,\n value: function (this: HTMLElement, force?: boolean): boolean {\n requirePopoverAttribute(this, 'togglePopover');\n\n const shouldOpen = force ?? !isOpen(this);\n\n if (shouldOpen) reveal(this);\n else conceal(this);\n\n if (shouldOpen) this.setAttribute(OPEN_ATTRIBUTE, '');\n else this.removeAttribute(OPEN_ATTRIBUTE);\n\n return isOpen(this);\n },\n });\n\n // The guard every component wraps its calls in. dom-selector (jsdom's engine) stubs `:popover-open`\n // out as a permanent false, so without this `hidePopover` is unreachable from component code.\n // Intercepted by exact selector string: anything else, including `:not(:popover-open)` inside a\n // stylesheet, still goes through jsdom's own engine untouched.\n const originalMatches = Element.prototype.matches;\n\n Element.prototype.matches = function (this: Element, selectors: string): boolean {\n if (selectors === ':popover-open') return this.hasAttribute(OPEN_ATTRIBUTE);\n\n return originalMatches.call(this, selectors);\n // Cast: the interception only ever answers for one exact selector string, but the declared\n // member carries element-tag type predicates that a plain predicate cannot structurally satisfy.\n } as unknown as typeof Element.prototype.matches;\n restorers.push(() => {\n Element.prototype.matches = originalMatches;\n });\n\n return () => {\n for (const restore of restorers) restore();\n\n restorers.length = 0;\n flagHost[INSTALLED_FLAG] = false;\n };\n};\n"],"mappings":";AAuCA,IAAa,+BAA6C;CACxD,IAAI,OAAO,cAAgB,KAAa,aAAa,CAAC;CAEtD,IAAMA,IAAiB,OAAO,IAAI,yCAAyC,GACrEC,IAAW;CAEjB,IAAIA,EAASD,IAAiB,aAAa,CAAC;CAE5C,EAASA,KAAkB;CAG3B,IAAME,IAA+B,CAAC,GAEhCC,IAAiB,gBAEjB,UAAU,MAAkCC,EAAQ,aAAaD,CAAc,GAI/EE,oBAAoB,IAAI,QAA6B,GAErD,UAAU,MAA+B;EAC7C,IAAMC,IAAOF,EAAQ,eAAe;EAIpC,AAAKE,KAAQA,EAAK,iBAAiBF,CAAO,CAAC,CAAC,YAAY,WAEnDC,EAAkB,IAAID,CAAO,KAChCC,EAAkB,IAAID,GAASA,EAAQ,MAAM,iBAAiB,SAAS,CAAC,GAG1EA,EAAQ,MAAM,YAAY,WAAW,OAAO;CAC9C,GAEM,WAAW,MAA+B;EAC9C,IAAI,CAACC,EAAkB,IAAID,CAAO,GAAG;EAErC,IAAMG,IAASF,EAAkB,IAAID,CAAO;EAI5C,AAFAC,EAAkB,OAAOD,CAAO,GAE5BG,IAAQH,EAAQ,MAAM,YAAY,WAAWG,CAAM,IAClDH,EAAQ,MAAM,eAAe,SAAS;CAC7C,GAEM,2BAA2B,GAAsB,MAAyB;EAC9E,IAAI,GAAQ,aAAa,SAAS,GAIlC,MAAM,IAAI,aACR,sBAAsBI,EAAO,qEAC7B,mBACF;CACF,GAKMC,IAAQ,YAAY,WAEpB,cAAc,GAAc,MAAyC;EACzE,AAAIC,KAAQD,MAEZ,OAAO,eAAeA,GAAOC,GAAMC,CAAU,GAC7CT,EAAU,WAAW,OAAOO,EAAMC,EAAK;CACzC;CA0BA,AAxBA,WAAW,eAAe;EACxB,cAAc;EACd,OAAO,SAA6B,GAA4D;GAG9F,AAFA,wBAAwB,MAAM,aAAa,IAEvC,QAAO,IAAI,KAAME,GAAS,WAE9B,OAAO,IAAI,GACX,KAAK,aAAaT,GAAgB,EAAE;EACtC;CACF,CAAC,GAED,WAAW,eAAe;EACxB,cAAc;EACd,OAAO,WAA6B;GAGlC,AAFA,wBAAwB,MAAM,aAAa,GAEtC,OAAO,IAAI,MAEhB,KAAK,gBAAgBA,CAAc,GACnC,QAAQ,IAAI;EACd;CACF,CAAC,GAED,WAAW,iBAAiB;EAC1B,cAAc;EACd,OAAO,SAA6B,GAA0B;GAC5D,wBAAwB,MAAM,eAAe;GAE7C,IAAMU,IAAaC,KAAS,CAAC,OAAO,IAAI;GAQxC,OANID,IAAY,OAAO,IAAI,IACtB,QAAQ,IAAI,GAEbA,IAAY,KAAK,aAAaV,GAAgB,EAAE,IAC/C,KAAK,gBAAgBA,CAAc,GAEjC,OAAO,IAAI;EACpB;CACF,CAAC;CAMD,IAAMY,IAAkB,QAAQ,UAAU;CAa1C,OAXA,QAAQ,UAAU,UAAU,SAAyB,GAA4B;EAG/E,OAFIC,MAAc,kBAAwB,KAAK,aAAab,CAAc,IAEnEY,EAAgB,KAAK,MAAMC,CAAS;CAG7C,GACAd,EAAU,WAAW;EACnB,QAAQ,UAAU,UAAUa;CAC9B,CAAC,SAEY;EACX,KAAK,IAAME,KAAWf,GAAW,EAAQ;EAGzC,AADA,EAAU,SAAS,GACnB,EAASF,KAAkB;CAC7B;AACF"}
package/dist/query.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AssayQueryError as e } from "./errors.js";
2
- //#region src/query.ts
2
+ // src/query.ts
3
3
  var describeRoot = (e) => e instanceof Element ? e.outerHTML.slice(0, 500) : e instanceof ShadowRoot ? `<shadow-root>${e.innerHTML.slice(0, 500)}</shadow-root>` : e.nodeName, requireMatch = (t, n, r) => {
4
4
  if (t) return t;
5
5
  throw new e(`Unable to find ${n} within ${describeRoot(r)}.`);
@@ -32,7 +32,6 @@ function within(e) {
32
32
  queryByText: (t, n = "*") => queryByText(e, t, n)
33
33
  };
34
34
  }
35
- //#endregion
36
35
  export { getSlotted, queryAllInShadow, queryInShadow, queryPart, within };
37
36
 
38
37
  //# sourceMappingURL=query.js.map
package/dist/wait.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AssayTimeoutError as e } from "./errors.js";
2
2
  import { abortError as t, sleep as n } from "@vielzeug/arsenal";
3
- //#region src/wait.ts
3
+ // src/wait.ts
4
4
  var r = Symbol("assay.deadline"), i = 2147483647, now = () => performance.now(), validateDuration = (e, t, n) => {
5
5
  if (!Number.isFinite(t) || t > i || (n ? t < 0 : t <= 0)) throw RangeError(`${e} must be a ${n ? "non-negative" : "positive"} finite number no greater than ${i}`);
6
6
  }, validateWait = (e, t) => {
@@ -81,7 +81,6 @@ function waitForEvent(n, r, { signal: i, timeout: a = 1e3 } = {}) {
81
81
  n.addEventListener(r, onEvent, { once: !0 }), i?.addEventListener("abort", onAbort, { once: !0 });
82
82
  });
83
83
  }
84
- //#endregion
85
84
  export { delay, eventually, waitForEvent, waitUntil };
86
85
 
87
86
  //# sourceMappingURL=wait.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/assay",
3
- "version": "26.11.4",
3
+ "version": "26.11.6",
4
4
  "description": "Framework-agnostic DOM testing primitives: scoped queries, event dispatch, async waiting",
5
5
  "repository": {
6
6
  "type": "git",
@@ -31,24 +31,24 @@
31
31
  "registry": "https://registry.npmjs.org/"
32
32
  },
33
33
  "scripts": {
34
- "build": "vite build && pnpm --silent run build:bundle && pnpm --silent run build:types && pnpm --silent run verify:exports",
34
+ "build": "vite build && bun run --silent build:bundle && bun run --silent build:types && bun run --silent verify:exports",
35
35
  "build:bundle": "vite build --config vite.bundle.config.ts",
36
36
  "build:types": "tsc -p tsconfig.declarations.json",
37
37
  "fix": "biome check --write src",
38
38
  "lint": "biome ci src",
39
- "prepublishOnly": "pnpm --silent run build",
39
+ "prepublishOnly": "bun run --silent build",
40
40
  "preview": "vite preview",
41
41
  "test": "vitest",
42
- "verify:exports": "node verify-exports.mjs"
42
+ "verify:exports": "bun verify-exports.mjs"
43
43
  },
44
44
  "dependencies": {
45
- "@vielzeug/arsenal": "26.11.4"
45
+ "@vielzeug/arsenal": "26.11.6"
46
46
  },
47
47
  "devDependencies": {
48
- "@types/node": "^26.6.5",
49
- "jsdom": "^30.1.3",
48
+ "@types/node": "^26.6.6",
49
+ "jsdom": "^31.0.0",
50
50
  "typescript": "^6.0.3",
51
- "vite": "^8.3.4",
52
- "vitest": "^5.0.5"
51
+ "vite": "^8.3.6",
52
+ "vitest": "^5.1.0"
53
53
  }
54
54
  }