@vielzeug/assay 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assay.cjs +1 -1
- package/dist/assay.cjs.map +1 -1
- package/dist/assay.iife.js +1 -1
- package/dist/assay.iife.js.map +1 -1
- package/dist/assay.js +1 -1
- package/dist/assay.js.map +1 -1
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +0 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -4
- package/dist/errors.js.map +1 -1
- package/dist/events.cjs +1 -1
- package/dist/events.cjs.map +1 -1
- package/dist/events.d.ts +1 -4
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/query.cjs.map +1 -1
- package/dist/query.d.ts +4 -4
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js.map +1 -1
- package/dist/wait.cjs.map +1 -1
- package/dist/wait.d.ts +2 -2
- package/dist/wait.d.ts.map +1 -1
- package/dist/wait.js.map +1 -1
- package/package.json +22 -18
- package/dist/_dev.d.ts +0 -2
- package/dist/_dev.d.ts.map +0 -1
package/dist/assay.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{},n=class extends e{},r=(e,t)=>e.dispatchEvent(t),i=(e,t={})=>r(e,new FocusEvent(`blur`,t)),a=(e,t={})=>r(e,new Event(`change`,{bubbles:!0,...t})),o=(e,t={})=>r(e,new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...t})),s=(e,t,n={})=>r(e,new CustomEvent(t,{bubbles:!0,cancelable:!0,composed:!1,...n})),c=(e,t={})=>r(e,new FocusEvent(`focus`,t)),l=(e,t={})=>r(e,new InputEvent(`input`,{bubbles:!0,...t})),u=(e,t={})=>r(e,new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...t})),d=(e,t={})=>r(e,new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...t})),f=(e,t={})=>r(e,new SubmitEvent(`submit`,{bubbles:!0,cancelable:!0,...t})),p=e=>e instanceof Element?e.outerHTML.slice(0,500):e instanceof ShadowRoot?`<shadow-root>${e.innerHTML.slice(0,500)}</shadow-root>`:e.nodeName,m=(e,n,r)=>{if(e)return e;throw new t(`Unable to find ${n} within ${p(r)}.`)},h=(e,t)=>e.querySelector(t),g=(e,t)=>Array.from(e.querySelectorAll(t)),_=(e,t)=>g(e,`[data-testid]`).find(e=>e.getAttribute(`data-testid`)===t)??null,v=(e,t)=>g(e,`[data-testid]`).filter(e=>e.getAttribute(`data-testid`)===t),y=(e,t,n=`*`)=>{for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null},b=(e,t,n=`*`)=>Array.from(e.querySelectorAll(n)).filter(e=>e.textContent?.trim()===t);function x(e,t){return e.shadowRoot?h(e.shadowRoot,t):null}function S(e,t){return e.shadowRoot?g(e.shadowRoot,t):[]}function C(e,t){return S(e,`[part]`).find(e=>e.getAttribute(`part`)?.split(/\s+/).includes(t))??null}function w(e,t){return Array.from(e.children).filter(e=>t===void 0?!e.getAttribute(`slot`):e.getAttribute(`slot`)===t)}function T(e){return{get:t=>m(h(e,t),`"${t}"`,e),getByTestId:t=>m(_(e,t),`data-testid "${t}"`,e),getByText:(t,n=`*`)=>m(y(e,t,n),`text "${t}" matching "${n}"`,e),query:t=>h(e,t),queryAll:t=>g(e,t),queryAllByTestId:t=>v(e,t),queryAllByText:(t,n=`*`)=>b(e,t,n),queryByTestId:t=>_(e,t),queryByText:(t,n=`*`)=>y(e,t,n)}}var E=e=>e.reason??new DOMException(`The operation was aborted.`,`AbortError`),D=(e=0,{signal:t}={})=>new Promise((n,r)=>{if(t?.aborted){r(E(t));return}let i=setTimeout(a,e);function a(){t?.removeEventListener(`abort`,o),n()}function o(){clearTimeout(i),r(E(t))}t?.addEventListener(`abort`,o,{once:!0})});async function O(e,{interval:t=50,signal:r,timeout:i=1e3}={}){let a=Date.now()+i;for(;;){if(r?.aborted)throw E(r);if(await e())return;if(Date.now()>=a)break;await D(t,{signal:r})}throw new n(`waitUntil timed out after ${i}ms`)}async function k(e,{interval:t=50,message:r,signal:i,timeout:a=1e3}={}){let o=Date.now()+a,s;for(;;){if(i?.aborted)throw E(i);try{await e();return}catch(e){s=e}if(Date.now()>=o)break;await D(t,{signal:i})}let c=`retry timed out after ${a}ms`,l=r?`${r} (${c})`:c,u=s instanceof Error?s.message:s==null?``:String(s);throw new n(u?`${l}\n${u}`:l,{cause:s})}function A(e,t,{signal:r,timeout:i=1e3}={}){return new Promise((a,o)=>{if(r?.aborted){o(E(r));return}let s=()=>{clearTimeout(l),r?.removeEventListener(`abort`,u),e.removeEventListener(t,c)},c=e=>{s(),a(e)},l=setTimeout(()=>{s(),o(new n(`waitForEvent: "${t}" timed out after ${i}ms`))},i),u=()=>{s(),o(E(r))};e.addEventListener(t,c,{once:!0}),r?.addEventListener(`abort`,u,{once:!0})})}var j=()=>new Promise(e=>{queueMicrotask(e)});exports.AssayError=e,exports.AssayQueryError=t,exports.AssayTimeoutError=n,exports.delay=D,exports.dispatch=r,exports.fireBlur=i,exports.fireChange=a,exports.fireClick=o,exports.fireCustom=s,exports.fireFocus=c,exports.fireInput=l,exports.fireKeyDown=u,exports.fireKeyUp=d,exports.fireSubmit=f,exports.getSlotted=w,exports.nextTick=j,exports.queryAllInShadow=S,exports.queryInShadow=x,exports.queryPart=C,exports.retry=k,exports.waitForEvent=A,exports.waitUntil=O,exports.within=T;
|
|
2
2
|
//# sourceMappingURL=assay.cjs.map
|
package/dist/assay.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assay.cjs","names":[],"sources":["../src/errors.ts","../src/events.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/** 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 static is(err: unknown): err is AssayError {\n return err instanceof AssayError;\n }\n}\n\n/** Thrown when a required query has no match. */\nexport class AssayQueryError extends AssayError {}\n\n/** Thrown by `waitUntil`/`retry`/`waitForEvent` when the timeout elapses. */\nexport class AssayTimeoutError extends AssayError {}\n","/** Synchronous, exact DOM event dispatchers for test environments. */\n\n/** Dispatch an event instance without modifying it. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\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 interface CustomEventOptions<T> extends CustomEventInit<T> {\n type: string;\n}\n\nexport const fireCustom = <T>(target: EventTarget, { type, ...init }: CustomEventOptions<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 { 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 query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n getByText<E extends Element = Element>(text: string, selector?: string): E;\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n getByTestId<E extends Element = Element>(testId: string): E;\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\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 el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] => {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n};\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 { AssayTimeoutError } from './errors';\n\nexport interface WaitOptions {\n /** Cancel the pending wait. */\n signal?: AbortSignal;\n /** Maximum wait time in ms (default: 1000). */\n timeout?: number;\n /** Polling interval in ms (default: 50). */\n interval?: number;\n}\n\nexport interface RetryOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nexport interface DelayOptions {\n /** Cancel the pending delay. */\n signal?: AbortSignal;\n}\n\nconst abortReason = (signal: AbortSignal): unknown =>\n signal.reason ?? new DOMException('The operation was aborted.', 'AbortError');\n\n/**\n * Resolve after `ms` milliseconds. Rejects with the abort reason when cancelled.\n */\nexport const delay = (ms = 0, { signal }: DelayOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const timer = setTimeout(done, ms);\n\n function done(): void {\n signal?.removeEventListener('abort', abort);\n resolve();\n }\n\n function abort(): void {\n clearTimeout(timer);\n reject(abortReason(signal!));\n }\n\n signal?.addEventListener('abort', abort, { once: true });\n });\n\n/** Poll until a synchronous or asynchronous predicate returns `true`. */\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n if (await predicate()) return;\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n}\n\n/** Retry an assertion until it stops throwing. */\nexport async function retry(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: RetryOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n try {\n await assertion();\n\n return;\n } catch (error) {\n lastError = error;\n }\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n const timing = `retry 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 return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (e: Event): void => {\n dispose();\n resolve(e 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(abortReason(signal!));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/** Resolve after one microtask tick. */\nexport const nextTick = (): Promise<void> =>\n new Promise((resolve) => {\n queueMicrotask(resolve);\n });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"assay.cjs","names":[],"sources":["../src/errors.ts","../src/events.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/** 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 by `waitUntil`/`retry`/`waitForEvent` when the timeout elapses. */\nexport class AssayTimeoutError extends AssayError {}\n","/** Synchronous, exact DOM event dispatchers for test environments. */\n\n/** Dispatch an event instance without modifying it. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\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 { 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 el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] => {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n};\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 { AssayTimeoutError } from './errors';\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 RetryOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nexport interface DelayOptions {\n /** Cancel the pending delay. */\n signal?: AbortSignal;\n}\n\nconst abortReason = (signal: AbortSignal): unknown =>\n signal.reason ?? new DOMException('The operation was aborted.', 'AbortError');\n\n/**\n * Resolve after `ms` milliseconds. Rejects with the abort reason when cancelled.\n */\nexport const delay = (ms = 0, { signal }: DelayOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const timer = setTimeout(done, ms);\n\n function done(): void {\n signal?.removeEventListener('abort', abort);\n resolve();\n }\n\n function abort(): void {\n clearTimeout(timer);\n reject(abortReason(signal!));\n }\n\n signal?.addEventListener('abort', abort, { once: true });\n });\n\n/** Poll until a synchronous or asynchronous predicate returns `true`. */\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n if (await predicate()) return;\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n}\n\n/** Retry an assertion until it stops throwing. */\nexport async function retry(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: RetryOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n try {\n await assertion();\n\n return;\n } catch (error) {\n lastError = error;\n }\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n const timing = `retry 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 return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (e: Event): void => {\n dispose();\n resolve(e 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(abortReason(signal!));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/** Resolve after one microtask tick. */\nexport const nextTick = (): Promise<void> =>\n new Promise((resolve) => {\n queueMicrotask(resolve);\n });\n"],"mappings":"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"}
|
package/dist/assay.iife.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var Assay=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=class
|
|
1
|
+
var Assay=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{},r=class extends t{},i=(e,t)=>e.dispatchEvent(t),a=(e,t={})=>i(e,new FocusEvent(`blur`,t)),o=(e,t={})=>i(e,new Event(`change`,{bubbles:!0,...t})),s=(e,t={})=>i(e,new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...t})),c=(e,t,n={})=>i(e,new CustomEvent(t,{bubbles:!0,cancelable:!0,composed:!1,...n})),l=(e,t={})=>i(e,new FocusEvent(`focus`,t)),u=(e,t={})=>i(e,new InputEvent(`input`,{bubbles:!0,...t})),d=(e,t={})=>i(e,new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...t})),f=(e,t={})=>i(e,new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...t})),p=(e,t={})=>i(e,new SubmitEvent(`submit`,{bubbles:!0,cancelable:!0,...t})),m=e=>e instanceof Element?e.outerHTML.slice(0,500):e instanceof ShadowRoot?`<shadow-root>${e.innerHTML.slice(0,500)}</shadow-root>`:e.nodeName,h=(e,t,r)=>{if(e)return e;throw new n(`Unable to find ${t} within ${m(r)}.`)},g=(e,t)=>e.querySelector(t),_=(e,t)=>Array.from(e.querySelectorAll(t)),v=(e,t)=>_(e,`[data-testid]`).find(e=>e.getAttribute(`data-testid`)===t)??null,y=(e,t)=>_(e,`[data-testid]`).filter(e=>e.getAttribute(`data-testid`)===t),b=(e,t,n=`*`)=>{for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null},x=(e,t,n=`*`)=>Array.from(e.querySelectorAll(n)).filter(e=>e.textContent?.trim()===t);function S(e,t){return e.shadowRoot?g(e.shadowRoot,t):null}function C(e,t){return e.shadowRoot?_(e.shadowRoot,t):[]}function w(e,t){return C(e,`[part]`).find(e=>e.getAttribute(`part`)?.split(/\s+/).includes(t))??null}function T(e,t){return Array.from(e.children).filter(e=>t===void 0?!e.getAttribute(`slot`):e.getAttribute(`slot`)===t)}function E(e){return{get:t=>h(g(e,t),`"${t}"`,e),getByTestId:t=>h(v(e,t),`data-testid "${t}"`,e),getByText:(t,n=`*`)=>h(b(e,t,n),`text "${t}" matching "${n}"`,e),query:t=>g(e,t),queryAll:t=>_(e,t),queryAllByTestId:t=>y(e,t),queryAllByText:(t,n=`*`)=>x(e,t,n),queryByTestId:t=>v(e,t),queryByText:(t,n=`*`)=>b(e,t,n)}}var D=e=>e.reason??new DOMException(`The operation was aborted.`,`AbortError`),O=(e=0,{signal:t}={})=>new Promise((n,r)=>{if(t?.aborted){r(D(t));return}let i=setTimeout(a,e);function a(){t?.removeEventListener(`abort`,o),n()}function o(){clearTimeout(i),r(D(t))}t?.addEventListener(`abort`,o,{once:!0})});async function k(e,{interval:t=50,signal:n,timeout:i=1e3}={}){let a=Date.now()+i;for(;;){if(n?.aborted)throw D(n);if(await e())return;if(Date.now()>=a)break;await O(t,{signal:n})}throw new r(`waitUntil timed out after ${i}ms`)}async function A(e,{interval:t=50,message:n,signal:i,timeout:a=1e3}={}){let o=Date.now()+a,s;for(;;){if(i?.aborted)throw D(i);try{await e();return}catch(e){s=e}if(Date.now()>=o)break;await O(t,{signal:i})}let c=`retry timed out after ${a}ms`,l=n?`${n} (${c})`:c,u=s instanceof Error?s.message:s==null?``:String(s);throw new r(u?`${l}\n${u}`:l,{cause:s})}function j(e,t,{signal:n,timeout:i=1e3}={}){return new Promise((a,o)=>{if(n?.aborted){o(D(n));return}let s=()=>{clearTimeout(l),n?.removeEventListener(`abort`,u),e.removeEventListener(t,c)},c=e=>{s(),a(e)},l=setTimeout(()=>{s(),o(new r(`waitForEvent: "${t}" timed out after ${i}ms`))},i),u=()=>{s(),o(D(n))};e.addEventListener(t,c,{once:!0}),n?.addEventListener(`abort`,u,{once:!0})})}return e.AssayError=t,e.AssayQueryError=n,e.AssayTimeoutError=r,e.delay=O,e.dispatch=i,e.fireBlur=a,e.fireChange=o,e.fireClick=s,e.fireCustom=c,e.fireFocus=l,e.fireInput=u,e.fireKeyDown=d,e.fireKeyUp=f,e.fireSubmit=p,e.getSlotted=T,e.nextTick=()=>new Promise(e=>{queueMicrotask(e)}),e.queryAllInShadow=C,e.queryInShadow=S,e.queryPart=w,e.retry=A,e.waitForEvent=j,e.waitUntil=k,e.within=E,e})({});
|
|
2
2
|
//# sourceMappingURL=assay.iife.js.map
|
package/dist/assay.iife.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assay.iife.js","names":[],"sources":["../src/errors.ts","../src/events.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/** 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 static is(err: unknown): err is AssayError {\n return err instanceof AssayError;\n }\n}\n\n/** Thrown when a required query has no match. */\nexport class AssayQueryError extends AssayError {}\n\n/** Thrown by `waitUntil`/`retry`/`waitForEvent` when the timeout elapses. */\nexport class AssayTimeoutError extends AssayError {}\n","/** Synchronous, exact DOM event dispatchers for test environments. */\n\n/** Dispatch an event instance without modifying it. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\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 interface CustomEventOptions<T> extends CustomEventInit<T> {\n type: string;\n}\n\nexport const fireCustom = <T>(target: EventTarget, { type, ...init }: CustomEventOptions<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 { 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 query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n getByText<E extends Element = Element>(text: string, selector?: string): E;\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n getByTestId<E extends Element = Element>(testId: string): E;\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\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 el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] => {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n};\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 { AssayTimeoutError } from './errors';\n\nexport interface WaitOptions {\n /** Cancel the pending wait. */\n signal?: AbortSignal;\n /** Maximum wait time in ms (default: 1000). */\n timeout?: number;\n /** Polling interval in ms (default: 50). */\n interval?: number;\n}\n\nexport interface RetryOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nexport interface DelayOptions {\n /** Cancel the pending delay. */\n signal?: AbortSignal;\n}\n\nconst abortReason = (signal: AbortSignal): unknown =>\n signal.reason ?? new DOMException('The operation was aborted.', 'AbortError');\n\n/**\n * Resolve after `ms` milliseconds. Rejects with the abort reason when cancelled.\n */\nexport const delay = (ms = 0, { signal }: DelayOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const timer = setTimeout(done, ms);\n\n function done(): void {\n signal?.removeEventListener('abort', abort);\n resolve();\n }\n\n function abort(): void {\n clearTimeout(timer);\n reject(abortReason(signal!));\n }\n\n signal?.addEventListener('abort', abort, { once: true });\n });\n\n/** Poll until a synchronous or asynchronous predicate returns `true`. */\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n if (await predicate()) return;\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n}\n\n/** Retry an assertion until it stops throwing. */\nexport async function retry(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: RetryOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n try {\n await assertion();\n\n return;\n } catch (error) {\n lastError = error;\n }\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n const timing = `retry 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 return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (e: Event): void => {\n dispose();\n resolve(e 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(abortReason(signal!));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/** Resolve after one microtask tick. */\nexport const nextTick = (): Promise<void> =>\n new Promise((resolve) => {\n queueMicrotask(resolve);\n });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"assay.iife.js","names":[],"sources":["../src/errors.ts","../src/events.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/** 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 by `waitUntil`/`retry`/`waitForEvent` when the timeout elapses. */\nexport class AssayTimeoutError extends AssayError {}\n","/** Synchronous, exact DOM event dispatchers for test environments. */\n\n/** Dispatch an event instance without modifying it. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\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 { 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 el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] => {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n};\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 { AssayTimeoutError } from './errors';\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 RetryOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nexport interface DelayOptions {\n /** Cancel the pending delay. */\n signal?: AbortSignal;\n}\n\nconst abortReason = (signal: AbortSignal): unknown =>\n signal.reason ?? new DOMException('The operation was aborted.', 'AbortError');\n\n/**\n * Resolve after `ms` milliseconds. Rejects with the abort reason when cancelled.\n */\nexport const delay = (ms = 0, { signal }: DelayOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const timer = setTimeout(done, ms);\n\n function done(): void {\n signal?.removeEventListener('abort', abort);\n resolve();\n }\n\n function abort(): void {\n clearTimeout(timer);\n reject(abortReason(signal!));\n }\n\n signal?.addEventListener('abort', abort, { once: true });\n });\n\n/** Poll until a synchronous or asynchronous predicate returns `true`. */\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n if (await predicate()) return;\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n}\n\n/** Retry an assertion until it stops throwing. */\nexport async function retry(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: RetryOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n try {\n await assertion();\n\n return;\n } catch (error) {\n lastError = error;\n }\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n const timing = `retry 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 return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (e: Event): void => {\n dispose();\n resolve(e 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(abortReason(signal!));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/** Resolve after one microtask tick. */\nexport const nextTick = (): Promise<void> =>\n new Promise((resolve) => {\n queueMicrotask(resolve);\n });\n"],"mappings":"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"}
|
package/dist/assay.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=class
|
|
1
|
+
var e=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{},n=class extends e{},r=(e,t)=>e.dispatchEvent(t),i=(e,t={})=>r(e,new FocusEvent(`blur`,t)),a=(e,t={})=>r(e,new Event(`change`,{bubbles:!0,...t})),o=(e,t={})=>r(e,new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...t})),s=(e,t,n={})=>r(e,new CustomEvent(t,{bubbles:!0,cancelable:!0,composed:!1,...n})),c=(e,t={})=>r(e,new FocusEvent(`focus`,t)),l=(e,t={})=>r(e,new InputEvent(`input`,{bubbles:!0,...t})),u=(e,t={})=>r(e,new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...t})),d=(e,t={})=>r(e,new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...t})),f=(e,t={})=>r(e,new SubmitEvent(`submit`,{bubbles:!0,cancelable:!0,...t})),p=e=>e instanceof Element?e.outerHTML.slice(0,500):e instanceof ShadowRoot?`<shadow-root>${e.innerHTML.slice(0,500)}</shadow-root>`:e.nodeName,m=(e,n,r)=>{if(e)return e;throw new t(`Unable to find ${n} within ${p(r)}.`)},h=(e,t)=>e.querySelector(t),g=(e,t)=>Array.from(e.querySelectorAll(t)),_=(e,t)=>g(e,`[data-testid]`).find(e=>e.getAttribute(`data-testid`)===t)??null,v=(e,t)=>g(e,`[data-testid]`).filter(e=>e.getAttribute(`data-testid`)===t),y=(e,t,n=`*`)=>{for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null},b=(e,t,n=`*`)=>Array.from(e.querySelectorAll(n)).filter(e=>e.textContent?.trim()===t);function x(e,t){return e.shadowRoot?h(e.shadowRoot,t):null}function S(e,t){return e.shadowRoot?g(e.shadowRoot,t):[]}function C(e,t){return S(e,`[part]`).find(e=>e.getAttribute(`part`)?.split(/\s+/).includes(t))??null}function w(e,t){return Array.from(e.children).filter(e=>t===void 0?!e.getAttribute(`slot`):e.getAttribute(`slot`)===t)}function T(e){return{get:t=>m(h(e,t),`"${t}"`,e),getByTestId:t=>m(_(e,t),`data-testid "${t}"`,e),getByText:(t,n=`*`)=>m(y(e,t,n),`text "${t}" matching "${n}"`,e),query:t=>h(e,t),queryAll:t=>g(e,t),queryAllByTestId:t=>v(e,t),queryAllByText:(t,n=`*`)=>b(e,t,n),queryByTestId:t=>_(e,t),queryByText:(t,n=`*`)=>y(e,t,n)}}var E=e=>e.reason??new DOMException(`The operation was aborted.`,`AbortError`),D=(e=0,{signal:t}={})=>new Promise((n,r)=>{if(t?.aborted){r(E(t));return}let i=setTimeout(a,e);function a(){t?.removeEventListener(`abort`,o),n()}function o(){clearTimeout(i),r(E(t))}t?.addEventListener(`abort`,o,{once:!0})});async function O(e,{interval:t=50,signal:r,timeout:i=1e3}={}){let a=Date.now()+i;for(;;){if(r?.aborted)throw E(r);if(await e())return;if(Date.now()>=a)break;await D(t,{signal:r})}throw new n(`waitUntil timed out after ${i}ms`)}async function k(e,{interval:t=50,message:r,signal:i,timeout:a=1e3}={}){let o=Date.now()+a,s;for(;;){if(i?.aborted)throw E(i);try{await e();return}catch(e){s=e}if(Date.now()>=o)break;await D(t,{signal:i})}let c=`retry timed out after ${a}ms`,l=r?`${r} (${c})`:c,u=s instanceof Error?s.message:s==null?``:String(s);throw new n(u?`${l}\n${u}`:l,{cause:s})}function A(e,t,{signal:r,timeout:i=1e3}={}){return new Promise((a,o)=>{if(r?.aborted){o(E(r));return}let s=()=>{clearTimeout(l),r?.removeEventListener(`abort`,u),e.removeEventListener(t,c)},c=e=>{s(),a(e)},l=setTimeout(()=>{s(),o(new n(`waitForEvent: "${t}" timed out after ${i}ms`))},i),u=()=>{s(),o(E(r))};e.addEventListener(t,c,{once:!0}),r?.addEventListener(`abort`,u,{once:!0})})}var j=()=>new Promise(e=>{queueMicrotask(e)});export{e as AssayError,t as AssayQueryError,n as AssayTimeoutError,D as delay,r as dispatch,i as fireBlur,a as fireChange,o as fireClick,s as fireCustom,c as fireFocus,l as fireInput,u as fireKeyDown,d as fireKeyUp,f as fireSubmit,w as getSlotted,j as nextTick,S as queryAllInShadow,x as queryInShadow,C as queryPart,k as retry,A as waitForEvent,O as waitUntil,T as within};
|
|
2
2
|
//# sourceMappingURL=assay.js.map
|
package/dist/assay.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assay.js","names":[],"sources":["../src/errors.ts","../src/events.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/** 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 static is(err: unknown): err is AssayError {\n return err instanceof AssayError;\n }\n}\n\n/** Thrown when a required query has no match. */\nexport class AssayQueryError extends AssayError {}\n\n/** Thrown by `waitUntil`/`retry`/`waitForEvent` when the timeout elapses. */\nexport class AssayTimeoutError extends AssayError {}\n","/** Synchronous, exact DOM event dispatchers for test environments. */\n\n/** Dispatch an event instance without modifying it. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\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 interface CustomEventOptions<T> extends CustomEventInit<T> {\n type: string;\n}\n\nexport const fireCustom = <T>(target: EventTarget, { type, ...init }: CustomEventOptions<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 { 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 query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n getByText<E extends Element = Element>(text: string, selector?: string): E;\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n getByTestId<E extends Element = Element>(testId: string): E;\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\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 el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] => {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n};\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 { AssayTimeoutError } from './errors';\n\nexport interface WaitOptions {\n /** Cancel the pending wait. */\n signal?: AbortSignal;\n /** Maximum wait time in ms (default: 1000). */\n timeout?: number;\n /** Polling interval in ms (default: 50). */\n interval?: number;\n}\n\nexport interface RetryOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nexport interface DelayOptions {\n /** Cancel the pending delay. */\n signal?: AbortSignal;\n}\n\nconst abortReason = (signal: AbortSignal): unknown =>\n signal.reason ?? new DOMException('The operation was aborted.', 'AbortError');\n\n/**\n * Resolve after `ms` milliseconds. Rejects with the abort reason when cancelled.\n */\nexport const delay = (ms = 0, { signal }: DelayOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const timer = setTimeout(done, ms);\n\n function done(): void {\n signal?.removeEventListener('abort', abort);\n resolve();\n }\n\n function abort(): void {\n clearTimeout(timer);\n reject(abortReason(signal!));\n }\n\n signal?.addEventListener('abort', abort, { once: true });\n });\n\n/** Poll until a synchronous or asynchronous predicate returns `true`. */\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n if (await predicate()) return;\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n}\n\n/** Retry an assertion until it stops throwing. */\nexport async function retry(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: RetryOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n try {\n await assertion();\n\n return;\n } catch (error) {\n lastError = error;\n }\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n const timing = `retry 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 return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (e: Event): void => {\n dispose();\n resolve(e 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(abortReason(signal!));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/** Resolve after one microtask tick. */\nexport const nextTick = (): Promise<void> =>\n new Promise((resolve) => {\n queueMicrotask(resolve);\n });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"assay.js","names":[],"sources":["../src/errors.ts","../src/events.ts","../src/query.ts","../src/wait.ts"],"sourcesContent":["/** 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 by `waitUntil`/`retry`/`waitForEvent` when the timeout elapses. */\nexport class AssayTimeoutError extends AssayError {}\n","/** Synchronous, exact DOM event dispatchers for test environments. */\n\n/** Dispatch an event instance without modifying it. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\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 { 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 el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] => {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n};\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 { AssayTimeoutError } from './errors';\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 RetryOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nexport interface DelayOptions {\n /** Cancel the pending delay. */\n signal?: AbortSignal;\n}\n\nconst abortReason = (signal: AbortSignal): unknown =>\n signal.reason ?? new DOMException('The operation was aborted.', 'AbortError');\n\n/**\n * Resolve after `ms` milliseconds. Rejects with the abort reason when cancelled.\n */\nexport const delay = (ms = 0, { signal }: DelayOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const timer = setTimeout(done, ms);\n\n function done(): void {\n signal?.removeEventListener('abort', abort);\n resolve();\n }\n\n function abort(): void {\n clearTimeout(timer);\n reject(abortReason(signal!));\n }\n\n signal?.addEventListener('abort', abort, { once: true });\n });\n\n/** Poll until a synchronous or asynchronous predicate returns `true`. */\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n if (await predicate()) return;\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n}\n\n/** Retry an assertion until it stops throwing. */\nexport async function retry(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: RetryOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n try {\n await assertion();\n\n return;\n } catch (error) {\n lastError = error;\n }\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n const timing = `retry 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 return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (e: Event): void => {\n dispose();\n resolve(e 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(abortReason(signal!));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/** Resolve after one microtask tick. */\nexport const nextTick = (): Promise<void> =>\n new Promise((resolve) => {\n queueMicrotask(resolve);\n });\n"],"mappings":"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"}
|
package/dist/errors.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=class
|
|
1
|
+
var e=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{},n=class extends e{};exports.AssayError=e,exports.AssayQueryError=t,exports.AssayTimeoutError=n;
|
|
2
2
|
//# sourceMappingURL=errors.cjs.map
|
package/dist/errors.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** 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
|
|
1
|
+
{"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** 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 by `waitUntil`/`retry`/`waitForEvent` when the timeout elapses. */\nexport class AssayTimeoutError extends AssayError {}\n"],"mappings":"AACA,IAAa,EAAb,cAAgC,KAAM,CACpC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAGa,EAAb,cAAqC,CAAW,CAAC,EAGpC,EAAb,cAAuC,CAAW,CAAC"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/** Base class for all Assay errors. Use `instanceof AssayError` to catch any Assay-originated error. */
|
|
2
2
|
export declare class AssayError extends Error {
|
|
3
3
|
constructor(message: string, opts?: ErrorOptions);
|
|
4
|
-
static is(err: unknown): err is AssayError;
|
|
5
4
|
}
|
|
6
5
|
/** Thrown when a required query has no match. */
|
|
7
6
|
export declare class AssayQueryError extends AssayError {
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wGAAwG;AACxG,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wGAAwG;AACxG,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAKjD;AAED,iDAAiD;AACjD,qBAAa,eAAgB,SAAQ,UAAU;CAAG;AAElD,6EAA6E;AAC7E,qBAAa,iBAAkB,SAAQ,UAAU;CAAG"}
|
package/dist/errors.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
//#region src/errors.ts
|
|
2
|
-
var e = class
|
|
2
|
+
var e = 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
|
-
static is(t) {
|
|
7
|
-
return t instanceof e;
|
|
8
|
-
}
|
|
9
6
|
}, t = class extends e {}, n = class extends e {};
|
|
10
7
|
//#endregion
|
|
11
8
|
export { e as AssayError, t as AssayQueryError, n as AssayTimeoutError };
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** 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
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** 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 by `waitUntil`/`retry`/`waitForEvent` when the timeout elapses. */\nexport class AssayTimeoutError extends AssayError {}\n"],"mappings":";AACA,IAAa,IAAb,cAAgC,MAAM;CACpC,YAAY,GAAiB,GAAqB;EAGhD,AAFA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,WAAW,MACvB,OAAO,eAAe,MAAM,WAAW,SAAS;CAClD;AACF,GAGa,IAAb,cAAqC,EAAW,CAAC,GAGpC,IAAb,cAAuC,EAAW,CAAC"}
|
package/dist/events.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=(e,t)=>e.dispatchEvent(t),t=(t,n={})=>e(t,new FocusEvent(`blur`,n)),n=(t,n={})=>e(t,new Event(`change`,{bubbles:!0,...n})),r=(t,n={})=>e(t,new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...n})),i=(t,
|
|
1
|
+
var e=(e,t)=>e.dispatchEvent(t),t=(t,n={})=>e(t,new FocusEvent(`blur`,n)),n=(t,n={})=>e(t,new Event(`change`,{bubbles:!0,...n})),r=(t,n={})=>e(t,new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...n})),i=(t,n,r={})=>e(t,new CustomEvent(n,{bubbles:!0,cancelable:!0,composed:!1,...r})),a=(t,n={})=>e(t,new FocusEvent(`focus`,n)),o=(t,n={})=>e(t,new InputEvent(`input`,{bubbles:!0,...n})),s=(t,n={})=>e(t,new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...n})),c=(t,n={})=>e(t,new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...n})),l=(t,n={})=>e(t,new SubmitEvent(`submit`,{bubbles:!0,cancelable:!0,...n}));exports.dispatch=e,exports.fireBlur=t,exports.fireChange=n,exports.fireClick=r,exports.fireCustom=i,exports.fireFocus=a,exports.fireInput=o,exports.fireKeyDown=s,exports.fireKeyUp=c,exports.fireSubmit=l;
|
|
2
2
|
//# sourceMappingURL=events.cjs.map
|
package/dist/events.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.cjs","names":[],"sources":["../src/events.ts"],"sourcesContent":["/** Synchronous, exact DOM event dispatchers for test environments. */\n\n/** Dispatch an event instance without modifying it. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\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
|
|
1
|
+
{"version":3,"file":"events.cjs","names":[],"sources":["../src/events.ts"],"sourcesContent":["/** Synchronous, exact DOM event dispatchers for test environments. */\n\n/** Dispatch an event instance without modifying it. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\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"],"mappings":"AAGA,IAAa,GAAY,EAAqB,IAA0B,EAAO,cAAc,CAAK,EAErF,GAAY,EAAqB,EAAuB,CAAC,IACpE,EAAS,EAAQ,IAAI,WAAW,OAAQ,CAAI,CAAC,EAElC,GAAc,EAAqB,EAAkB,CAAC,IACjE,EAAS,EAAQ,IAAI,MAAM,SAAU,CAAE,QAAS,GAAM,GAAG,CAAK,CAAC,CAAC,EAErD,GAAa,EAAqB,EAAuB,CAAC,IACrE,EAAS,EAAQ,IAAI,WAAW,QAAS,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAE3E,GAAiB,EAAqB,EAAc,EAA2B,CAAC,IAC3F,EAAS,EAAQ,IAAI,YAAY,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,SAAU,GAAO,GAAG,CAAK,CAAC,CAAC,EAE1F,GAAa,EAAqB,EAAuB,CAAC,IACrE,EAAS,EAAQ,IAAI,WAAW,QAAS,CAAI,CAAC,EAEnC,GAAa,EAAqB,EAAuB,CAAC,IACrE,EAAS,EAAQ,IAAI,WAAW,QAAS,CAAE,QAAS,GAAM,GAAG,CAAK,CAAC,CAAC,EAEzD,GAAe,EAAqB,EAA0B,CAAC,IAC1E,EAAS,EAAQ,IAAI,cAAc,UAAW,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAEhF,GAAa,EAAqB,EAA0B,CAAC,IACxE,EAAS,EAAQ,IAAI,cAAc,QAAS,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAE9E,GAAc,EAAqB,EAAwB,CAAC,IACvE,EAAS,EAAQ,IAAI,YAAY,SAAU,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC"}
|
package/dist/events.d.ts
CHANGED
|
@@ -4,10 +4,7 @@ export declare const dispatch: (target: EventTarget, event: Event) => boolean;
|
|
|
4
4
|
export declare const fireBlur: (target: EventTarget, init?: FocusEventInit) => boolean;
|
|
5
5
|
export declare const fireChange: (target: EventTarget, init?: EventInit) => boolean;
|
|
6
6
|
export declare const fireClick: (target: EventTarget, init?: MouseEventInit) => boolean;
|
|
7
|
-
export
|
|
8
|
-
type: string;
|
|
9
|
-
}
|
|
10
|
-
export declare const fireCustom: <T>(target: EventTarget, { type, ...init }: CustomEventOptions<T>) => boolean;
|
|
7
|
+
export declare const fireCustom: <T>(target: EventTarget, type: string, init?: CustomEventInit<T>) => boolean;
|
|
11
8
|
export declare const fireFocus: (target: EventTarget, init?: FocusEventInit) => boolean;
|
|
12
9
|
export declare const fireInput: (target: EventTarget, init?: InputEventInit) => boolean;
|
|
13
10
|
export declare const fireKeyDown: (target: EventTarget, init?: KeyboardEventInit) => boolean;
|
package/dist/events.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,uDAAuD;AACvD,eAAO,MAAM,QAAQ,GAAI,QAAQ,WAAW,EAAE,OAAO,KAAK,KAAG,OAAsC,CAAC;AAEpG,eAAO,MAAM,QAAQ,GAAI,QAAQ,WAAW,EAAE,OAAM,cAAmB,KAAG,OAC1B,CAAC;AAEjD,eAAO,MAAM,UAAU,GAAI,QAAQ,WAAW,EAAE,OAAM,SAAc,KAAG,OACJ,CAAC;AAEpE,eAAO,MAAM,SAAS,GAAI,QAAQ,WAAW,EAAE,OAAM,cAAmB,KAAG,OACc,CAAC;AAE1F,
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,uDAAuD;AACvD,eAAO,MAAM,QAAQ,GAAI,QAAQ,WAAW,EAAE,OAAO,KAAK,KAAG,OAAsC,CAAC;AAEpG,eAAO,MAAM,QAAQ,GAAI,QAAQ,WAAW,EAAE,OAAM,cAAmB,KAAG,OAC1B,CAAC;AAEjD,eAAO,MAAM,UAAU,GAAI,QAAQ,WAAW,EAAE,OAAM,SAAc,KAAG,OACJ,CAAC;AAEpE,eAAO,MAAM,SAAS,GAAI,QAAQ,WAAW,EAAE,OAAM,cAAmB,KAAG,OACc,CAAC;AAE1F,eAAO,MAAM,UAAU,GAAI,CAAC,EAAE,QAAQ,WAAW,EAAE,MAAM,MAAM,EAAE,OAAM,eAAe,CAAC,CAAC,CAAM,KAAG,OACO,CAAC;AAEzG,eAAO,MAAM,SAAS,GAAI,QAAQ,WAAW,EAAE,OAAM,cAAmB,KAAG,OAC1B,CAAC;AAElD,eAAO,MAAM,SAAS,GAAI,QAAQ,WAAW,EAAE,OAAM,cAAmB,KAAG,OACJ,CAAC;AAExE,eAAO,MAAM,WAAW,GAAI,QAAQ,WAAW,EAAE,OAAM,iBAAsB,KAAG,OACc,CAAC;AAE/F,eAAO,MAAM,SAAS,GAAI,QAAQ,WAAW,EAAE,OAAM,iBAAsB,KAAG,OACc,CAAC;AAE7F,eAAO,MAAM,UAAU,GAAI,QAAQ,WAAW,EAAE,OAAM,eAAoB,KAAG,OACc,CAAC"}
|
package/dist/events.js
CHANGED
|
@@ -6,7 +6,7 @@ var e = (e, t) => e.dispatchEvent(t), t = (t, n = {}) => e(t, new FocusEvent("bl
|
|
|
6
6
|
bubbles: !0,
|
|
7
7
|
cancelable: !0,
|
|
8
8
|
...n
|
|
9
|
-
})), i = (t,
|
|
9
|
+
})), i = (t, n, r = {}) => e(t, new CustomEvent(n, {
|
|
10
10
|
bubbles: !0,
|
|
11
11
|
cancelable: !0,
|
|
12
12
|
composed: !1,
|
package/dist/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","names":[],"sources":["../src/events.ts"],"sourcesContent":["/** Synchronous, exact DOM event dispatchers for test environments. */\n\n/** Dispatch an event instance without modifying it. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\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
|
|
1
|
+
{"version":3,"file":"events.js","names":[],"sources":["../src/events.ts"],"sourcesContent":["/** Synchronous, exact DOM event dispatchers for test environments. */\n\n/** Dispatch an event instance without modifying it. */\nexport const dispatch = (target: EventTarget, event: Event): boolean => target.dispatchEvent(event);\n\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"],"mappings":";AAGA,IAAa,KAAY,GAAqB,MAA0B,EAAO,cAAc,CAAK,GAErF,KAAY,GAAqB,IAAuB,CAAC,MACpE,EAAS,GAAQ,IAAI,WAAW,QAAQ,CAAI,CAAC,GAElC,KAAc,GAAqB,IAAkB,CAAC,MACjE,EAAS,GAAQ,IAAI,MAAM,UAAU;CAAE,SAAS;CAAM,GAAG;AAAK,CAAC,CAAC,GAErD,KAAa,GAAqB,IAAuB,CAAC,MACrE,EAAS,GAAQ,IAAI,WAAW,SAAS;CAAE,SAAS;CAAM,YAAY;CAAM,GAAG;AAAK,CAAC,CAAC,GAE3E,KAAiB,GAAqB,GAAc,IAA2B,CAAC,MAC3F,EAAS,GAAQ,IAAI,YAAY,GAAM;CAAE,SAAS;CAAM,YAAY;CAAM,UAAU;CAAO,GAAG;AAAK,CAAC,CAAC,GAE1F,KAAa,GAAqB,IAAuB,CAAC,MACrE,EAAS,GAAQ,IAAI,WAAW,SAAS,CAAI,CAAC,GAEnC,KAAa,GAAqB,IAAuB,CAAC,MACrE,EAAS,GAAQ,IAAI,WAAW,SAAS;CAAE,SAAS;CAAM,GAAG;AAAK,CAAC,CAAC,GAEzD,KAAe,GAAqB,IAA0B,CAAC,MAC1E,EAAS,GAAQ,IAAI,cAAc,WAAW;CAAE,SAAS;CAAM,YAAY;CAAM,GAAG;AAAK,CAAC,CAAC,GAEhF,KAAa,GAAqB,IAA0B,CAAC,MACxE,EAAS,GAAQ,IAAI,cAAc,SAAS;CAAE,SAAS;CAAM,YAAY;CAAM,GAAG;AAAK,CAAC,CAAC,GAE9E,KAAc,GAAqB,IAAwB,CAAC,MACvE,EAAS,GAAQ,IAAI,YAAY,UAAU;CAAE,SAAS;CAAM,YAAY;CAAM,GAAG;AAAK,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { AssayError, AssayQueryError, AssayTimeoutError } from './errors';
|
|
2
|
-
export { dispatch, fireBlur, fireChange, fireClick, fireCustom, fireFocus, fireInput, fireKeyDown, fireKeyUp, fireSubmit,
|
|
3
|
-
export {
|
|
4
|
-
export { delay, nextTick,
|
|
2
|
+
export { dispatch, fireBlur, fireChange, fireClick, fireCustom, fireFocus, fireInput, fireKeyDown, fireKeyUp, fireSubmit, } from './events';
|
|
3
|
+
export { getSlotted, type QueryScope, queryAllInShadow, queryInShadow, queryPart, within } from './query';
|
|
4
|
+
export { type DelayOptions, delay, nextTick, type RetryOptions, retry, type WaitOptions, waitForEvent, waitUntil, } from './wait';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE1E,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,WAAW,EACX,SAAS,EACT,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE1E,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,UAAU,EAAE,KAAK,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1G,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,EACL,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,EACL,KAAK,WAAW,EAChB,YAAY,EACZ,SAAS,GACV,MAAM,QAAQ,CAAC"}
|
package/dist/query.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.cjs","names":[],"sources":["../src/query.ts"],"sourcesContent":["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
|
|
1
|
+
{"version":3,"file":"query.cjs","names":[],"sources":["../src/query.ts"],"sourcesContent":["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 el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] => {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n};\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"],"mappings":"gCAuBA,IAAM,EAAgB,GAChB,aAAgB,QAAgB,EAAK,UAAU,MAAM,EAAG,GAAG,EAE3D,aAAgB,WAAmB,gBAAgB,EAAK,UAAU,MAAM,EAAG,GAAG,EAAE,gBAE7E,EAAK,SAGR,GAAmC,EAAmB,EAAqB,IAAuB,CACtG,GAAI,EAAS,OAAO,EAEpB,MAAM,IAAI,EAAA,gBAAgB,kBAAkB,EAAY,UAAU,EAAa,CAAI,EAAE,EAAE,CACzF,EAEM,GAAsC,EAAiB,IAC3D,EAAK,cAAiB,CAAQ,EAE1B,GAAyC,EAAiB,IACvD,MAAM,KAAK,EAAK,iBAAoB,CAAQ,CAAC,EAGhD,GAA8C,EAAiB,IACnE,EAAY,EAAM,eAAe,CAAC,CAAC,KAAM,GAAY,EAAQ,aAAa,aAAa,IAAM,CAAM,GAAK,KAEpG,GAAiD,EAAiB,IACtE,EAAY,EAAM,eAAe,CAAC,CAAC,OAAQ,GAAY,EAAQ,aAAa,aAAa,IAAM,CAAM,EAEjG,GAA4C,EAAiB,EAAc,EAAW,MAAkB,CAC5G,IAAK,IAAM,KAAM,EAAK,iBAAoB,CAAQ,EAChD,GAAI,EAAG,aAAa,KAAK,IAAM,EAAM,OAAO,EAG9C,OAAO,IACT,EAEM,GAA+C,EAAiB,EAAc,EAAW,MACtF,MAAM,KAAK,EAAK,iBAAoB,CAAQ,CAAC,CAAC,CAAC,OAAQ,GAAO,EAAG,aAAa,KAAK,IAAM,CAAI,EAQtG,SAAgB,EAA2C,EAAe,EAA4B,CACpG,OAAO,EAAK,WAAa,EAAS,EAAK,WAAY,CAAQ,EAAI,IACjE,CAGA,SAAgB,EAA8C,EAAe,EAAuB,CAClG,OAAO,EAAK,WAAa,EAAY,EAAK,WAAY,CAAQ,EAAI,CAAC,CACrE,CAUA,SAAgB,EAAuC,EAAe,EAAwB,CAC5F,OACE,EAAoB,EAAM,QAAQ,CAAC,CAAC,KAAM,GAAY,EAAQ,aAAa,MAAM,CAAC,EAAE,MAAM,KAAK,CAAC,CAAC,SAAS,CAAI,CAAC,GAC/G,IAEJ,CAUA,SAAgB,EAAwC,EAAe,EAAwB,CAC7F,OAAO,MAAM,KAAK,EAAK,QAAQ,CAAC,CAAC,OAAQ,GACvC,IAAa,IAAA,GAAY,CAAC,EAAQ,aAAa,MAAM,EAAI,EAAQ,aAAa,MAAM,IAAM,CAC5F,CACF,CAWA,SAAgB,EAAO,EAA6B,CAClD,MAAO,CACL,IAAmC,GACjC,EAAa,EAAS,EAAM,CAAQ,EAAG,IAAI,EAAS,GAAI,CAAI,EAC9D,YAA2C,GACzC,EAAa,EAAiB,EAAM,CAAM,EAAG,gBAAgB,EAAO,GAAI,CAAI,EAC9E,WAAyC,EAAc,EAAW,MAChE,EAAa,EAAe,EAAM,EAAM,CAAQ,EAAG,SAAS,EAAK,cAAc,EAAS,GAAI,CAAI,EAClG,MAAqC,GAAqB,EAAS,EAAM,CAAQ,EACjF,SAAwC,GAAqB,EAAY,EAAM,CAAQ,EACvF,iBAAgD,GAAmB,EAAoB,EAAM,CAAM,EACnG,gBAA8C,EAAc,EAAW,MACrE,EAAkB,EAAM,EAAM,CAAQ,EACxC,cAA6C,GAAmB,EAAiB,EAAM,CAAM,EAC7F,aAA2C,EAAc,EAAW,MAAQ,EAAe,EAAM,EAAM,CAAQ,CACjH,CACF"}
|
package/dist/query.d.ts
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
/** Scoped query helpers for any queryable DOM root — see {@link within}. */
|
|
3
3
|
export interface QueryScope {
|
|
4
4
|
get<E extends Element = Element>(selector: string): E;
|
|
5
|
+
getByTestId<E extends Element = Element>(testId: string): E;
|
|
6
|
+
getByText<E extends Element = Element>(text: string, selector?: string): E;
|
|
5
7
|
query<E extends Element = Element>(selector: string): E | null;
|
|
6
8
|
queryAll<E extends Element = Element>(selector: string): E[];
|
|
7
|
-
|
|
8
|
-
queryByText<E extends Element = Element>(text: string, selector?: string): E | null;
|
|
9
|
+
queryAllByTestId<E extends Element = Element>(testId: string): E[];
|
|
9
10
|
queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];
|
|
10
|
-
getByTestId<E extends Element = Element>(testId: string): E;
|
|
11
11
|
queryByTestId<E extends Element = Element>(testId: string): E | null;
|
|
12
|
-
|
|
12
|
+
queryByText<E extends Element = Element>(text: string, selector?: string): E | null;
|
|
13
13
|
}
|
|
14
14
|
type QueryRoot = ParentNode;
|
|
15
15
|
/**
|
package/dist/query.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAEA,+CAA+C;AAI/C,4EAA4E;AAC5E,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;IACtD,
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAEA,+CAA+C;AAI/C,4EAA4E;AAC5E,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;IACtD,WAAW,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC;IAC5D,SAAS,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC;IAC3E,KAAK,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;IAC/D,QAAQ,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;IAC7D,gBAAgB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;IACnE,cAAc,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;IAClF,aAAa,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;IACrE,WAAW,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;CACrF;AAID,KAAK,SAAS,GAAG,UAAU,CAAC;AAyC5B;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAEpG;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,EAAE,CAElG;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAK5F;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,CAI7F;AAID;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,SAAS,GAAG,UAAU,CAgBlD"}
|
package/dist/query.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","names":[],"sources":["../src/query.ts"],"sourcesContent":["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
|
|
1
|
+
{"version":3,"file":"query.js","names":[],"sources":["../src/query.ts"],"sourcesContent":["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 el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n};\n\nconst queryAllByText = <E extends Element = Element>(root: QueryRoot, text: string, selector = '*'): E[] => {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n};\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"],"mappings":";;AAuBA,IAAM,KAAgB,MAChB,aAAgB,UAAgB,EAAK,UAAU,MAAM,GAAG,GAAG,IAE3D,aAAgB,aAAmB,gBAAgB,EAAK,UAAU,MAAM,GAAG,GAAG,EAAE,kBAE7E,EAAK,UAGR,KAAmC,GAAmB,GAAqB,MAAuB;CACtG,IAAI,GAAS,OAAO;CAEpB,MAAM,IAAI,EAAgB,kBAAkB,EAAY,UAAU,EAAa,CAAI,EAAE,EAAE;AACzF,GAEM,KAAsC,GAAiB,MAC3D,EAAK,cAAiB,CAAQ,GAE1B,KAAyC,GAAiB,MACvD,MAAM,KAAK,EAAK,iBAAoB,CAAQ,CAAC,GAGhD,KAA8C,GAAiB,MACnE,EAAY,GAAM,eAAe,CAAC,CAAC,MAAM,MAAY,EAAQ,aAAa,aAAa,MAAM,CAAM,KAAK,MAEpG,KAAiD,GAAiB,MACtE,EAAY,GAAM,eAAe,CAAC,CAAC,QAAQ,MAAY,EAAQ,aAAa,aAAa,MAAM,CAAM,GAEjG,KAA4C,GAAiB,GAAc,IAAW,QAAkB;CAC5G,KAAK,IAAM,KAAM,EAAK,iBAAoB,CAAQ,GAChD,IAAI,EAAG,aAAa,KAAK,MAAM,GAAM,OAAO;CAG9C,OAAO;AACT,GAEM,KAA+C,GAAiB,GAAc,IAAW,QACtF,MAAM,KAAK,EAAK,iBAAoB,CAAQ,CAAC,CAAC,CAAC,QAAQ,MAAO,EAAG,aAAa,KAAK,MAAM,CAAI;AAQtG,SAAgB,EAA2C,GAAe,GAA4B;CACpG,OAAO,EAAK,aAAa,EAAS,EAAK,YAAY,CAAQ,IAAI;AACjE;AAGA,SAAgB,EAA8C,GAAe,GAAuB;CAClG,OAAO,EAAK,aAAa,EAAY,EAAK,YAAY,CAAQ,IAAI,CAAC;AACrE;AAUA,SAAgB,EAAuC,GAAe,GAAwB;CAC5F,OACE,EAAoB,GAAM,QAAQ,CAAC,CAAC,MAAM,MAAY,EAAQ,aAAa,MAAM,CAAC,EAAE,MAAM,KAAK,CAAC,CAAC,SAAS,CAAI,CAAC,KAC/G;AAEJ;AAUA,SAAgB,EAAwC,GAAe,GAAwB;CAC7F,OAAO,MAAM,KAAK,EAAK,QAAQ,CAAC,CAAC,QAAQ,MACvC,MAAa,KAAA,IAAY,CAAC,EAAQ,aAAa,MAAM,IAAI,EAAQ,aAAa,MAAM,MAAM,CAC5F;AACF;AAWA,SAAgB,EAAO,GAA6B;CAClD,OAAO;EACL,MAAmC,MACjC,EAAa,EAAS,GAAM,CAAQ,GAAG,IAAI,EAAS,IAAI,CAAI;EAC9D,cAA2C,MACzC,EAAa,EAAiB,GAAM,CAAM,GAAG,gBAAgB,EAAO,IAAI,CAAI;EAC9E,YAAyC,GAAc,IAAW,QAChE,EAAa,EAAe,GAAM,GAAM,CAAQ,GAAG,SAAS,EAAK,cAAc,EAAS,IAAI,CAAI;EAClG,QAAqC,MAAqB,EAAS,GAAM,CAAQ;EACjF,WAAwC,MAAqB,EAAY,GAAM,CAAQ;EACvF,mBAAgD,MAAmB,EAAoB,GAAM,CAAM;EACnG,iBAA8C,GAAc,IAAW,QACrE,EAAkB,GAAM,GAAM,CAAQ;EACxC,gBAA6C,MAAmB,EAAiB,GAAM,CAAM;EAC7F,cAA2C,GAAc,IAAW,QAAQ,EAAe,GAAM,GAAM,CAAQ;CACjH;AACF"}
|
package/dist/wait.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wait.cjs","names":[],"sources":["../src/wait.ts"],"sourcesContent":["import { AssayTimeoutError } from './errors';\n\nexport interface WaitOptions {\n /**
|
|
1
|
+
{"version":3,"file":"wait.cjs","names":[],"sources":["../src/wait.ts"],"sourcesContent":["import { AssayTimeoutError } from './errors';\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 RetryOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nexport interface DelayOptions {\n /** Cancel the pending delay. */\n signal?: AbortSignal;\n}\n\nconst abortReason = (signal: AbortSignal): unknown =>\n signal.reason ?? new DOMException('The operation was aborted.', 'AbortError');\n\n/**\n * Resolve after `ms` milliseconds. Rejects with the abort reason when cancelled.\n */\nexport const delay = (ms = 0, { signal }: DelayOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const timer = setTimeout(done, ms);\n\n function done(): void {\n signal?.removeEventListener('abort', abort);\n resolve();\n }\n\n function abort(): void {\n clearTimeout(timer);\n reject(abortReason(signal!));\n }\n\n signal?.addEventListener('abort', abort, { once: true });\n });\n\n/** Poll until a synchronous or asynchronous predicate returns `true`. */\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n if (await predicate()) return;\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n}\n\n/** Retry an assertion until it stops throwing. */\nexport async function retry(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: RetryOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n try {\n await assertion();\n\n return;\n } catch (error) {\n lastError = error;\n }\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n const timing = `retry 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 return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (e: Event): void => {\n dispose();\n resolve(e 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(abortReason(signal!));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/** Resolve after one microtask tick. */\nexport const nextTick = (): Promise<void> =>\n new Promise((resolve) => {\n queueMicrotask(resolve);\n });\n"],"mappings":"gCAqBA,IAAM,EAAe,GACnB,EAAO,QAAU,IAAI,aAAa,6BAA8B,YAAY,EAKjE,GAAS,EAAK,EAAG,CAAE,UAAyB,CAAC,IACxD,IAAI,SAAS,EAAS,IAAW,CAC/B,GAAI,GAAQ,QAAS,CACnB,EAAO,EAAY,CAAM,CAAC,EAE1B,MACF,CAEA,IAAM,EAAQ,WAAW,EAAM,CAAE,EAEjC,SAAS,GAAa,CACpB,GAAQ,oBAAoB,QAAS,CAAK,EAC1C,EAAQ,CACV,CAEA,SAAS,GAAc,CACrB,aAAa,CAAK,EAClB,EAAO,EAAY,CAAO,CAAC,CAC7B,CAEA,GAAQ,iBAAiB,QAAS,EAAO,CAAE,KAAM,EAAK,CAAC,CACzD,CAAC,EAGH,eAAsB,EACpB,EACA,CAAE,WAAW,GAAI,SAAQ,UAAU,KAAsB,CAAC,EAC3C,CACf,IAAM,EAAW,KAAK,IAAI,EAAI,EAE9B,OAAS,CACP,GAAI,GAAQ,QAAS,MAAM,EAAY,CAAM,EAE7C,GAAI,MAAM,EAAU,EAAG,OAEvB,GAAI,KAAK,IAAI,GAAK,EAAU,MAE5B,MAAM,EAAM,EAAU,CAAE,QAAO,CAAC,CAClC,CAEA,MAAM,IAAI,EAAA,kBAAkB,6BAA6B,EAAQ,GAAG,CACtE,CAGA,eAAsB,EACpB,EACA,CAAE,WAAW,GAAI,UAAS,SAAQ,UAAU,KAAuB,CAAC,EACrD,CACf,IAAM,EAAW,KAAK,IAAI,EAAI,EAC1B,EAEJ,OAAS,CACP,GAAI,GAAQ,QAAS,MAAM,EAAY,CAAM,EAE7C,GAAI,CACF,MAAM,EAAU,EAEhB,MACF,OAAS,EAAO,CACd,EAAY,CACd,CAEA,GAAI,KAAK,IAAI,GAAK,EAAU,MAE5B,MAAM,EAAM,EAAU,CAAE,QAAO,CAAC,CAClC,CAEA,IAAM,EAAS,yBAAyB,EAAQ,IAC1C,EAAU,EAAU,GAAG,EAAQ,IAAI,EAAO,GAAK,EAC/C,EAAS,aAAqB,MAAQ,EAAU,QAAU,GAAa,KAAO,GAAK,OAAO,CAAS,EAEzG,MAAM,IAAI,EAAA,kBAAkB,EAAS,GAAG,EAAQ,IAAI,IAAW,EAAS,CAAE,MAAO,CAAU,CAAC,CAC9F,CAGA,SAAgB,EACd,EACA,EACA,CAAE,SAAQ,UAAU,KAAwC,CAAC,EACjD,CACZ,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,GAAI,GAAQ,QAAS,CACnB,EAAO,EAAY,CAAM,CAAC,EAE1B,MACF,CAEA,IAAM,MAAgB,CACpB,aAAa,CAAK,EAClB,GAAQ,oBAAoB,QAAS,CAAO,EAC5C,EAAO,oBAAoB,EAAM,CAAO,CAC1C,EACM,EAAW,GAAmB,CAClC,EAAQ,EACR,EAAQ,CAAM,CAChB,EACM,EAAQ,eAAiB,CAC7B,EAAQ,EACR,EAAO,IAAI,EAAA,kBAAkB,kBAAkB,EAAK,oBAAoB,EAAQ,GAAG,CAAC,CACtF,EAAG,CAAO,EACJ,MAAgB,CACpB,EAAQ,EACR,EAAO,EAAY,CAAO,CAAC,CAC7B,EAEA,EAAO,iBAAiB,EAAM,EAAS,CAAE,KAAM,EAAK,CAAC,EACrD,GAAQ,iBAAiB,QAAS,EAAS,CAAE,KAAM,EAAK,CAAC,CAC3D,CAAC,CACH,CAGA,IAAa,MACX,IAAI,QAAS,GAAY,CACvB,eAAe,CAAO,CACxB,CAAC"}
|
package/dist/wait.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export interface WaitOptions {
|
|
2
|
+
/** Polling interval in ms (default: 50). */
|
|
3
|
+
interval?: number;
|
|
2
4
|
/** Cancel the pending wait. */
|
|
3
5
|
signal?: AbortSignal;
|
|
4
6
|
/** Maximum wait time in ms (default: 1000). */
|
|
5
7
|
timeout?: number;
|
|
6
|
-
/** Polling interval in ms (default: 50). */
|
|
7
|
-
interval?: number;
|
|
8
8
|
}
|
|
9
9
|
export interface RetryOptions extends WaitOptions {
|
|
10
10
|
/** Context included in the timeout error. */
|
package/dist/wait.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wait.d.ts","sourceRoot":"","sources":["../src/wait.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,+BAA+B;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"wait.d.ts","sourceRoot":"","sources":["../src/wait.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAKD;;GAEG;AACH,eAAO,MAAM,KAAK,GAAI,WAAM,EAAE,aAAY,YAAiB,KAAG,OAAO,CAAC,IAAI,CAqBtE,CAAC;AAEL,yEAAyE;AACzE,wBAAsB,SAAS,CAC7B,SAAS,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,EAC3C,EAAE,QAAa,EAAE,MAAM,EAAE,OAAc,EAAE,GAAE,WAAgB,GAC1D,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,kDAAkD;AAClD,wBAAsB,KAAK,CACzB,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EACrC,EAAE,QAAa,EAAE,OAAO,EAAE,MAAM,EAAE,OAAc,EAAE,GAAE,YAAiB,GACpE,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,EAClD,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,EACZ,EAAE,MAAM,EAAE,OAAc,EAAE,GAAE,IAAI,CAAC,WAAW,EAAE,UAAU,CAAM,GAC7D,OAAO,CAAC,CAAC,CAAC,CA6BZ;AAED,wCAAwC;AACxC,eAAO,MAAM,QAAQ,QAAO,OAAO,CAAC,IAAI,CAGpC,CAAC"}
|
package/dist/wait.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wait.js","names":[],"sources":["../src/wait.ts"],"sourcesContent":["import { AssayTimeoutError } from './errors';\n\nexport interface WaitOptions {\n /**
|
|
1
|
+
{"version":3,"file":"wait.js","names":[],"sources":["../src/wait.ts"],"sourcesContent":["import { AssayTimeoutError } from './errors';\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 RetryOptions extends WaitOptions {\n /** Context included in the timeout error. */\n message?: string;\n}\n\nexport interface DelayOptions {\n /** Cancel the pending delay. */\n signal?: AbortSignal;\n}\n\nconst abortReason = (signal: AbortSignal): unknown =>\n signal.reason ?? new DOMException('The operation was aborted.', 'AbortError');\n\n/**\n * Resolve after `ms` milliseconds. Rejects with the abort reason when cancelled.\n */\nexport const delay = (ms = 0, { signal }: DelayOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const timer = setTimeout(done, ms);\n\n function done(): void {\n signal?.removeEventListener('abort', abort);\n resolve();\n }\n\n function abort(): void {\n clearTimeout(timer);\n reject(abortReason(signal!));\n }\n\n signal?.addEventListener('abort', abort, { once: true });\n });\n\n/** Poll until a synchronous or asynchronous predicate returns `true`. */\nexport async function waitUntil(\n predicate: () => boolean | Promise<boolean>,\n { interval = 50, signal, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n if (await predicate()) return;\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n throw new AssayTimeoutError(`waitUntil timed out after ${timeout}ms`);\n}\n\n/** Retry an assertion until it stops throwing. */\nexport async function retry(\n assertion: () => void | Promise<void>,\n { interval = 50, message, signal, timeout = 1000 }: RetryOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n for (;;) {\n if (signal?.aborted) throw abortReason(signal);\n\n try {\n await assertion();\n\n return;\n } catch (error) {\n lastError = error;\n }\n\n if (Date.now() >= deadline) break;\n\n await delay(interval, { signal });\n }\n\n const timing = `retry 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 return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortReason(signal));\n\n return;\n }\n\n const dispose = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n target.removeEventListener(type, onEvent);\n };\n const onEvent = (e: Event): void => {\n dispose();\n resolve(e 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(abortReason(signal!));\n };\n\n target.addEventListener(type, onEvent, { once: true });\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/** Resolve after one microtask tick. */\nexport const nextTick = (): Promise<void> =>\n new Promise((resolve) => {\n queueMicrotask(resolve);\n });\n"],"mappings":";;AAqBA,IAAM,KAAe,MACnB,EAAO,UAAU,IAAI,aAAa,8BAA8B,YAAY,GAKjE,KAAS,IAAK,GAAG,EAAE,cAAyB,CAAC,MACxD,IAAI,SAAS,GAAS,MAAW;CAC/B,IAAI,GAAQ,SAAS;EACnB,EAAO,EAAY,CAAM,CAAC;EAE1B;CACF;CAEA,IAAM,IAAQ,WAAW,GAAM,CAAE;CAEjC,SAAS,IAAa;EAEpB,AADA,GAAQ,oBAAoB,SAAS,CAAK,GAC1C,EAAQ;CACV;CAEA,SAAS,IAAc;EAErB,AADA,aAAa,CAAK,GAClB,EAAO,EAAY,CAAO,CAAC;CAC7B;CAEA,GAAQ,iBAAiB,SAAS,GAAO,EAAE,MAAM,GAAK,CAAC;AACzD,CAAC;AAGH,eAAsB,EACpB,GACA,EAAE,cAAW,IAAI,WAAQ,aAAU,QAAsB,CAAC,GAC3C;CACf,IAAM,IAAW,KAAK,IAAI,IAAI;CAE9B,SAAS;EACP,IAAI,GAAQ,SAAS,MAAM,EAAY,CAAM;EAE7C,IAAI,MAAM,EAAU,GAAG;EAEvB,IAAI,KAAK,IAAI,KAAK,GAAU;EAE5B,MAAM,EAAM,GAAU,EAAE,UAAO,CAAC;CAClC;CAEA,MAAM,IAAI,EAAkB,6BAA6B,EAAQ,GAAG;AACtE;AAGA,eAAsB,EACpB,GACA,EAAE,cAAW,IAAI,YAAS,WAAQ,aAAU,QAAuB,CAAC,GACrD;CACf,IAAM,IAAW,KAAK,IAAI,IAAI,GAC1B;CAEJ,SAAS;EACP,IAAI,GAAQ,SAAS,MAAM,EAAY,CAAM;EAE7C,IAAI;GACF,MAAM,EAAU;GAEhB;EACF,SAAS,GAAO;GACd,IAAY;EACd;EAEA,IAAI,KAAK,IAAI,KAAK,GAAU;EAE5B,MAAM,EAAM,GAAU,EAAE,UAAO,CAAC;CAClC;CAEA,IAAM,IAAS,yBAAyB,EAAQ,KAC1C,IAAU,IAAU,GAAG,EAAQ,IAAI,EAAO,KAAK,GAC/C,IAAS,aAAqB,QAAQ,EAAU,UAAU,KAAa,OAAO,KAAK,OAAO,CAAS;CAEzG,MAAM,IAAI,EAAkB,IAAS,GAAG,EAAQ,IAAI,MAAW,GAAS,EAAE,OAAO,EAAU,CAAC;AAC9F;AAGA,SAAgB,EACd,GACA,GACA,EAAE,WAAQ,aAAU,QAAwC,CAAC,GACjD;CACZ,OAAO,IAAI,SAAS,GAAS,MAAW;EACtC,IAAI,GAAQ,SAAS;GACnB,EAAO,EAAY,CAAM,CAAC;GAE1B;EACF;EAEA,IAAM,UAAgB;GAGpB,AAFA,aAAa,CAAK,GAClB,GAAQ,oBAAoB,SAAS,CAAO,GAC5C,EAAO,oBAAoB,GAAM,CAAO;EAC1C,GACM,KAAW,MAAmB;GAElC,AADA,EAAQ,GACR,EAAQ,CAAM;EAChB,GACM,IAAQ,iBAAiB;GAE7B,AADA,EAAQ,GACR,EAAO,IAAI,EAAkB,kBAAkB,EAAK,oBAAoB,EAAQ,GAAG,CAAC;EACtF,GAAG,CAAO,GACJ,UAAgB;GAEpB,AADA,EAAQ,GACR,EAAO,EAAY,CAAO,CAAC;EAC7B;EAGA,AADA,EAAO,iBAAiB,GAAM,GAAS,EAAE,MAAM,GAAK,CAAC,GACrD,GAAQ,iBAAiB,SAAS,GAAS,EAAE,MAAM,GAAK,CAAC;CAC3D,CAAC;AACH;AAGA,IAAa,UACX,IAAI,SAAS,MAAY;CACvB,eAAe,CAAO;AACxB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vielzeug/assay",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Framework-agnostic DOM testing primitives — scoped queries and
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Framework-agnostic DOM testing primitives — scoped queries, event dispatch, and async waiting",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/helmuthdu/vielzeug",
|
|
8
|
+
"directory": "packages/assay"
|
|
9
|
+
},
|
|
5
10
|
"type": "module",
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=22"
|
|
13
|
+
},
|
|
6
14
|
"files": [
|
|
7
15
|
"dist"
|
|
8
16
|
],
|
|
@@ -11,34 +19,30 @@
|
|
|
11
19
|
"types": "dist/index.d.ts",
|
|
12
20
|
"exports": {
|
|
13
21
|
".": {
|
|
14
|
-
"source": "./src/index.ts",
|
|
15
|
-
"types": "./dist/index.d.ts",
|
|
16
22
|
"import": "./dist/index.js",
|
|
17
|
-
"require": "./dist/index.cjs"
|
|
23
|
+
"require": "./dist/index.cjs",
|
|
24
|
+
"types": "./dist/index.d.ts"
|
|
18
25
|
}
|
|
19
26
|
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"registry": "https://registry.npmjs.org/"
|
|
30
|
+
},
|
|
20
31
|
"scripts": {
|
|
21
32
|
"build": "vite build && pnpm run build:bundle && pnpm run build:types",
|
|
33
|
+
"build:bundle": "vite build --config vite.bundle.config.ts",
|
|
22
34
|
"build:types": "tsc -p tsconfig.declarations.json",
|
|
23
|
-
"fix": "
|
|
24
|
-
"lint": "
|
|
35
|
+
"fix": "biome check --write src",
|
|
36
|
+
"lint": "biome ci src",
|
|
25
37
|
"prepublishOnly": "pnpm run build",
|
|
26
38
|
"preview": "vite preview",
|
|
27
|
-
"test": "vitest"
|
|
28
|
-
"build:bundle": "vite build --config vite.bundle.config.ts"
|
|
29
|
-
},
|
|
30
|
-
"publishConfig": {
|
|
31
|
-
"access": "public",
|
|
32
|
-
"registry": "https://registry.npmjs.org/"
|
|
33
|
-
},
|
|
34
|
-
"engines": {
|
|
35
|
-
"node": ">=22"
|
|
39
|
+
"test": "vitest"
|
|
36
40
|
},
|
|
37
41
|
"devDependencies": {
|
|
38
|
-
"@types/node": "^26.
|
|
42
|
+
"@types/node": "^26.2.0",
|
|
39
43
|
"jsdom": "^30.0.1",
|
|
40
44
|
"typescript": "^6.0.3",
|
|
41
|
-
"vite": "^8.2.
|
|
45
|
+
"vite": "^8.2.1",
|
|
42
46
|
"vitest": "^4.1.10"
|
|
43
47
|
}
|
|
44
48
|
}
|
package/dist/_dev.d.ts
DELETED
package/dist/_dev.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"_dev.d.ts","sourceRoot":"","sources":["../src/_dev.ts"],"names":[],"mappings":""}
|