Skip to content

API Overview ​

SymbolPurposeExecution modeCommon gotcha
withinCreates scoped query APISyncRequired get* methods throw AssayQueryError
queryInShadow / queryPart / getSlottedCrosses custom-element boundariesSyncOpen shadow roots are required

| fire* / dispatch | Dispatches platform event instances | Sync | Does not reproduce browser default behavior | | waitUntil / eventually / waitForEvent | Waits for conditions, assertions, or events | Async | Use a signal or timeout for bounded waits | | delay | Schedules a cancellable timer | Async | Pass a signal to cancel a pending wait |

Package Entry Point ​

ImportPurpose
@vielzeug/assayDOM queries, events, wait helpers, errors, and types

Queries ​

within(root) ​

Creates a QueryScope for an Element, ShadowRoot, Document, or DocumentFragment.

MethodReturnsUse
get(selector)ElementRequired CSS match; throws AssayQueryError
query(selector)Element | nullOptional CSS match
queryAll(selector)Element[]All CSS matches
getByText(text, selector?)ElementRequired exact trimmed-text match
queryByText(text, selector?)Element | nullOptional exact trimmed-text match
queryAllByText(text, selector?)Element[]All exact trimmed-text matches
getByTestId(id)ElementRequired data-testid match
queryByTestId(id)Element | nullOptional data-testid match
queryAllByTestId(id)Element[]All data-testid matches

Text selectors default to '*'. Required-query failures include the lookup and a bounded view of the scoped DOM.

Shadow and slot helpers ​

FunctionReturnsDescription
queryInShadow(host, selector)Element | nullFirst match in an open shadow root
queryAllInShadow(host, selector)Element[]All matches in an open shadow root
queryPart(host, part)Element | nullFirst shadow element whose part token matches
getSlotted(host, slotName?)Element[]Direct light-DOM children in a named or default slot

These helpers return null or [] when there is no shadow root. Dynamic test IDs, parts, and slot names are matched as attribute values rather than interpolated into CSS selectors.

Event dispatch ​

All event helpers synchronously return dispatchEvent()'s boolean result.

ts
import {
  dispatch,
  fireBlur,
  fireChange,
  fireClick,
  fireCustom,
  fireFocus,
  fireInput,
  fireKeyDown,
  fireKeyUp,
  fireSubmit,
} from '@vielzeug/assay';

fireClick(button, { clientX: 20 });
fireInput(input);
fireKeyDown(input, { key: 'Enter' });
fireCustom(element, 'item-added', { detail: { id: '42' } });
dispatch(element, new Event('ready'));
FunctionEvent classDefaults
fireBlur / fireFocusFocusEventPlatform defaults (bubbles: false)
fireChangeEventbubbles: true
fireInputInputEventbubbles: true
fireClickMouseEventbubbles: true, cancelable: true
fireKeyDown / fireKeyUpKeyboardEventbubbles: true, cancelable: true
fireSubmitSubmitEventbubbles: true, cancelable: true
fireCustomCustomEventbubbles: true, cancelable: true, composed: false

fireCustom(target, type, init?) dispatches a CustomEvent with the given type. Assay intentionally does not provide browser-default or fallback pointer/touch simulation.

Async waiting ​

ts
await waitUntil(() => ready, { interval: 20, signal, timeout: 1000 });
await eventually(() => expect(spy).toHaveBeenCalled(), { signal, timeout: 1000 });
await waitForEvent(target, 'ready', { signal, timeout: 1000 });
await delay(100, { signal });
FunctionSuccess conditionOptions
waitUntil(predicate, options?)Predicate returns truetimeout, interval, signal
eventually(assertion, options?)Assertion stops throwingtimeout, interval, signal, message
waitForEvent(target, type, options?)Target emits typetimeout, signal
delay(ms?, options?)Timer elapsessignal

waitUntil(), eventually(), and waitForEvent() reject with AssayTimeoutError when their shared deadline expires. waitUntil() and eventually() remain bounded while an asynchronous callback is pending. Abort rejects with the signal reason and removes Assay-owned timers and listeners. Callback work itself must cooperate with application cancellation.

timeout and delay milliseconds must be finite, non-negative, and no greater than 2,147,483,647 ms; interval must be finite, positive, and within the same timer limit. Invalid durations throw RangeError. eventually() also accepts message for diagnostic timeout context.

Types ​

ts
export interface QueryScope {
  get<E extends Element = Element>(selector: string): E;
  getByTestId<E extends Element = Element>(testId: string): E;
  getByText<E extends Element = Element>(text: string, selector?: string): E;
  query<E extends Element = Element>(selector: string): E | null;
  queryAll<E extends Element = Element>(selector: string): E[];
  queryAllByTestId<E extends Element = Element>(testId: string): E[];
  queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];
  queryByTestId<E extends Element = Element>(testId: string): E | null;
  queryByText<E extends Element = Element>(text: string, selector?: string): E | null;
}

Scoped query helpers returned by within(root).

ts
export interface WaitOptions {
  /** Polling interval in ms (default: 50). */
  interval?: number;
  /** Cancel the pending wait. */
  signal?: AbortSignal;
  /** Maximum wait time in ms (default: 1000). */
  timeout?: number;
}

export interface EventuallyOptions extends WaitOptions {
  /** Context included in the timeout error. */
  message?: string;
}

export interface DelayOptions {
  /** Cancel the pending delay. */
  signal?: AbortSignal;
}

WaitOptions configures waitUntil(). EventuallyOptions configures eventually(). DelayOptions configures delay().

Errors ​

ErrorMeaning
AssayErrorBase class for Assay-originated errors
AssayQueryErrorA required get* query had no match
AssayTimeoutErrorA wait operation reached its timeout

Use instanceof AssayError to narrow any value to the Assay error hierarchy.