{"version":3,"file":"index.mjs","names":[],"sources":["../src/fakeEvents/FakeDataTransfer.ts","../src/fakeEvents/FakeMouseEvent.ts","../src/DOMInteractor.ts","../src/createTestEngine.ts"],"sourcesContent":["/**\n * Minimal `DataTransfer` implementation for synthesizing HTML5 drag-and-drop\n * events under jsdom, which implements neither `DragEvent` nor `DataTransfer`\n * (only `MouseEvent` — see {@link FakeMouseEvent}). `@testing-library/dom`'s\n * `fireEvent.drag*` helpers special-case a `dataTransfer` init value and attach\n * it to the dispatched event verbatim when `window.DataTransfer` is absent —\n * this is that value, shared across one gesture's `dragstart` → `dragenter` →\n * `dragover` → `drop` → `dragend` sequence so a `dragstart` handler's\n * `setData` is readable from `drop`'s `getData`.\n *\n * `files`/`items` are not supported — the drag primitives synthesize element\n * drag-and-drop, not OS file drops, which {@link DOMInteractor.setInputFiles}\n * already covers.\n *\n * @see https://github.com/jsdom/jsdom/issues/1568\n * @internal\n */\nexport class FakeDataTransfer implements DataTransfer {\n  private readonly store = new Map<string, string>();\n\n  dropEffect: DataTransfer['dropEffect'] = 'move';\n  effectAllowed: DataTransfer['effectAllowed'] = 'all';\n  readonly files: FileList = { length: 0, item: () => null, [Symbol.iterator]: [][Symbol.iterator] } as FileList;\n  readonly items: DataTransferItemList = { length: 0 } as DataTransferItemList;\n\n  get types(): readonly string[] {\n    return Array.from(this.store.keys());\n  }\n\n  clearData(format?: string): void {\n    if (format != null) {\n      this.store.delete(format);\n    } else {\n      this.store.clear();\n    }\n  }\n\n  getData(format: string): string {\n    return this.store.get(format) ?? '';\n  }\n\n  setData(format: string, data: string): void {\n    this.store.set(format, data);\n  }\n\n  /**\n   * No-op: jsdom has no layout/paint, so a custom drag image has nothing to\n   * render. (Overrides the inherited `DataTransfer.setDragImage` doc comment,\n   * which embeds raw `<img>`/`<canvas>` markup that breaks MDX rendering on\n   * the generated API reference page.)\n   */\n  setDragImage(_image: Element, _x: number, _y: number): void {\n    // Intentionally empty — see the doc comment above.\n  }\n}\n","/**\n * Fake mouse event used internally by `DOMInteractor` to synthesize positioned\n * mouse events. Exported for cross-package reuse within the monorepo, not part\n * of the stable 1.0 consumer API.\n *\n * `pageX`/`pageY` are getter-only accessors on the `MouseEvent` prototype in\n * real browsers (the Angular fixtures run DOM tests in Chromium, ADR-013), so\n * they are shadowed with own properties rather than assigned — plain\n * assignment throws where jsdom happened to tolerate it.\n *\n * @see https://github.com/testing-library/react-testing-library/issues/268\n * @internal\n */\nexport class FakeMouseEvent extends MouseEvent {\n  constructor(type: string, overrides: Partial<MouseEvent> = {}) {\n    super(type, overrides);\n    Object.defineProperty(this, 'pageX', { value: overrides.pageX ?? 0, configurable: true });\n    Object.defineProperty(this, 'pageY', { value: overrides.pageY ?? 0, configurable: true });\n  }\n}\n","import {\n  AccessibleRoleLocator,\n  assertValidClickCount,\n  BlurOption,\n  BoundingRect,\n  ClickOption,\n  CssProperty,\n  dateUtil,\n  defaultWaitForOption,\n  ElementNotFoundError,\n  EnterTextOption,\n  FocusOption,\n  HoverOption,\n  Interactor,\n  interactorUtil,\n  locatorUtil,\n  MouseDownOption,\n  MouseEnterOption,\n  MouseLeaveOption,\n  MouseMoveOption,\n  MouseOutOption,\n  MouseUpOption,\n  Optional,\n  PartLocator,\n  Point,\n  PressKeyOption,\n  timingUtil,\n  elementStateUtil,\n  visibilityUtil,\n  WaitForOption,\n  WaitUntilOption,\n} from '@atomic-testing/core';\nimport { fireEvent, queryAllByRole } from '@testing-library/dom';\nimport defaultUserEvent from '@testing-library/user-event';\n\nimport { FakeDataTransfer, FakeMouseEvent } from './fakeEvents';\nimport { DOMInteractorOption, UserEventDispatcher } from './types';\n\n/**\n * Derive a `KeyboardEvent.code` from a `KeyboardEvent.key`, approximating what\n * a real browser reports for a standard US layout: letters map to `KeyX`,\n * digits to `DigitX`, space to `Space`, and named keys (`ArrowRight`, `Enter`,\n * `Home`, …) carry their own name as the code. jsdom leaves `code` empty\n * unless supplied, but real keyboard events always populate it — and component\n * libraries legitimately switch on `code` (PrimeVue's Slider does), so the\n * jsdom leg must match. Left/right-variant modifiers (`Shift` → `ShiftLeft`)\n * are not disambiguated; a bare modifier press is not a supported gesture here.\n */\nfunction deriveKeyCode(key: string): string {\n  if (key === ' ') {\n    return 'Space';\n  }\n  if (/^[a-zA-Z]$/.test(key)) {\n    return `Key${key.toUpperCase()}`;\n  }\n  if (/^[0-9]$/.test(key)) {\n    return `Digit${key}`;\n  }\n  return key;\n}\n\n/**\n * Whether a key press on this element needs `beforeinput`/`input` fidelity — true\n * only for a `contenteditable` host. Such a host commits edits from input events\n * that a bare `keydown`/`keyup` never produces (the MUI X picker section field\n * clears on `Backspace` this way, see #903), so it must go through\n * `userEvent.keyboard`.\n *\n * Everything else — including `<input>`/`<textarea>` — keeps the direct\n * `fireEvent.keyDown` dispatch on the element, which is what keyboard-driven\n * drivers rely on and matches the pre-existing behavior. `userEvent.keyboard`\n * delivers to `document.activeElement` and regressed command-key contracts on\n * both non-editable and editable targets: Angular Material `MatSelect`\n * (open on `Enter`) and `MatAutocomplete` (close on `Escape`, whose target is a\n * text `<input>`). Text fields do their actual editing through\n * {@link DOMInteractor.enterText}/{@link DOMInteractor.typeText}, not `pressKey`,\n * so excluding them here loses nothing. jsdom leaves `isContentEditable`\n * `undefined`, so the attribute is consulted directly rather than the property.\n */\nfunction needsInputEventFidelity(el: Element): boolean {\n  if ((el as HTMLElement).isContentEditable === true) {\n    return true;\n  }\n  const contentEditable = el.getAttribute('contenteditable');\n  return contentEditable === '' || contentEditable === 'true';\n}\n\n/**\n * The jsdom-backed {@link Interactor} implementation — dispatches events and\n * reads the DOM via `@testing-library/dom`'s `fireEvent` and `user-event`. The\n * blessed base for every framework adapter that runs against jsdom (ADR-002,\n * ADR-007): `ReactInteractor` and `VueInteractor` extend it and layer their\n * reactivity flush onto the {@link runInteraction} seam rather than\n * reimplementing the primitives. `PlaywrightInteractor` does not extend this\n * class — its browser backing shares no implementation with jsdom.\n */\nexport class DOMInteractor implements Interactor {\n  protected readonly userEvent: UserEventDispatcher;\n\n  constructor(\n    protected readonly rootEl: HTMLElement = document.documentElement,\n    option?: DOMInteractorOption\n  ) {\n    this.userEvent = option?.userEvent ?? defaultUserEvent;\n  }\n\n  /**\n   * Template-method seam every mutating primitive (and both wait conditions)\n   * routes through. The base runs the interaction verbatim; framework adapters\n   * override it to flush their reactivity around the whole interaction —\n   * `ReactInteractor` wraps it in `act(...)`, `VueInteractor` awaits\n   * `nextTick()`. Because every mutation funnels through this one method, a new\n   * mutating primitive added to this base is flushed by every adapter\n   * automatically — closing the silent gap that the previous per-method\n   * overrides left open, where an un-mirrored primitive was inherited unwrapped\n   * (#1052).\n   *\n   * Reads (`getText`, `getAttribute`, `exists`, …) deliberately do NOT route\n   * through here: they observe state without mutating it, so there is nothing to\n   * flush.\n   */\n  protected runInteraction<T>(fn: () => Promise<T>): Promise<T> {\n    return fn();\n  }\n\n  async getAttribute(locator: PartLocator, name: string, isMultiple: true): Promise<readonly string[]>;\n  async getAttribute(locator: PartLocator, name: string, isMultiple: false): Promise<Optional<string>>;\n  async getAttribute(locator: PartLocator, name: string): Promise<Optional<string>>;\n  async getAttribute(\n    locator: PartLocator,\n    name: string,\n    isMultiple?: boolean\n  ): Promise<Optional<string> | readonly string[]> {\n    if (isMultiple) {\n      const elements = await this.getElement(locator, true);\n      return Promise.resolve(elements.map(el => el.getAttribute(name)!));\n    } else {\n      const el = await this.getElement(locator);\n      if (el != null) {\n        return Promise.resolve(el.getAttribute(name) ?? undefined);\n      }\n      return undefined;\n    }\n  }\n\n  async getStyleValue(locator: PartLocator, propertyName: CssProperty): Promise<Optional<string>> {\n    const el = await this.getElement(locator);\n    if (el != null) {\n      const computedStyle = window.getComputedStyle(el as HTMLElement);\n      const val = computedStyle[propertyName] as string;\n      return Promise.resolve(val ?? undefined);\n    }\n    return undefined;\n  }\n\n  protected calculateMousePosition(el: Element, preferredPoint?: Point) {\n    const rect = el.getBoundingClientRect();\n    const mouseLocation: Point = {\n      x: preferredPoint?.x != null ? rect.left + preferredPoint?.x : rect.left + rect.width / 2,\n      y: preferredPoint?.y != null ? rect.top + preferredPoint?.y : rect.top + rect.height / 2,\n    };\n    return mouseLocation;\n  }\n\n  /**\n   * Dispatch a click event on the element that matches the locator.\n   *\n   * @param locator - Locator used to find the target element\n   * @param option - Optional click configuration such as the click position\n   * @returns A promise that resolves after the event is triggered\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async click(locator: PartLocator, option?: ClickOption): Promise<void> {\n    assertValidClickCount(option?.clickCount);\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'click');\n      }\n\n      const isDoubleClick = option?.clickCount === 2;\n      const isSimpleEvent = option?.position == null;\n      if (isSimpleEvent) {\n        // Some MUI component does not work with fireEvent('click', ...)\n        await (isDoubleClick ? this.userEvent.dblClick(el) : this.userEvent.click(el));\n      } else {\n        const clickLocation = this.calculateMousePosition(el, option?.position);\n        const dispatch = (type: string) =>\n          fireEvent(\n            el,\n            new FakeMouseEvent(type, {\n              bubbles: true,\n              clientX: clickLocation.x,\n              clientY: clickLocation.y,\n            })\n          );\n        // A real double-click gesture is two full clicks followed by the\n        // `dblclick` event — firing `dblclick` alone would skip `onClick`\n        // handlers a component also relies on.\n        if (isDoubleClick) {\n          dispatch('click');\n          dispatch('click');\n          dispatch('dblclick');\n        } else {\n          dispatch('click');\n        }\n      }\n    });\n  }\n\n  /**\n   * Move the mouse over the element.\n   *\n   * @param locator - Locator used to find the target element\n   * @param _option - Reserved for future use\n   * @returns A promise that resolves after the hover event\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async hover(locator: PartLocator, _option?: HoverOption): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'hover');\n      }\n      await this.userEvent.hover(el);\n    });\n  }\n\n  /**\n   * Dispatch a `mousemove` event on the target element.\n   *\n   * @param locator - Locator used to find the target element\n   * @param option - Allows specifying the mouse position relative to the element\n   * @returns A promise that resolves once the event has been dispatched\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async mouseMove(locator: PartLocator, option?: Partial<MouseMoveOption>): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'mouseMove');\n      }\n\n      const moveLocation = this.calculateMousePosition(el, option?.position);\n      const evt = new FakeMouseEvent('mousemove', {\n        bubbles: true,\n        clientX: moveLocation.x,\n        clientY: moveLocation.y,\n      });\n\n      fireEvent(el, evt);\n    });\n  }\n\n  /**\n   * Dispatch a `mousedown` event on the target element.\n   *\n   * @param locator - Locator used to find the target element\n   * @param option - Allows specifying the mouse position relative to the element\n   * @returns Promise resolved when the event is dispatched\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async mouseDown(locator: PartLocator, option?: Partial<MouseDownOption>): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'mouseDown');\n      }\n\n      const mouseLocation = this.calculateMousePosition(el, option?.position);\n      const evt = new FakeMouseEvent('mousedown', {\n        bubbles: true,\n        clientX: mouseLocation.x,\n        clientY: mouseLocation.y,\n      });\n\n      fireEvent(el, evt);\n    });\n  }\n\n  /**\n   * Dispatch a `mouseup` event on the target element.\n   *\n   * @param locator - Locator used to find the target element\n   * @param option - Allows specifying the mouse position relative to the element\n   * @returns Promise resolved when the event is dispatched\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async mouseUp(locator: PartLocator, option?: Partial<MouseUpOption>): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'mouseUp');\n      }\n\n      const mouseLocation = this.calculateMousePosition(el, option?.position);\n      const evt = new FakeMouseEvent('mouseup', {\n        bubbles: true,\n        clientX: mouseLocation.x,\n        clientY: mouseLocation.y,\n      });\n\n      fireEvent(el, evt);\n    });\n  }\n\n  /**\n   * Dispatch a `mouseover` event on the target element.\n   *\n   * @param locator - Locator used to find the target element\n   * @param option - Optional mouse position relative to the element\n   * @returns Promise resolved once the event is dispatched\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async mouseOver(locator: PartLocator, option?: Partial<HoverOption>): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'mouseOver');\n      }\n\n      const moveLocation = this.calculateMousePosition(el, option?.position);\n      const evt = new FakeMouseEvent('mouseover', {\n        bubbles: true,\n        clientX: moveLocation.x,\n        clientY: moveLocation.y,\n      });\n\n      fireEvent(el, evt);\n    });\n  }\n\n  /**\n   * Dispatch a `mouseout` event on the target element.\n   *\n   * @param locator - Locator used to find the target element\n   * @param _option - Reserved for future use\n   * @returns Promise resolved once the event is dispatched\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async mouseOut(locator: PartLocator, _option?: Partial<MouseOutOption>): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'mouseOut');\n      }\n\n      fireEvent.mouseOut(el);\n    });\n  }\n\n  /**\n   * Dispatch a `mouseenter` event on the target element.\n   *\n   * @param locator - Locator used to find the target element\n   * @param _option - Reserved for future use\n   * @returns Promise resolved after the event dispatches\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async mouseEnter(locator: PartLocator, _option?: Partial<MouseEnterOption>): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'mouseEnter');\n      }\n\n      // mouseOver would trigger mouseEnter event\n      // hover fireEvent.mouseEnter does not\n      fireEvent.mouseOver(el);\n    });\n  }\n\n  /**\n   * Dispatch a `mouseleave` event on the target element.\n   *\n   * @param locator - Locator used to find the target element\n   * @param _option - Reserved for future use\n   * @returns Promise resolved once the event is dispatched\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async mouseLeave(locator: PartLocator, _option?: Partial<MouseLeaveOption>): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'mouseLeave');\n      }\n\n      fireEvent.mouseOut(el);\n    });\n  }\n\n  /**\n   * Move focus to the element found by the locator.\n   *\n   * @param locator - Locator used to find the target element\n   * @param _option - Reserved for future use\n   * @returns Promise resolved when focus has been applied\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async focus(locator: PartLocator, _option?: Partial<FocusOption>): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'focus');\n      }\n      if ('focus' in el === false) {\n        return;\n      }\n      (el as HTMLInputElement).focus();\n    });\n  }\n\n  /**\n   * Remove focus from the element found by the locator.\n   *\n   * @param locator - Locator used to find the target element\n   * @param _option - Reserved for future use\n   * @returns Promise resolved when blur has been applied\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async blur(locator: PartLocator, _option?: Partial<BlurOption>): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'blur');\n      }\n      if ('blur' in el === false) {\n        return;\n      }\n      (el as HTMLInputElement).blur();\n    });\n  }\n\n  /**\n   * Legacy numeric key codes for the named keys drivers press. Synthetic\n   * `KeyboardEvent`s carry `keyCode: 0` unless told otherwise, and several\n   * component libraries (Angular Material/CDK among them) still dispatch on\n   * `event.keyCode` rather than `event.key` — without this a synthetic\n   * `Escape`/`Enter` is silently ignored. Real browser input (Playwright)\n   * carries the code natively; this map restores parity for the DOM path.\n   */\n  private static readonly legacyKeyCodes: Readonly<Record<string, number>> = {\n    Backspace: 8,\n    Tab: 9,\n    Enter: 13,\n    Escape: 27,\n    ' ': 32,\n    PageUp: 33,\n    PageDown: 34,\n    End: 35,\n    Home: 36,\n    ArrowLeft: 37,\n    ArrowUp: 38,\n    ArrowRight: 39,\n    ArrowDown: 40,\n    Delete: 46,\n  };\n\n  private static legacyKeyCodeOf(key: string): number | undefined {\n    const named = DOMInteractor.legacyKeyCodes[key];\n    if (named != null) {\n      return named;\n    }\n    // Letters and digits: the legacy code is the uppercase character code.\n    return /^[a-zA-Z0-9]$/.test(key) ? key.toUpperCase().charCodeAt(0) : undefined;\n  }\n\n  /**\n   * Dispatch a key press (`keydown` + `keyup`) on the element matched by the locator.\n   *\n   * The element is focused first so the key originates from the active element,\n   * matching a real key press. `fireEvent` is used over `userEvent.keyboard` for\n   * determinism and because MUI handlers read `event.key` directly. The physical\n   * `code` is derived from `key` (see {@link deriveKeyCode}) so handlers that\n   * switch on `event.code` — e.g. PrimeVue's Slider — behave as they do under a\n   * real browser event, where `code` is always populated.\n   *\n   * `key` is dispatched verbatim — a `shift` modifier is NOT used to derive a\n   * shifted character (`{ key: 'a', shift: true }` stays `key: 'a'`, never\n   * folded to `'A'`), matching `PlaywrightInteractor`'s behavior (see\n   * {@link KeyboardActions.pressKey} for the cross-engine verification, #924).\n   *\n   * @param locator - Locator used to find the target element\n   * @param key - A `KeyboardEvent.key` value, e.g. `'Escape'`, `'Backspace'`\n   * @param option - Modifier flags folded into the event init as\n   * `ctrlKey`/`shiftKey`/`altKey`/`metaKey`, so a handler reading\n   * `event.ctrlKey` (etc.) sees the chord — see {@link PressKeyOption}\n   * @returns Promise resolved once the events have been dispatched\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async pressKey(locator: PartLocator, key: string, option?: Partial<PressKeyOption>): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'pressKey');\n      }\n      if ('focus' in el) {\n        (el as HTMLElement).focus();\n      }\n\n      // For a focused text-editing target, dispatch through `userEvent.keyboard`\n      // so the press carries full editing fidelity — keydown → beforeinput/input →\n      // keyup — matching Playwright's `locator.press()`. A bare keydown/keyup pair\n      // reaches `KeyboardEvent.key` handlers but is invisible to components that\n      // commit edits from input events (e.g. the MUI X picker section field\n      // clearing on Backspace, see #903). This is gated to editing targets\n      // ({@link needsInputEventFidelity}): command targets (combobox, dialog,\n      // chip) must keep the direct `fireEvent` dispatch their keyboard handlers\n      // rely on — `userEvent.keyboard` delivers to `document.activeElement`, which\n      // broke the Angular Material `MatSelect` open-on-Enter path.\n      const activeElement = el.ownerDocument?.activeElement;\n      const holdsFocus = el === activeElement || (activeElement != null && el.contains(activeElement));\n      if (holdsFocus && needsInputEventFidelity(el)) {\n        // Printable keys are typed as-is (doubling `{`/`[` so user-event's\n        // descriptor syntax never engages); named keys become `{Key}` descriptors.\n        // The global flag is defensive — `key.length === 1` means at most one char\n        // here — and keeps the escape consistent with `typeText`'s.\n        const descriptor = key.length === 1 ? key.replace(/[{[]/g, '$&$&') : `{${key}}`;\n        let chord = descriptor;\n        if (option?.shift) {\n          chord = `{Shift>}${chord}{/Shift}`;\n        }\n        if (option?.alt) {\n          chord = `{Alt>}${chord}{/Alt}`;\n        }\n        if (option?.ctrl) {\n          chord = `{Control>}${chord}{/Control}`;\n        }\n        if (option?.meta) {\n          chord = `{Meta>}${chord}{/Meta}`;\n        }\n        try {\n          await this.userEvent.keyboard(chord);\n          return;\n        } catch {\n          // user-event rejects keys outside its keyboard map while parsing,\n          // before dispatching anything — fall through to the bare key events so\n          // exotic keys still reach KeyboardEvent.key handlers as before.\n        }\n      }\n\n      // Non-focusable target (or a key user-event cannot type): dispatch the key\n      // events directly on the element, as a real key press cannot originate\n      // from it anyway.\n      // `keyCode`/`which` mirror `key` for handlers that still read the legacy\n      // numeric code (see legacyKeyCodes above).\n      const keyCode = DOMInteractor.legacyKeyCodeOf(key);\n      const eventInit = {\n        key,\n        code: deriveKeyCode(key),\n        ...(keyCode != null ? { keyCode, which: keyCode } : {}),\n        ctrlKey: !!option?.ctrl,\n        shiftKey: !!option?.shift,\n        altKey: !!option?.alt,\n        metaKey: !!option?.meta,\n      };\n      fireEvent.keyDown(el, eventInit);\n      fireEvent.keyUp(el, eventInit);\n    });\n  }\n\n  /**\n   * Dispatch a `contextmenu` (right-click) event on the element matched by the locator.\n   *\n   * The element is focused first if focusable, mirroring {@link pressKey}, so the\n   * event originates from the active element as a real right-click would. A\n   * context menu has no `aria-expanded`/controlled-open path, so this dispatched\n   * event is the only way to exercise the menu-opening behavior.\n   *\n   * @param locator - Locator used to find the target element\n   * @returns Promise resolved once the event has been dispatched\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async contextMenu(locator: PartLocator): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'contextMenu');\n      }\n      if ('focus' in el) {\n        (el as HTMLElement).focus();\n      }\n      fireEvent.contextMenu(el);\n    });\n  }\n\n  /**\n   * Activate the element matched by the locator without pointer geometry.\n   *\n   * Uses `userEvent.click`, which ignores layout and coordinates, so it reaches a\n   * visually-hidden or covered input that a positional click would miss (e.g. MUI\n   * Rating's hidden `<input type=\"radio\">`).\n   *\n   * @param locator - Locator used to find the target element\n   * @returns Promise resolved once the element has been activated\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async activate(locator: PartLocator): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'activate');\n      }\n      await this.userEvent.click(el);\n    });\n  }\n\n  /**\n   * Type text into the element matched by the locator.\n   *\n   * @param locator - Locator used to find the target element\n   * @param text - The string to type\n   * @param option - Options such as appending or replacing existing value\n   * @returns Promise resolved when typing has completed\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async enterText(locator: PartLocator, text: string, option?: Partial<EnterTextOption> | undefined): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'enterText');\n      }\n\n      if (!option?.append) {\n        await this.userEvent.clear(el);\n      }\n\n      // An empty value is a pure clear: `userEvent.clear()` above already emptied\n      // the field and `userEvent.type` rejects `''` (\"Expected key descriptor\"),\n      // so there is nothing left to type. Return early on the mechanism grounds\n      // that `userEvent.type` cannot take `''`; the shared date-format policy\n      // (`dateUtil.assertValidHtmlDateInputValue`) likewise treats `''` as a valid\n      // clear, keeping this in lockstep with PlaywrightInteractor's `clear()` +\n      // `fill('')`.\n      if (text === '') {\n        return;\n      }\n\n      // Enforce the shared date/time/datetime-local format policy (#1053).\n      if (el.tagName === 'INPUT') {\n        dateUtil.assertValidHtmlDateInputValue(el.getAttribute('type') ?? '', text);\n      }\n\n      await this.userEvent.type(el, text);\n    });\n  }\n\n  /**\n   * Type text into the element as real per-character keystrokes.\n   *\n   * Focuses the element, then dispatches the characters through\n   * `userEvent.keyboard`, which fires the full key event sequence\n   * (keydown → beforeinput → input → keyup) against the active element —\n   * matching `PlaywrightInteractor`'s `pressSequentially` (focus + keys, no\n   * pointer event, no clearing). `{`/`[` are doubled so user-event's\n   * descriptor syntax never engages and the text is typed literally.\n   *\n   * @param locator - Locator used to find the target element\n   * @param text - The literal text to type, one keystroke per character\n   * @returns Promise resolved once every keystroke has been dispatched\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async typeText(locator: PartLocator, text: string): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'typeText');\n      }\n      if ('focus' in el) {\n        (el as HTMLElement).focus();\n      }\n      // A real browser places a caret inside a contenteditable host on focus;\n      // jsdom does not, and userEvent.keyboard inserts at the document selection\n      // — so without a caret the keystrokes would land nowhere. Collapse a\n      // selection to the end of the host's content (matching userEvent.type's\n      // append behavior) unless the caret is already inside it.\n      if (el.hasAttribute('contenteditable')) {\n        const selection = el.ownerDocument.getSelection();\n        if (selection != null && (selection.anchorNode == null || !el.contains(selection.anchorNode))) {\n          const range = el.ownerDocument.createRange();\n          range.selectNodeContents(el);\n          range.collapse(false);\n          selection.removeAllRanges();\n          selection.addRange(range);\n        }\n      }\n      // userEvent.keyboard('') throws (\"Expected key descriptor\"), so an empty\n      // text is focus-only — the same outcome pressSequentially('') produces.\n      if (text === '') {\n        return;\n      }\n      const literalText = text.replace(/[{[]/g, '$&$&');\n      await this.userEvent.keyboard(literalText);\n    });\n  }\n\n  /**\n   * Set the value of a range input and fire its change event.\n   *\n   * `fireEvent.change` assigns the value through the element's native value\n   * setter (which both sanitizes it to the input's step and lets React's value\n   * tracker observe the change) and dispatches the event so a controlled\n   * component re-renders. Typing (`enterText`) does not apply to a range input.\n   *\n   * @param locator - Locator used to find the range input element\n   * @param value - The numeric value to set\n   * @returns Promise resolved once the change event has fired\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async setRangeValue(locator: PartLocator, value: number): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'setRangeValue');\n      }\n      fireEvent.change(el, { target: { value: String(value) } });\n    });\n  }\n\n  /**\n   * Select one or more option values in a `<select>` element.\n   *\n   * @param locator - Locator used to find the select element\n   * @param values - Values of the options to select\n   * @returns Promise resolved when the options have been selected\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async selectOptionValue(locator: PartLocator, values: string[]): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'selectOptionValue');\n      }\n      await this.userEvent.selectOptions(el, values);\n    });\n  }\n\n  /**\n   * Set the selected files on an `<input type=\"file\">` element.\n   *\n   * The interactor contract passes filesystem paths, but a file input's value\n   * cannot be assigned programmatically — the browser blocks it — so the\n   * `FileList` must be populated through `userEvent.upload`, which also fires the\n   * `change` event. jsdom has no filesystem and never reads file bytes; only\n   * `File.name` is observable, so each path is wrapped in an empty `File` named\n   * by its basename. The real bytes matter only to the Playwright layer, which\n   * reads the paths natively — keeping `dom-core` free of any `node` dependency.\n   *\n   * @param locator - Locator used to find the file input element\n   * @param files - One or more filesystem paths to upload\n   * @returns Promise resolved once the upload change event has fired\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async setInputFiles(locator: PartLocator, files: string | string[]): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'setInputFiles');\n      }\n      const paths = Array.isArray(files) ? files : [files];\n      const fileObjects = paths.map(filePath => {\n        // `||` (not `??`): split().pop() yields '' (not undefined) for a\n        // trailing-separator path, and an empty File name is useless — fall back\n        // to the full path in that case.\n        const name = filePath.split(/[\\\\/]/).pop() || filePath;\n        return new File([], name);\n      });\n      await this.userEvent.upload(el as HTMLElement, fileObjects);\n    });\n  }\n\n  /**\n   * Scroll the located element into view.\n   *\n   * jsdom has no layout engine, so this never produces an observable scroll —\n   * geometry stays zeroed and nothing becomes \"visible\". Worse, jsdom does not\n   * implement `Element.prototype.scrollIntoView` as a function in every version,\n   * so calling it unguarded would throw a `TypeError`. The `typeof` guard keeps\n   * this a safe no-op that resolves; real scrolling behavior is E2E-only.\n   *\n   * @param locator - Locator used to find the element\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async scrollIntoView(locator: PartLocator): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'scrollIntoView');\n      }\n      if (typeof (el as HTMLElement).scrollIntoView === 'function') {\n        (el as HTMLElement).scrollIntoView();\n      }\n    });\n  }\n\n  /**\n   * Scroll the located element by the given pixel delta.\n   *\n   * jsdom has no layout engine, so the scroll offset never changes — this is a\n   * no-op behaviorally. As with {@link scrollIntoView}, jsdom may not implement\n   * `Element.prototype.scrollBy` as a function, so the `typeof` guard prevents a\n   * `TypeError` and keeps the call a safe no-op that resolves; real scroll\n   * behavior is E2E-only.\n   *\n   * @param locator - Locator used to find the scrollable element\n   * @param delta - Pixel offset to scroll by\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async scrollBy(locator: PartLocator, delta: Point): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'scrollBy');\n      }\n      if (typeof (el as HTMLElement).scrollBy === 'function') {\n        (el as HTMLElement).scrollBy(delta.x, delta.y);\n      }\n    });\n  }\n\n  /**\n   * Dispatch a single bubbling mouse event at `point` using the shared\n   * {@link FakeMouseEvent}. Centralizes the drag gesture's event shape so\n   * {@link drag} and {@link dragTo} cannot drift apart.\n   */\n  private dispatchMouse(el: Element, type: string, point: Point): void {\n    fireEvent(el, new FakeMouseEvent(type, { bubbles: true, clientX: point.x, clientY: point.y }));\n  }\n\n  /**\n   * Fire the native HTML5 drag-and-drop event sequence — `dragstart` on\n   * `sourceEl` → `dragenter`/`dragover`/`drop` on `targetEl` → `dragend` on\n   * `sourceEl` — sharing one {@link FakeDataTransfer} across every event, so a\n   * `dragstart` handler's `setData` is readable from `drop`'s `getData`.\n   * `sourceEl === targetEl` is valid: {@link drag}'s single-element delta\n   * gesture has no separate drop target, so it drags and drops onto itself.\n   *\n   * Fired unconditionally: unlike a real browser — which fires `drop` only\n   * when the `dragover` listener calls `preventDefault()` to accept the drop —\n   * jsdom has no native drag-recognition machinery to gate on, so this always\n   * runs the full sequence. This is NOT identical to {@link\n   * PlaywrightInteractor}, whose `drag`/`dragTo` drive a REAL pointer gesture\n   * that the real browser's own native DnD recognition processes — including\n   * the real `preventDefault()` gate — see #922. A target that opts in the\n   * way any real HTML5-DnD target must (calling `preventDefault()` in its\n   * `dragover`/`dragenter` handler, as the shared `.suite.ts` fixture does)\n   * sees `drop` fire in both engines regardless of this difference; a target\n   * that never opts in would still see `drop` here but not in a real browser\n   * — an accepted simplification for a synthetic environment with no native\n   * gesture recognition to simulate faithfully.\n   *\n   * jsdom implements neither `DragEvent` nor `DataTransfer` (only\n   * `MouseEvent`), so `@testing-library/dom`'s `fireEvent.drag*` dispatch a\n   * plain `Event` with `dataTransfer` attached as a property rather than a\n   * real `DragEvent` — its own documented recipe for jsdom HTML5 DnD (see\n   * https://github.com/jsdom/jsdom/issues/1568). Coordinates are not carried on\n   * these events for the same reason {@link dispatchMouse}'s are E2E-only:\n   * jsdom has no layout.\n   */\n  private dispatchHtml5DragSequence(sourceEl: Element, targetEl: Element): void {\n    const dataTransfer = new FakeDataTransfer();\n    fireEvent.dragStart(sourceEl, { dataTransfer });\n    fireEvent.dragEnter(targetEl, { dataTransfer });\n    fireEvent.dragOver(targetEl, { dataTransfer });\n    fireEvent.drop(targetEl, { dataTransfer });\n    fireEvent.dragEnd(sourceEl, { dataTransfer });\n  }\n\n  /**\n   * Drag the source element and drop it onto the target element.\n   *\n   * The pointer sequence (`mousedown` on source → `mousemove` on target →\n   * `mouseup` on target) is synthesized with the shared {@link dispatchMouse} +\n   * {@link calculateMousePosition} pattern. jsdom has no layout, so those\n   * coordinates are all zeros — the event wiring (and any drop handler the\n   * sequence triggers) is exercised, but the positional outcome is E2E-only.\n   *\n   * The native HTML5 drag-and-drop sequence\n   * (`dragstart`/`dragenter`/`dragover`/`drop`/`dragend` + `dataTransfer`) is\n   * ALSO synthesized via {@link dispatchHtml5DragSequence}, so both DnD\n   * models — pointer/mouse-based (dnd-kit, react-beautiful-dnd) and native\n   * HTML5 (`draggable` + `ondragstart`/`ondragover`/`ondrop`) — are driven by\n   * this one primitive (#922).\n   *\n   * @param source - Locator used to find the element to drag\n   * @param target - Locator used to find the drop target\n   * @throws {ElementNotFoundError} If either element is not found\n   */\n  async dragTo(source: PartLocator, target: PartLocator): Promise<void> {\n    return this.runInteraction(async () => {\n      const sourceEl = await this.getElement(source);\n      if (sourceEl == null) {\n        throw new ElementNotFoundError(source, 'dragTo');\n      }\n      const targetEl = await this.getElement(target);\n      if (targetEl == null) {\n        throw new ElementNotFoundError(target, 'dragTo');\n      }\n\n      const sourcePoint = this.calculateMousePosition(sourceEl);\n      const targetPoint = this.calculateMousePosition(targetEl);\n\n      this.dispatchMouse(sourceEl, 'mousedown', sourcePoint);\n      this.dispatchMouse(targetEl, 'mousemove', targetPoint);\n      this.dispatchMouse(targetEl, 'mouseup', targetPoint);\n      this.dispatchHtml5DragSequence(sourceEl, targetEl);\n    });\n  }\n\n  /**\n   * Drag the located element by the given pixel delta from its center.\n   *\n   * The sequence (`mousedown` at center → `mousemove` at center + delta →\n   * `mouseup` at center + delta) is synthesized with the shared\n   * {@link dispatchMouse} + {@link calculateMousePosition} pattern, using the\n   * caller-supplied delta for the move/up coordinates. jsdom has no layout, so the\n   * center resolves to zeros and only the event wiring is exercised — the\n   * behavioral outcome of the drag is E2E-only.\n   *\n   * The native HTML5 drag-and-drop sequence is ALSO synthesized (on the same\n   * element, as its own drop target — see {@link dispatchHtml5DragSequence}),\n   * so a `draggable` element driven by this primitive sees `dragstart` and\n   * `dragend` regardless of DnD model (#922).\n   *\n   * @param locator - Locator used to find the element to drag\n   * @param delta - Pixel offset to drag by\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async drag(locator: PartLocator, delta: Point): Promise<void> {\n    return this.runInteraction(async () => {\n      const el = await this.getElement(locator);\n      if (el == null) {\n        throw new ElementNotFoundError(locator, 'drag');\n      }\n\n      const start = this.calculateMousePosition(el);\n      const end: Point = { x: start.x + delta.x, y: start.y + delta.y };\n\n      this.dispatchMouse(el, 'mousedown', start);\n      this.dispatchMouse(el, 'mousemove', end);\n      this.dispatchMouse(el, 'mouseup', end);\n      this.dispatchHtml5DragSequence(el, el);\n    });\n  }\n\n  //#region wait conditions\n  async waitUntilComponentState(\n    locator: PartLocator,\n    option: Partial<Readonly<WaitForOption>> = defaultWaitForOption\n  ): Promise<void> {\n    // Routed through the seam so a framework adapter's flush wraps the ENTIRE\n    // probe loop in one pass (React's single surrounding `act`), not each probe.\n    return this.runInteraction(() => interactorUtil.interactorWaitUtil(locator, this, option));\n  }\n\n  waitUntil<T>(option: WaitUntilOption<T>): Promise<T> {\n    return this.runInteraction(() => timingUtil.waitUntil(option));\n  }\n  //#endregion\n\n  async exists(locator: PartLocator): Promise<boolean> {\n    const el = await this.getElement(locator);\n    return Promise.resolve(el != null);\n  }\n\n  /**\n   * Count every element matching the locator — the length of the multi-match\n   * query. Reuses the {@link getElement} multiple-overload rather than a second\n   * `querySelectorAll` path, so the document-root (`:root`) escape is honored in\n   * exactly one place. A read: it does NOT route through {@link runInteraction}.\n   */\n  async getElementCount(locator: PartLocator): Promise<number> {\n    const elements = await this.getElement(locator, true);\n    return elements.length;\n  }\n\n  async getElement<T extends Element = Element>(locator: PartLocator, isMultiple: true): Promise<readonly T[]>;\n  async getElement<T extends Element = Element>(locator: PartLocator, isMultiple: false): Promise<Optional<T>>;\n  async getElement<T extends Element = Element>(locator: PartLocator): Promise<Optional<T>>;\n  async getElement<T extends Element = Element>(locator: PartLocator, isMultiple = false) {\n    const accessibleRoleSplit = locatorUtil.splitAtAccessibleRoleLocator(locator);\n    if (accessibleRoleSplit != null) {\n      return this.getElementByAccessibleRole<T>(accessibleRoleSplit, isMultiple);\n    }\n\n    const cssLocator = await locatorUtil.toCssSelector(locator, this);\n    // The engine-root locator (`[]`) resolves to `:root`, which matches `<html>` —\n    // an ancestor of `rootEl`, so `rootEl.querySelector(':root')` finds nothing.\n    // Query from the document in that case, matching `document.querySelector(':root')`\n    // and Playwright's `page.locator(':root')`. See #1048.\n    const escapesToDocumentRoot =\n      cssLocator === locatorUtil.documentRootSelector || this.escapesToDocumentRoot(locator);\n    const queryRoot = escapesToDocumentRoot ? this.rootEl.ownerDocument : this.rootEl;\n    if (isMultiple) {\n      const elList = queryRoot.querySelectorAll<T>(cssLocator);\n      const result: T[] = [];\n      elList.forEach(el => result.push(el));\n      return result;\n    }\n    return queryRoot.querySelector<T>(cssLocator) ?? undefined;\n  }\n\n  /**\n   * Resolve a locator chain split at its {@link AccessibleRoleLocator}\n   * segment (`findByRole`) — the second resolution channel, bypassing CSS\n   * entirely (#923). Three cases for the scope the accname search runs\n   * within, mirroring how an ordinary CSS chain resolves:\n   *\n   * - `roleLocator.relative === 'Root'` — escapes to the document root\n   *   (via {@link getElement}'s existing `[]` → `:root` handling), mirroring\n   *   how a trailing `'Root'` locator in an ordinary chain slices away\n   *   everything before it (see `escapesToDocumentRoot`).\n   * - `before` is non-empty — resolves normally (recursing back into\n   *   {@link getElement}, so it fully supports nested `LinkedCssLocator`s\n   *   etc.) to a single scope element.\n   * - `before` is empty and NOT a `'Root'` escape — scopes to `this.rootEl`\n   *   directly, NOT the document root. An unscoped `findByRole(...)` must\n   *   still respect the interactor's own scoping (e.g. a Storybook canvas),\n   *   exactly like a bare CSS locator does; routing this case through\n   *   `getElement([])` would incorrectly escape to the document regardless\n   *   of `rootEl`, since an empty chain always reduces to `:root`.\n   *\n   * Within that scope, `@testing-library/dom`'s `queryAllByRole` resolves by\n   * the accname algorithm — the same engine `dom-core` already depends on for\n   * this exact purpose (see the `findByRole` design in ADR 0001, Decision B).\n   * `hidden: true` matches this codebase's other locators, which resolve\n   * structurally regardless of visibility (`isVisible` is the dedicated\n   * visibility check, not baked into resolution).\n   */\n  private async getElementByAccessibleRole<T extends Element>(\n    split: { before: PartLocator; roleLocator: AccessibleRoleLocator },\n    isMultiple: boolean\n  ): Promise<T[] | Optional<T>> {\n    const scopeEl =\n      split.roleLocator.relative === 'Root'\n        ? await this.getElement([])\n        : split.before.length === 0\n          ? this.rootEl\n          : await this.getElement(split.before);\n    if (scopeEl == null) {\n      return isMultiple ? [] : undefined;\n    }\n    const matches = queryAllByRole(scopeEl as HTMLElement, split.roleLocator.role, {\n      hidden: true,\n      ...(split.roleLocator.name != null ? { name: split.roleLocator.name } : {}),\n    }) as unknown as T[];\n    return isMultiple ? matches : matches[0];\n  }\n\n  /**\n   * A `'Root'`-relative locator (the portal escape — see the portals guide) is\n   * documented to search from the document, not from this interactor's root, so\n   * portalled content (dialogs, dropdowns rendered at `<body>`) stays reachable\n   * even when the interactor is scoped to a sub-tree such as a Storybook canvas.\n   * Mirrors `locatorUtil.getEffectiveLocator`'s slicing rule: the last `'Root'`\n   * locator wins unless it is `'linked'`, whose CSS still needs the scoped\n   * context.\n   */\n  private escapesToDocumentRoot(locator: PartLocator): boolean {\n    for (let i = locator.length - 1; i >= 0; i--) {\n      if (locator[i].relative === 'Root') {\n        return locator[i].complexity !== 'linked';\n      }\n    }\n    return false;\n  }\n\n  async getInputValue(locator: PartLocator): Promise<Optional<string>> {\n    const el = await this.getElement(locator);\n    if (el != null) {\n      if (el.nodeName === 'INPUT') {\n        return Promise.resolve((el as HTMLInputElement).value ?? undefined);\n      } else if (el.nodeName === 'TEXTAREA') {\n        return Promise.resolve((el as HTMLTextAreaElement).value ?? undefined);\n      }\n    }\n    return undefined;\n  }\n\n  async getSelectValues(locator: PartLocator): Promise<Optional<readonly string[]>> {\n    const el = await this.getElement(locator);\n    if (el != null && el.nodeName === 'SELECT') {\n      const options = el.querySelectorAll<HTMLOptionElement>('option:checked');\n      const values = Array.from(options).map(o => o.value);\n      return Promise.resolve(values);\n    }\n    return Promise.resolve(undefined);\n  }\n\n  async getSelectLabels(locator: PartLocator): Promise<Optional<readonly string[]>> {\n    const el = await this.getElement(locator);\n    if (el != null && el.nodeName === 'SELECT') {\n      const options = el.querySelectorAll<HTMLOptionElement>('option:checked');\n      const values = Array.from(options).map(o => o.text);\n      return Promise.resolve(values);\n    }\n    return Promise.resolve(undefined);\n  }\n\n  async getText(locator: PartLocator): Promise<Optional<string>> {\n    const el = await this.getElement(locator);\n    if (el != null) {\n      return Promise.resolve(el.textContent ?? undefined);\n    }\n    return undefined;\n  }\n\n  /**\n   * Get the located element's bounding rectangle.\n   *\n   * jsdom has no layout engine, so `getBoundingClientRect` returns all zeros: the\n   * rect is structurally valid but behaviorally meaningless. Real geometry is\n   * E2E-only.\n   *\n   * @param locator - Locator used to find the element to measure\n   * @returns The element's bounding rectangle (a zero-rect under jsdom)\n   * @throws {ElementNotFoundError} If the element is not found\n   */\n  async getBoundingRect(locator: PartLocator): Promise<BoundingRect> {\n    const el = await this.getElement(locator);\n    if (el == null) {\n      throw new ElementNotFoundError(locator, 'getBoundingRect');\n    }\n    const r = el.getBoundingClientRect();\n    return { x: r.x, y: r.y, width: r.width, height: r.height };\n  }\n\n  async isChecked(locator: PartLocator): Promise<boolean> {\n    const el = await this.getElement(locator);\n    if (el == null) {\n      return false;\n    }\n    // Shared with PlaywrightInteractor so both engines answer identically.\n    return elementStateUtil.isElementChecked(el);\n  }\n\n  async isDisabled(locator: PartLocator): Promise<boolean> {\n    const el = await this.getElement(locator);\n    if (el == null) {\n      return false;\n    }\n    // Shared with PlaywrightInteractor so both engines answer identically.\n    return elementStateUtil.isElementDisabled(el);\n  }\n\n  async isReadonly(locator: PartLocator): Promise<boolean> {\n    // Honor `aria-readonly` for symmetry with `isRequired`'s `aria-required`\n    // check (#1053): the native `readonly` attribute only exists on native form\n    // controls, whereas composite/custom widgets (comboboxes, grids,\n    // contenteditable regions) expose read-only state through ARIA. The two\n    // capability probes now read both the native and ARIA signals.\n    if (await this.hasAttribute(locator, 'readonly')) {\n      return true;\n    }\n    return (await this.getAttribute(locator, 'aria-readonly')) === 'true';\n  }\n\n  async isRequired(locator: PartLocator): Promise<boolean> {\n    const el = await this.getElement(locator);\n    if (el != null) {\n      if ('required' in el && Boolean((el as { required?: boolean }).required)) {\n        return true;\n      }\n      return el.getAttribute('aria-required') === 'true';\n    }\n    return false;\n  }\n\n  async isError(locator: PartLocator): Promise<boolean> {\n    const el = await this.getElement(locator);\n    return el != null && el.getAttribute('aria-invalid') === 'true';\n  }\n\n  async isVisible(locator: PartLocator): Promise<boolean> {\n    const el = await this.getElement(locator);\n    if (el == null) {\n      return false;\n    }\n    // Apply the shared visibility policy (#1053): walk the ancestor chain so a\n    // child of a `display: none` / `opacity: 0` ancestor is reported hidden, not\n    // visible. `visibility` is inherited and handled on the element alone inside\n    // the predicate.\n    return visibilityUtil.isElementVisibleByStyle(el, target => window.getComputedStyle(target as HTMLElement));\n  }\n\n  async hasCssClass(locator: PartLocator, className: string): Promise<boolean> {\n    const el = await this.getElement(locator);\n    if (el != null) {\n      return Promise.resolve(el.classList.contains(className));\n    }\n    return Promise.resolve(false);\n  }\n\n  async hasAttribute(locator: PartLocator, name: string): Promise<boolean> {\n    const el = await this.getElement(locator);\n    if (el != null) {\n      return Promise.resolve(el.hasAttribute(name));\n    }\n    return Promise.resolve(false);\n  }\n\n  //#region\n  async innerHTML(locator: PartLocator): Promise<string> {\n    const el = await this.getElement(locator);\n    return el?.innerHTML ?? '';\n  }\n  //#endregion\n}\n","import { ScenePart, TestEngine } from '@atomic-testing/core';\n\nimport { DOMInteractor } from './DOMInteractor';\n\n/**\n * Create test engine for DOM testing\n * @param element The element to test, if not sure, use document.body\n * @param partDefinitions The scene part definitions\n * @returns The test engine\n */\nexport function createTestEngine<T extends ScenePart>(element: HTMLElement, partDefinitions: T): TestEngine<T> {\n  const cleanup = () => Promise.resolve();\n  return new TestEngine(\n    [],\n    new DOMInteractor(element),\n    {\n      parts: partDefinitions,\n    },\n    cleanup\n  );\n}\n\n/**\n * @deprecated Use {@link createTestEngine}. Kept as an alias for backward\n * compatibility; every adapter now exports `createTestEngine`.\n */\nexport const createDomTestEngine = createTestEngine;\n"],"mappings":"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"}