@orkestrel/test 0.0.15 → 0.0.17
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/README.md +7 -5
- package/dist/src/browser/index.d.ts +677 -8
- package/dist/src/browser/index.js +686 -1
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +99 -16
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +580 -456
- package/dist/src/core/index.d.ts +580 -456
- package/dist/src/core/index.js +98 -17
- package/dist/src/core/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/browser/constants.ts","../../../src/browser/helpers.ts","../../../src/browser/factories.ts"],"sourcesContent":["import type { Color } from './types.js'\n\n/**\n * Names the interactive ARIA roles a bare accessible name is searched across.\n *\n * @remarks\n * A person names a control, not a role, so the one-argument resolver searches every role a control\n * can compute. The two-argument form searches exactly the role it is given, which is how a name\n * shared by a tab and its panel is disambiguated.\n */\nexport const ACCESSIBLE_ROLES: readonly string[] = Object.freeze([\n\t'button',\n\t'checkbox',\n\t'combobox',\n\t'link',\n\t'listbox',\n\t'menuitem',\n\t'option',\n\t'radio',\n\t'searchbox',\n\t'slider',\n\t'spinbutton',\n\t'switch',\n\t'tab',\n\t'tabpanel',\n\t'textbox',\n\t'treeitem',\n])\n\n/**\n * Names the color a browser paints an unstyled document with: opaque white.\n *\n * @remarks\n * This is the floor a backdrop walk ends on wherever the caller wants the browser's own canvas\n * assumed. `readBackdrop` takes its floor as an argument rather than reaching for this one, so a\n * measurement over a surface the canvas never shows through names the color it actually sits on.\n */\nexport const CANVAS_COLOR: Color = Object.freeze([255, 255, 255, 1])\n\n/**\n * Names the attribute marking the runner's tester pane, and the rule that sizes it, while a frame\n * is staged.\n *\n * @remarks\n * `stagePane` writes it onto the pane and onto the stylesheet it appends, and `releasePane` finds\n * both by it. The stylesheet's value is the viewport the tester had before the first staging, in\n * `<width>x<height>` form, which is what `releasePane` hands back. Nothing else reads it, so a\n * document carrying it after a capture returned is a pane that was never released.\n */\nexport const CAPTURE_PANE = 'data-capture-pane'\n\n/**\n * Bounds the restagings one capture takes before it refuses a document whose height never settles.\n *\n * @remarks\n * `captureFrame` stages the pane at the content edge `measureContent` reads, and a rule bound to\n * the viewport height lays that document out taller against the taller pane, so the edge has to be\n * read again after every staging. The re-reading stops when the pane and the edge agree, and a rule\n * that adds height with every pane never reaches that point, so the re-reading is bounded here and\n * the shot is refused rather than taken at a height that is already stale.\n *\n * The bound is the measured need plus one. A document holding half the pane plus a fixed block\n * settles in two restagings, because the second carries the growth the first produced and lands on\n * the fixed point; a document whose growth is capped part way settles in three, because it takes\n * one restaging past the cap before it comes back down to the edge. Nothing measured needs a\n * fourth, so a fourth is the headroom that keeps a settling document off the refusal.\n */\nexport const CAPTURE_STAGINGS = 4\n\n/**\n * Names the roles whose accessible name is the text a reader can see inside them.\n *\n * @remarks\n * `readName` reads an element in this list from its own rendered text, after every `aria-hidden`\n * descendant is dropped, and falls through to `title` for every other role.\n */\nexport const CONTENT_ROLES: readonly string[] = Object.freeze([\n\t'button',\n\t'cell',\n\t'columnheader',\n\t'heading',\n\t'link',\n\t'listitem',\n\t'option',\n\t'row',\n\t'rowheader',\n\t'tab',\n])\n\n/**\n * Names the role each `input` type carries.\n *\n * @remarks\n * Membership is the contract. The map answers for `button`, `checkbox`, `email`, `number`,\n * `password`, `radio`, `range`, `reset`, `search`, `submit`, `tel`, `text`, and `url`. A type the\n * map omits — `color`, `date`, `file`, `hidden`, and the rest — exposes no role of its own, so\n * `readRole` returns `undefined` for it and `describeTree` writes no line for it.\n */\nexport const FIELD_ROLES: Readonly<Record<string, string>> = Object.freeze({\n\tbutton: 'button',\n\tcheckbox: 'checkbox',\n\temail: 'textbox',\n\tnumber: 'spinbutton',\n\tpassword: 'textbox',\n\tradio: 'radio',\n\trange: 'slider',\n\treset: 'button',\n\tsearch: 'searchbox',\n\tsubmit: 'button',\n\ttel: 'textbox',\n\ttext: 'textbox',\n\turl: 'textbox',\n})\n\n/**\n * Names what sequential keyboard navigation can reach, before disabled and unrendered elements go.\n *\n * @remarks\n * `describeFocus` queries this selector and then drops what a browser drops: an element the\n * accessibility tree does not present, a disabled control, and one removed from the sequence by\n * `tabindex=\"-1\"`. `traverseAccessible` counts the same population to bound its walk, so this is\n * the one list either one reads.\n */\nexport const FOCUSABLE_SELECTOR =\n\t'a[href], area[href], button, input, select, summary, textarea, [tabindex]'\n\n/**\n * Names the role a `th` carries for the header axis its `scope` names.\n *\n * @remarks\n * A header cell heads a column or a row, and this map answers for the `col` and `row` scopes that\n * say which. A `th` declaring no scope keeps {@link IMPLICIT_ROLES}' `columnheader` rather than the\n * ARIA computation that infers the axis from the table's shape.\n */\nexport const HEADER_ROLES: Readonly<Record<string, string>> = Object.freeze({\n\tcol: 'columnheader',\n\trow: 'rowheader',\n})\n\n/**\n * Names the role each listed tag carries in the accessibility tree when it declares none of its\n * own.\n *\n * @remarks\n * Membership is the contract. The map answers for the sectioning elements `ARTICLE`, `ASIDE`,\n * `FOOTER`, `HEADER`, `MAIN`, `NAV`, `SEARCH`, and `SECTION`; the headings `H1` through `H6`; the\n * grouping and list elements `FIELDSET`, `FORM`, `HR`, `LI`, `OL`, and `UL`; the table elements\n * `TABLE`, `TBODY`, `THEAD`, `TR`, `TD`, and `TH`; and the widgets `BUTTON`, `DIALOG`, `IMG`,\n * `OPTION`, `OUTPUT`, `PROGRESS`, `SUMMARY`, and `TEXTAREA`.\n *\n * A tag the map omits carries no implicit role, so `readRole` returns `undefined` for it,\n * `describeTree` writes no line for it, and the walk continues straight into its children at the\n * depth the omitted element sat at. `A`, `INPUT`, and `SELECT` are absent deliberately: each takes\n * its role from an attribute rather than from its tag, and `readRole` answers for them from their\n * own anatomy.\n *\n * `SECTION` maps to `region`, which `readRole` withholds from an unnamed one, because an unnamed\n * section is not a landmark. `TH` maps to `columnheader`, which {@link HEADER_ROLES} replaces when\n * the cell declares a `scope`.\n */\nexport const IMPLICIT_ROLES: Readonly<Record<string, string>> = Object.freeze({\n\tARTICLE: 'article',\n\tASIDE: 'complementary',\n\tBUTTON: 'button',\n\tDIALOG: 'dialog',\n\tFIELDSET: 'group',\n\tFOOTER: 'contentinfo',\n\tFORM: 'form',\n\tH1: 'heading',\n\tH2: 'heading',\n\tH3: 'heading',\n\tH4: 'heading',\n\tH5: 'heading',\n\tH6: 'heading',\n\tHEADER: 'banner',\n\tHR: 'separator',\n\tIMG: 'img',\n\tLI: 'listitem',\n\tMAIN: 'main',\n\tNAV: 'navigation',\n\tOL: 'list',\n\tOPTION: 'option',\n\tOUTPUT: 'status',\n\tPROGRESS: 'progressbar',\n\tSEARCH: 'search',\n\tSECTION: 'region',\n\tSUMMARY: 'button',\n\tTABLE: 'table',\n\tTBODY: 'rowgroup',\n\tTD: 'cell',\n\tTEXTAREA: 'textbox',\n\tTH: 'columnheader',\n\tTHEAD: 'rowgroup',\n\tTR: 'row',\n\tUL: 'list',\n})\n","import type { CaptureVariant, Color, ElementOptions, FrameOptions, FrameReading } from './types.js'\nimport { commands, page, userEvent } from 'vitest/browser'\nimport {\n\tACCESSIBLE_ROLES,\n\tCANVAS_COLOR,\n\tCAPTURE_PANE,\n\tCAPTURE_STAGINGS,\n\tCONTENT_ROLES,\n\tFIELD_ROLES,\n\tFOCUSABLE_SELECTOR,\n\tHEADER_ROLES,\n\tIMPLICIT_ROLES,\n} from './constants.js'\n\n/**\n * Determines whether a rectangle lies wholly outside the browser viewport.\n *\n * @param rectangle - The measured client rectangle to inspect.\n * @returns True if no part of the rectangle intersects the viewport; false otherwise.\n *\n * @example\n * ```ts\n * isOutsideViewport(element.getBoundingClientRect())\n * ```\n */\nexport function isOutsideViewport(rectangle: DOMRectReadOnly): boolean {\n\treturn (\n\t\trectangle.bottom <= 0 ||\n\t\trectangle.right <= 0 ||\n\t\trectangle.top >= window.innerHeight ||\n\t\trectangle.left >= window.innerWidth\n\t)\n}\n\n/**\n * Determines whether a person can click one element where it sits.\n *\n * @param element - The element to judge.\n * @returns True if the element is connected, visible, laid out with a non-zero box, in the\n * sequential focus order, neither disabled nor marked `aria-disabled=\"true\"`, and outside every\n * `[inert]` subtree; false otherwise.\n *\n * @remarks\n * This is the one reachability filter the layer applies. `resolveRendered`, `clickAccessibleWithin`,\n * and `clickDisclosure` each narrow their own candidates and then keep the ones this accepts, so a\n * journey meets one rule rather than three near-copies of it.\n *\n * It measures geometry, which is what separates it from {@link isRendered}. A control clipped to a\n * zero-size rectangle is announced and is not clickable, so `isRendered` accepts it and this\n * refuses it. Nothing here asks about the viewport: `resolveAccessible` scrolls a wholly\n * off-viewport target into view and measures that separately with {@link isOutsideViewport}.\n *\n * @example\n * ```ts\n * isReachable(requireValue(container.querySelector('button')))\n * ```\n */\nexport function isReachable(element: Element): boolean {\n\tif (!(element instanceof HTMLElement) && !(element instanceof SVGElement)) return false\n\tconst rectangle = element.getBoundingClientRect()\n\treturn (\n\t\telement.isConnected &&\n\t\telement.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true }) &&\n\t\trectangle.width > 0 &&\n\t\trectangle.height > 0 &&\n\t\telement.tabIndex >= 0 &&\n\t\t!element.matches(':disabled, [aria-disabled=\"true\"]') &&\n\t\telement.closest('[inert]') === null\n\t)\n}\n\n/**\n * Determines whether the accessibility tree presents one element at all.\n *\n * @param element - The element to judge.\n * @returns True if the element is presented to assistive technology and to sight; false otherwise.\n *\n * @remarks\n * A control clipped to a zero-size rectangle is still announced, which is the whole point of that\n * idiom, so nothing here reads geometry: only the removals a browser honours — `aria-hidden`\n * anywhere above it, the `hidden` attribute, a hidden input, and a `display` or `visibility` that\n * takes it off the page. {@link isReachable} is the clickable half of the pair and does read\n * geometry.\n *\n * The last two are asked about the element's ancestors as well as itself, which reading a computed\n * `display` cannot do: the computed value of a child of a `display: none` container is the child's\n * own, so a control inside a closed drawer reports itself as laid out. `checkVisibility` answers\n * for the box tree, and `visibility` inherits, so between them an ancestor cannot hide a control\n * from a reader and leave it standing in a description.\n *\n * @example\n * ```ts\n * isRendered(requireValue(container.querySelector('[aria-hidden=\"true\"] button'))) // false\n * ```\n */\nexport function isRendered(element: Element): boolean {\n\tif (element.closest('[aria-hidden=\"true\"]') !== null) return false\n\tif (element instanceof HTMLElement && element.hidden) return false\n\tif (element instanceof HTMLInputElement && element.type === 'hidden') return false\n\tif (!element.checkVisibility()) return false\n\treturn getComputedStyle(element).visibility !== 'hidden'\n}\n\n/**\n * Computes the pattern that matches one accessible name a decorative glyph may sit beside.\n *\n * @param name - The exact accessible name a person reads, whitespace runs collapsed on the way in.\n * @returns A pattern anchored at both ends, admitting a run of characters that are neither letters\n * nor digits before the name and after it.\n *\n * @remarks\n * A role query that includes hidden elements computes a name from the `aria-hidden` subtrees too,\n * so an icon font's `::before` glyph joins the name a person never hears and an exact string never\n * matches again. This pattern is what {@link resolveRendered} asks the hidden pass with, and its\n * tolerance is bounded to what a glyph can be: a leading or trailing run carrying no letter and no\n * digit. A hidden icon whose own content is a word still defeats it, and a name differing from the\n * requested one by punctuation alone still satisfies it.\n *\n * That bound is affordable because the hidden pass chooses between two refusal voices and returns\n * nothing. The visible pass decides which element a resolver returns, and it matches the exact\n * string against the name the accessibility tree actually publishes.\n *\n * Pass this to a role query with `exact: true`. That flag is the engine's case-sensitivity switch\n * as well as its exactness one, so a query carrying `exact: false` uppercases the computed name\n * before testing a pattern against it and a lowercase letter in the requested name never matches.\n *\n * @example\n * ```ts\n * computeNamePattern('Add building').test('\\uF4FE Add building') // true\n * ```\n */\nexport function computeNamePattern(name: string): RegExp {\n\tconst wanted = name\n\t\t.replaceAll(/\\s+/g, ' ')\n\t\t.trim()\n\t\t.replaceAll(/[$()*+.?[\\\\\\]^{|}]/g, '\\\\$&')\n\treturn new RegExp(`^[^\\\\p{L}\\\\p{N}]*${wanted}[^\\\\p{L}\\\\p{N}]*$`, 'u')\n}\n\n/**\n * Resolves one rendered, focus-reachable interactive element without requiring it to intersect the\n * viewport yet.\n *\n * @param first - The accessible name, or the exact ARIA role when `second` is present.\n * @param second - The accessible name when `first` supplies the role.\n * @returns The one rendered element carrying that name and optional role.\n * @throws When no matching element exists, every match is hidden or unreachable, or several\n * rendered matches make the name ambiguous.\n *\n * @remarks\n * This is the resolver the acting verbs use, so a click does not fail on a target the act itself\n * scrolls into view. Use {@link resolveAccessible} wherever the target must already be on screen.\n *\n * It runs two passes, and only the first one can return an element. The visible pass asks the role\n * engine for the exact name over the elements the accessibility tree presents, which is the name a\n * screen reader announces: an `aria-hidden` icon beside the text contributes nothing to it. The\n * hidden pass runs only when the visible pass found nothing at all, and it decides which refusal\n * the caller hears — a name the page carries nowhere, or a target that is there and out of reach.\n * That pass must include hidden elements to see a folded control, which is what puts a glyph back\n * into the computed name, so it asks with {@link computeNamePattern} rather than the exact string.\n *\n * @example\n * ```ts\n * resolveRendered('tab', 'Drafts')\n * ```\n */\nexport function resolveRendered(first: string, second?: string): HTMLElement {\n\tconst name = second ?? first\n\tconst roles = second === undefined ? ACCESSIBLE_ROLES : [first]\n\tconst matches: HTMLElement[] = []\n\tfor (const role of roles) {\n\t\tfor (const element of page.getByRole(role, { name, exact: true }).elements()) {\n\t\t\tif (element instanceof HTMLElement && !matches.includes(element)) matches.push(element)\n\t\t}\n\t}\n\tif (matches.length === 0) {\n\t\tconst pattern = computeNamePattern(name)\n\t\tconst hidden = roles.some(\n\t\t\t(role) =>\n\t\t\t\tpage.getByRole(role, { name: pattern, exact: true, includeHidden: true }).elements()\n\t\t\t\t\t.length > 0,\n\t\t)\n\t\tif (!hidden) throw new Error(`No interactive element has the accessible name \"${name}\"`)\n\t\tthrow new Error(`Interactive target \"${name}\" is not visible and focus-reachable`)\n\t}\n\tconst reachable = matches.filter((element) => isReachable(element))\n\tif (reachable.length === 0) {\n\t\tthrow new Error(`Interactive target \"${name}\" is not visible and focus-reachable`)\n\t}\n\tif (reachable.length > 1) {\n\t\tthrow new Error(`Interactive target \"${name}\" is ambiguous across ${reachable.length} elements`)\n\t}\n\tconst [target] = reachable\n\tif (target === undefined) throw new Error(`Interactive target \"${name}\" could not be resolved`)\n\treturn target\n}\n\n/**\n * Resolves one visible, focus-reachable interactive element by its exact accessible name. A\n * wholly-off-viewport target is scrolled into view before reachability is measured.\n *\n * @param name - The accessible name rendered for the target.\n * @returns The one reachable element carrying that name.\n * @throws When no matching element exists; every match is disconnected, hidden, zero-sized, still\n * outside the viewport after being scrolled into view, removed from sequential focus, disabled, or\n * inside an inert subtree; or several reachable matches make the name ambiguous.\n *\n * @example\n * ```ts\n * resolveAccessible('Save changes')\n * ```\n */\nexport function resolveAccessible(name: string): HTMLElement\n/**\n * Resolves one visible, focus-reachable interactive element by its exact ARIA role and accessible\n * name, disambiguating a bare name that answers for more than one rendered element. A\n * wholly-off-viewport target is scrolled into view before reachability is measured.\n *\n * @param role - The element's exact ARIA role.\n * @param name - The accessible name rendered for the target.\n * @returns The one reachable element carrying that role and name.\n * @throws When no matching element exists; every match is disconnected, hidden, zero-sized, still\n * outside the viewport after being scrolled into view, removed from sequential focus, disabled, or\n * inside an inert subtree; or several reachable matches make the role/name pair ambiguous.\n *\n * @example\n * ```ts\n * resolveAccessible('tab', 'Drafts')\n * ```\n */\nexport function resolveAccessible(role: string, name: string): HTMLElement\nexport function resolveAccessible(first: string, second?: string): HTMLElement {\n\tconst target = resolveRendered(first, second)\n\tlet rectangle = target.getBoundingClientRect()\n\tif (isOutsideViewport(rectangle)) {\n\t\ttarget.scrollIntoView({ block: 'nearest', behavior: 'instant' })\n\t\trectangle = target.getBoundingClientRect()\n\t}\n\tif (isOutsideViewport(rectangle)) {\n\t\tthrow new Error(`Interactive target \"${second ?? first}\" is unreachable after scrolling`)\n\t}\n\treturn target\n}\n\n/**\n * Clicks one visible, focus-reachable control by its accessible name through the browser provider.\n *\n * @param name - The target's exact accessible name.\n * @returns A promise resolving after trusted activation completes.\n *\n * @example\n * ```ts\n * await clickAccessible('Apply')\n * ```\n */\nexport async function clickAccessible(name: string): Promise<void>\n/**\n * Clicks one visible, focus-reachable control by its exact ARIA role and accessible name,\n * disambiguating a bare name that answers for more than one rendered element.\n *\n * @param role - The control's exact ARIA role.\n * @param name - The target's exact accessible name.\n * @returns A promise resolving after trusted activation completes.\n *\n * @example\n * ```ts\n * await clickAccessible('tab', 'Drafts')\n * ```\n */\nexport async function clickAccessible(role: string, name: string): Promise<void>\nexport async function clickAccessible(first: string, second?: string): Promise<void> {\n\tconst target = resolveRendered(first, second)\n\tawait userEvent.click(target)\n}\n\n/**\n * Clicks one human-reachable control by role and accessible-name text inside a named region.\n *\n * @param region - The containing region's exact accessible name.\n * @param role - The control's exact ARIA role.\n * @param name - The rendered accessible-name text that identifies the control in that region.\n * @returns A promise resolving after trusted activation completes.\n * @throws When the named control is absent, unreachable, or ambiguous inside the region.\n *\n * @remarks\n * Use this form when repeated short verbs such as `Add`, or a line whose status completes its\n * accessible name, need the same region context a person uses to disambiguate them.\n *\n * @example\n * ```ts\n * await clickAccessibleWithin('Ledger', 'button', 'Monthly income')\n * ```\n */\nexport async function clickAccessibleWithin(\n\tregion: string,\n\trole: string,\n\tname: string,\n): Promise<void> {\n\tconst matches = page\n\t\t.getByRole('region', { name: region, exact: true })\n\t\t.getByRole(role, { name, exact: false, includeHidden: true })\n\t\t.elements()\n\tconst reachable = matches.filter(\n\t\t(element) => element instanceof HTMLElement && isReachable(element),\n\t)\n\tif (reachable.length === 0) {\n\t\tthrow new Error(`Interactive target \"${name}\" is not reachable inside \"${region}\"`)\n\t}\n\tif (reachable.length > 1) {\n\t\tthrow new Error(\n\t\t\t`Interactive target \"${name}\" is ambiguous across ${reachable.length} elements inside \"${region}\"`,\n\t\t)\n\t}\n\tconst [target] = reachable\n\tif (!(target instanceof HTMLElement)) {\n\t\tthrow new Error(`Interactive target \"${name}\" could not be resolved inside \"${region}\"`)\n\t}\n\tawait userEvent.click(target)\n}\n\n/**\n * Opens or closes one native details disclosure by its rendered summary.\n *\n * @param name - The summary text a person reads.\n * @returns A promise resolving after trusted activation completes.\n * @throws When no native summary with that rendered name passes {@link isReachable}, or several do.\n *\n * @remarks\n * Chromium exposes `<summary>` as a native disclosure rather than through an ARIA role accepted by\n * `getByRole`, so this resolver names the platform element and its rendered text directly.\n *\n * It applies the same {@link isReachable} filter the other acting verbs apply, so a summary marked\n * `aria-disabled=\"true\"` is refused here exactly as a button marked that way is refused there.\n *\n * @example\n * ```ts\n * await clickDisclosure('Advanced')\n * ```\n */\nexport async function clickDisclosure(name: string): Promise<void> {\n\tconst matches = [...document.querySelectorAll('summary')].filter(\n\t\t(element) => element.innerText.replaceAll(/\\s+/g, ' ').trim() === name,\n\t)\n\tconst reachable = matches.filter((element) => isReachable(element))\n\tif (reachable.length === 0) {\n\t\tthrow new Error(`Native disclosure \"${name}\" is not visible and focus-reachable`)\n\t}\n\tif (reachable.length > 1) {\n\t\tthrow new Error(`Native disclosure \"${name}\" is ambiguous across ${reachable.length} elements`)\n\t}\n\tconst [target] = reachable\n\tif (target === undefined) throw new Error(`Native disclosure \"${name}\" could not be resolved`)\n\tawait userEvent.click(target)\n}\n\n/**\n * Replaces a named field's value through focus, select-all, deletion, and real keystrokes.\n *\n * @param name - The field's exact accessible name.\n * @param text - The text to type.\n * @returns A promise resolving after every keystroke completes.\n *\n * @remarks\n * The text is escaped against the provider's own key syntax, so a literal `{` or `[` is typed\n * rather than read as the start of a key sequence.\n *\n * @example\n * ```ts\n * await typeAccessible('Runs', '3')\n * ```\n */\nexport async function typeAccessible(name: string, text: string): Promise<void> {\n\tawait userEvent.click(resolveRendered(name))\n\tawait userEvent.keyboard('{Control>}a{/Control}{Backspace}')\n\tif (text === '') return\n\tawait userEvent.keyboard(text.replaceAll('{', '{{').replaceAll('[', '[['))\n}\n\n/**\n * Replaces a named field's value in one operation, for text too long to type key by key.\n *\n * @param name - The field's exact accessible name.\n * @param text - The text to place in the field.\n * @returns A promise resolving after the browser commits the value.\n *\n * @remarks\n * The provider drives the real element, so the field publishes the same input event a person's\n * typing publishes. Use {@link typeAccessible} wherever the keystrokes themselves are the subject.\n *\n * @example\n * ```ts\n * await fillAccessible('Payload', '{\"status\":\"ready\"}')\n * ```\n */\nexport async function fillAccessible(name: string, text: string): Promise<void> {\n\tawait userEvent.fill(resolveRendered(name), text)\n}\n\n/**\n * Reaches a named control only through natural forward Tab traversal from the current focus.\n *\n * @param name - The target's exact accessible name.\n * @returns The target after the browser moves focus to it.\n * @throws When one complete traversal cannot reach the target.\n *\n * @example\n * ```ts\n * await traverseAccessible('Evaluate')\n * ```\n */\nexport async function traverseAccessible(name: string): Promise<HTMLElement> {\n\tresolveRendered(name)\n\t// Two facts shape the loop. A Tab pressed before the page has real input focus moves nothing,\n\t// so a step counts only when focus actually lands somewhere; the traversal is over when focus\n\t// revisits an element, because that is one full cycle of the tab order. And the target is\n\t// re-resolved on every step, because a framework may replace the node between resolution and\n\t// focus arrival: the person's target is the role and name, never one node.\n\t// The bound is counted off `FOCUSABLE_SELECTOR`, the one population this environment reads\n\t// sequential navigation from, so a tag the selector gains is a tag this traversal budgets for.\n\tconst cap = document.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR).length * 3 + 10\n\tconst visited = new Set<Element>()\n\tconst trail: string[] = []\n\tfor (let attempt = 0; attempt < cap; attempt += 1) {\n\t\tawait userEvent.tab()\n\t\tconst focused = document.activeElement\n\t\tif (!(focused instanceof HTMLElement) || focused === document.body) continue\n\t\tlet current: HTMLElement | undefined\n\t\ttry {\n\t\t\tcurrent = resolveRendered(name)\n\t\t} catch {\n\t\t\tcontinue\n\t\t}\n\t\tif (focused === current) return current\n\t\tif (visited.has(focused)) break\n\t\tvisited.add(focused)\n\t\ttrail.push(`${focused.tagName}:${focused.innerText.slice(0, 20)}`)\n\t}\n\tthrow new Error(\n\t\t`Interactive target \"${name}\" is not reachable through forward Tab traversal: ${trail.join(' > ')}`,\n\t)\n}\n\n/**\n * Reads the normalized visible text of one named region, dialog, table, tab panel, or alert.\n *\n * @param name - The region's exact accessible name.\n * @returns The text a screen reader can perceive in the visible region, including descendant\n * visually-hidden content.\n * @throws When the named region is absent, hidden, or ambiguous.\n *\n * @remarks\n * One pass answers this, because absence and concealment share the refusal. The pass asks the role\n * engine over the elements the accessibility tree presents, so the name matched is the one a screen\n * reader announces and an `aria-hidden` glyph in a heading a region points at contributes nothing\n * to it. A region the tree does not present is refused as not visible, which is what a reader\n * perceiving nothing there means.\n *\n * @example\n * ```ts\n * readPerception('Run')\n * ```\n */\nexport function readPerception(name: string): string {\n\tconst matches: HTMLElement[] = []\n\tfor (const role of ['alert', 'alertdialog', 'dialog', 'region', 'status', 'table', 'tabpanel']) {\n\t\tfor (const element of page.getByRole(role, { name, exact: true }).elements()) {\n\t\t\tif (element instanceof HTMLElement && !matches.includes(element)) matches.push(element)\n\t\t}\n\t}\n\tconst visible = matches.filter((element) => {\n\t\tconst rectangle = element.getBoundingClientRect()\n\t\treturn (\n\t\t\telement.isConnected &&\n\t\t\telement.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true }) &&\n\t\t\trectangle.width > 0 &&\n\t\t\trectangle.height > 0\n\t\t)\n\t})\n\tif (visible.length === 0) throw new Error(`Named region \"${name}\" is not visible`)\n\tif (visible.length > 1) {\n\t\tthrow new Error(`Named region \"${name}\" is ambiguous across ${visible.length} elements`)\n\t}\n\tconst [region] = visible\n\tif (region === undefined) throw new Error(`Named region \"${name}\" could not be resolved`)\n\treturn region.innerText.replaceAll(/\\s+/g, ' ').trim()\n}\n\n/**\n * Reads the normalized visible text of the whole page.\n *\n * @returns Every rendered word in the document body, its whitespace runs collapsed and trimmed.\n *\n * @remarks\n * This is the reader for a sentence that spans two regions and for a vocabulary sweep over the\n * words an interface uses. Reach for {@link readPerception} wherever one named region is the\n * subject, because that one throws when the region is missing and this one returns whatever is\n * there.\n *\n * @example\n * ```ts\n * readPage().includes('No cases yet')\n * ```\n */\nexport function readPage(): string {\n\treturn document.body.innerText.replaceAll(/\\s+/g, ' ').trim()\n}\n\n/**\n * Reads the rendered text of the element that holds focus.\n *\n * @returns The focused HTML element's trimmed rendered text, including an empty string, or\n * `undefined` when focus rests on a non-HTML element. When nothing holds focus, the browser\n * reports the document body as active, so the whole page's rendered text returns.\n *\n * @example\n * ```ts\n * await traverseAccessible('Evaluate')\n * readFocus() // 'Evaluate'\n * ```\n */\nexport function readFocus(): string | undefined {\n\tconst focused = document.activeElement\n\treturn focused instanceof HTMLElement ? focused.innerText.trim() : undefined\n}\n\n/**\n * Reads the value a resolved control renders.\n *\n * @param role - The control's exact ARIA role.\n * @param name - The control's exact accessible name.\n * @returns The control's current value.\n * @throws When the target does not resolve, or resolves to an element that carries no value.\n *\n * @remarks\n * A control's value is a rendered fact a person can read, not internal state, so it is read from\n * the resolved element rather than from the component that produced it.\n *\n * @example\n * ```ts\n * readValue('spinbutton', 'Runs') // '3'\n * ```\n */\nexport function readValue(role: string, name: string): string {\n\tconst control = resolveAccessible(role, name)\n\tif (\n\t\t!(control instanceof HTMLInputElement) &&\n\t\t!(control instanceof HTMLTextAreaElement) &&\n\t\t!(control instanceof HTMLSelectElement)\n\t) {\n\t\tthrow new Error(`Interactive target \"${name}\" does not carry a value`)\n\t}\n\treturn control.value\n}\n\n/**\n * Reads one element's rendered text the way a name computation reads it.\n *\n * @param element - The element whose announced words are wanted.\n * @returns The text with every `aria-hidden` descendant dropped and whitespace runs collapsed.\n *\n * @remarks\n * A glyph marked `aria-hidden` contributes nothing to a name, so a control captioned by an icon\n * plus a word reads as the word alone — which is what a reader hears, and what a verdict citing a\n * description has to compare against the copy a template writes. Reach for `readRows` wherever the\n * subject is what the page paints rather than what it announces: that one keeps the glyph.\n *\n * @example\n * ```ts\n * readText(requireValue(container.querySelector('button'))) // 'Save'\n * ```\n */\nexport function readText(element: Element): string {\n\tconst parts: string[] = []\n\tconst walker = element.ownerDocument.createTreeWalker(element, NodeFilter.SHOW_TEXT)\n\tfor (let node = walker.nextNode(); node !== null; node = walker.nextNode()) {\n\t\tconst owner = node.parentElement\n\t\tif (owner === null || owner.closest('[aria-hidden=\"true\"]') !== null) continue\n\t\tparts.push(node.textContent ?? '')\n\t}\n\treturn parts.join(' ').replaceAll(/\\s+/g, ' ').trim()\n}\n\n/**\n * Reads the role one element carries in the accessibility tree.\n *\n * @param element - The element to classify.\n * @returns The declared role, the implicit one, or `undefined` when the element carries none.\n *\n * @remarks\n * A declared `role` wins outright, and its first token is the answer when several are listed.\n * Otherwise the element's own anatomy decides: an anchor is a link only while it holds an `href`,\n * an `input` takes the role {@link FIELD_ROLES} gives its type, a `select` is a combobox until it\n * offers several rows at once, a `section` is a region only once something names it, and a `th`\n * heads whichever axis its `scope` names. Every other tag answers from {@link IMPLICIT_ROLES},\n * whose membership is the contract for what this can answer at all.\n *\n * @example\n * ```ts\n * readRole(requireValue(container.querySelector('a[href]'))) // 'link'\n * ```\n */\nexport function readRole(element: Element): string | undefined {\n\tconst declared = element.getAttribute('role')?.trim()\n\tif (declared !== undefined && declared.length > 0) return declared.split(/\\s+/)[0]\n\tif (element instanceof HTMLAnchorElement) return element.href.length > 0 ? 'link' : undefined\n\tif (element instanceof HTMLInputElement) return FIELD_ROLES[element.type]\n\tif (element instanceof HTMLSelectElement) {\n\t\treturn element.multiple || element.size > 1 ? 'listbox' : 'combobox'\n\t}\n\tconst implicit = IMPLICIT_ROLES[element.tagName]\n\tconst scope = element.tagName === 'TH' ? element.getAttribute('scope')?.trim() : undefined\n\tif (scope !== undefined) return HEADER_ROLES[scope] ?? implicit\n\tif (\n\t\timplicit === 'region' &&\n\t\t!element.hasAttribute('aria-label') &&\n\t\t!element.hasAttribute('aria-labelledby')\n\t) {\n\t\treturn undefined\n\t}\n\treturn implicit\n}\n\n/**\n * Reads the accessible name one element is announced under.\n *\n * @param element - The element to name.\n * @returns The computed name, or an empty string when the element carries none.\n *\n * @remarks\n * The order is the one a browser follows: `aria-labelledby`, then `aria-label`, then a form\n * control's own labels, then an image's `alt`, then the text inside a role {@link CONTENT_ROLES}\n * names, then `title`. A submit, reset, or button input is named by its value, because it renders\n * no text to read. An `aria-labelledby` naming several ids joins their texts in the order the\n * attribute lists them, and an id nothing answers for is skipped rather than fatal.\n *\n * Each step answers only when it has something to say, so a step that carries nothing hands the\n * element to the next one. An image whose `alt` is absent or blank is the case that shows it:\n * `<img title=\"Chart\">` is named `Chart` rather than the empty string its own `alt` step would\n * have returned, and an image carrying both keeps answering `alt`.\n *\n * @example\n * ```ts\n * readName(requireValue(container.querySelector('button'))) // 'Save changes'\n * ```\n */\nexport function readName(element: Element): string {\n\tconst referenced = element.getAttribute('aria-labelledby')\n\tif (referenced !== null) {\n\t\tconst named = referenced\n\t\t\t.split(/\\s+/)\n\t\t\t.map((id) => element.ownerDocument.getElementById(id))\n\t\t\t.filter((node) => node !== null)\n\t\t\t.map((node) => readText(node))\n\t\t\t.filter((text) => text.length > 0)\n\t\tif (named.length > 0) return named.join(' ')\n\t}\n\tconst labelled = element.getAttribute('aria-label')?.trim()\n\tif (labelled !== undefined && labelled.length > 0) return labelled\n\tif (\n\t\telement instanceof HTMLInputElement ||\n\t\telement instanceof HTMLSelectElement ||\n\t\telement instanceof HTMLTextAreaElement\n\t) {\n\t\tconst labels = [...(element.labels ?? [])]\n\t\t\t.map((label) => readText(label))\n\t\t\t.filter((text) => text.length > 0)\n\t\tif (labels.length > 0) return labels.join(' ')\n\t\tif (element instanceof HTMLInputElement && element.value.length > 0) {\n\t\t\tif (FIELD_ROLES[element.type] === 'button') return element.value\n\t\t}\n\t}\n\tif (element instanceof HTMLImageElement) {\n\t\tconst alternative = element.alt.trim()\n\t\tif (alternative.length > 0) return alternative\n\t}\n\tconst role = readRole(element)\n\tif (role !== undefined && CONTENT_ROLES.includes(role)) {\n\t\tconst text = readText(element)\n\t\tif (text.length > 0) return text\n\t}\n\treturn element.getAttribute('title')?.trim() ?? ''\n}\n\n/**\n * Reads the states one element is announced in.\n *\n * @param element - The element to read.\n * @returns Every state the element declares, in one fixed order.\n *\n * @remarks\n * A state a reader is told about is one this records: what is unavailable, disclosed, pressed,\n * current, refused, chosen, announcing itself, demanded, uneditable, described, or busy. The order\n * is fixed, so two descriptions of the same surface are comparable line for line.\n *\n * A native disclosure states its expansion on the parent `details` element's own `open` rather than\n * on an ARIA attribute, so a summary that declares no `aria-expanded` is read from the platform's\n * one copy of that fact.\n *\n * @example\n * ```ts\n * readStates(requireValue(container.querySelector('summary'))) // ['collapsed']\n * ```\n */\nexport function readStates(element: Element): readonly string[] {\n\tconst states: string[] = []\n\tif (element.matches(':disabled') || element.getAttribute('aria-disabled') === 'true') {\n\t\tstates.push('disabled')\n\t}\n\tconst expanded = element.getAttribute('aria-expanded')\n\tif (expanded === 'true') states.push('expanded')\n\tif (expanded === 'false') states.push('collapsed')\n\tif (\n\t\texpanded === null &&\n\t\telement.tagName === 'SUMMARY' &&\n\t\telement.parentElement instanceof HTMLDetailsElement\n\t) {\n\t\tstates.push(element.parentElement.open ? 'expanded' : 'collapsed')\n\t}\n\tconst pressed = element.getAttribute('aria-pressed')\n\tif (pressed !== null) states.push(`pressed=${pressed}`)\n\tconst current = element.getAttribute('aria-current')\n\tif (current !== null && current !== 'false') states.push('current')\n\tif (element.getAttribute('aria-invalid') === 'true') states.push('invalid')\n\tconst checked =\n\t\telement instanceof HTMLInputElement\n\t\t\t? element.checked\n\t\t\t: element.getAttribute('aria-checked') === 'true'\n\tif (checked) states.push('checked')\n\tconst selected = element.getAttribute('aria-selected')\n\tif (selected !== null) states.push(`selected=${selected}`)\n\tconst live = element.getAttribute('aria-live')\n\tif (live !== null) states.push(`live=${live}`)\n\tif (element.matches(':required')) states.push('required')\n\tif (element instanceof HTMLInputElement && element.readOnly) states.push('readonly')\n\tif (element.hasAttribute('aria-describedby')) states.push('described')\n\tif (element.getAttribute('aria-busy') === 'true') states.push('busy')\n\treturn Object.freeze(states)\n}\n\n/**\n * Describes the accessible tree one rendered element presents.\n *\n * @param element - The host to walk, which is described first when it carries a role of its own.\n * @returns One indented line per element carrying a role, naming its role, its name, and its\n * states, in document order; an empty string when nothing in the subtree carries one.\n *\n * @remarks\n * The walk is over the real rendered DOM, so what it reports is the tree the shipped markup and the\n * shipped cascade produce together — a landmark lost to a hidden ancestor is missing here exactly as\n * it is missing for a reader. An element {@link isRendered} refuses is dropped with its whole\n * subtree.\n *\n * Depth follows the roles rather than the elements, so the indentation reads as the structure a\n * screen reader announces instead of as the markup's nesting. An element {@link readRole} answers\n * `undefined` for writes no line and adds no depth, so its children sit where it sat. That is how\n * a wrapper `div` disappears, and it is also how an element {@link IMPLICIT_ROLES} does not answer\n * for disappears — visibly, because its roled children stay at the depth it occupied.\n *\n * @example\n * ```ts\n * describeTree(container)\n * // main \"Board\"\n * // heading \"Totals\"\n * ```\n */\nexport function describeTree(element: Element): string {\n\tconst lines: string[] = []\n\tconst pending: Array<{ readonly node: Element; readonly depth: number }> = [\n\t\t{ node: element, depth: 0 },\n\t]\n\twhile (pending.length > 0) {\n\t\tconst entry = pending.pop()\n\t\tif (entry === undefined) break\n\t\tif (!isRendered(entry.node)) continue\n\t\tconst role = readRole(entry.node)\n\t\tlet depth = entry.depth\n\t\tif (role !== undefined) {\n\t\t\tconst name = readName(entry.node)\n\t\t\tconst states = readStates(entry.node)\n\t\t\tlines.push(\n\t\t\t\t`${' '.repeat(depth)}${role}${name.length > 0 ? ` \"${name}\"` : ''}${\n\t\t\t\t\tstates.length > 0 ? ` [${states.join(', ')}]` : ''\n\t\t\t\t}`,\n\t\t\t)\n\t\t\tdepth += 1\n\t\t}\n\t\tfor (let index = entry.node.children.length - 1; index >= 0; index -= 1) {\n\t\t\tconst child = entry.node.children[index]\n\t\t\tif (child !== undefined) pending.push({ node: child, depth })\n\t\t}\n\t}\n\treturn lines.join('\\n')\n}\n\n/**\n * Describes the order sequential keyboard navigation visits one element's controls in.\n *\n * @param element - The host to walk; its own controls are described, and it is not itself one.\n * @returns One numbered line per reachable control, naming its role and its name.\n *\n * @remarks\n * A positive `tabindex` is honoured, because a browser honours it: those controls come first in\n * ascending order and everything else follows in document order. A control removed from the\n * sequence by `tabindex=\"-1\"`, by being disabled, or by not being rendered at all is absent here,\n * which is the fact a focus-order verdict is about. A control {@link readRole} answers `undefined`\n * for is named by its lowercased tag, so it is still counted rather than silently dropped.\n *\n * @example\n * ```ts\n * describeFocus(container)\n * // 1. button \"Save\"\n * // 2. link \"Cancel\"\n * ```\n */\nexport function describeFocus(element: Element): string {\n\treturn [...element.querySelectorAll(FOCUSABLE_SELECTOR)]\n\t\t.filter(\n\t\t\t(node) =>\n\t\t\t\tisRendered(node) && !node.matches(':disabled') && node.getAttribute('tabindex') !== '-1',\n\t\t)\n\t\t.sort((first, second) => {\n\t\t\tconst left = Number.parseInt(first.getAttribute('tabindex') ?? '0', 10)\n\t\t\tconst right = Number.parseInt(second.getAttribute('tabindex') ?? '0', 10)\n\t\t\tif (left > 0 && right > 0) return left - right\n\t\t\tif (left > 0) return -1\n\t\t\tif (right > 0) return 1\n\t\t\treturn 0\n\t\t})\n\t\t.map((node, index) => {\n\t\t\tconst role = readRole(node) ?? node.tagName.toLowerCase()\n\t\t\tconst name = readName(node)\n\t\t\treturn `${String(index + 1)}. ${role}${name.length > 0 ? ` \"${name}\"` : ''}`\n\t\t})\n\t\t.join('\\n')\n}\n\n/**\n * Waits for one animation frame to settle pending browser paint work.\n *\n * @returns A promise resolving after one `requestAnimationFrame`.\n *\n * @example\n * ```ts\n * await waitForFrame()\n * ```\n */\nexport function waitForFrame(): Promise<void> {\n\treturn new Promise<void>((resolve) => requestAnimationFrame(() => resolve()))\n}\n\n/**\n * Builds one unmounted element of a known tag, wearing the classes, text, and attributes asked for.\n *\n * @param tag - The HTML tag name, which fixes the returned element's exact type.\n * @param options - The class list, the text, and the attributes to apply.\n * @returns The built element, not yet in any document.\n *\n * @remarks\n * The element is unmounted on purpose, so a fixture is assembled before the page ever sees it and a\n * test decides where it goes. Nothing here resolves against the cascade: a built element computes no\n * style and lays out no box until {@link mount} puts it in the document.\n *\n * The text is set as text rather than parsed as markup, so a `<` in it stays a `<`. Use\n * {@link render} where the fixture is markup.\n *\n * @example\n * ```ts\n * const button = build('button', { classes: 'primary', text: 'Save', attributes: { type: 'button' } })\n * ```\n */\nexport function build<K extends keyof HTMLElementTagNameMap>(\n\ttag: K,\n\toptions?: ElementOptions,\n): HTMLElementTagNameMap[K] {\n\tconst element = document.createElement(tag)\n\tif (options?.classes !== undefined) element.className = options.classes\n\tif (options?.text !== undefined) element.textContent = options.text\n\tfor (const [name, value] of Object.entries(options?.attributes ?? {})) {\n\t\telement.setAttribute(name, value)\n\t}\n\treturn element\n}\n\n/**\n * Puts one element into the document and hands it straight back.\n *\n * @param element - The element to attach.\n * @returns The same element, now appended to `document.body`.\n *\n * @remarks\n * What this buys is the composition, not the attachment: the `append` method returns `void`, and\n * this hands the element back, so it fits where an expression is expected. The {@link render} helper\n * returns its fixture through it, and the {@link parseCSSColor} helper probes through\n * `mount(build('span'))`. A bare `append` call breaks each of those call sites.\n *\n * Being connected is what the attachment then buys: `getComputedStyle` resolves against the shipped\n * cascade, custom properties inherit from `:root`, and the element lays out a real box. A detached\n * element answers each of those questions with the initial value instead, which reads as a styling\n * defect rather than as a detached node.\n *\n * Taking it back out belongs to the consumer's teardown, because this records nothing: a browser\n * test file shares one page, so a fixture left behind is the next test's resolver ambiguity. Build a\n * recorded container in a setup module and remove it from an `afterEach` hook.\n *\n * @example\n * ```ts\n * const panel = mount(build('div', { classes: 'surface' }))\n * panel.remove()\n * ```\n */\nexport function mount<T extends Element>(element: T): T {\n\tdocument.body.append(element)\n\treturn element\n}\n\n/**\n * Renders one fixture into the document from trusted markup.\n *\n * @param markup - The fixture markup to parse.\n * @returns The attached container holding the fixture's own nodes.\n *\n * @remarks\n * The class list is required in the tag form, which is what keeps the two forms apart: a\n * one-argument call is always markup.\n *\n * This form parses `markup` into a fresh container and returns that container, so the fixture's own\n * nodes are its children. It attaches to `document.body` and records nothing, so removal is the\n * caller's, exactly as it is for {@link mount}.\n *\n * @example\n * ```ts\n * const container = render('<button type=\"button\">Save</button>')\n * container.remove()\n * ```\n */\nexport function render(markup: string): HTMLDivElement\n/**\n * Renders one fixture into the document from a tag name and its class list.\n *\n * @param tag - The HTML tag name to create.\n * @param classes - The class list to place on the created element.\n * @returns The attached element itself, typed as exactly that tag.\n *\n * @remarks\n * The class list is required in the tag form, which is what keeps the two forms apart: a\n * one-argument call is always markup. A tag with no classes is `mount(build(tag))`.\n *\n * This form returns the element itself rather than a container. It attaches to `document.body` and\n * records nothing, so removal is the caller's, exactly as it is for {@link mount}.\n *\n * @example\n * ```ts\n * const panel = render('section', 'surface muted')\n * panel.remove()\n * ```\n */\nexport function render<K extends keyof HTMLElementTagNameMap>(\n\ttag: K,\n\tclasses: string,\n): HTMLElementTagNameMap[K]\nexport function render(first: string, second?: string): HTMLElement {\n\tif (second === undefined) {\n\t\tconst container = build('div')\n\t\tcontainer.innerHTML = first\n\t\treturn mount(container)\n\t}\n\t// `build` is generic over the known tag names and this signature carries a plain string, so the\n\t// tag branch cannot route through it without an assertion. It applies the class list the one way\n\t// `build` applies it, so the two forms stay one behaviour.\n\tconst element = document.createElement(first)\n\telement.className = second\n\treturn mount(element)\n}\n\n/**\n * Sets one field's value and announces it the way typing into the field does.\n *\n * @param element - The input or textarea to write into.\n * @param text - The value to set.\n *\n * @remarks\n * This is the synthetic pair of {@link typeAccessible}, for a component that listens for `input` and\n * a test that has the element already. It sets the value in one write and dispatches one bubbling\n * `input` event, so a delegated listener on an ancestor hears it. It sends no keystrokes, so a\n * component reading `key`, composition, or selection sees nothing. The dispatched event is a plain\n * `Event`, never an `InputEvent`, so a component reading `inputType` or testing\n * `instanceof InputEvent` sees neither. Drive a component that reads any of those through\n * `typeAccessible` instead.\n *\n * No `change` event follows. Use {@link commitInput} where the component waits for the field to be\n * committed.\n *\n * @example\n * ```ts\n * typeInput(requireValue(container.querySelector('input')), 'Ada')\n * ```\n */\nexport function typeInput(element: HTMLInputElement | HTMLTextAreaElement, text: string): void {\n\telement.value = text\n\telement.dispatchEvent(new Event('input', { bubbles: true }))\n}\n\n/**\n * Sets one field's value and commits it, the way typing and then leaving the field does.\n *\n * @param element - The input or textarea to write into.\n * @param text - The value to set.\n *\n * @remarks\n * The order is the browser's: {@link typeInput} first, so `input` is dispatched with the value\n * already set, and one bubbling `change` after it. A component that reads the value from either\n * event therefore reads `text` from both.\n *\n * @example\n * ```ts\n * commitInput(requireValue(container.querySelector('input')), 'Ada')\n * ```\n */\nexport function commitInput(element: HTMLInputElement | HTMLTextAreaElement, text: string): void {\n\ttypeInput(element, text)\n\telement.dispatchEvent(new Event('change', { bubbles: true }))\n}\n\n/**\n * Clears both browser storage surfaces.\n *\n * @remarks\n * A browser test file shares one page, so a key written by one test is read by the next one that\n * looks for it. Call this from an `afterEach` hook, which runs after a failed test as well as a\n * passing one, rather than at the end of each test that happens to write a key.\n *\n * @example\n * ```ts\n * afterEach(clearStorage)\n * ```\n */\nexport function clearStorage(): void {\n\tlocalStorage.clear()\n\tsessionStorage.clear()\n}\n\n/**\n * Deletes one IndexedDB database and reports what the request actually did.\n *\n * @param name - The database name to delete.\n * @returns A promise resolving after the deletion completes.\n * @throws Thrown when the request errors, and when an open connection blocks it.\n *\n * @remarks\n * Deleting a database that was never created succeeds, so this is safe to call from a teardown hook\n * that runs whether or not the test reached the code that opens one.\n *\n * A block is a rejection rather than a wait. `blocked` fires when another connection is still open,\n * and a suite that swallowed it would leave the next test reading the previous test's records\n * through a database that reports itself deleted. The connection holding it open is the caller's to\n * close, so the block is handed back rather than absorbed.\n *\n * @example\n * ```ts\n * afterEach(() => removeDatabase('ledger'))\n * ```\n */\nexport function removeDatabase(name: string): Promise<void> {\n\treturn new Promise<void>((resolve, reject) => {\n\t\tconst request = globalThis.indexedDB.deleteDatabase(name)\n\t\trequest.addEventListener('success', () => resolve())\n\t\trequest.addEventListener('error', () =>\n\t\t\treject(new Error(`IndexedDB database \"${name}\" could not be deleted`)),\n\t\t)\n\t\trequest.addEventListener('blocked', () =>\n\t\t\treject(new Error(`IndexedDB database \"${name}\" is blocked by an open connection`)),\n\t\t)\n\t})\n}\n\n/**\n * Parses one computed CSS color value into straight sRGB channels.\n *\n * @param value - A computed `rgb()`, `rgba()`, or `color(srgb …)` value.\n * @returns The color's channels, or `undefined` when the value names no color this reader speaks.\n *\n * @remarks\n * A computed color resolves to `rgb()` or `rgba()` for every legacy source, and a `color-mix()`\n * declaration resolves to `color(srgb r g b [/ a])` with channels on the 0–1 scale. Both forms are\n * read here and nothing else is: a keyword, a hex triple, an empty string from a detached element,\n * and a color space the cascade never hands back all return `undefined`. Absence is the answer\n * rather than a transparent color, so a caller decides what an unreadable value means instead of\n * measuring a black it never saw.\n *\n * @example\n * ```ts\n * parseColor('rgba(255, 255, 255, 0.5)') // [255, 255, 255, 0.5]\n * parseColor('rebeccapurple') // undefined\n * ```\n */\nexport function parseColor(value: string): Color | undefined {\n\tconst modern =\n\t\t/^color\\(srgb\\s+(?<red>[\\d.]+)\\s+(?<green>[\\d.]+)\\s+(?<blue>[\\d.]+)(?:\\s*\\/\\s*(?<alpha>[\\d.]+))?\\)$/u.exec(\n\t\t\tvalue,\n\t\t)\n\tconst legacy = /^rgba?\\((?<channels>[^)]*)\\)$/u.exec(value)\n\tconst parts =\n\t\tmodern?.groups === undefined\n\t\t\t? (legacy?.groups?.channels ?? '')\n\t\t\t\t\t.split(/[\\s,/]+/u)\n\t\t\t\t\t.filter((part) => part.length > 0)\n\t\t\t\t\t.map((part) => Number.parseFloat(part))\n\t\t\t: [\n\t\t\t\t\tNumber.parseFloat(modern.groups.red ?? '') * 255,\n\t\t\t\t\tNumber.parseFloat(modern.groups.green ?? '') * 255,\n\t\t\t\t\tNumber.parseFloat(modern.groups.blue ?? '') * 255,\n\t\t\t\t\tmodern.groups.alpha === undefined ? 1 : Number.parseFloat(modern.groups.alpha),\n\t\t\t\t]\n\tconst [red, green, blue, alpha = 1] = parts\n\tif (red === undefined || green === undefined || blue === undefined) return undefined\n\tif (![red, green, blue, alpha].every((channel) => Number.isFinite(channel))) return undefined\n\treturn Object.freeze([red, green, blue, alpha])\n}\n\n/**\n * Resolves any CSS color expression to straight sRGB channels, by asking the browser.\n *\n * @param value - Any value the `color` property accepts: a keyword, a hex triple, a `var()`\n * reference, a `color-mix()`, or an already-computed `rgb()`.\n * @returns The resolved color's channels, or `undefined` when the CSSOM refuses the value or the\n * computed result names no color {@link parseColor} speaks.\n *\n * @remarks\n * This is the live half of the pair {@link parseColor} opens. `parseColor` reads text and speaks\n * only the computed syntaxes a cascade hands back; this stages a probe element, hands it to the real\n * cascade, and reads back what the engine computed — which is the only way a keyword, a hex triple,\n * or a `var()` reference becomes channels at all. The read itself goes through `parseColor`, so both\n * halves agree on what a computed value means.\n *\n * The probe is mounted, because an unmounted element inherits nothing and a `var()` reference to a\n * token declared on `:root` would resolve to the initial value instead. It is removed in a `finally`,\n * so a value that throws on the way through leaves no node behind.\n *\n * Refusal is the CSSOM's: an expression it will not parse leaves the probe's inline `color` empty\n * and this returns `undefined`. A `var()` naming an undeclared custom property is not refused,\n * because the cascade accepts it and computes the inherited color, so a test that means to catch a\n * missing token asserts on {@link readToken} rather than on this.\n *\n * @example\n * ```ts\n * parseCSSColor('rebeccapurple') // [102, 51, 153, 1]\n * parseCSSColor('not-a-color') // undefined\n * ```\n */\nexport function parseCSSColor(value: string): Color | undefined {\n\tconst probe = mount(build('span'))\n\ttry {\n\t\tprobe.style.color = value\n\t\tif (probe.style.color === '') return undefined\n\t\treturn parseColor(readStyle(probe, 'color'))\n\t} finally {\n\t\tprobe.remove()\n\t}\n}\n\n/**\n * Determines whether two colors render the same, within the rounding a browser does.\n *\n * @param first - A CSS color expression or an already-parsed color.\n * @param second - A CSS color expression or an already-parsed color.\n * @returns True if every channel and the alpha agree within the tolerance; false otherwise,\n * including when either side names no readable color.\n *\n * @remarks\n * Each string side is resolved through {@link parseCSSColor}, so a keyword, a token reference, and the\n * `rgb()` the engine computes for either of them compare equal without a test converting anything\n * first. A side that resolves to nothing makes the answer `false` rather than a throw, because this\n * is a predicate.\n *\n * The tolerance is half a channel step on the 0–255 scale, and the alpha is scaled onto that same\n * range before it is compared, so one number covers both. Half a step is what a composite of\n * translucent layers and a `color-mix()` round trip actually drift by; anything a reader could see\n * is further than that and reports unequal.\n *\n * @example\n * ```ts\n * matchesColor('rebeccapurple', 'rgb(102, 51, 153)') // true\n * matchesColor('red', [0, 0, 255, 1]) // false\n * ```\n */\nexport function matchesColor(first: string | Color, second: string | Color): boolean {\n\tconst left = typeof first === 'string' ? parseCSSColor(first) : first\n\tconst right = typeof second === 'string' ? parseCSSColor(second) : second\n\tif (left === undefined || right === undefined) return false\n\tconst tolerance = 0.5\n\tconst [leftRed, leftGreen, leftBlue, leftAlpha] = left\n\tconst [rightRed, rightGreen, rightBlue, rightAlpha] = right\n\treturn (\n\t\tMath.abs(leftRed - rightRed) <= tolerance &&\n\t\tMath.abs(leftGreen - rightGreen) <= tolerance &&\n\t\tMath.abs(leftBlue - rightBlue) <= tolerance &&\n\t\tMath.abs(leftAlpha - rightAlpha) * 255 <= tolerance\n\t)\n}\n\n/**\n * Composites one color over another.\n *\n * @param front - The color painted on top.\n * @param back - The color already on the surface.\n * @returns The opaque result a reader sees, its alpha always `1`.\n *\n * @example\n * ```ts\n * blendColor([255, 255, 255, 0.5], [0, 0, 0, 1]) // [127.5, 127.5, 127.5, 1]\n * ```\n */\nexport function blendColor(front: Color, back: Color): Color {\n\tconst [red, green, blue, alpha] = front\n\tconst [under, over, beneath] = back\n\treturn Object.freeze([\n\t\tred * alpha + under * (1 - alpha),\n\t\tgreen * alpha + over * (1 - alpha),\n\t\tblue * alpha + beneath * (1 - alpha),\n\t\t1,\n\t])\n}\n\n/**\n * Measures one opaque color's WCAG relative luminance.\n *\n * @param color - The color to weigh. Its alpha is ignored, so composite before calling.\n * @returns The relative luminance, from `0` for black to `1` for white.\n *\n * @example\n * ```ts\n * measureLuminance([255, 255, 255, 1]) // 1\n * ```\n */\nexport function measureLuminance(color: Color): number {\n\tconst [red, green, blue] = color\n\tconst [first = 0, second = 0, third = 0] = [red, green, blue].map((channel) => {\n\t\tconst part = channel / 255\n\t\treturn part <= 0.040_45 ? part / 12.92 : ((part + 0.055) / 1.055) ** 2.4\n\t})\n\treturn 0.2126 * first + 0.7152 * second + 0.0722 * third\n}\n\n/**\n * Measures the WCAG 2.x contrast ratio between two opaque colors.\n *\n * @param front - The foreground color, already composited.\n * @param back - The opaque backdrop.\n * @returns The ratio, from `1` for two identical colors to `21` for black against white.\n *\n * @remarks\n * The ratio is symmetric: the brighter of the two luminances is always the numerator, so swapping\n * the arguments returns the same number.\n *\n * @example\n * ```ts\n * measureContrast([0, 0, 0, 1], [255, 255, 255, 1]) // 21\n * ```\n */\nexport function measureContrast(front: Color, back: Color): number {\n\tconst bright = Math.max(measureLuminance(front), measureLuminance(back))\n\tconst dark = Math.min(measureLuminance(front), measureLuminance(back))\n\treturn (bright + 0.05) / (dark + 0.05)\n}\n\n/**\n * Collects the painted layers standing between one element and the surface it sits on.\n *\n * @param element - The element to walk up from.\n * @returns Every layer the walk paints, the element's own first and the deepest last.\n *\n * @remarks\n * A surface token paints one ancestor while every element between it and the text paints nothing,\n * so a backdrop is found by walking up rather than by reading the element's own `background-color`,\n * which is almost always transparent. A fully transparent layer paints nothing and is left out, and\n * the walk stops at the first fully opaque layer, because nothing above that layer is visible.\n *\n * The stack is what tells a resolved backdrop from an assumed one: the walk reached an opaque\n * surface exactly when its last layer's alpha is `1`. {@link readContrast} refuses on that reading,\n * which no comparison of composited colors can replace — 64 half-transparent layers composite to\n * the same channels over opposite floors, because the floor's remaining share falls below the last\n * bit a channel carries.\n *\n * @example\n * ```ts\n * readLayers(requireValue(container.querySelector('p')))\n * ```\n */\nexport function readLayers(element: Element): readonly Color[] {\n\tconst layers: Color[] = []\n\tfor (let node: Element | null = element; node !== null; node = node.parentElement) {\n\t\tconst layer = parseColor(getComputedStyle(node).backgroundColor)\n\t\tif (layer === undefined || layer[3] === 0) continue\n\t\tlayers.push(layer)\n\t\tif (layer[3] >= 1) break\n\t}\n\treturn Object.freeze(layers)\n}\n\n/**\n * Resolves the opaque color standing behind one element.\n *\n * @param element - The element whose backdrop to resolve.\n * @param floor - The opaque color the walk ends on when nothing above it paints.\n * @returns The composited color a reader sees behind the element.\n *\n * @remarks\n * The layers {@link readLayers} collects composite top-over-bottom onto the floor, so a 3% surface\n * tint reads as a tint over what shows through it rather than as a full-strength paint.\n *\n * The floor is required, because this leaf never guesses what a document sits on. Pass\n * {@link CANVAS_COLOR} for the page a browser paints behind an unstyled document, or the color of\n * the surface a fragment is really rendered into. When no layer paints, the floor is returned by\n * identity.\n *\n * The composite alone never says whether the floor is part of the answer. A caller that must know\n * reads the stack instead.\n *\n * @example\n * ```ts\n * readBackdrop(requireValue(container.querySelector('p')), CANVAS_COLOR)\n * ```\n */\nexport function readBackdrop(element: Element, floor: Color): Color {\n\treturn readLayers(element).reduceRight((back, front) => blendColor(front, back), floor)\n}\n\n/**\n * Measures the WCAG 2.x contrast ratio between an element's computed text and background colors.\n *\n * @param element - The element whose rendered text contrast to measure.\n * @param floor - The opaque color the backdrop walk ends on. Omit it to refuse a stack the floor\n * would show through instead of assuming one.\n * @returns The relative-luminance contrast ratio.\n * @throws Thrown when the element exposes no computed foreground color, and — with `floor` omitted\n * — when the walk from the element upwards reaches no opaque layer.\n *\n * @remarks\n * A transparent or translucent background resolves through the element's ancestors: every painted\n * layer from the element up to the first opaque one composites top-over-bottom onto that opaque\n * base, so a 3% surface tint reads as a tint over what shows through it rather than as a\n * full-strength paint. A translucent foreground then resolves against that effective background\n * before luminance is measured.\n *\n * With `floor` omitted, the walk from the target upwards must reach a fully opaque layer: the\n * measurement throws rather than assuming a white canvas wherever that canvas would still be part\n * of the answer. The refusal reads the alpha of the deepest layer {@link readLayers} collected, so\n * a chain that declares no background color at all, a chain painting only translucent layers, and a\n * chain deep enough for its composite to round to the canvas's own channels are refused alike,\n * because the number any of them produces is as much a report of the assumption as of the page.\n * Supply a floor wherever the caller knows what the stack sits on — a fragment mounted into a\n * painted host, or a document whose canvas is {@link CANVAS_COLOR} — and the composite is taken\n * over it rather than refused.\n *\n * The element itself must expose a computed foreground color either way. A detached element exposes\n * none, and the measurement throws rather than guessing one.\n *\n * @example\n * ```ts\n * const container = render('<p style=\"background: #000; color: #fff\">Ready</p>')\n * readContrast(requireValue(container.firstElementChild)) // 21\n * readContrast(requireValue(container.firstElementChild), CANVAS_COLOR) // 21, and never refuses\n * ```\n */\nexport function readContrast(element: Element, floor?: Color): number {\n\tconst foreground = parseColor(getComputedStyle(element).color)\n\tif (foreground === undefined) throw new Error('Computed foreground color is unavailable')\n\tconst layers = readLayers(element)\n\tconst deepest = layers.at(-1)\n\t// The walk reached a real surface exactly when its deepest layer is fully opaque. An empty stack\n\t// paints nothing, and a stack ending translucent leaves the floor showing through whatever the\n\t// composite reports: 64 half-transparent layers round to identical channels over opposite floors,\n\t// so comparing two composited readings admits the stack this refusal exists for.\n\tif (floor === undefined && (deepest === undefined || deepest[3] < 1)) {\n\t\tthrow new Error('Computed background color is unavailable')\n\t}\n\tconst backdrop = layers.reduceRight(\n\t\t(back, front) => blendColor(front, back),\n\t\tfloor ?? CANVAS_COLOR,\n\t)\n\treturn measureContrast(blendColor(foreground, backdrop), backdrop)\n}\n\n/**\n * Measures the contrast the focus chrome painted on one control reaches against its own backdrop.\n *\n * @param control - The control that holds the focus.\n * @param worn - The element the control's focus chrome is painted onto. Default: `control`.\n * @returns The strongest ratio the painted focus chrome reaches, or `undefined` when the control is\n * not showing `:focus-visible` or the cascade paints no chrome of its own.\n *\n * @remarks\n * This reads and never acts. Focus arrives through the published verbs — `traverseAccessible`,\n * `userEvent.keyboard` from `vitest/browser`, a real click — and this measures what the browser\n * painted once it landed. A control that is not matching `:focus-visible` when the call is made\n * reports nothing, because no measurement taken then would be about focus.\n *\n * Some controls are two elements: one that takes the focus and one a reader can see. A hidden radio\n * beside the label that carries every pixel of its chrome is the case `worn` exists for, so a\n * measurement is not taken on a rectangle nobody is looking at. The focus state is still read off\n * `control`, because that is what holds it.\n *\n * The backdrop is the surface behind the element the chrome is worn on, resolved from that element's\n * parent through {@link readBackdrop} onto {@link CANVAS_COLOR}. A control whose ancestry paints\n * nothing is therefore measured against the browser's own canvas, which is what a reader looking at\n * an unstyled document sees.\n *\n * Only chrome the cascade paints is measured — an `outline` with a real style and width, and the\n * first color in a `box-shadow`. A control left the browser's own `outline-style: auto` ring reports\n * `undefined`, because that ring's two tones are guaranteed against any backdrop and its computed\n * color names neither. A focus style that only changes the control's own fill reports `undefined`\n * too: the resting fill is gone by the time focus is on the control, and this never moves focus to\n * go and read it.\n *\n * @example\n * ```ts\n * await traverseAccessible('Evaluate')\n * readRing(resolveRendered('Evaluate')) // the ratio the painted ring reaches\n * ```\n */\nexport function readRing(control: Element, worn?: Element): number | undefined {\n\tif (!control.matches(':focus-visible')) return undefined\n\tconst target = worn ?? control\n\tconst declared = getComputedStyle(target)\n\tconst backdrop = readBackdrop(target.parentElement ?? target, CANVAS_COLOR)\n\tconst outline =\n\t\tdeclared.outlineStyle === 'none' ||\n\t\tdeclared.outlineStyle === 'auto' ||\n\t\tNumber.parseFloat(declared.outlineWidth) === 0\n\t\t\t? undefined\n\t\t\t: parseColor(declared.outlineColor)\n\tconst shadow = parseColor(/(?:rgba?|color)\\([^)]*\\)/u.exec(declared.boxShadow)?.[0] ?? '')\n\tconst ratios: number[] = []\n\tfor (const painted of [outline, shadow]) {\n\t\tif (painted === undefined) continue\n\t\tratios.push(measureContrast(blendColor(painted, backdrop), backdrop))\n\t}\n\treturn ratios.length === 0 ? undefined : Math.max(...ratios)\n}\n\n/**\n * Collects every class token the stylesheets loaded into this document actually define.\n *\n * @returns The set of class names reachable in the shipped cascade, in {@link readRules} order.\n *\n * @remarks\n * The set is what an authored-class conformance check measures against, so a class no loaded\n * stylesheet defines — an invented utility, a misspelled framework name — is absent from it.\n *\n * The tokens come from the {@link readRules} walk, which decides both the membership and the\n * insertion order this reader reports, and each answer is a deliberate difference from 0.0.8. A\n * class declared inside a grouping rule — a media query, a supports block, a layer, a nested style\n * rule — counts as defined, because a class the cascade defines under a condition is still one the\n * cascade defines; 0.0.8 read the top-level rules alone. Insertion order is breadth-first, so a\n * top-level class lands before a class declared inside an earlier grouping rule; 0.0.8 popped a\n * stack and inserted the deepest rule first. Iterate the set where the order is the subject, and\n * read `has` where membership is.\n *\n * `@keyframes` children are outside that walk, so an animation's own rules define no token here.\n * Reach the animation itself through {@link findKeyframes}.\n *\n * @example\n * ```ts\n * readCascade().has('card')\n * ```\n */\nexport function readCascade(): ReadonlySet<string> {\n\tconst known = new Set<string>()\n\tfor (const rule of readRules()) {\n\t\tif (!(rule instanceof CSSStyleRule)) continue\n\t\tfor (const match of rule.selectorText.matchAll(/\\.([a-zA-Z][\\w-]*)/g)) {\n\t\t\tknown.add(String(match[1]))\n\t\t}\n\t}\n\treturn known\n}\n\n/**\n * Collects every class token the markup under one root carries.\n *\n * @param root - The subtree to sweep. A detached element and a `DocumentFragment` both work.\n * @returns The class tokens in document order of first sighting; an empty set for markup carrying no\n * class at all.\n *\n * @remarks\n * The root's own classes count when the root is an `Element`, so a `DocumentFragment` contributes\n * its descendants alone. Every element is read through `classList`, which is what makes an SVG\n * element count the same as an HTML one: `className` on an SVG element is an `SVGAnimatedString`\n * rather than a string, and a reader splitting that value finds nothing.\n *\n * This is the authored half of a class conformance check and {@link readCascade} is the defined\n * half, so the difference between them is the set of classes the markup uses and no loaded\n * stylesheet declares.\n *\n * @example\n * ```ts\n * [...readClasses(container)].filter((name) => !readCascade().has(name))\n * ```\n */\nexport function readClasses(root: ParentNode): ReadonlySet<string> {\n\tconst authored = new Set<string>()\n\tif (root instanceof Element) for (const name of root.classList) authored.add(name)\n\tfor (const element of root.querySelectorAll('*')) {\n\t\tfor (const name of element.classList) authored.add(name)\n\t}\n\treturn authored\n}\n\n/**\n * Collects every rule the stylesheets loaded into this document hold, nested grouping rules\n * included.\n *\n * @returns Every rule reachable in the shipped cascade: each sheet's own rules in sheet order, then\n * the rules nested inside them, level by level.\n *\n * @remarks\n * The walk is iterative and reads the list it is still appending to, which is what expands a media\n * query, a supports block, a layer, and a nested style rule without recursion. Expanding by level\n * rather than by depth is why a top-level rule is always met before a rule nested inside an earlier\n * one; {@link findRule} returns the first match in exactly this order.\n *\n * The descent reaches a `CSSGroupingRule` and nothing else, and a `@keyframes` rule is not one. The\n * `@keyframes` rule itself is collected wherever it sits, and the keyframe rules inside it are not;\n * {@link findKeyframes} is the door to those.\n *\n * A stylesheet the document cannot read — a cross-origin sheet with no CORS grant — throws from its\n * own `cssRules` getter, and that sheet is skipped rather than ending the walk. What a page loaded\n * from another origin declares is unreadable to every caller here, so the alternative is a helper\n * that works until a test page adds a font or an analytics stylesheet.\n *\n * @example\n * ```ts\n * readRules().filter((rule) => rule instanceof CSSKeyframesRule)\n * ```\n */\nexport function readRules(): readonly CSSRule[] {\n\tconst rules: CSSRule[] = []\n\tfor (const sheet of document.styleSheets) {\n\t\ttry {\n\t\t\trules.push(...sheet.cssRules)\n\t\t} catch {\n\t\t\tcontinue\n\t\t}\n\t}\n\tfor (let index = 0; index < rules.length; index += 1) {\n\t\tconst rule = rules[index]\n\t\tif (rule instanceof CSSGroupingRule) rules.push(...rule.cssRules)\n\t}\n\treturn rules\n}\n\n/**\n * Finds the first style rule in the cascade whose selector carries a fragment.\n *\n * @param selector - The selector fragment to look for, matched as a substring of the whole selector\n * text.\n * @returns The first matching rule in {@link readRules} order, or `undefined` when no rule carries\n * the fragment.\n *\n * @remarks\n * This proves a declaration exists in the cascade at all, which is a different question from what an\n * element resolves to: {@link readStyle} reads the winner, and a rule this finds may be overridden by\n * another. Assert on this where the subject is the stylesheet, and on `readStyle` where the subject is\n * the rendered result.\n *\n * The match is a substring, so `findRule('.card')` finds `.card`, `.card:hover`, and\n * `.panel > .card` alike. Pass more of the selector to narrow it.\n *\n * @example\n * ```ts\n * findRule('.card')?.style.getPropertyValue('padding')\n * ```\n */\nexport function findRule(selector: string): CSSStyleRule | undefined {\n\tfor (const rule of readRules()) {\n\t\tif (rule instanceof CSSStyleRule && rule.selectorText.includes(selector)) return rule\n\t}\n\treturn undefined\n}\n\n/**\n * Finds the animation the cascade declares under one name.\n *\n * @param name - The exact `@keyframes` name.\n * @returns The first matching rule in {@link readRules} order, or `undefined` when the cascade\n * declares no animation under that name.\n *\n * @remarks\n * The name is matched exactly, which is where this parts from {@link findRule}: a selector is\n * compound and a fragment of one is a useful question, and an animation name is one atom that either\n * is or is not the one an `animation` declaration references.\n *\n * @example\n * ```ts\n * findKeyframes('fade')?.cssRules.length\n * ```\n */\nexport function findKeyframes(name: string): CSSKeyframesRule | undefined {\n\tfor (const rule of readRules()) {\n\t\tif (rule instanceof CSSKeyframesRule && rule.name === name) return rule\n\t}\n\treturn undefined\n}\n\n/**\n * Reads the normalized visible text of every element a selector matches, in document order.\n *\n * @param root - The subtree to search.\n * @param selector - The CSS selector naming the rows.\n * @returns One line per matched element, its text runs collapsed and single-space joined.\n *\n * @remarks\n * The line is built from the row's text nodes rather than from `textContent`, because adjacent\n * inline elements carry no whitespace between them in compiled template output and would otherwise\n * read as one run-together word.\n *\n * @example\n * ```ts\n * readRows(container, 'li')\n * ```\n */\nexport function readRows(root: ParentNode, selector: string): readonly string[] {\n\tconst rows: string[] = []\n\tfor (const row of root.querySelectorAll(selector)) {\n\t\tconst parts: string[] = []\n\t\tconst walker = document.createTreeWalker(row, NodeFilter.SHOW_TEXT)\n\t\twhile (walker.nextNode() !== null) {\n\t\t\tconst text = (walker.currentNode.textContent ?? '').replaceAll(/\\s+/g, ' ').trim()\n\t\t\tif (text !== '') parts.push(text)\n\t\t}\n\t\trows.push(parts.join(' '))\n\t}\n\treturn rows\n}\n\n/**\n * Collects every element carrying a component class rendered outside the container it belongs to.\n *\n * @param root - The subtree to sweep.\n * @param child - The component class whose anatomy requires a container, such as `list-group-item`.\n * @param parent - The container class that child class must render inside, such as `list-group`.\n * @returns The markup of every element carrying `child` with no `parent` above it, in document\n * order; an empty list when every one of them is nested correctly.\n *\n * @remarks\n * A component keeps its padding, borders, and radii on the container, so a child class rendered\n * outside one is an unstyled box wearing a component's name, and the interface has to hand-roll the\n * chrome back. The search for the container starts at the element's parent, so an element can never\n * answer the invariant by carrying both classes itself.\n *\n * The class names are arguments, so the check belongs to no framework: name the pair your own\n * cascade defines.\n *\n * @example\n * ```ts\n * extractOrphans(container, 'list-group-item', 'list-group') // []\n * ```\n */\nexport function extractOrphans(root: ParentNode, child: string, parent: string): readonly string[] {\n\treturn [...root.querySelectorAll(`.${child}`)]\n\t\t.filter((node) => (node.parentElement?.closest(`.${parent}`) ?? null) === null)\n\t\t.map((node) => node.outerHTML)\n}\n\n/**\n * Collects the markup of every element carrying a non-empty `style` attribute and of every `<style>`\n * element, in document order, `root` included in both populations when it is an `Element`.\n *\n * @param root - The subtree to sweep. A detached element and a `DocumentFragment` both work.\n * @returns The `outerHTML` of each such element, in document order; an empty list when the markup\n * declares no style of its own.\n *\n * @remarks\n * These are the declarations the stylesheet never sees: an inline `style` attribute, wherever it\n * sits, and a `<style>` element, whatever it holds. Nothing else counts. A class and a `data-*`\n * attribute name something the cascade resolves, so neither is reported however unusual it looks;\n * an inline `style` on a `<path>` inside an SVG is reported, because a namespace changes nothing\n * about what an inline declaration is.\n *\n * A `style` attribute holding nothing but whitespace declares nothing, so it is not reported. A\n * `DocumentFragment` root contributes its descendants alone, because it is not an `Element`; a\n * `<style>` root and a root carrying an inline attribute are each reported, and an element that is a\n * `<style>` element and carries an inline attribute too is reported once.\n *\n * @example\n * ```ts\n * extractStyles(container) // []\n * ```\n */\nexport function extractStyles(root: ParentNode): readonly string[] {\n\tconst elements: Element[] = root instanceof Element ? [root] : []\n\telements.push(...root.querySelectorAll('*'))\n\tconst styled: string[] = []\n\tfor (const element of elements) {\n\t\tconst inline = element.getAttribute('style') ?? ''\n\t\tif (inline.trim() !== '' || element.localName === 'style') styled.push(element.outerHTML)\n\t}\n\treturn styled\n}\n\n/**\n * Reads one resolved CSS property from a real browser element.\n *\n * @param element - The element whose resolved style to inspect.\n * @param property - The CSS property name, registered or custom.\n * @returns The browser's resolved property value, trimmed; an empty string when the element resolves\n * none.\n *\n * @remarks\n * The value is trimmed, so what comes back is the value and never the whitespace around it. Internal\n * whitespace is kept: `--shadow: 0 0 2px` reads back with its spaces.\n *\n * @example\n * ```ts\n * readStyle(button, 'padding-left')\n * ```\n */\nexport function readStyle(element: Element, property: string): string {\n\treturn getComputedStyle(element).getPropertyValue(property).trim()\n}\n\n/**\n * Reads one custom property from an element's resolved style.\n *\n * @param element - The element whose resolved style to inspect.\n * @param name - The custom property name, with or without its leading dashes.\n * @returns The resolved value, trimmed; an empty string when the element inherits no such property.\n *\n * @remarks\n * The dashes are optional because a token is spoken about both ways — `--surface` in a stylesheet\n * and `surface` in prose — and a reader that accepted only one spelling would turn that into a silent\n * empty string. An absent token reads as `''`, which is what the CSSOM returns and is\n * indistinguishable from a token declared empty; assert on the value you expect rather than on\n * presence.\n *\n * Resolution is inheritance, so a token declared on `:root` reads from any mounted descendant and\n * from an unmounted element reads as `''`. Use {@link readRootToken} where the declaration is the\n * document's.\n *\n * @example\n * ```ts\n * readToken(panel, 'surface') // '#ffffff'\n * readToken(panel, '--surface') // '#ffffff'\n * ```\n */\nexport function readToken(element: Element, name: string): string {\n\treturn readStyle(element, name.startsWith('--') ? name : `--${name}`)\n}\n\n/**\n * Reads one custom property from the document element.\n *\n * @param name - The custom property name, with or without its leading dashes.\n * @returns The resolved value, trimmed; an empty string when the document declares no such property.\n *\n * @remarks\n * This is {@link readToken} against `document.documentElement`, which is where a theme declares its\n * tokens and where a `[data-theme]` switch retunes them. It exists as its own name because that\n * element is the one a token question is nearly always about, and naming it at every call site\n * buries the question.\n *\n * @example\n * ```ts\n * readRootToken('surface')\n * ```\n */\nexport function readRootToken(name: string): string {\n\treturn readToken(document.documentElement, name)\n}\n\n/**\n * Reads one resolved CSS length as a number of pixels.\n *\n * @param element - The element whose resolved style to inspect.\n * @param property - The CSS property name, registered or custom.\n * @returns The leading numeric part of the resolved value, and `0` when it carries none.\n *\n * @remarks\n * A resolved length is text with a unit — `'12px'` — so this reads the number in front of the unit\n * and discards the rest. The unit is not checked: the resolved value of a length is in pixels in\n * every case a browser hands back, and a property that resolves to something else is the caller's\n * mistake rather than this reader's.\n *\n * An unparsable value reads as `0` rather than as absence, because every caller of this is measuring\n * and `'auto'`, `'none'`, and `''` each contribute no pixels to what a reader sees. Where the\n * distinction matters, read the text with {@link readStyle} instead.\n *\n * @example\n * ```ts\n * readPixels(button, 'padding-left') // 12\n * readPixels(button, 'width') // 0 when the width resolves to `auto`\n * ```\n */\nexport function readPixels(element: Element, property: string): number {\n\tconst measured = Number.parseFloat(readStyle(element, property))\n\treturn Number.isFinite(measured) ? measured : 0\n}\n\n/**\n * Measures the row the document's own content ends on, in document coordinates.\n *\n * @returns The content edge, rounded up to a whole row.\n *\n * @remarks\n * The body's box is not the document's height: it is the larger of the content and the pane. A pane\n * taller than the document stretches it, and `document.body.getBoundingClientRect()`,\n * `body.scrollHeight`, `body.offsetHeight`, and `documentElement.scrollHeight` all read that pane\n * back rather than the content under it. So a caller that has staged a pane taller than the\n * document cannot find its way down again from any of them. This reading can, because it is taken\n * over the elements inside the body rather than over the box around them: a document of fixed\n * content answers the same number under a short pane and a tall one, and a document laid out\n * against the viewport answers what that viewport actually laid out.\n *\n * Each element contributes its client rectangle's bottom edge in document coordinates plus its own\n * bottom margin, which sits outside that rectangle, and the largest contribution wins. Taking the\n * largest is what handles a collapsed margin without asking whether it collapsed: a child margin\n * that collapses out through its parent is counted once, at the child, and one the parent's padding\n * holds in is counted once, at the parent. The body's and the root's own bottom padding and margin\n * sit under every child rather than beside them, so they are added after the walk.\n *\n * The sum is rounded up because a box can end part way through a row and a frame cannot hold part\n * of one.\n *\n * @example\n * ```ts\n * const covered = measureContent()\n * ```\n */\nexport function measureContent(): number {\n\tlet edge = 0\n\tfor (const element of document.body.querySelectorAll('*')) {\n\t\tconst bottom =\n\t\t\telement.getBoundingClientRect().bottom + window.scrollY + readPixels(element, 'margin-bottom')\n\t\tif (bottom > edge) edge = bottom\n\t}\n\treturn Math.ceil(\n\t\tedge +\n\t\t\treadPixels(document.body, 'padding-bottom') +\n\t\t\treadPixels(document.body, 'margin-bottom') +\n\t\t\treadPixels(document.documentElement, 'padding-bottom') +\n\t\t\treadPixels(document.documentElement, 'margin-bottom'),\n\t)\n}\n\n/**\n * Sets the tester's viewport and renders the runner's pane at the size that viewport claims.\n *\n * @param width - The viewport width in CSS pixels.\n * @param height - The viewport height in CSS pixels.\n * @returns A promise resolving after the resized pane has been painted.\n * @throws Thrown when the tester sits inside no pane a capture can size, and when the staged pane\n * does not render at the viewport it was given.\n *\n * @remarks\n * This depends on the runner's own tester layout, and that dependency is contract rather than an\n * accident: `vitest@4.1.11` lays its tester out inside a smaller page, fits it by scaling the pane\n * the tester sits in, and clips whatever overflows that pane. Layout inside the tester is\n * unaffected — the tester reports the viewport it was given and every breakpoint answers to it —\n * but a screenshot is taken off the page the runner painted, so a frame shot through that scale is\n * a thumbnail of the surface and a frame shot after only unscaling it is a sliver. The tester is\n * therefore unscaled and lifted to the window's own origin for the shot. The `iframe[data-vitest]`\n * selector and the `--tester-transform`, `--tester-margin-left`, `--viewport-width`, and\n * `--viewport-height` custom properties are the runner's, so a Vitest release that renames any of\n * them reddens the size check that follows rather than writing a wrong frame.\n *\n * Hand the pane straight back with {@link releasePane}. A tester pinned at a viewport taller than\n * the window puts its lower half beyond what a pointer can reach, so an ordinary press then fails\n * as a control outside the viewport, in a test that took no picture at all.\n *\n * This is a capture's staging alone. A suite that resizes the tester for a journey — a breakpoint\n * to drive, a variant to act at — calls `page.viewport` from `vitest/browser` and leaves the tester\n * there. Staging and releasing as a pair resizes and then undoes the resize, so the journey step\n * after it runs at the size the file started at.\n *\n * The rule is declared rather than written inline, because the runner writes its own scale onto the\n * pane as inline custom properties and rewrites them whenever the tester resizes. A declared rule\n * marked important outranks an inline value and survives every rewrite. It finds the pane by the\n * tester it contains as well as by {@link CAPTURE_PANE}, because a re-render between the staging and\n * the shot replaces the node and takes any attribute of ours with it.\n *\n * The wait is two frames rather than a delay: the first carries the resize into layout and the\n * second is the paint a screenshot reads.\n *\n * The viewport the tester had before this staging is written onto that rule element as the\n * {@link CAPTURE_PANE} value, in `<width>x<height>` form, and {@link releasePane} hands it back.\n * Staging an already-staged pane leaves that value alone, so a capture that stages a second time to\n * cover a taller document still releases to the viewport the tester started with.\n *\n * @example\n * ```ts\n * await stagePane(390, 844)\n * ```\n */\nexport async function stagePane(width: number, height: number): Promise<void> {\n\tconst viewport = `${String(window.innerWidth)}x${String(window.innerHeight)}`\n\tawait page.viewport(width, height)\n\tconst frame = window.frameElement\n\tconst pane = frame?.parentElement\n\tconst owner = pane?.ownerDocument\n\tif (frame === null || pane === null || pane === undefined || owner === undefined) {\n\t\tthrow new Error('Tester pane is unavailable for a capture')\n\t}\n\tpane.setAttribute(CAPTURE_PANE, '')\n\tif (owner.querySelector(`style[${CAPTURE_PANE}]`) === null) {\n\t\tconst rule = owner.createElement('style')\n\t\trule.setAttribute(CAPTURE_PANE, viewport)\n\t\trule.textContent = [\n\t\t\t`[${CAPTURE_PANE}],:has(>iframe[data-vitest])`,\n\t\t\t'{--tester-transform:none !important;--tester-margin-left:0px !important}',\n\t\t\t'iframe[data-vitest]',\n\t\t\t'{position:fixed !important;left:0 !important;top:0 !important;right:auto !important;',\n\t\t\t'bottom:auto !important;width:var(--viewport-width) !important;',\n\t\t\t'height:var(--viewport-height) !important;z-index:2147483647 !important}',\n\t\t].join('')\n\t\towner.head.append(rule)\n\t}\n\tawait waitForFrame()\n\tawait waitForFrame()\n\tconst box = frame.getBoundingClientRect()\n\tif (Math.round(box.width) !== width || Math.round(box.height) !== height) {\n\t\tthrow new Error(\n\t\t\t`Tester pane rendered ${String(Math.round(box.width))}x${String(Math.round(box.height))} for a ${String(width)}x${String(height)} viewport`,\n\t\t)\n\t}\n}\n\n/**\n * Hands the tester pane back to the runner's own layout, at the viewport it had before staging.\n *\n * @remarks\n * A staged pane is the runner's fitting scale suppressed, so a pane left staged outlives the capture\n * that needed it and every later act in the file happens on a surface the runner is no longer\n * fitting to its window. What that costs is not a wrong picture: it is a control whose page\n * coordinates fall outside the pane, which the runner's own layout then intercepts, so an ordinary\n * press fails with the voice of a control that is covered.\n *\n * The viewport goes back too, because a capture resizes the tester and the size it chose belongs to\n * the frame rather than to the file: a test that runs after one and reads a breakpoint would\n * otherwise read the last capture's variant. The size comes off the {@link CAPTURE_PANE} value\n * {@link stagePane} wrote onto the rule element, which is the reading taken before the first\n * staging. Calling this on an unstaged pane finds no such value, so it changes nothing and resizes\n * nothing.\n *\n * That hand-back is what makes {@link stagePane} and this pair a capture's staging rather than a\n * resize: the pair puts the tester back where it found it, so a suite that used it to reach a\n * breakpoint runs its next step at the old size. Call `page.viewport` from `vitest/browser` for a\n * journey's own size, and leave this pair to the capture.\n *\n * @example\n * ```ts\n * await releasePane()\n * ```\n */\nexport async function releasePane(): Promise<void> {\n\tconst pane = window.frameElement?.parentElement\n\tconst rule = pane?.ownerDocument.querySelector(`style[${CAPTURE_PANE}]`)\n\tconst viewport = rule?.getAttribute(CAPTURE_PANE)?.split('x') ?? []\n\tpane?.removeAttribute(CAPTURE_PANE)\n\trule?.remove()\n\tconst width = Number(viewport[0])\n\tconst height = Number(viewport[1])\n\tif (Number.isFinite(width) && Number.isFinite(height)) await page.viewport(width, height)\n}\n\n/**\n * Shoots one frame at one viewport size and proves the file on disk holds this run's bytes.\n *\n * @param options - The path to write, the viewport to shoot at, and the element to shoot.\n * @returns The absolute path of the written frame, after it has been read back and matched.\n * @throws Thrown when the pane cannot be staged, when the document's height never settles under\n * {@link CAPTURE_STAGINGS} restagings, when the provider wrote the frame somewhere else, and when\n * the bytes on disk are not the ones this shot produced.\n *\n * @remarks\n * The path a screenshot call returns is the path it meant to write, so it is not evidence a file\n * exists. The file is read back through the runner's built-in `readFile` command and compared with\n * the shot itself, which is what separates a frame this run wrote from one an earlier run left\n * behind. The provider resolves `options.path` against the calling test file and returns an absolute\n * path, so the two are compared by the segments that survive resolving `.` and `..` lexically — the\n * refusal is what a provider resolving that path against a different base would trip.\n *\n * The frame covers the whole document at `options.width`, whatever `options.height` is. The\n * provider shoots the tester's body in the top-level page's own coordinates, so a document taller\n * than the pane is painted for the pane's height and the rows below it are the runner's page rather\n * than the document — a frame that reads as the surface down to the fold and as bare canvas after\n * it. The document is therefore laid out at the declared viewport first and, where it is taller\n * than that, the pane is staged again at the height the document needs, for the shot alone.\n *\n * That height is {@link measureContent}, never less than `options.height`, because the declared\n * viewport is the smallest frame a variant asks for. The reading is the content's own edge rather\n * than the body's box: the box is the larger of the content and the pane, so it stretches with\n * every pane staged over it and a capture that staged too tall a pane could not read its way back\n * down. Rounding up is what covers a body ending part way through a row, which the box does and an\n * integer scroll height does not.\n *\n * The edge is read again after every staging, because a rule bound to the viewport height — a `vh`\n * length, a fixed footer, a full-height panel — lays the document out taller against the taller\n * pane, so a surface built out of those photographs as its scrolled-open self rather than as one\n * screen, and the reading taken before that staging is stale by exactly what the reflow added.\n * Restaging at the edge alone converges on such a document without arriving: each staging closes\n * the same fraction of what is left, so a rule keeping half the pane reads 1322, 1561, 1681, and\n * 1741 against a fixed point of 1800. Each staging therefore carries the growth the one before it\n * produced — the pane is the edge plus that growth — which lands on the fixed point rather than\n * creeping up to it. The first staging carries no growth, because nothing has grown yet, so a\n * document of fixed content is staged at its own edge and shot there rather than at a pane the\n * overshoot stretched.\n *\n * The re-reading stops when the pane and the edge agree, which is the pane the shot is taken at. A\n * rule that adds height with every pane never reaches that point, so the re-reading is bounded by\n * {@link CAPTURE_STAGINGS} and the shot is refused with\n * `Capture frame at <path> never settled after <n> restagings: <h> over a <h> pane` rather than\n * written at a height that is already wrong.\n *\n * Omit `options.element` to shoot the whole page. The pane is staged for the frame and released\n * before this returns, on the failing path as well as the passing one, which hands the tester back\n * the viewport it had before the first staging.\n *\n * @example\n * ```ts\n * await captureFrame({ path: '../../tmp/capture/start.png', width: 390, height: 844 })\n * ```\n */\nexport async function captureFrame(options: FrameOptions): Promise<string> {\n\ttry {\n\t\tawait stagePane(options.width, options.height)\n\t\tlet pane = options.height\n\t\tlet covered = Math.max(measureContent(), options.height)\n\t\tlet growth = 0\n\t\tfor (let staging = 0; pane !== covered; staging += 1) {\n\t\t\tif (staging === CAPTURE_STAGINGS) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Capture frame at ${options.path} never settled after ${String(CAPTURE_STAGINGS)} restagings: ${String(covered)} over a ${String(pane)} pane`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tpane = covered + growth\n\t\t\tawait stagePane(options.width, pane)\n\t\t\tconst reading = Math.max(measureContent(), options.height)\n\t\t\tgrowth = Math.max(0, reading - covered)\n\t\t\tcovered = reading\n\t\t}\n\t\tconst shot =\n\t\t\toptions.element === undefined\n\t\t\t\t? await page.screenshot({ path: options.path, base64: true })\n\t\t\t\t: await page.screenshot({ element: options.element, path: options.path, base64: true })\n\t\tconst segments: string[] = []\n\t\tfor (const segment of options.path.replaceAll('\\\\', '/').split('/')) {\n\t\t\tif (segment === '' || segment === '.') continue\n\t\t\tif (segment === '..') segments.pop()\n\t\t\telse segments.push(segment)\n\t\t}\n\t\tif (!shot.path.replaceAll('\\\\', '/').endsWith(segments.join('/'))) {\n\t\t\tthrow new Error(\n\t\t\t\t`Capture frame was written to ${shot.path} where ${options.path} was asked for`,\n\t\t\t)\n\t\t}\n\t\tif ((await commands.readFile(shot.path, 'base64')) !== shot.base64) {\n\t\t\tthrow new Error(`Capture frame at ${options.path} is not the one this run shot`)\n\t\t}\n\t\treturn shot.path\n\t} finally {\n\t\tawait releasePane()\n\t}\n}\n\n/**\n * Reads one written frame back and reports its size and the color its bottom row paints.\n *\n * @param path - The frame's absolute path, as `captureFrame` returns it.\n * @returns The frame's size in device pixels and its floor.\n * @throws Thrown when the runner cannot read the path, when the bytes there are not an image this\n * browser decodes, and when the browser hands out no 2D canvas to measure them on.\n *\n * @remarks\n * The reading comes off the written file rather than off the document that produced it, which is\n * what makes it evidence about a capture: the browser's own image decoding and an\n * `OffscreenCanvas` answer for the pixels a viewer would see, so a frame that ends on the runner's\n * canvas reports that canvas whatever the document's style resolves to. Pass the path the provider\n * resolved and `captureFrame` returned; the runner's `readFile` command resolves a relative path\n * against its own root rather than against the calling test file, so a relative path names a file\n * somewhere else.\n *\n * @example\n * ```ts\n * const reading = await readFrame(written)\n * ```\n */\nexport async function readFrame(path: string): Promise<FrameReading> {\n\tconst encoded = await commands.readFile(path, 'base64').catch((cause: unknown) => {\n\t\tthrow new Error(`Capture frame at ${path} could not be read`, { cause })\n\t})\n\tconst image = new Image()\n\timage.src = `data:image/png;base64,${encoded}`\n\tawait image.decode().catch((cause: unknown) => {\n\t\tthrow new Error(`Capture frame at ${path} is not an image this browser decodes`, { cause })\n\t})\n\tconst context = new OffscreenCanvas(image.width, image.height).getContext('2d')\n\tif (context === null) {\n\t\tthrow new Error(`Capture frame at ${path} cannot be measured without a 2D canvas`)\n\t}\n\tcontext.drawImage(image, 0, 0)\n\tconst row = context.getImageData(0, image.height - 1, image.width, 1).data\n\tconst red = row[0]\n\tconst green = row[1]\n\tconst blue = row[2]\n\tconst alpha = row[3]\n\tlet single = red !== undefined && green !== undefined && blue !== undefined\n\tfor (let pixel = 4; single && pixel < row.length; pixel += 4) {\n\t\tsingle =\n\t\t\trow[pixel] === red &&\n\t\t\trow[pixel + 1] === green &&\n\t\t\trow[pixel + 2] === blue &&\n\t\t\trow[pixel + 3] === alpha\n\t}\n\treturn {\n\t\twidth: image.width,\n\t\theight: image.height,\n\t\tfloor: single ? `rgb(${String(red)}, ${String(green)}, ${String(blue)})` : undefined,\n\t}\n}\n\n/**\n * Expands a capture registry across every variant into the filenames a complete portfolio holds.\n *\n * @param states - The registered state names.\n * @param variants - The variants the portfolio is rendered in.\n * @returns One `<state>--<variant>.png` name per pair, each state's variants together, in registry\n * order.\n *\n * @remarks\n * The expansion is the portfolio's own definition of complete, so a duplicate in it is a registry\n * defect a proof reads directly rather than a collision discovered on disk.\n *\n * @example\n * ```ts\n * expandCaptures(['start'], [{ name: 'dark-390', width: 390, height: 844 }])\n * // ['start--dark-390.png']\n * ```\n */\nexport function expandCaptures(\n\tstates: readonly string[],\n\tvariants: readonly CaptureVariant[],\n): readonly string[] {\n\tconst files: string[] = []\n\tfor (const state of states) {\n\t\tfor (const variant of variants) files.push(`${state}--${variant.name}.png`)\n\t}\n\treturn files\n}\n","import type {\n\tJournalInterface,\n\tJournalStep,\n\tPortfolioInterface,\n\tPortfolioOptions,\n} from './types.js'\nimport { captureFrame, expandCaptures } from './helpers.js'\n\n/**\n * Creates one real pointer event, ready to dispatch.\n *\n * @param name - The event type, such as `pointerdown`.\n * @param options - Any `PointerEventInit` member, each one overriding the default beneath it.\n * @returns A real `PointerEvent` of that type.\n *\n * @remarks\n * The defaults are what a browser's own pointer event carries and a hand-built one does not:\n * `bubbles` and `cancelable` are set, so a delegated listener hears it and a handler can prevent it,\n * and `pointerId`, `pointerType`, and `isPrimary` describe a single primary mouse, so a component\n * that branches on the pointer kind takes the branch a mouse takes. Override any of them by naming\n * it; a touch is `{ pointerType: 'touch' }` and nothing else has to be restated.\n *\n * The event is real rather than a shaped object, so `instanceof PointerEvent` holds and the\n * coordinate and modifier members a handler reads are the ones the platform defines.\n *\n * @example\n * ```ts\n * element.dispatchEvent(createPointerEvent('pointerdown', { clientX: 10, clientY: 20 }))\n * ```\n */\nexport function createPointerEvent(name: string, options?: PointerEventInit): PointerEvent {\n\treturn new PointerEvent(name, {\n\t\tbubbles: true,\n\t\tcancelable: true,\n\t\tpointerId: 1,\n\t\tpointerType: 'mouse',\n\t\tisPrimary: true,\n\t\t...options,\n\t})\n}\n\n/**\n * Creates one real drag event carrying a live data transfer, ready to dispatch.\n *\n * @param name - The event type, such as `dragstart`.\n * @param options - Any `DragEventInit` member, each one overriding the default beneath it.\n * @returns A real `DragEvent` of that type.\n *\n * @remarks\n * A drag event with no `dataTransfer` is the shape that makes a drop handler fail in a test and work\n * in a browser, so one is allocated. Pass your own to seed it: a `dataTransfer` given in `options`\n * replaces the allocated one, which is how a drop is driven with the payload the drag was supposed\n * to carry.\n *\n * The platform declares the `dataTransfer` member on the constructed event as nullable, so calling\n * code still narrows it even though this always supplies one.\n *\n * `bubbles` and `cancelable` are set, because a drop handler that never prevents the default event\n * is a drop the browser handles itself.\n *\n * @example\n * ```ts\n * const started = createDragEvent('dragstart')\n * started.dataTransfer?.setData('text/plain', 'row-3')\n * element.dispatchEvent(started)\n * ```\n */\nexport function createDragEvent(name: string, options?: DragEventInit): DragEvent {\n\treturn new DragEvent(name, {\n\t\tbubbles: true,\n\t\tcancelable: true,\n\t\tdataTransfer: new DataTransfer(),\n\t\t...options,\n\t})\n}\n\n/**\n * Creates the capture portfolio one run places its screenshots through.\n *\n * @param options - The state registry, the variant matrix, the variant this run renders, the\n * directory it writes into, and whether it writes at all.\n * @returns The portfolio: its registry expansion, what it has placed, and `place`.\n * @throws When no registered variant carries the name `variant` names.\n *\n * @remarks\n * A disabled portfolio is the ordinary run. `place` then resizes nothing, writes nothing, and\n * records nothing, so a journey calls it unconditionally and a suite with the flag unset pays for\n * none of it. The portfolio refuses an unregistered variant at creation. An enabled run refuses an\n * unregistered state name and a second placement of one state.\n *\n * An enabled `place` writes through `captureFrame`, so a placed state carries that helper's staged\n * pane and its byte readback: a path is recorded only after the file on disk has been proved to hold\n * this run's own frame.\n *\n * @example\n * ```ts\n * const portfolio = createPortfolio({\n * \tstates: ['start-empty'],\n * \tvariants: [{ name: 'dark-390', width: 390, height: 844 }],\n * \tvariant: 'dark-390',\n * \tdirectory: '../../tmp/capture/states',\n * })\n * await portfolio.place('start-empty')\n * ```\n */\nexport function createPortfolio(options: PortfolioOptions): PortfolioInterface {\n\tconst selected = options.variants.find((candidate) => candidate.name === options.variant)\n\tif (selected === undefined) {\n\t\tthrow new Error(`Capture variant \"${options.variant}\" is not registered`)\n\t}\n\tconst registry = [...options.states]\n\tconst files = expandCaptures(registry, options.variants)\n\tconst enabled = options.enabled ?? false\n\tconst placed: string[] = []\n\tconst paths: string[] = []\n\treturn {\n\t\tvariant: options.variant,\n\t\tfiles,\n\t\tget placements() {\n\t\t\treturn [...placed]\n\t\t},\n\t\tget paths() {\n\t\t\treturn [...paths]\n\t\t},\n\t\tasync place(state, element) {\n\t\t\tif (!enabled) return undefined\n\t\t\tif (!registry.includes(state)) {\n\t\t\t\tthrow new Error(`Capture state \"${state}\" is not registered`)\n\t\t\t}\n\t\t\tif (placed.includes(state)) {\n\t\t\t\tthrow new Error(`Capture state \"${state}\" is already placed`)\n\t\t\t}\n\t\t\tconst file = `${state}--${options.variant}.png`\n\t\t\tselected.apply?.()\n\t\t\tconst written = await captureFrame({\n\t\t\t\tpath: `${options.directory}/${file}`,\n\t\t\t\twidth: selected.width,\n\t\t\t\theight: selected.height,\n\t\t\t\telement,\n\t\t\t})\n\t\t\tplaced.push(state)\n\t\t\tpaths.push(written)\n\t\t\treturn written\n\t\t},\n\t}\n}\n\n/**\n * Creates one console channel that records every call it receives and hands that call on unchanged.\n *\n * @param name - The channel's name, which prefixes each line it records.\n * @param output - The list each call is recorded into, appended to in place.\n * @param forward - The channel every call is passed on to after it is recorded.\n * @returns A channel carrying the console's own call signature.\n *\n * @remarks\n * One call becomes one line. Every argument of that call is put through `String` and joined with a\n * space, so a call carrying several values reads as the one line the page printed rather than as\n * several entries.\n *\n * Nothing is swallowed. The record happens first and `forward` receives the arguments it would have\n * received, so a page recorded through this prints exactly what it printed without it. The list\n * belongs to the caller, so a channel writes into whatever it was handed and holds no state of its\n * own. {@link createJournal} builds one channel per console method over one list.\n *\n * @example\n * ```ts\n * const output: string[] = []\n * console.log = createChannel('log', output, console.log)\n * ```\n */\nexport function createChannel(\n\tname: string,\n\toutput: string[],\n\tforward: (...data: unknown[]) => void,\n): (...data: unknown[]) => void {\n\treturn (...data) => {\n\t\toutput.push(`${name}: ${data.map((value) => String(value)).join(' ')}`)\n\t\tforward(...data)\n\t}\n}\n\n/**\n * Creates the journal one scenario records its steps and the page's own output into.\n *\n * @returns A journal that records nothing until it is started.\n *\n * @remarks\n * The console is recorded rather than replaced: every intercepted call is forwarded to the channel\n * that was there when the journal started, so a run under a journal prints exactly what it printed\n * without one. `stop` puts those same function references back by identity.\n *\n * Uncaught errors and unhandled rejections are recorded too, through listeners the journal drops\n * when it stops. `steps` and `output` hand out snapshots, so a list read mid-scenario stays what it\n * was. Each journal owns its own recording, so a file that needs one per scenario creates one per\n * scenario.\n *\n * @example\n * ```ts\n * const journal = createJournal()\n * journal.start()\n * journal.record('click', 'Evaluate', 'alerts=0')\n * journal.stop()\n * journal.steps // [{ action: 'click', trigger: 'Evaluate', result: 'alerts=0' }]\n * ```\n */\nexport function createJournal(): JournalInterface {\n\tconst steps: JournalStep[] = []\n\tconst output: string[] = []\n\t// The channels the page was writing to when the journal started. Their presence is what \"started\"\n\t// means, so no second flag can disagree with it. The listeners are dropped through one signal,\n\t// which is why no handler reference has to be kept to take them off again.\n\tlet intercepted: Pick<Console, 'debug' | 'error' | 'info' | 'log' | 'warn'> | undefined\n\tlet listeners: AbortController | undefined\n\treturn {\n\t\tget steps() {\n\t\t\treturn [...steps]\n\t\t},\n\t\tget output() {\n\t\t\treturn [...output]\n\t\t},\n\t\tstart() {\n\t\t\tsteps.length = 0\n\t\t\toutput.length = 0\n\t\t\tif (intercepted !== undefined) return\n\t\t\tconst forwarded = {\n\t\t\t\tdebug: console.debug,\n\t\t\t\terror: console.error,\n\t\t\t\tinfo: console.info,\n\t\t\t\tlog: console.log,\n\t\t\t\twarn: console.warn,\n\t\t\t}\n\t\t\tintercepted = forwarded\n\t\t\tfor (const channel of ['debug', 'error', 'info', 'log', 'warn'] as const) {\n\t\t\t\tconsole[channel] = createChannel(channel, output, forwarded[channel])\n\t\t\t}\n\t\t\tconst dropped = new AbortController()\n\t\t\tlisteners = dropped\n\t\t\twindow.addEventListener(\n\t\t\t\t'error',\n\t\t\t\t(event) => {\n\t\t\t\t\toutput.push(`error: ${event.message}`)\n\t\t\t\t},\n\t\t\t\t{ signal: dropped.signal },\n\t\t\t)\n\t\t\twindow.addEventListener(\n\t\t\t\t'unhandledrejection',\n\t\t\t\t(event) => {\n\t\t\t\t\toutput.push(`rejection: ${String(event.reason)}`)\n\t\t\t\t},\n\t\t\t\t{ signal: dropped.signal },\n\t\t\t)\n\t\t},\n\t\tstop() {\n\t\t\tif (intercepted === undefined) return\n\t\t\tObject.assign(console, intercepted)\n\t\t\tintercepted = undefined\n\t\t\tlisteners?.abort()\n\t\t\tlisteners = undefined\n\t\t},\n\t\trecord(action, trigger, result) {\n\t\t\tif (intercepted === undefined) return\n\t\t\tsteps.push(Object.freeze({ action, trigger, result }))\n\t\t},\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/browser/constants.ts","../../../src/browser/helpers.ts","../../../src/browser/factories.ts"],"sourcesContent":["import type { Color } from './types.js'\n\n/**\n * Names the interactive ARIA roles a bare accessible name is searched across.\n *\n * @remarks\n * A person names a control, not a role, so the one-argument resolver searches every role a control\n * can compute. The two-argument form searches exactly the role it is given, which is how a name\n * shared by a tab and its panel is disambiguated.\n */\nexport const ACCESSIBLE_ROLES: readonly string[] = Object.freeze([\n\t'button',\n\t'checkbox',\n\t'combobox',\n\t'link',\n\t'listbox',\n\t'menuitem',\n\t'option',\n\t'radio',\n\t'searchbox',\n\t'slider',\n\t'spinbutton',\n\t'switch',\n\t'tab',\n\t'tabpanel',\n\t'textbox',\n\t'treeitem',\n])\n\n/**\n * Names the color a browser paints an unstyled document with: opaque white.\n *\n * @remarks\n * This is the floor a backdrop walk ends on wherever the caller wants the browser's own canvas\n * assumed. `readBackdrop` takes its floor as an argument rather than reaching for this one, so a\n * measurement over a surface the canvas never shows through names the color it actually sits on.\n */\nexport const CANVAS_COLOR: Color = Object.freeze([255, 255, 255, 1])\n\n/**\n * Names the attribute marking the runner's tester pane, and the rule that sizes it, while a frame\n * is staged.\n *\n * @remarks\n * `stagePane` writes it onto the pane and onto the stylesheet it appends, and `releasePane` finds\n * both by it. The stylesheet's value is the viewport the tester had before the first staging, in\n * `<width>x<height>` form, which is what `releasePane` hands back. Nothing else reads it, so a\n * document carrying it after a capture returned is a pane that was never released.\n */\nexport const CAPTURE_PANE = 'data-capture-pane'\n\n/**\n * Bounds the restagings one capture takes before it refuses a document whose height never settles.\n *\n * @remarks\n * `captureFrame` stages the pane at the content edge `measureContent` reads, and a rule bound to\n * the viewport height lays that document out taller against the taller pane, so the edge has to be\n * read again after every staging. The re-reading stops when the pane and the edge agree, and a rule\n * that adds height with every pane never reaches that point, so the re-reading is bounded here and\n * the shot is refused rather than taken at a height that is already stale.\n *\n * The bound is the measured need plus one. A document holding half the pane plus a fixed block\n * settles in two restagings, because the second carries the growth the first produced and lands on\n * the fixed point; a document whose growth is capped part way settles in three, because it takes\n * one restaging past the cap before it comes back down to the edge. Nothing measured needs a\n * fourth, so a fourth is the headroom that keeps a settling document off the refusal.\n */\nexport const CAPTURE_STAGINGS = 4\n\n/**\n * Names the roles whose accessible name is the text a reader can see inside them.\n *\n * @remarks\n * `readName` reads an element in this list from its own rendered text, after every `aria-hidden`\n * descendant is dropped, and falls through to `title` for every other role.\n */\nexport const CONTENT_ROLES: readonly string[] = Object.freeze([\n\t'button',\n\t'cell',\n\t'columnheader',\n\t'heading',\n\t'link',\n\t'listitem',\n\t'option',\n\t'row',\n\t'rowheader',\n\t'tab',\n])\n\n/**\n * Names the role each `input` type carries.\n *\n * @remarks\n * Membership is the contract. The map answers for `button`, `checkbox`, `email`, `number`,\n * `password`, `radio`, `range`, `reset`, `search`, `submit`, `tel`, `text`, and `url`. A type the\n * map omits — `color`, `date`, `file`, `hidden`, and the rest — exposes no role of its own, so\n * `readRole` returns `undefined` for it and `describeTree` writes no line for it.\n */\nexport const FIELD_ROLES: Readonly<Record<string, string>> = Object.freeze({\n\tbutton: 'button',\n\tcheckbox: 'checkbox',\n\temail: 'textbox',\n\tnumber: 'spinbutton',\n\tpassword: 'textbox',\n\tradio: 'radio',\n\trange: 'slider',\n\treset: 'button',\n\tsearch: 'searchbox',\n\tsubmit: 'button',\n\ttel: 'textbox',\n\ttext: 'textbox',\n\turl: 'textbox',\n})\n\n/**\n * Names what sequential keyboard navigation can reach, before disabled and unrendered elements go.\n *\n * @remarks\n * `describeFocus` queries this selector and then drops what a browser drops: an element the\n * accessibility tree does not present, a disabled control, and one removed from the sequence by\n * `tabindex=\"-1\"`. `traverseAccessible` counts the same population to bound its walk, so this is\n * the one list either one reads.\n */\nexport const FOCUSABLE_SELECTOR =\n\t'a[href], area[href], button, input, select, summary, textarea, [tabindex]'\n\n/**\n * Names the role a `th` carries for the header axis its `scope` names.\n *\n * @remarks\n * A header cell heads a column or a row, and this map answers for the `col` and `row` scopes that\n * say which. A `th` declaring no scope keeps {@link IMPLICIT_ROLES}' `columnheader` rather than the\n * ARIA computation that infers the axis from the table's shape.\n */\nexport const HEADER_ROLES: Readonly<Record<string, string>> = Object.freeze({\n\tcol: 'columnheader',\n\trow: 'rowheader',\n})\n\n/**\n * Names the role each listed tag carries in the accessibility tree when it declares none of its\n * own.\n *\n * @remarks\n * Membership is the contract. The map answers for the sectioning elements `ARTICLE`, `ASIDE`,\n * `FOOTER`, `HEADER`, `MAIN`, `NAV`, `SEARCH`, and `SECTION`; the headings `H1` through `H6`; the\n * grouping and list elements `FIELDSET`, `FORM`, `HR`, `LI`, `OL`, and `UL`; the table elements\n * `TABLE`, `TBODY`, `THEAD`, `TR`, `TD`, and `TH`; and the widgets `BUTTON`, `DIALOG`, `IMG`,\n * `OPTION`, `OUTPUT`, `PROGRESS`, `SUMMARY`, and `TEXTAREA`.\n *\n * A tag the map omits carries no implicit role, so `readRole` returns `undefined` for it,\n * `describeTree` writes no line for it, and the walk continues straight into its children at the\n * depth the omitted element sat at. `A`, `INPUT`, and `SELECT` are absent deliberately: each takes\n * its role from an attribute rather than from its tag, and `readRole` answers for them from their\n * own anatomy.\n *\n * `SECTION` maps to `region`, which `readRole` withholds from an unnamed one, because an unnamed\n * section is not a landmark. `TH` maps to `columnheader`, which {@link HEADER_ROLES} replaces when\n * the cell declares a `scope`.\n */\nexport const IMPLICIT_ROLES: Readonly<Record<string, string>> = Object.freeze({\n\tARTICLE: 'article',\n\tASIDE: 'complementary',\n\tBUTTON: 'button',\n\tDIALOG: 'dialog',\n\tFIELDSET: 'group',\n\tFOOTER: 'contentinfo',\n\tFORM: 'form',\n\tH1: 'heading',\n\tH2: 'heading',\n\tH3: 'heading',\n\tH4: 'heading',\n\tH5: 'heading',\n\tH6: 'heading',\n\tHEADER: 'banner',\n\tHR: 'separator',\n\tIMG: 'img',\n\tLI: 'listitem',\n\tMAIN: 'main',\n\tNAV: 'navigation',\n\tOL: 'list',\n\tOPTION: 'option',\n\tOUTPUT: 'status',\n\tPROGRESS: 'progressbar',\n\tSEARCH: 'search',\n\tSECTION: 'region',\n\tSUMMARY: 'button',\n\tTABLE: 'table',\n\tTBODY: 'rowgroup',\n\tTD: 'cell',\n\tTEXTAREA: 'textbox',\n\tTH: 'columnheader',\n\tTHEAD: 'rowgroup',\n\tTR: 'row',\n\tUL: 'list',\n})\n","import type { WaitOptions } from '@src/core'\nimport type {\n\tCaptureVariant,\n\tCensusFixture,\n\tCensusReading,\n\tColor,\n\tContrastFixture,\n\tElementOptions,\n\tEscapeFixture,\n\tFrameOptions,\n\tFrameReading,\n\tStateOptions,\n} from './types.js'\nimport { isError, isString } from '@orkestrel/contract'\nimport { checkBounds, waitForAbort, waitForCondition } from '@src/core'\nimport { commands, page, userEvent } from 'vitest/browser'\nimport {\n\tACCESSIBLE_ROLES,\n\tCANVAS_COLOR,\n\tCAPTURE_PANE,\n\tCAPTURE_STAGINGS,\n\tCONTENT_ROLES,\n\tFIELD_ROLES,\n\tFOCUSABLE_SELECTOR,\n\tHEADER_ROLES,\n\tIMPLICIT_ROLES,\n} from './constants.js'\n\n/**\n * Determines whether a rectangle lies wholly outside the browser viewport.\n *\n * @param rectangle - The measured client rectangle to inspect.\n * @returns True if no part of the rectangle intersects the viewport; false otherwise.\n *\n * @example\n * ```ts\n * isOutsideViewport(element.getBoundingClientRect())\n * ```\n */\nexport function isOutsideViewport(rectangle: DOMRectReadOnly): boolean {\n\treturn (\n\t\trectangle.bottom <= 0 ||\n\t\trectangle.right <= 0 ||\n\t\trectangle.top >= window.innerHeight ||\n\t\trectangle.left >= window.innerWidth\n\t)\n}\n\n/**\n * Determines whether a person can click one element where it sits.\n *\n * @param element - The element to judge.\n * @returns True if the element is connected, visible, laid out with a non-zero box, in the\n * sequential focus order, neither disabled nor marked `aria-disabled=\"true\"`, and outside every\n * `[inert]` subtree; false otherwise.\n *\n * @remarks\n * This is the one reachability filter the layer applies. `resolveRendered`, `clickAccessibleWithin`,\n * and `clickDisclosure` each narrow their own candidates and then keep the ones this accepts, so a\n * journey meets one rule rather than three near-copies of it.\n *\n * It measures geometry, which is what separates it from {@link isRendered}. A control clipped to a\n * zero-size rectangle is announced and is not clickable, so `isRendered` accepts it and this\n * refuses it. Nothing here asks about the viewport: `resolveAccessible` scrolls a wholly\n * off-viewport target into view and measures that separately with {@link isOutsideViewport}.\n *\n * Inside a shadow tree it answers for the element's own facts, in an open root and a closed one\n * alike: the box, the focus order, `:disabled`, and `aria-disabled` are all the element's. The\n * `[inert]` ancestor is the one read that stops at the boundary, because `closest` never leaves the\n * element's own tree, so a host marked `[inert]` is invisible here. What the flat tree decides still\n * reaches the subject — a host the document does not lay out takes the element off the page and this\n * refuses it. Ask the host separately where an ancestor attribute is the subject.\n *\n * @example\n * ```ts\n * isReachable(requireValue(container.querySelector('button')))\n * ```\n */\nexport function isReachable(element: Element): boolean {\n\tif (!(element instanceof HTMLElement) && !(element instanceof SVGElement)) return false\n\tconst rectangle = element.getBoundingClientRect()\n\treturn (\n\t\telement.isConnected &&\n\t\telement.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true }) &&\n\t\trectangle.width > 0 &&\n\t\trectangle.height > 0 &&\n\t\telement.tabIndex >= 0 &&\n\t\t!element.matches(':disabled, [aria-disabled=\"true\"]') &&\n\t\telement.closest('[inert]') === null\n\t)\n}\n\n/**\n * Determines whether the accessibility tree presents one element at all.\n *\n * @param element - The element to judge.\n * @returns True if the element is presented to assistive technology and to sight; false otherwise.\n *\n * @remarks\n * A control clipped to a zero-size rectangle is still announced, which is the whole point of that\n * idiom, so nothing here reads geometry: only the removals a browser honours — `aria-hidden`\n * anywhere above it, the `hidden` attribute, a hidden input, and a `display` or `visibility` that\n * takes it off the page. {@link isReachable} is the clickable half of the pair and does read\n * geometry.\n *\n * The last two are asked about the element's ancestors as well as itself, which reading a computed\n * `display` cannot do: the computed value of a child of a `display: none` container is the child's\n * own, so a control inside a closed drawer reports itself as laid out. `checkVisibility` answers\n * for the box tree, and `visibility` inherits, so between them an ancestor cannot hide a control\n * from a reader and leave it standing in a description.\n *\n * Inside a shadow tree it answers for the element's own facts, in an open root and a closed one\n * alike. The `aria-hidden` ancestor is the one read that stops at the boundary, because `closest`\n * never leaves the element's own tree, so a host marked `aria-hidden=\"true\"` is invisible here and\n * this reports `true` for a subject a reader is never told about. `checkVisibility` and the computed\n * `visibility` read the flat tree, so a host the document does not lay out still takes the element\n * off the page. Ask the host separately where an ancestor attribute is the subject.\n *\n * @example\n * ```ts\n * isRendered(requireValue(container.querySelector('[aria-hidden=\"true\"] button'))) // false\n * ```\n */\nexport function isRendered(element: Element): boolean {\n\tif (element.closest('[aria-hidden=\"true\"]') !== null) return false\n\tif (element instanceof HTMLElement && element.hidden) return false\n\tif (element instanceof HTMLInputElement && element.type === 'hidden') return false\n\tif (!element.checkVisibility()) return false\n\treturn getComputedStyle(element).visibility !== 'hidden'\n}\n\n/**\n * Reads the topmost element at one element's bounding-box centre.\n *\n * @param element - The element whose bounding-box centre is the point to read.\n * @returns The element the owner document's hit test names at that point, or `undefined` where the\n * point lies outside that viewport or reaches nothing.\n *\n * @remarks\n * This reads one point and nothing else: the centre of the element's own bounding box, hit-tested\n * against `element.ownerDocument`. That point is where a thumb aimed at the middle of what it sees\n * lands, and the arrangements that take it away are the ones {@link isReachable} cannot see: a\n * sticky masthead covering a control that was scrolled to, and a wrapped inline target, whose\n * per-line rectangles leave a gap the single bounding box spans and whose centre falls in that gap\n * on the ancestor. `isReachable` reads `checkVisibility`, geometry, and the focus order, and each\n * arrangement passes all three while a click at that point misses.\n *\n * It does not predict where the installed driver clicks. `playwright-core@1.63.0` clips each\n * content quad to the viewport, drops every quad left without area, and takes the midpoint of the\n * first quad that survives — `_clickablePoint` at `playwright-core/lib/coreBundle.js:20084`,\n * reached from the locator `click` the Vitest provider delegates to. For the wrapped target the\n * first surviving quad is the first line box, so the driver aims inside the link while this centre\n * sits in the gap. Read a result as the answer for the point this names, and for no other.\n *\n * It returns the node rather than a verdict, because the node is the diagnosis: a caller narrows\n * the result, rules on `link.contains(hit)`, and names what came back — the list item rather than\n * the link, the masthead rather than the control.\n *\n * Pass {@link isRendered} and {@link isReachable} before reading, because neither answer means\n * anything on an element that failed them. An element the document does not render measures a zero\n * rectangle at the origin, and a zero-area element measures a point on its own edge; each is\n * hit-tested like any other point and names whatever paints there — the surrounding container for\n * a control clipped inside one, and the document body for a rectangle collapsed at the origin.\n * `contains` is then false, and a caller that skipped the gates reports a cover that is not there.\n *\n * A returned node carries silences of its own. A cover painted with `pointer-events: none` is\n * absent from the hit test, so the reading names the element underneath it and the caller reads\n * reachable for a cover a person can see. An element inside a shadow tree retargets, in an open\n * root and a closed one alike: the document-level hit test names the host, the inner element does\n * not contain the host, and the caller reads the element's own host as a cover. Ask\n * `element.getRootNode()` for its own `elementFromPoint` where the subject sits in a shadow tree.\n *\n * `undefined` carries one silence: a centre outside the viewport reads the same as a centre that\n * reaches nothing. {@link isOutsideViewport} does not separate them, because it asks whether the\n * whole rectangle misses the viewport while this asks where one point lands — a rectangle at\n * `left: -80` with `width: 100` has its right edge at 20, so that predicate reports false while the\n * centre at -30 reads `undefined` here. The two also measure different windows: the predicate reads\n * the global `window`, and this reads `element.ownerDocument`. Compare the centre against that\n * document's own viewport where the distinction is the subject.\n *\n * @example\n * ```ts\n * const link = requireValue(container.querySelector('a'))\n * const hit = readHit(link)\n * // False for a wrapped link whose centre sits between its line boxes.\n * hit !== undefined && link.contains(hit)\n * ```\n */\nexport function readHit(element: Element): Element | undefined {\n\tconst rectangle = element.getBoundingClientRect()\n\tconst hit = element.ownerDocument.elementFromPoint(\n\t\trectangle.left + rectangle.width / 2,\n\t\trectangle.top + rectangle.height / 2,\n\t)\n\treturn hit ?? undefined\n}\n\n/**\n * Computes the pattern that matches one accessible name a decorative glyph may sit beside.\n *\n * @param name - The exact accessible name a person reads, whitespace runs collapsed on the way in.\n * @returns A pattern anchored at both ends, admitting a run of characters that are neither letters\n * nor digits before the name and after it.\n *\n * @remarks\n * A role query that includes hidden elements computes a name from the `aria-hidden` subtrees too,\n * so an icon font's `::before` glyph joins the name a person never hears and an exact string never\n * matches again. This pattern is what {@link resolveRendered} asks the hidden pass with, and its\n * tolerance is bounded to what a glyph can be: a leading or trailing run carrying no letter and no\n * digit. A hidden icon whose own content is a word still defeats it, and a name differing from the\n * requested one by punctuation alone still satisfies it.\n *\n * That bound is affordable because the hidden pass chooses between two refusal voices and returns\n * nothing. The visible pass decides which element a resolver returns, and it matches the exact\n * string against the name the accessibility tree actually publishes.\n *\n * Pass this to a role query with `exact: true`. That flag is the engine's case-sensitivity switch\n * as well as its exactness one, so a query carrying `exact: false` uppercases the computed name\n * before testing a pattern against it and a lowercase letter in the requested name never matches.\n *\n * @example\n * ```ts\n * computeNamePattern('Add building').test('\\uF4FE Add building') // true\n * ```\n */\nexport function computeNamePattern(name: string): RegExp {\n\tconst wanted = name\n\t\t.replaceAll(/\\s+/g, ' ')\n\t\t.trim()\n\t\t.replaceAll(/[$()*+.?[\\\\\\]^{|}]/g, '\\\\$&')\n\treturn new RegExp(`^[^\\\\p{L}\\\\p{N}]*${wanted}[^\\\\p{L}\\\\p{N}]*$`, 'u')\n}\n\n/**\n * Resolves one rendered, focus-reachable interactive element without requiring it to intersect the\n * viewport yet.\n *\n * @param first - The accessible name, or the exact ARIA role when `second` is present.\n * @param second - The accessible name when `first` supplies the role.\n * @returns The one rendered element carrying that name and optional role.\n * @throws When no matching element exists, every match is hidden or unreachable, or several\n * rendered matches make the name ambiguous.\n *\n * @remarks\n * This is the resolver the acting verbs use, so a click does not fail on a target the act itself\n * scrolls into view. Use {@link resolveAccessible} wherever the target must already be on screen.\n *\n * It runs two passes, and only the first one can return an element. The visible pass asks the role\n * engine for the exact name over the elements the accessibility tree presents, which is the name a\n * screen reader announces: an `aria-hidden` icon beside the text contributes nothing to it. The\n * hidden pass runs only when the visible pass found nothing at all, and it decides which refusal\n * the caller hears — a name the page carries nowhere, or a target that is there and out of reach.\n * That pass must include hidden elements to see a folded control, which is what puts a glyph back\n * into the computed name, so it asks with {@link computeNamePattern} rather than the exact string.\n *\n * @example\n * ```ts\n * resolveRendered('tab', 'Drafts')\n * ```\n */\nexport function resolveRendered(first: string, second?: string): HTMLElement {\n\tconst name = second ?? first\n\tconst roles = second === undefined ? ACCESSIBLE_ROLES : [first]\n\tconst matches: HTMLElement[] = []\n\tfor (const role of roles) {\n\t\tfor (const element of page.getByRole(role, { name, exact: true }).elements()) {\n\t\t\tif (element instanceof HTMLElement && !matches.includes(element)) matches.push(element)\n\t\t}\n\t}\n\tif (matches.length === 0) {\n\t\tconst pattern = computeNamePattern(name)\n\t\tconst hidden = roles.some(\n\t\t\t(role) =>\n\t\t\t\tpage.getByRole(role, { name: pattern, exact: true, includeHidden: true }).elements()\n\t\t\t\t\t.length > 0,\n\t\t)\n\t\tif (!hidden) throw new Error(`No interactive element has the accessible name \"${name}\"`)\n\t\tthrow new Error(`Interactive target \"${name}\" is not visible and focus-reachable`)\n\t}\n\tconst reachable = matches.filter((element) => isReachable(element))\n\tif (reachable.length === 0) {\n\t\tthrow new Error(`Interactive target \"${name}\" is not visible and focus-reachable`)\n\t}\n\tif (reachable.length > 1) {\n\t\tthrow new Error(`Interactive target \"${name}\" is ambiguous across ${reachable.length} elements`)\n\t}\n\tconst [target] = reachable\n\tif (target === undefined) throw new Error(`Interactive target \"${name}\" could not be resolved`)\n\treturn target\n}\n\n/**\n * Resolves one visible, focus-reachable interactive element by its exact accessible name. A\n * wholly-off-viewport target is scrolled into view before reachability is measured.\n *\n * @param name - The accessible name rendered for the target.\n * @returns The one reachable element carrying that name.\n * @throws When no matching element exists; every match is disconnected, hidden, zero-sized, still\n * outside the viewport after being scrolled into view, removed from sequential focus, disabled, or\n * inside an inert subtree; or several reachable matches make the name ambiguous.\n *\n * @example\n * ```ts\n * resolveAccessible('Save changes')\n * ```\n */\nexport function resolveAccessible(name: string): HTMLElement\n/**\n * Resolves one visible, focus-reachable interactive element by its exact ARIA role and accessible\n * name, disambiguating a bare name that answers for more than one rendered element. A\n * wholly-off-viewport target is scrolled into view before reachability is measured.\n *\n * @param role - The element's exact ARIA role.\n * @param name - The accessible name rendered for the target.\n * @returns The one reachable element carrying that role and name.\n * @throws When no matching element exists; every match is disconnected, hidden, zero-sized, still\n * outside the viewport after being scrolled into view, removed from sequential focus, disabled, or\n * inside an inert subtree; or several reachable matches make the role/name pair ambiguous.\n *\n * @example\n * ```ts\n * resolveAccessible('tab', 'Drafts')\n * ```\n */\nexport function resolveAccessible(role: string, name: string): HTMLElement\nexport function resolveAccessible(first: string, second?: string): HTMLElement {\n\tconst target = resolveRendered(first, second)\n\tlet rectangle = target.getBoundingClientRect()\n\tif (isOutsideViewport(rectangle)) {\n\t\ttarget.scrollIntoView({ block: 'nearest', behavior: 'instant' })\n\t\trectangle = target.getBoundingClientRect()\n\t}\n\tif (isOutsideViewport(rectangle)) {\n\t\tthrow new Error(`Interactive target \"${second ?? first}\" is unreachable after scrolling`)\n\t}\n\treturn target\n}\n\n/**\n * Clicks one visible, focus-reachable control by its accessible name through the browser provider.\n *\n * @param name - The target's exact accessible name.\n * @returns A promise resolving after trusted activation completes.\n *\n * @example\n * ```ts\n * await clickAccessible('Apply')\n * ```\n */\nexport async function clickAccessible(name: string): Promise<void>\n/**\n * Clicks one visible, focus-reachable control by its exact ARIA role and accessible name,\n * disambiguating a bare name that answers for more than one rendered element.\n *\n * @param role - The control's exact ARIA role.\n * @param name - The target's exact accessible name.\n * @returns A promise resolving after trusted activation completes.\n *\n * @example\n * ```ts\n * await clickAccessible('tab', 'Drafts')\n * ```\n */\nexport async function clickAccessible(role: string, name: string): Promise<void>\nexport async function clickAccessible(first: string, second?: string): Promise<void> {\n\tconst target = resolveRendered(first, second)\n\tawait userEvent.click(target)\n}\n\n/**\n * Clicks one human-reachable control by role and accessible-name text inside a named region.\n *\n * @param region - The containing region's exact accessible name.\n * @param role - The control's exact ARIA role.\n * @param name - The rendered accessible-name text that identifies the control in that region.\n * @returns A promise resolving after trusted activation completes.\n * @throws When the named control is absent, unreachable, or ambiguous inside the region.\n *\n * @remarks\n * Use this form when repeated short verbs such as `Add`, or a line whose status completes its\n * accessible name, need the same region context a person uses to disambiguate them.\n *\n * @example\n * ```ts\n * await clickAccessibleWithin('Ledger', 'button', 'Monthly income')\n * ```\n */\nexport async function clickAccessibleWithin(\n\tregion: string,\n\trole: string,\n\tname: string,\n): Promise<void> {\n\tconst matches = page\n\t\t.getByRole('region', { name: region, exact: true })\n\t\t.getByRole(role, { name, exact: false, includeHidden: true })\n\t\t.elements()\n\tconst reachable = matches.filter(\n\t\t(element) => element instanceof HTMLElement && isReachable(element),\n\t)\n\tif (reachable.length === 0) {\n\t\tthrow new Error(`Interactive target \"${name}\" is not reachable inside \"${region}\"`)\n\t}\n\tif (reachable.length > 1) {\n\t\tthrow new Error(\n\t\t\t`Interactive target \"${name}\" is ambiguous across ${reachable.length} elements inside \"${region}\"`,\n\t\t)\n\t}\n\tconst [target] = reachable\n\tif (!(target instanceof HTMLElement)) {\n\t\tthrow new Error(`Interactive target \"${name}\" could not be resolved inside \"${region}\"`)\n\t}\n\tawait userEvent.click(target)\n}\n\n/**\n * Opens or closes one native details disclosure by its rendered summary.\n *\n * @param name - The summary text a person reads.\n * @returns A promise resolving after trusted activation completes.\n * @throws When no native summary with that rendered name passes {@link isReachable}, or several do.\n *\n * @remarks\n * Chromium exposes `<summary>` as a native disclosure rather than through an ARIA role accepted by\n * `getByRole`, so this resolver names the platform element and its rendered text directly.\n *\n * It applies the same {@link isReachable} filter the other acting verbs apply, so a summary marked\n * `aria-disabled=\"true\"` is refused here exactly as a button marked that way is refused there.\n *\n * @example\n * ```ts\n * await clickDisclosure('Advanced')\n * ```\n */\nexport async function clickDisclosure(name: string): Promise<void> {\n\tconst matches = [...document.querySelectorAll('summary')].filter(\n\t\t(element) => element.innerText.replaceAll(/\\s+/g, ' ').trim() === name,\n\t)\n\tconst reachable = matches.filter((element) => isReachable(element))\n\tif (reachable.length === 0) {\n\t\tthrow new Error(`Native disclosure \"${name}\" is not visible and focus-reachable`)\n\t}\n\tif (reachable.length > 1) {\n\t\tthrow new Error(`Native disclosure \"${name}\" is ambiguous across ${reachable.length} elements`)\n\t}\n\tconst [target] = reachable\n\tif (target === undefined) throw new Error(`Native disclosure \"${name}\" could not be resolved`)\n\tawait userEvent.click(target)\n}\n\n/**\n * Replaces a named field's value through focus, select-all, deletion, and real keystrokes.\n *\n * @param name - The field's exact accessible name.\n * @param text - The text to type.\n * @returns A promise resolving after every keystroke completes.\n *\n * @remarks\n * The text is escaped against the provider's own key syntax, so a literal `{` or `[` is typed\n * rather than read as the start of a key sequence.\n *\n * @example\n * ```ts\n * await typeAccessible('Runs', '3')\n * ```\n */\nexport async function typeAccessible(name: string, text: string): Promise<void> {\n\tawait userEvent.click(resolveRendered(name))\n\tawait userEvent.keyboard('{Control>}a{/Control}{Backspace}')\n\tif (text === '') return\n\tawait userEvent.keyboard(text.replaceAll('{', '{{').replaceAll('[', '[['))\n}\n\n/**\n * Replaces a named field's value in one operation, for text too long to type key by key.\n *\n * @param name - The field's exact accessible name.\n * @param text - The text to place in the field.\n * @returns A promise resolving after the browser commits the value.\n *\n * @remarks\n * The provider drives the real element, so the field publishes the same input event a person's\n * typing publishes. Use {@link typeAccessible} wherever the keystrokes themselves are the subject.\n *\n * @example\n * ```ts\n * await fillAccessible('Payload', '{\"status\":\"ready\"}')\n * ```\n */\nexport async function fillAccessible(name: string, text: string): Promise<void> {\n\tawait userEvent.fill(resolveRendered(name), text)\n}\n\n/**\n * Sends a key sequence to whatever holds focus, and refuses to send it to nothing.\n *\n * @param keys - The sequence in the provider's own key syntax, such as `{Enter}` or `{Escape}`.\n * @returns A promise resolving after every keystroke completes.\n * @throws When the document body holds focus, or nothing does.\n *\n * @remarks\n * The refusal is the whole of what this adds over `userEvent.keyboard`. A key sent while focus sits\n * on the body reaches no control, and every assertion after it reads the surface the key never\n * touched — which is the false green a guarded keyboard step exists to catch. Bring focus about\n * first through {@link traverseAccessible}, {@link clickAccessible}, or {@link typeAccessible}, and\n * send the sequence here.\n *\n * Escaping is the caller's, because the sequence is the subject: `{` opens a key name and `[` opens\n * a code name. Reach for {@link typeAccessible} where the text is the subject and the syntax is in\n * the way.\n *\n * @example\n * ```ts\n * await traverseAccessible('Evaluate')\n * await pressKeys('{Enter}')\n * ```\n */\nexport async function pressKeys(keys: string): Promise<void> {\n\tconst focused = document.activeElement\n\tif (focused === null || focused === document.body) {\n\t\tthrow new Error(`Key sequence \"${keys}\" was sent with nothing focused`)\n\t}\n\tawait userEvent.keyboard(keys)\n}\n\n/**\n * Reaches a named control only through natural forward Tab traversal from the current focus.\n *\n * @param name - The target's exact accessible name.\n * @returns The target after the browser moves focus to it.\n * @throws When one complete traversal cannot reach the target.\n *\n * @example\n * ```ts\n * await traverseAccessible('Evaluate')\n * ```\n */\nexport async function traverseAccessible(name: string): Promise<HTMLElement> {\n\tresolveRendered(name)\n\t// Two facts shape the loop. A Tab pressed before the page has real input focus moves nothing,\n\t// so a step counts only when focus actually lands somewhere; the traversal is over when focus\n\t// revisits an element, because that is one full cycle of the tab order. And the target is\n\t// re-resolved on every step, because a framework may replace the node between resolution and\n\t// focus arrival: the person's target is the role and name, never one node.\n\t// The bound is counted off `FOCUSABLE_SELECTOR`, the one population this environment reads\n\t// sequential navigation from, so a tag the selector gains is a tag this traversal budgets for.\n\tconst cap = document.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR).length * 3 + 10\n\tconst visited = new Set<Element>()\n\tconst trail: string[] = []\n\tfor (let attempt = 0; attempt < cap; attempt += 1) {\n\t\tawait userEvent.tab()\n\t\tconst focused = document.activeElement\n\t\tif (!(focused instanceof HTMLElement) || focused === document.body) continue\n\t\tlet current: HTMLElement | undefined\n\t\ttry {\n\t\t\tcurrent = resolveRendered(name)\n\t\t} catch {\n\t\t\tcontinue\n\t\t}\n\t\tif (focused === current) return current\n\t\tif (visited.has(focused)) break\n\t\tvisited.add(focused)\n\t\ttrail.push(`${focused.tagName}:${focused.innerText.slice(0, 20)}`)\n\t}\n\tthrow new Error(\n\t\t`Interactive target \"${name}\" is not reachable through forward Tab traversal: ${trail.join(' > ')}`,\n\t)\n}\n\n/**\n * Reads the normalized visible text of one named region, dialog, table, tab panel, or alert.\n *\n * @param name - The region's exact accessible name.\n * @returns The text a screen reader can perceive in the visible region, including descendant\n * visually-hidden content.\n * @throws When the named region is absent, hidden, or ambiguous.\n *\n * @remarks\n * One pass answers this, because absence and concealment share the refusal. The pass asks the role\n * engine over the elements the accessibility tree presents, so the name matched is the one a screen\n * reader announces and an `aria-hidden` glyph in a heading a region points at contributes nothing\n * to it. A region the tree does not present is refused as not visible, which is what a reader\n * perceiving nothing there means.\n *\n * @example\n * ```ts\n * readPerception('Run')\n * ```\n */\nexport function readPerception(name: string): string {\n\tconst matches: HTMLElement[] = []\n\tfor (const role of ['alert', 'alertdialog', 'dialog', 'region', 'status', 'table', 'tabpanel']) {\n\t\tfor (const element of page.getByRole(role, { name, exact: true }).elements()) {\n\t\t\tif (element instanceof HTMLElement && !matches.includes(element)) matches.push(element)\n\t\t}\n\t}\n\tconst visible = matches.filter((element) => {\n\t\tconst rectangle = element.getBoundingClientRect()\n\t\treturn (\n\t\t\telement.isConnected &&\n\t\t\telement.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true }) &&\n\t\t\trectangle.width > 0 &&\n\t\t\trectangle.height > 0\n\t\t)\n\t})\n\tif (visible.length === 0) throw new Error(`Named region \"${name}\" is not visible`)\n\tif (visible.length > 1) {\n\t\tthrow new Error(`Named region \"${name}\" is ambiguous across ${visible.length} elements`)\n\t}\n\tconst [region] = visible\n\tif (region === undefined) throw new Error(`Named region \"${name}\" could not be resolved`)\n\treturn region.innerText.replaceAll(/\\s+/g, ' ').trim()\n}\n\n/**\n * Reads the normalized visible text of the whole page.\n *\n * @returns Every rendered word in the document body, its whitespace runs collapsed and trimmed.\n *\n * @remarks\n * This is the reader for a sentence that spans two regions and for a vocabulary sweep over the\n * words an interface uses. Reach for {@link readPerception} wherever one named region is the\n * subject, because that one throws when the region is missing and this one returns whatever is\n * there.\n *\n * @example\n * ```ts\n * readPage().includes('No cases yet')\n * ```\n */\nexport function readPage(): string {\n\treturn document.body.innerText.replaceAll(/\\s+/g, ' ').trim()\n}\n\n/**\n * Reads the rendered text of the element that holds focus.\n *\n * @returns The focused HTML element's trimmed rendered text, including an empty string, or\n * `undefined` when focus rests on a non-HTML element. When nothing holds focus, the browser\n * reports the document body as active, so the whole page's rendered text returns.\n *\n * @example\n * ```ts\n * await traverseAccessible('Evaluate')\n * readFocus() // 'Evaluate'\n * ```\n */\nexport function readFocus(): string | undefined {\n\tconst focused = document.activeElement\n\treturn focused instanceof HTMLElement ? focused.innerText.trim() : undefined\n}\n\n/**\n * Reads the value a resolved control renders.\n *\n * @param role - The control's exact ARIA role.\n * @param name - The control's exact accessible name.\n * @returns The control's current value.\n * @throws When the target does not resolve, or resolves to an element that carries no value.\n *\n * @remarks\n * A control's value is a rendered fact a person can read, not internal state, so it is read from\n * the resolved element rather than from the component that produced it.\n *\n * @example\n * ```ts\n * readValue('spinbutton', 'Runs') // '3'\n * ```\n */\nexport function readValue(role: string, name: string): string {\n\tconst control = resolveAccessible(role, name)\n\tif (\n\t\t!(control instanceof HTMLInputElement) &&\n\t\t!(control instanceof HTMLTextAreaElement) &&\n\t\t!(control instanceof HTMLSelectElement)\n\t) {\n\t\tthrow new Error(`Interactive target \"${name}\" does not carry a value`)\n\t}\n\treturn control.value\n}\n\n/**\n * Reads the refusal one named target answers with, or nothing when it resolves.\n *\n * @param name - The target's exact accessible name.\n * @returns The refusal sentence {@link resolveRendered} raised, or `undefined` when it resolved.\n * @throws Whatever the resolver threw that is not an `Error`.\n *\n * @example\n * ```ts\n * readRefusal('Save changes') // undefined — the control resolves\n * readRefusal('Menu') // 'Interactive target \"Menu\" is not visible and focus-reachable'\n * ```\n */\nexport function readRefusal(name: string): string | undefined\n/**\n * Reads the refusal one named target answers with under an exact role, or nothing when it resolves.\n *\n * @param role - The target's exact ARIA role.\n * @param name - The target's exact accessible name.\n * @returns The refusal sentence {@link resolveRendered} raised, or `undefined` when it resolved.\n * @throws Whatever the resolver threw that is not an `Error`.\n *\n * @remarks\n * Absent, present-but-gated, and ambiguous are different findings about an interface, and the\n * layer keeps their sentences distinct, so a journey asserting on the one it means needs the\n * sentence rather than a boolean. This fixes the resolver, translates the `unknown` a `catch` binds\n * into `string | undefined`, and rethrows anything that is not an `Error` — a value no resolver\n * raises, and one a caller reading a message would otherwise lose. `undefined` is rethrown with the\n * rest: a resolver that returned and a hostile getter that threw `undefined` are different findings,\n * which is why the `catch` is this function's own rather than a captured thrown value.\n *\n * It resolves rather than acts, so a target it reports `undefined` for is one an acting verb\n * reaches. Assert on the exact sentence: a comparison against a substring passes for a refusal\n * about a different condition.\n *\n * @example\n * ```ts\n * readRefusal('tab', 'Drafts') // undefined — the tab resolves under its role\n * ```\n */\nexport function readRefusal(role: string, name: string): string | undefined\nexport function readRefusal(first: string, second?: string): string | undefined {\n\ttry {\n\t\tresolveRendered(first, second)\n\t} catch (thrown) {\n\t\t// The `catch` is local rather than routed through `captureError`, which returns the thrown\n\t\t// value and therefore reads a hostile `throw undefined` as a resolver that returned.\n\t\tif (isError(thrown)) return thrown.message\n\t\tthrow thrown\n\t}\n\treturn undefined\n}\n\n/**\n * Reads one element's rendered text the way a name computation reads it.\n *\n * @param element - The element whose announced words are wanted.\n * @returns The text with every `aria-hidden` descendant dropped and whitespace runs collapsed.\n *\n * @remarks\n * A glyph marked `aria-hidden` contributes nothing to a name, so a control captioned by an icon\n * plus a word reads as the word alone — which is what a reader hears, and what a verdict citing a\n * description has to compare against the copy a template writes. Reach for `readRows` wherever the\n * subject is what the page paints rather than what it announces: that one keeps the glyph.\n *\n * @example\n * ```ts\n * readText(requireValue(container.querySelector('button'))) // 'Save'\n * ```\n */\nexport function readText(element: Element): string {\n\tconst parts: string[] = []\n\tconst walker = element.ownerDocument.createTreeWalker(element, NodeFilter.SHOW_TEXT)\n\tfor (let node = walker.nextNode(); node !== null; node = walker.nextNode()) {\n\t\tconst owner = node.parentElement\n\t\tif (owner === null || owner.closest('[aria-hidden=\"true\"]') !== null) continue\n\t\tparts.push(node.textContent ?? '')\n\t}\n\treturn parts.join(' ').replaceAll(/\\s+/g, ' ').trim()\n}\n\n/**\n * Reads the role one element carries in the accessibility tree.\n *\n * @param element - The element to classify.\n * @returns The declared role, the implicit one, or `undefined` when the element carries none.\n *\n * @remarks\n * A declared `role` wins outright, and its first token is the answer when several are listed.\n * Otherwise the element's own anatomy decides: an anchor is a link only while it holds an `href`,\n * an `input` takes the role {@link FIELD_ROLES} gives its type, a `select` is a combobox until it\n * offers several rows at once, a `section` is a region only once something names it, and a `th`\n * heads whichever axis its `scope` names. Every other tag answers from {@link IMPLICIT_ROLES},\n * whose membership is the contract for what this can answer at all.\n *\n * @example\n * ```ts\n * readRole(requireValue(container.querySelector('a[href]'))) // 'link'\n * ```\n */\nexport function readRole(element: Element): string | undefined {\n\tconst declared = element.getAttribute('role')?.trim()\n\tif (declared !== undefined && declared.length > 0) return declared.split(/\\s+/)[0]\n\tif (element instanceof HTMLAnchorElement) return element.href.length > 0 ? 'link' : undefined\n\tif (element instanceof HTMLInputElement) return FIELD_ROLES[element.type]\n\tif (element instanceof HTMLSelectElement) {\n\t\treturn element.multiple || element.size > 1 ? 'listbox' : 'combobox'\n\t}\n\tconst implicit = IMPLICIT_ROLES[element.tagName]\n\tconst scope = element.tagName === 'TH' ? element.getAttribute('scope')?.trim() : undefined\n\tif (scope !== undefined) return HEADER_ROLES[scope] ?? implicit\n\tif (\n\t\timplicit === 'region' &&\n\t\t!element.hasAttribute('aria-label') &&\n\t\t!element.hasAttribute('aria-labelledby')\n\t) {\n\t\treturn undefined\n\t}\n\treturn implicit\n}\n\n/**\n * Reads the accessible name one element is announced under.\n *\n * @param element - The element to name.\n * @returns The computed name, or an empty string when the element carries none.\n *\n * @remarks\n * The order is the one a browser follows: `aria-labelledby`, then `aria-label`, then a form\n * control's own labels, then an image's `alt`, then the text inside a role {@link CONTENT_ROLES}\n * names, then `title`. A submit, reset, or button input is named by its value, because it renders\n * no text to read. An `aria-labelledby` naming several ids joins their texts in the order the\n * attribute lists them, and an id nothing answers for is skipped rather than fatal.\n *\n * Each step answers only when it has something to say, so a step that carries nothing hands the\n * element to the next one. An image whose `alt` is absent or blank is the case that shows it:\n * `<img title=\"Chart\">` is named `Chart` rather than the empty string its own `alt` step would\n * have returned, and an image carrying both keeps answering `alt`.\n *\n * @example\n * ```ts\n * readName(requireValue(container.querySelector('button'))) // 'Save changes'\n * ```\n */\nexport function readName(element: Element): string {\n\tconst referenced = element.getAttribute('aria-labelledby')\n\tif (referenced !== null) {\n\t\tconst named = referenced\n\t\t\t.split(/\\s+/)\n\t\t\t.map((id) => element.ownerDocument.getElementById(id))\n\t\t\t.filter((node) => node !== null)\n\t\t\t.map((node) => readText(node))\n\t\t\t.filter((text) => text.length > 0)\n\t\tif (named.length > 0) return named.join(' ')\n\t}\n\tconst labelled = element.getAttribute('aria-label')?.trim()\n\tif (labelled !== undefined && labelled.length > 0) return labelled\n\tif (\n\t\telement instanceof HTMLInputElement ||\n\t\telement instanceof HTMLSelectElement ||\n\t\telement instanceof HTMLTextAreaElement\n\t) {\n\t\tconst labels = [...(element.labels ?? [])]\n\t\t\t.map((label) => readText(label))\n\t\t\t.filter((text) => text.length > 0)\n\t\tif (labels.length > 0) return labels.join(' ')\n\t\tif (element instanceof HTMLInputElement && element.value.length > 0) {\n\t\t\tif (FIELD_ROLES[element.type] === 'button') return element.value\n\t\t}\n\t}\n\tif (element instanceof HTMLImageElement) {\n\t\tconst alternative = element.alt.trim()\n\t\tif (alternative.length > 0) return alternative\n\t}\n\tconst role = readRole(element)\n\tif (role !== undefined && CONTENT_ROLES.includes(role)) {\n\t\tconst text = readText(element)\n\t\tif (text.length > 0) return text\n\t}\n\treturn element.getAttribute('title')?.trim() ?? ''\n}\n\n/**\n * Reads the states one element is announced in.\n *\n * @param element - The element to read.\n * @returns Every state the element declares, in one fixed order.\n *\n * @remarks\n * A state a reader is told about is one this records: what is unavailable, disclosed, pressed,\n * current, refused, chosen, announcing itself, demanded, uneditable, described, or busy. The order\n * is fixed, so two descriptions of the same surface are comparable line for line.\n *\n * A native disclosure states its expansion on the parent `details` element's own `open` rather than\n * on an ARIA attribute, so a summary that declares no `aria-expanded` is read from the platform's\n * one copy of that fact.\n *\n * @example\n * ```ts\n * readStates(requireValue(container.querySelector('summary'))) // ['collapsed']\n * ```\n */\nexport function readStates(element: Element): readonly string[] {\n\tconst states: string[] = []\n\tif (element.matches(':disabled') || element.getAttribute('aria-disabled') === 'true') {\n\t\tstates.push('disabled')\n\t}\n\tconst expanded = element.getAttribute('aria-expanded')\n\tif (expanded === 'true') states.push('expanded')\n\tif (expanded === 'false') states.push('collapsed')\n\tif (\n\t\texpanded === null &&\n\t\telement.tagName === 'SUMMARY' &&\n\t\telement.parentElement instanceof HTMLDetailsElement\n\t) {\n\t\tstates.push(element.parentElement.open ? 'expanded' : 'collapsed')\n\t}\n\tconst pressed = element.getAttribute('aria-pressed')\n\tif (pressed !== null) states.push(`pressed=${pressed}`)\n\tconst current = element.getAttribute('aria-current')\n\tif (current !== null && current !== 'false') states.push('current')\n\tif (element.getAttribute('aria-invalid') === 'true') states.push('invalid')\n\tconst checked =\n\t\telement instanceof HTMLInputElement\n\t\t\t? element.checked\n\t\t\t: element.getAttribute('aria-checked') === 'true'\n\tif (checked) states.push('checked')\n\tconst selected = element.getAttribute('aria-selected')\n\tif (selected !== null) states.push(`selected=${selected}`)\n\tconst live = element.getAttribute('aria-live')\n\tif (live !== null) states.push(`live=${live}`)\n\tif (element.matches(':required')) states.push('required')\n\tif (element instanceof HTMLInputElement && element.readOnly) states.push('readonly')\n\tif (element.hasAttribute('aria-describedby')) states.push('described')\n\tif (element.getAttribute('aria-busy') === 'true') states.push('busy')\n\treturn Object.freeze(states)\n}\n\n/**\n * Describes the accessible tree one rendered element presents.\n *\n * @param element - The host to walk, which is described first when it carries a role of its own.\n * @returns One indented line per element carrying a role, naming its role, its name, and its\n * states, in document order; an empty string when nothing in the subtree carries one.\n *\n * @remarks\n * The walk is over the real rendered DOM, so what it reports is the tree the shipped markup and the\n * shipped cascade produce together — a landmark lost to a hidden ancestor is missing here exactly as\n * it is missing for a reader. An element {@link isRendered} refuses is dropped with its whole\n * subtree.\n *\n * Depth follows the roles rather than the elements, so the indentation reads as the structure a\n * screen reader announces instead of as the markup's nesting. An element {@link readRole} answers\n * `undefined` for writes no line and adds no depth, so its children sit where it sat. That is how\n * a wrapper `div` disappears, and it is also how an element {@link IMPLICIT_ROLES} does not answer\n * for disappears — visibly, because its roled children stay at the depth it occupied.\n *\n * @example\n * ```ts\n * describeTree(container)\n * // main \"Board\"\n * // heading \"Totals\"\n * ```\n */\nexport function describeTree(element: Element): string {\n\tconst lines: string[] = []\n\tconst pending: Array<{ readonly node: Element; readonly depth: number }> = [\n\t\t{ node: element, depth: 0 },\n\t]\n\twhile (pending.length > 0) {\n\t\tconst entry = pending.pop()\n\t\tif (entry === undefined) break\n\t\tif (!isRendered(entry.node)) continue\n\t\tconst role = readRole(entry.node)\n\t\tlet depth = entry.depth\n\t\tif (role !== undefined) {\n\t\t\tconst name = readName(entry.node)\n\t\t\tconst states = readStates(entry.node)\n\t\t\tlines.push(\n\t\t\t\t`${' '.repeat(depth)}${role}${name.length > 0 ? ` \"${name}\"` : ''}${\n\t\t\t\t\tstates.length > 0 ? ` [${states.join(', ')}]` : ''\n\t\t\t\t}`,\n\t\t\t)\n\t\t\tdepth += 1\n\t\t}\n\t\tfor (let index = entry.node.children.length - 1; index >= 0; index -= 1) {\n\t\t\tconst child = entry.node.children[index]\n\t\t\tif (child !== undefined) pending.push({ node: child, depth })\n\t\t}\n\t}\n\treturn lines.join('\\n')\n}\n\n/**\n * Describes the order sequential keyboard navigation visits one element's controls in.\n *\n * @param element - The host to walk; its own controls are described, and it is not itself one.\n * @returns One numbered line per reachable control, naming its role and its name.\n *\n * @remarks\n * A positive `tabindex` is honoured, because a browser honours it: those controls come first in\n * ascending order and everything else follows in document order. A control removed from the\n * sequence by `tabindex=\"-1\"`, by being disabled, or by not being rendered at all is absent here,\n * which is the fact a focus-order verdict is about. A control {@link readRole} answers `undefined`\n * for is named by its lowercased tag, so it is still counted rather than silently dropped.\n *\n * @example\n * ```ts\n * describeFocus(container)\n * // 1. button \"Save\"\n * // 2. link \"Cancel\"\n * ```\n */\nexport function describeFocus(element: Element): string {\n\treturn [...element.querySelectorAll(FOCUSABLE_SELECTOR)]\n\t\t.filter(\n\t\t\t(node) =>\n\t\t\t\tisRendered(node) && !node.matches(':disabled') && node.getAttribute('tabindex') !== '-1',\n\t\t)\n\t\t.sort((first, second) => {\n\t\t\tconst left = Number.parseInt(first.getAttribute('tabindex') ?? '0', 10)\n\t\t\tconst right = Number.parseInt(second.getAttribute('tabindex') ?? '0', 10)\n\t\t\tif (left > 0 && right > 0) return left - right\n\t\t\tif (left > 0) return -1\n\t\t\tif (right > 0) return 1\n\t\t\treturn 0\n\t\t})\n\t\t.map((node, index) => {\n\t\t\tconst role = readRole(node) ?? node.tagName.toLowerCase()\n\t\t\tconst name = readName(node)\n\t\t\treturn `${String(index + 1)}. ${role}${name.length > 0 ? ` \"${name}\"` : ''}`\n\t\t})\n\t\t.join('\\n')\n}\n\n/**\n * Waits for one animation frame to settle pending browser paint work.\n *\n * @returns A promise resolving after one `requestAnimationFrame`.\n *\n * @example\n * ```ts\n * await waitForFrame()\n * ```\n */\nexport function waitForFrame(): Promise<void> {\n\treturn new Promise<void>((resolve) => requestAnimationFrame(() => resolve()))\n}\n\n/**\n * Waits until one named control announces a state, or stops announcing it.\n *\n * @param name - The control's exact accessible name.\n * @param state - The state, spelled as {@link readStates} reports it.\n * @param options - The time bounds, the abort signal, and the direction.\n * @returns The states the control announced when the wait resolved.\n * @throws The resolver's own refusal, the abort reason, or an `Error` when a bound is invalid or\n * the state is not reached within the budget.\n *\n * @example\n * ```ts\n * await clickAccessible('Pin note')\n * await waitForState('Pin note', 'pressed=true')\n * ```\n */\nexport function waitForState(\n\tname: string,\n\tstate: string,\n\toptions?: StateOptions,\n): Promise<readonly string[]>\n/**\n * Waits until one control of an exact role announces a state, or stops announcing it.\n *\n * @param role - The control's exact ARIA role.\n * @param name - The control's exact accessible name.\n * @param state - The state, spelled as {@link readStates} reports it.\n * @param options - The time bounds, the abort signal, and the direction.\n * @returns The states the control announced when the wait resolved.\n * @throws The resolver's own refusal, the abort reason, or an `Error` when a bound is invalid or\n * the state is not reached within the budget.\n *\n * @remarks\n * The control is resolved afresh on every reading, because a framework replaces the node between\n * one render and the next: the subject is the role and the name, never one element. That also means\n * the resolver's own voices reach the caller unchanged — a control that leaves the document\n * mid-wait refuses as absent rather than timing out as unannounced, which is the more useful\n * finding.\n *\n * {@link waitForCondition} owns the poll, so the bounds and the abort reason are that helper's.\n * Default budget: `1000` milliseconds. Default interval: `10` milliseconds. The exhaustion message\n * names the control and the state, and carries the last states read, so a wait that ran out says\n * what the control was announcing instead.\n *\n * This is the published replacement for a settle keyed to a framework's own class names. Where a\n * surface announces nothing, the finding is the surface's: give the control its `aria-expanded`,\n * `aria-pressed`, or `aria-busy` rather than reading the classes a stylesheet happens to use.\n *\n * @example\n * ```ts\n * await clickDisclosure('Advanced')\n * await waitForState('button', 'Advanced', 'collapsed', { absent: true })\n * ```\n */\nexport function waitForState(\n\trole: string,\n\tname: string,\n\tstate: string,\n\toptions?: StateOptions,\n): Promise<readonly string[]>\nexport async function waitForState(\n\tfirst: string,\n\tsecond: string,\n\tthird?: string | StateOptions,\n\tfourth?: StateOptions,\n): Promise<readonly string[]> {\n\tconst keyed = isString(third)\n\tconst role = keyed ? first : undefined\n\tconst name = keyed ? second : first\n\tconst state = keyed ? third : second\n\tconst options = keyed ? fourth : third\n\tconst absent = options?.absent ?? false\n\tconst description = `\"${name}\" to ${absent ? 'stop announcing' : 'announce'} \"${state}\"`\n\tlet observed: readonly string[] = []\n\tlet readings = 0\n\tlet refused: { readonly thrown: unknown } | undefined\n\ttry {\n\t\tawait waitForCondition(\n\t\t\tdescription,\n\t\t\t() => {\n\t\t\t\treadings += 1\n\t\t\t\ttry {\n\t\t\t\t\tobserved = readStates(\n\t\t\t\t\t\trole === undefined ? resolveRendered(name) : resolveRendered(role, name),\n\t\t\t\t\t)\n\t\t\t\t} catch (thrown) {\n\t\t\t\t\t// The box records what the reading threw, so the `catch` beneath recognizes the\n\t\t\t\t\t// resolver's own finding by identity instead of by how another module worded it.\n\t\t\t\t\trefused = { thrown }\n\t\t\t\t\tthrow thrown\n\t\t\t\t}\n\t\t\t\treturn observed.includes(state) !== absent\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t} catch (cause) {\n\t\t// Only the poll's own exhaustion has a last observation worth adding, and it is what remains\n\t\t// after the three values that are not it: the reading's own throw, recorded as it was raised;\n\t\t// the abort reason, which is the caller's value on the signal; and a refused bound, which is\n\t\t// raised before any reading. Each of those leaves by identity.\n\t\tif (refused !== undefined && cause === refused.thrown) throw cause\n\t\tif (cause === options?.signal?.reason) throw cause\n\t\tif (readings === 0) throw cause\n\t\tif (!isError(cause)) throw cause\n\t\tthrow new Error(`${cause.message} (last states: ${JSON.stringify(observed)})`, { cause })\n\t}\n\treturn observed\n}\n\n/**\n * Waits until every finite animation on one element and its subtree has stopped moving.\n *\n * @param element - The element whose own animations and descendants' animations to wait on.\n * @param options - The time bounds and the abort signal.\n * @returns A promise resolving once no finite animation is still running.\n * @throws An `Error` when the element is not in a document, when a bound is invalid, or when an\n * animation is still running at the budget; or the abort reason.\n *\n * @remarks\n * A reading taken while paint is moving reports an interpolated frame — a `background-color` at a\n * fraction of its alpha, a `color` part way between two values — that no state of the interface\n * ever paints. This waits for the paint a person sees, whichever state it settles in.\n *\n * It parks on each animation's own `finished` promise rather than re-reading on a timer, and reads\n * the list again after each completion or cancellation, so an animation a finishing one starts is\n * waited on too.\n *\n * Some animations are left out, and each exclusion is a decision rather than an oversight. An animation\n * whose effect declares infinite iterations never finishes, so a spinner that runs forever is a\n * finding about the reading rather than a wait to lengthen. A finished animation filling its target\n * stays in the list a browser reports and is already at rest. A paused animation is at rest too,\n * and nothing here resumes it.\n *\n * The bounds are the wait family's, validated the same way. Default budget: `1000` milliseconds.\n * The interval is validated for consistency with the family and is not used, because this parks on\n * the animations. A detached element is refused rather than reported settled, because an element in\n * no document runs no animation and would answer `true` to every wait.\n *\n * @example\n * ```ts\n * await clickAccessible('Dark')\n * await waitForAnimations(document.body)\n * ```\n */\nexport async function waitForAnimations(element: Element, options?: WaitOptions): Promise<void> {\n\tconst budget = options?.budget ?? 1000\n\tconst interval = options?.interval ?? 10\n\tcheckBounds('Animation', budget, interval)\n\tif (!element.isConnected) throw new Error('Animation subject is not connected')\n\tconst signal = options?.signal\n\tconst label = readName(element)\n\tconst subject = `${readRole(element) ?? element.localName}${label.length > 0 ? ` \"${label}\"` : ''}`\n\tconst start = performance.now()\n\tlet expired = false\n\tlet aborted: Promise<void> | undefined\n\tlet timer: ReturnType<typeof setTimeout> | undefined\n\tconst expiry = new Promise<void>((resolve) => {\n\t\ttimer = setTimeout(() => {\n\t\t\texpired = true\n\t\t\tresolve()\n\t\t}, budget)\n\t})\n\ttry {\n\t\twhile (true) {\n\t\t\tsignal?.throwIfAborted()\n\t\t\tconst running = element.getAnimations({ subtree: true }).filter((animation) => {\n\t\t\t\tconst iterations = animation.effect?.getTiming().iterations ?? 1\n\t\t\t\treturn animation.playState === 'running' && Number.isFinite(iterations)\n\t\t\t})\n\t\t\tif (running.length === 0) return\n\t\t\tconst elapsed = performance.now() - start\n\t\t\tif (expired || elapsed >= budget) {\n\t\t\t\tconst names = running.map((animation) => {\n\t\t\t\t\tif (animation instanceof CSSAnimation) return animation.animationName\n\t\t\t\t\tif (animation instanceof CSSTransition) return animation.transitionProperty\n\t\t\t\t\treturn animation.id\n\t\t\t\t})\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Animation \"${subject}\" did not settle within ${budget}ms (waited ${elapsed}ms): ${names.join(', ')}`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tconst pending: Array<Promise<unknown>> = running.map((animation) =>\n\t\t\t\tanimation.finished.catch(() => undefined),\n\t\t\t)\n\t\t\tpending.push(expiry)\n\t\t\tif (signal !== undefined) {\n\t\t\t\t// Installed on the first park rather than up front, so a wait that finds nothing running\n\t\t\t\t// leaves no listener on a signal the caller still owns.\n\t\t\t\taborted ??= waitForAbort(signal)\n\t\t\t\tpending.push(aborted)\n\t\t\t}\n\t\t\tawait Promise.race(pending)\n\t\t}\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer)\n\t}\n}\n\n/**\n * Builds one unmounted element of a known tag, wearing the classes, text, and attributes asked for.\n *\n * @param tag - The HTML tag name, which fixes the returned element's exact type.\n * @param options - The class list, the text, and the attributes to apply.\n * @returns The built element, not yet in any document.\n *\n * @remarks\n * The element is unmounted on purpose, so a fixture is assembled before the page ever sees it and a\n * test decides where it goes. Nothing here resolves against the cascade: a built element computes no\n * style and lays out no box until {@link mount} puts it in the document.\n *\n * The text is set as text rather than parsed as markup, so a `<` in it stays a `<`. Use\n * {@link render} where the fixture is markup.\n *\n * @example\n * ```ts\n * const button = build('button', { classes: 'primary', text: 'Save', attributes: { type: 'button' } })\n * ```\n */\nexport function build<K extends keyof HTMLElementTagNameMap>(\n\ttag: K,\n\toptions?: ElementOptions,\n): HTMLElementTagNameMap[K] {\n\tconst element = document.createElement(tag)\n\tif (options?.classes !== undefined) element.className = options.classes\n\tif (options?.text !== undefined) element.textContent = options.text\n\tfor (const [name, value] of Object.entries(options?.attributes ?? {})) {\n\t\telement.setAttribute(name, value)\n\t}\n\treturn element\n}\n\n/**\n * Puts one element into the document and hands it straight back.\n *\n * @param element - The element to attach.\n * @returns The same element, now appended to `document.body`.\n *\n * @remarks\n * What this buys is the composition, not the attachment: the `append` method returns `void`, and\n * this hands the element back, so it fits where an expression is expected. The {@link render} helper\n * returns its fixture through it, and the {@link parseCSSColor} helper probes through\n * `mount(build('span'))`. A bare `append` call breaks each of those call sites.\n *\n * Being connected is what the attachment then buys: `getComputedStyle` resolves against the shipped\n * cascade, custom properties inherit from `:root`, and the element lays out a real box. A detached\n * element answers each of those questions with the initial value instead, which reads as a styling\n * defect rather than as a detached node.\n *\n * Taking it back out belongs to the consumer's teardown, because this records nothing: a browser\n * test file shares one page, so a fixture left behind is the next test's resolver ambiguity. Build a\n * recorded container in a setup module and remove it from an `afterEach` hook.\n *\n * @example\n * ```ts\n * const panel = mount(build('div', { classes: 'surface' }))\n * panel.remove()\n * ```\n */\nexport function mount<T extends Element>(element: T): T {\n\tdocument.body.append(element)\n\treturn element\n}\n\n/**\n * Renders one fixture into the document from trusted markup.\n *\n * @param markup - The fixture markup to parse.\n * @returns The attached container holding the fixture's own nodes.\n *\n * @remarks\n * The class list is required in the tag form, which is what keeps the two forms apart: a\n * one-argument call is always markup.\n *\n * This form parses `markup` into a fresh container and returns that container, so the fixture's own\n * nodes are its children. It attaches to `document.body` and records nothing, so removal is the\n * caller's, exactly as it is for {@link mount}.\n *\n * @example\n * ```ts\n * const container = render('<button type=\"button\">Save</button>')\n * container.remove()\n * ```\n */\nexport function render(markup: string): HTMLDivElement\n/**\n * Renders one fixture into the document from a tag name and its class list.\n *\n * @param tag - The HTML tag name to create.\n * @param classes - The class list to place on the created element.\n * @returns The attached element itself, typed as exactly that tag.\n *\n * @remarks\n * The class list is required in the tag form, which is what keeps the two forms apart: a\n * one-argument call is always markup. A tag with no classes is `mount(build(tag))`.\n *\n * This form returns the element itself rather than a container. It attaches to `document.body` and\n * records nothing, so removal is the caller's, exactly as it is for {@link mount}.\n *\n * @example\n * ```ts\n * const panel = render('section', 'surface muted')\n * panel.remove()\n * ```\n */\nexport function render<K extends keyof HTMLElementTagNameMap>(\n\ttag: K,\n\tclasses: string,\n): HTMLElementTagNameMap[K]\nexport function render(first: string, second?: string): HTMLElement {\n\tif (second === undefined) {\n\t\tconst container = build('div')\n\t\tcontainer.innerHTML = first\n\t\treturn mount(container)\n\t}\n\t// `build` is generic over the known tag names and this signature carries a plain string, so the\n\t// tag branch cannot route through it without an assertion. It applies the class list the one way\n\t// `build` applies it, so the two forms stay one behaviour.\n\tconst element = document.createElement(first)\n\telement.className = second\n\treturn mount(element)\n}\n\n/**\n * Sets one field's value and announces it the way typing into the field does.\n *\n * @param element - The input or textarea to write into.\n * @param text - The value to set.\n *\n * @remarks\n * This is the synthetic pair of {@link typeAccessible}, for a component that listens for `input` and\n * a test that has the element already. It sets the value in one write and dispatches one bubbling\n * `input` event, so a delegated listener on an ancestor hears it. It sends no keystrokes, so a\n * component reading `key`, composition, or selection sees nothing. The dispatched event is a plain\n * `Event`, never an `InputEvent`, so a component reading `inputType` or testing\n * `instanceof InputEvent` sees neither. Drive a component that reads any of those through\n * `typeAccessible` instead.\n *\n * No `change` event follows. Use {@link commitInput} where the component waits for the field to be\n * committed.\n *\n * @example\n * ```ts\n * typeInput(requireValue(container.querySelector('input')), 'Ada')\n * ```\n */\nexport function typeInput(element: HTMLInputElement | HTMLTextAreaElement, text: string): void {\n\telement.value = text\n\telement.dispatchEvent(new Event('input', { bubbles: true }))\n}\n\n/**\n * Sets one field's value and commits it, the way typing and then leaving the field does.\n *\n * @param element - The input or textarea to write into.\n * @param text - The value to set.\n *\n * @remarks\n * The order is the browser's: {@link typeInput} first, so `input` is dispatched with the value\n * already set, and one bubbling `change` after it. A component that reads the value from either\n * event therefore reads `text` from both.\n *\n * @example\n * ```ts\n * commitInput(requireValue(container.querySelector('input')), 'Ada')\n * ```\n */\nexport function commitInput(element: HTMLInputElement | HTMLTextAreaElement, text: string): void {\n\ttypeInput(element, text)\n\telement.dispatchEvent(new Event('change', { bubbles: true }))\n}\n\n/**\n * Clears both browser storage surfaces.\n *\n * @remarks\n * A browser test file shares one page, so a key written by one test is read by the next one that\n * looks for it. Call this from an `afterEach` hook, which runs after a failed test as well as a\n * passing one, rather than at the end of each test that happens to write a key.\n *\n * @example\n * ```ts\n * afterEach(clearStorage)\n * ```\n */\nexport function clearStorage(): void {\n\tlocalStorage.clear()\n\tsessionStorage.clear()\n}\n\n/**\n * Deletes one IndexedDB database and reports what the request actually did.\n *\n * @param name - The database name to delete.\n * @returns A promise resolving after the deletion completes.\n * @throws Thrown when the request errors, and when an open connection blocks it.\n *\n * @remarks\n * Deleting a database that was never created succeeds, so this is safe to call from a teardown hook\n * that runs whether or not the test reached the code that opens one.\n *\n * A block is a rejection rather than a wait. `blocked` fires when another connection is still open,\n * and a suite that swallowed it would leave the next test reading the previous test's records\n * through a database that reports itself deleted. The connection holding it open is the caller's to\n * close, so the block is handed back rather than absorbed.\n *\n * @example\n * ```ts\n * afterEach(() => removeDatabase('ledger'))\n * ```\n */\nexport function removeDatabase(name: string): Promise<void> {\n\treturn new Promise<void>((resolve, reject) => {\n\t\tconst request = globalThis.indexedDB.deleteDatabase(name)\n\t\trequest.addEventListener('success', () => resolve())\n\t\trequest.addEventListener('error', () =>\n\t\t\treject(new Error(`IndexedDB database \"${name}\" could not be deleted`)),\n\t\t)\n\t\trequest.addEventListener('blocked', () =>\n\t\t\treject(new Error(`IndexedDB database \"${name}\" is blocked by an open connection`)),\n\t\t)\n\t})\n}\n\n/**\n * Parses one computed CSS color value into straight sRGB channels.\n *\n * @param value - A computed `rgb()`, `rgba()`, or `color(srgb …)` value.\n * @returns The color's channels, or `undefined` when the value names no color this reader speaks.\n *\n * @remarks\n * A computed color resolves to `rgb()` or `rgba()` for every legacy source, and a `color-mix()`\n * declaration resolves to `color(srgb r g b [/ a])` with channels on the 0–1 scale. Both forms are\n * read here and nothing else is: a keyword, a hex triple, an empty string from a detached element,\n * and a color space the cascade never hands back all return `undefined`. Absence is the answer\n * rather than a transparent color, so a caller decides what an unreadable value means instead of\n * measuring a black it never saw.\n *\n * @example\n * ```ts\n * parseColor('rgba(255, 255, 255, 0.5)') // [255, 255, 255, 0.5]\n * parseColor('rebeccapurple') // undefined\n * ```\n */\nexport function parseColor(value: string): Color | undefined {\n\tconst modern =\n\t\t/^color\\(srgb\\s+(?<red>[\\d.]+)\\s+(?<green>[\\d.]+)\\s+(?<blue>[\\d.]+)(?:\\s*\\/\\s*(?<alpha>[\\d.]+))?\\)$/u.exec(\n\t\t\tvalue,\n\t\t)\n\tconst legacy = /^rgba?\\((?<channels>[^)]*)\\)$/u.exec(value)\n\tconst parts =\n\t\tmodern?.groups === undefined\n\t\t\t? (legacy?.groups?.channels ?? '')\n\t\t\t\t\t.split(/[\\s,/]+/u)\n\t\t\t\t\t.filter((part) => part.length > 0)\n\t\t\t\t\t.map((part) => Number.parseFloat(part))\n\t\t\t: [\n\t\t\t\t\tNumber.parseFloat(modern.groups.red ?? '') * 255,\n\t\t\t\t\tNumber.parseFloat(modern.groups.green ?? '') * 255,\n\t\t\t\t\tNumber.parseFloat(modern.groups.blue ?? '') * 255,\n\t\t\t\t\tmodern.groups.alpha === undefined ? 1 : Number.parseFloat(modern.groups.alpha),\n\t\t\t\t]\n\tconst [red, green, blue, alpha = 1] = parts\n\tif (red === undefined || green === undefined || blue === undefined) return undefined\n\tif (![red, green, blue, alpha].every((channel) => Number.isFinite(channel))) return undefined\n\treturn Object.freeze([red, green, blue, alpha])\n}\n\n/**\n * Resolves any CSS color expression to straight sRGB channels, by asking the browser.\n *\n * @param value - Any value the `color` property accepts: a keyword, a hex triple, a `var()`\n * reference, a `color-mix()`, or an already-computed `rgb()`.\n * @returns The resolved color's channels, or `undefined` when the CSSOM refuses the value or the\n * computed result names no color {@link parseColor} speaks.\n *\n * @remarks\n * This is the live half of the pair {@link parseColor} opens. `parseColor` reads text and speaks\n * only the computed syntaxes a cascade hands back; this stages a probe element, hands it to the real\n * cascade, and reads back what the engine computed — which is the only way a keyword, a hex triple,\n * or a `var()` reference becomes channels at all. The read itself goes through `parseColor`, so both\n * halves agree on what a computed value means.\n *\n * The probe is mounted, because an unmounted element inherits nothing and a `var()` reference to a\n * token declared on `:root` would resolve to the initial value instead. It is removed in a `finally`,\n * so a value that throws on the way through leaves no node behind.\n *\n * Refusal is the CSSOM's: an expression it will not parse leaves the probe's inline `color` empty\n * and this returns `undefined`. A `var()` naming an undeclared custom property is not refused,\n * because the cascade accepts it and computes the inherited color, so a test that means to catch a\n * missing token asserts on {@link readToken} rather than on this.\n *\n * @example\n * ```ts\n * parseCSSColor('rebeccapurple') // [102, 51, 153, 1]\n * parseCSSColor('not-a-color') // undefined\n * ```\n */\nexport function parseCSSColor(value: string): Color | undefined {\n\tconst probe = mount(build('span'))\n\ttry {\n\t\tprobe.style.color = value\n\t\tif (probe.style.color === '') return undefined\n\t\treturn parseColor(readStyle(probe, 'color'))\n\t} finally {\n\t\tprobe.remove()\n\t}\n}\n\n/**\n * Determines whether two colors render the same, within the rounding a browser does.\n *\n * @param first - A CSS color expression or an already-parsed color.\n * @param second - A CSS color expression or an already-parsed color.\n * @returns True if every channel and the alpha agree within the tolerance; false otherwise,\n * including when either side names no readable color.\n *\n * @remarks\n * Each string side is resolved through {@link parseCSSColor}, so a keyword, a token reference, and the\n * `rgb()` the engine computes for either of them compare equal without a test converting anything\n * first. A side that resolves to nothing makes the answer `false` rather than a throw, because this\n * is a predicate.\n *\n * The tolerance is half a channel step on the 0–255 scale, and the alpha is scaled onto that same\n * range before it is compared, so one number covers both. Half a step is what a composite of\n * translucent layers and a `color-mix()` round trip actually drift by; anything a reader could see\n * is further than that and reports unequal.\n *\n * @example\n * ```ts\n * matchesColor('rebeccapurple', 'rgb(102, 51, 153)') // true\n * matchesColor('red', [0, 0, 255, 1]) // false\n * ```\n */\nexport function matchesColor(first: string | Color, second: string | Color): boolean {\n\tconst left = typeof first === 'string' ? parseCSSColor(first) : first\n\tconst right = typeof second === 'string' ? parseCSSColor(second) : second\n\tif (left === undefined || right === undefined) return false\n\tconst tolerance = 0.5\n\tconst [leftRed, leftGreen, leftBlue, leftAlpha] = left\n\tconst [rightRed, rightGreen, rightBlue, rightAlpha] = right\n\treturn (\n\t\tMath.abs(leftRed - rightRed) <= tolerance &&\n\t\tMath.abs(leftGreen - rightGreen) <= tolerance &&\n\t\tMath.abs(leftBlue - rightBlue) <= tolerance &&\n\t\tMath.abs(leftAlpha - rightAlpha) * 255 <= tolerance\n\t)\n}\n\n/**\n * Composites one color over another.\n *\n * @param front - The color painted on top.\n * @param back - The color already on the surface.\n * @returns The opaque result a reader sees, its alpha always `1`.\n *\n * @example\n * ```ts\n * blendColor([255, 255, 255, 0.5], [0, 0, 0, 1]) // [127.5, 127.5, 127.5, 1]\n * ```\n */\nexport function blendColor(front: Color, back: Color): Color {\n\tconst [red, green, blue, alpha] = front\n\tconst [under, over, beneath] = back\n\treturn Object.freeze([\n\t\tred * alpha + under * (1 - alpha),\n\t\tgreen * alpha + over * (1 - alpha),\n\t\tblue * alpha + beneath * (1 - alpha),\n\t\t1,\n\t])\n}\n\n/**\n * Measures one opaque color's WCAG relative luminance.\n *\n * @param color - The color to weigh. Its alpha is ignored, so composite before calling.\n * @returns The relative luminance, from `0` for black to `1` for white.\n *\n * @example\n * ```ts\n * measureLuminance([255, 255, 255, 1]) // 1\n * ```\n */\nexport function measureLuminance(color: Color): number {\n\tconst [red, green, blue] = color\n\tconst [first = 0, second = 0, third = 0] = [red, green, blue].map((channel) => {\n\t\tconst part = channel / 255\n\t\treturn part <= 0.040_45 ? part / 12.92 : ((part + 0.055) / 1.055) ** 2.4\n\t})\n\treturn 0.2126 * first + 0.7152 * second + 0.0722 * third\n}\n\n/**\n * Measures the WCAG 2.x contrast ratio between two opaque colors.\n *\n * @param front - The foreground color, already composited.\n * @param back - The opaque backdrop.\n * @returns The ratio, from `1` for two identical colors to `21` for black against white.\n *\n * @remarks\n * The ratio is symmetric: the brighter of the two luminances is always the numerator, so swapping\n * the arguments returns the same number.\n *\n * @example\n * ```ts\n * measureContrast([0, 0, 0, 1], [255, 255, 255, 1]) // 21\n * ```\n */\nexport function measureContrast(front: Color, back: Color): number {\n\tconst bright = Math.max(measureLuminance(front), measureLuminance(back))\n\tconst dark = Math.min(measureLuminance(front), measureLuminance(back))\n\treturn (bright + 0.05) / (dark + 0.05)\n}\n\n/**\n * Collects the painted layers standing between one element and the surface it sits on.\n *\n * @param element - The element to walk up from.\n * @returns Every layer the walk paints, the element's own first and the deepest last.\n *\n * @remarks\n * A surface token paints one ancestor while every element between it and the text paints nothing,\n * so a backdrop is found by walking up rather than by reading the element's own `background-color`,\n * which is almost always transparent. A fully transparent layer paints nothing and is left out, and\n * the walk stops at the first fully opaque layer, because nothing above that layer is visible.\n *\n * The stack is what tells a resolved backdrop from an assumed one: the walk reached an opaque\n * surface exactly when its last layer's alpha is `1`. {@link readContrast} refuses on that reading,\n * which no comparison of composited colors can replace — 64 half-transparent layers composite to\n * the same channels over opposite floors, because the floor's remaining share falls below the last\n * bit a channel carries.\n *\n * @example\n * ```ts\n * readLayers(requireValue(container.querySelector('p')))\n * ```\n */\nexport function readLayers(element: Element): readonly Color[] {\n\tconst layers: Color[] = []\n\tfor (let node: Element | null = element; node !== null; node = node.parentElement) {\n\t\tconst layer = parseColor(getComputedStyle(node).backgroundColor)\n\t\tif (layer === undefined || layer[3] === 0) continue\n\t\tlayers.push(layer)\n\t\tif (layer[3] >= 1) break\n\t}\n\treturn Object.freeze(layers)\n}\n\n/**\n * Resolves the opaque color standing behind one element.\n *\n * @param element - The element whose backdrop to resolve.\n * @param floor - The opaque color the walk ends on when nothing above it paints.\n * @returns The composited color a reader sees behind the element.\n *\n * @remarks\n * The layers {@link readLayers} collects composite top-over-bottom onto the floor, so a 3% surface\n * tint reads as a tint over what shows through it rather than as a full-strength paint.\n *\n * The floor is required, because this leaf never guesses what a document sits on. Pass\n * {@link CANVAS_COLOR} for the page a browser paints behind an unstyled document, or the color of\n * the surface a fragment is really rendered into. When no layer paints, the floor is returned by\n * identity.\n *\n * The composite alone never says whether the floor is part of the answer. A caller that must know\n * reads the stack instead.\n *\n * @example\n * ```ts\n * readBackdrop(requireValue(container.querySelector('p')), CANVAS_COLOR)\n * ```\n */\nexport function readBackdrop(element: Element, floor: Color): Color {\n\treturn readLayers(element).reduceRight((back, front) => blendColor(front, back), floor)\n}\n\n/**\n * Measures the WCAG 2.x contrast ratio between an element's computed text and background colors.\n *\n * @param element - The element whose rendered text contrast to measure.\n * @param floor - The opaque color the backdrop walk ends on. Omit it to refuse a stack the floor\n * would show through instead of assuming one.\n * @returns The relative-luminance contrast ratio.\n * @throws Thrown when the element exposes no computed foreground color, and — with `floor` omitted\n * — when the walk from the element upwards reaches no opaque layer.\n *\n * @remarks\n * A transparent or translucent background resolves through the element's ancestors: every painted\n * layer from the element up to the first opaque one composites top-over-bottom onto that opaque\n * base, so a 3% surface tint reads as a tint over what shows through it rather than as a\n * full-strength paint. A translucent foreground then resolves against that effective background\n * before luminance is measured.\n *\n * With `floor` omitted, the walk from the target upwards must reach a fully opaque layer: the\n * measurement throws rather than assuming a white canvas wherever that canvas would still be part\n * of the answer. The refusal reads the alpha of the deepest layer {@link readLayers} collected, so\n * a chain that declares no background color at all, a chain painting only translucent layers, and a\n * chain deep enough for its composite to round to the canvas's own channels are refused alike,\n * because the number any of them produces is as much a report of the assumption as of the page.\n * Supply a floor wherever the caller knows what the stack sits on — a fragment mounted into a\n * painted host, or a document whose canvas is {@link CANVAS_COLOR} — and the composite is taken\n * over it rather than refused.\n *\n * The element itself must expose a computed foreground color either way. A detached element exposes\n * none, and the measurement throws rather than guessing one.\n *\n * @example\n * ```ts\n * const container = render('<p style=\"background: #000; color: #fff\">Ready</p>')\n * readContrast(requireValue(container.firstElementChild)) // 21\n * readContrast(requireValue(container.firstElementChild), CANVAS_COLOR) // 21, and never refuses\n * ```\n */\nexport function readContrast(element: Element, floor?: Color): number {\n\tconst foreground = parseColor(getComputedStyle(element).color)\n\tif (foreground === undefined) throw new Error('Computed foreground color is unavailable')\n\tconst layers = readLayers(element)\n\tconst deepest = layers.at(-1)\n\t// The walk reached a real surface exactly when its deepest layer is fully opaque. An empty stack\n\t// paints nothing, and a stack ending translucent leaves the floor showing through whatever the\n\t// composite reports: 64 half-transparent layers round to identical channels over opposite floors,\n\t// so comparing two composited readings admits the stack this refusal exists for.\n\tif (floor === undefined && (deepest === undefined || deepest[3] < 1)) {\n\t\tthrow new Error('Computed background color is unavailable')\n\t}\n\tconst backdrop = layers.reduceRight(\n\t\t(back, front) => blendColor(front, back),\n\t\tfloor ?? CANVAS_COLOR,\n\t)\n\treturn measureContrast(blendColor(foreground, backdrop), backdrop)\n}\n\n/**\n * Measures the contrast the focus chrome painted on one control reaches against its own backdrop.\n *\n * @param control - The control that holds the focus.\n * @param worn - The element the control's focus chrome is painted onto. Default: `control`.\n * @returns The strongest ratio the painted focus chrome reaches, or `undefined` when the control is\n * not showing `:focus-visible` or the cascade paints no chrome of its own.\n *\n * @remarks\n * This reads and never acts. Focus arrives through the published verbs — `traverseAccessible`,\n * `userEvent.keyboard` from `vitest/browser`, a real click — and this measures what the browser\n * painted once it landed. A control that is not matching `:focus-visible` when the call is made\n * reports nothing, because no measurement taken then would be about focus.\n *\n * Some controls are two elements: one that takes the focus and one a reader can see. A hidden radio\n * beside the label that carries every pixel of its chrome is the case `worn` exists for, so a\n * measurement is not taken on a rectangle nobody is looking at. The focus state is still read off\n * `control`, because that is what holds it.\n *\n * The backdrop is the surface behind the element the chrome is worn on, resolved from that element's\n * parent through {@link readBackdrop} onto {@link CANVAS_COLOR}. A control whose ancestry paints\n * nothing is therefore measured against the browser's own canvas, which is what a reader looking at\n * an unstyled document sees.\n *\n * Only chrome the cascade paints is measured — an `outline` with a real style and width, and the\n * first color in a `box-shadow`. A control left the browser's own `outline-style: auto` ring reports\n * `undefined`, because that ring's two tones are guaranteed against any backdrop and its computed\n * color names neither. A focus style that only changes the control's own fill reports `undefined`\n * too: the resting fill is gone by the time focus is on the control, and this never moves focus to\n * go and read it.\n *\n * @example\n * ```ts\n * await traverseAccessible('Evaluate')\n * readRing(resolveRendered('Evaluate')) // the ratio the painted ring reaches\n * ```\n */\nexport function readRing(control: Element, worn?: Element): number | undefined {\n\tif (!control.matches(':focus-visible')) return undefined\n\tconst target = worn ?? control\n\tconst declared = getComputedStyle(target)\n\tconst backdrop = readBackdrop(target.parentElement ?? target, CANVAS_COLOR)\n\tconst outline =\n\t\tdeclared.outlineStyle === 'none' ||\n\t\tdeclared.outlineStyle === 'auto' ||\n\t\tNumber.parseFloat(declared.outlineWidth) === 0\n\t\t\t? undefined\n\t\t\t: parseColor(declared.outlineColor)\n\tconst shadow = parseColor(/(?:rgba?|color)\\([^)]*\\)/u.exec(declared.boxShadow)?.[0] ?? '')\n\tconst ratios: number[] = []\n\tfor (const painted of [outline, shadow]) {\n\t\tif (painted === undefined) continue\n\t\tratios.push(measureContrast(blendColor(painted, backdrop), backdrop))\n\t}\n\treturn ratios.length === 0 ? undefined : Math.max(...ratios)\n}\n\n/**\n * Collects every class token the stylesheets loaded into this document actually define.\n *\n * @returns The set of class names reachable in the shipped cascade, in {@link readRules} order.\n *\n * @remarks\n * The set is what an authored-class conformance check measures against, so a class no loaded\n * stylesheet defines — an invented utility, a misspelled framework name — is absent from it.\n *\n * The tokens come from the {@link readRules} walk, which decides both the membership and the\n * insertion order this reader reports, and each answer is a deliberate difference from 0.0.8. A\n * class declared inside a grouping rule — a media query, a supports block, a layer, a nested style\n * rule — counts as defined, because a class the cascade defines under a condition is still one the\n * cascade defines; 0.0.8 read the top-level rules alone. Insertion order is breadth-first, so a\n * top-level class lands before a class declared inside an earlier grouping rule; 0.0.8 popped a\n * stack and inserted the deepest rule first. Iterate the set where the order is the subject, and\n * read `has` where membership is.\n *\n * `@keyframes` children are outside that walk, so an animation's own rules define no token here.\n * Reach the animation itself through {@link findKeyframes}.\n *\n * @example\n * ```ts\n * readCascade().has('card')\n * ```\n */\nexport function readCascade(): ReadonlySet<string> {\n\tconst known = new Set<string>()\n\tfor (const rule of readRules()) {\n\t\tif (!(rule instanceof CSSStyleRule)) continue\n\t\tfor (const match of rule.selectorText.matchAll(/\\.([a-zA-Z][\\w-]*)/g)) {\n\t\t\tknown.add(String(match[1]))\n\t\t}\n\t}\n\treturn known\n}\n\n/**\n * Collects every class token the markup under one root carries.\n *\n * @param root - The subtree to sweep. A detached element and a `DocumentFragment` both work.\n * @returns The class tokens in document order of first sighting; an empty set for markup carrying no\n * class at all.\n *\n * @remarks\n * The root's own classes count when the root is an `Element`, so a `DocumentFragment` contributes\n * its descendants alone. Every element is read through `classList`, which is what makes an SVG\n * element count the same as an HTML one: `className` on an SVG element is an `SVGAnimatedString`\n * rather than a string, and a reader splitting that value finds nothing.\n *\n * This is the authored half of a class conformance check and {@link readCascade} is the defined\n * half, so the difference between them is the set of classes the markup uses and no loaded\n * stylesheet declares.\n *\n * @example\n * ```ts\n * [...readClasses(container)].filter((name) => !readCascade().has(name))\n * ```\n */\nexport function readClasses(root: ParentNode): ReadonlySet<string> {\n\tconst authored = new Set<string>()\n\tif (root instanceof Element) for (const name of root.classList) authored.add(name)\n\tfor (const element of root.querySelectorAll('*')) {\n\t\tfor (const name of element.classList) authored.add(name)\n\t}\n\treturn authored\n}\n\n/**\n * Takes the authored-class census of one subtree against the cascade this document loaded.\n *\n * @param root - The subtree to walk. A detached element and a `DocumentFragment` both work.\n * @returns The population walked, every class token the markup carries, and every one of them no\n * loaded stylesheet declares; both lists sorted.\n * @throws An `Error` when the walk reads no element at all.\n *\n * @remarks\n * This is {@link readClasses} differenced against {@link readCascade}, with the population reported\n * beside the difference. The population is what makes the reading falsifiable: an empty walk\n * reports no undeclared token, and so does a subtree whose every class the cascade declares, so a\n * check reading `undeclared` alone passes for a census that read nothing. The empty walk is refused\n * outright for the same reason.\n *\n * The root counts when it is an `Element`, so a `DocumentFragment` contributes its descendants\n * alone. Both lists are sorted rather than left in sighting order, because a census is compared\n * against a previous one or against an expected list, and document order is not a fact about the\n * classes.\n *\n * @example\n * ```ts\n * readCensus(container).undeclared // ['lead'] — no loaded stylesheet declares it\n * ```\n */\nexport function readCensus(root: ParentNode): CensusReading {\n\tconst elements = (root instanceof Element ? 1 : 0) + root.querySelectorAll('*').length\n\tif (elements === 0) throw new Error('Class census walked no element')\n\tconst declared = readCascade()\n\tconst tokens = [...readClasses(root)].sort()\n\treturn Object.freeze({\n\t\telements,\n\t\ttokens: Object.freeze(tokens),\n\t\tundeclared: Object.freeze(tokens.filter((token) => !declared.has(token))),\n\t})\n}\n\n/**\n * Collects every rule the stylesheets loaded into this document hold, nested grouping rules\n * included.\n *\n * @returns Every rule reachable in the shipped cascade: each sheet's own rules in sheet order, then\n * the rules nested inside them, level by level.\n *\n * @remarks\n * The walk is iterative and reads the list it is still appending to, which is what expands a media\n * query, a supports block, a layer, and a nested style rule without recursion. Expanding by level\n * rather than by depth is why a top-level rule is always met before a rule nested inside an earlier\n * one; {@link findRule} returns the first match in exactly this order.\n *\n * The descent reaches a `CSSGroupingRule` and nothing else, and a `@keyframes` rule is not one. The\n * `@keyframes` rule itself is collected wherever it sits, and the keyframe rules inside it are not;\n * {@link findKeyframes} is the door to those.\n *\n * A stylesheet the document cannot read — a cross-origin sheet with no CORS grant — throws from its\n * own `cssRules` getter, and that sheet is skipped rather than ending the walk. What a page loaded\n * from another origin declares is unreadable to every caller here, so the alternative is a helper\n * that works until a test page adds a font or an analytics stylesheet.\n *\n * @example\n * ```ts\n * readRules().filter((rule) => rule instanceof CSSKeyframesRule)\n * ```\n */\nexport function readRules(): readonly CSSRule[] {\n\tconst rules: CSSRule[] = []\n\tfor (const sheet of document.styleSheets) {\n\t\ttry {\n\t\t\trules.push(...sheet.cssRules)\n\t\t} catch {\n\t\t\tcontinue\n\t\t}\n\t}\n\tfor (let index = 0; index < rules.length; index += 1) {\n\t\tconst rule = rules[index]\n\t\tif (rule instanceof CSSGroupingRule) rules.push(...rule.cssRules)\n\t}\n\treturn rules\n}\n\n/**\n * Finds the first style rule in the cascade whose selector carries a fragment.\n *\n * @param selector - The selector fragment to look for, matched as a substring of the whole selector\n * text.\n * @returns The first matching rule in {@link readRules} order, or `undefined` when no rule carries\n * the fragment.\n *\n * @remarks\n * This proves a declaration exists in the cascade at all, which is a different question from what an\n * element resolves to: {@link readStyle} reads the winner, and a rule this finds may be overridden by\n * another. Assert on this where the subject is the stylesheet, and on `readStyle` where the subject is\n * the rendered result.\n *\n * The match is a substring, so `findRule('.card')` finds `.card`, `.card:hover`, and\n * `.panel > .card` alike. Pass more of the selector to narrow it.\n *\n * @example\n * ```ts\n * findRule('.card')?.style.getPropertyValue('padding')\n * ```\n */\nexport function findRule(selector: string): CSSStyleRule | undefined {\n\tfor (const rule of readRules()) {\n\t\tif (rule instanceof CSSStyleRule && rule.selectorText.includes(selector)) return rule\n\t}\n\treturn undefined\n}\n\n/**\n * Finds the animation the cascade declares under one name.\n *\n * @param name - The exact `@keyframes` name.\n * @returns The first matching rule in {@link readRules} order, or `undefined` when the cascade\n * declares no animation under that name.\n *\n * @remarks\n * The name is matched exactly, which is where this parts from {@link findRule}: a selector is\n * compound and a fragment of one is a useful question, and an animation name is one atom that either\n * is or is not the one an `animation` declaration references.\n *\n * @example\n * ```ts\n * findKeyframes('fade')?.cssRules.length\n * ```\n */\nexport function findKeyframes(name: string): CSSKeyframesRule | undefined {\n\tfor (const rule of readRules()) {\n\t\tif (rule instanceof CSSKeyframesRule && rule.name === name) return rule\n\t}\n\treturn undefined\n}\n\n/**\n * Reads the normalized visible text of every element a selector matches, in document order.\n *\n * @param root - The subtree to search.\n * @param selector - The CSS selector naming the rows.\n * @returns One line per matched element, its text runs collapsed and single-space joined.\n *\n * @remarks\n * The line is built from the row's text nodes rather than from `textContent`, because adjacent\n * inline elements carry no whitespace between them in compiled template output and would otherwise\n * read as one run-together word.\n *\n * @example\n * ```ts\n * readRows(container, 'li')\n * ```\n */\nexport function readRows(root: ParentNode, selector: string): readonly string[] {\n\tconst rows: string[] = []\n\tfor (const row of root.querySelectorAll(selector)) {\n\t\tconst parts: string[] = []\n\t\tconst walker = document.createTreeWalker(row, NodeFilter.SHOW_TEXT)\n\t\twhile (walker.nextNode() !== null) {\n\t\t\tconst text = (walker.currentNode.textContent ?? '').replaceAll(/\\s+/g, ' ').trim()\n\t\t\tif (text !== '') parts.push(text)\n\t\t}\n\t\trows.push(parts.join(' '))\n\t}\n\treturn rows\n}\n\n/**\n * Collects every element carrying a component class rendered outside the container it belongs to.\n *\n * @param root - The subtree to sweep.\n * @param child - The component class whose anatomy requires a container, such as `list-group-item`.\n * @param parent - The container class that child class must render inside, such as `list-group`.\n * @returns The markup of every element carrying `child` with no `parent` above it, in document\n * order; an empty list when every one of them is nested correctly.\n *\n * @remarks\n * A component keeps its padding, borders, and radii on the container, so a child class rendered\n * outside one is an unstyled box wearing a component's name, and the interface has to hand-roll the\n * chrome back. The search for the container starts at the element's parent, so an element can never\n * answer the invariant by carrying both classes itself.\n *\n * The class names are arguments, so the check belongs to no framework: name the pair your own\n * cascade defines.\n *\n * @example\n * ```ts\n * extractOrphans(container, 'list-group-item', 'list-group') // []\n * ```\n */\nexport function extractOrphans(root: ParentNode, child: string, parent: string): readonly string[] {\n\treturn [...root.querySelectorAll(`.${child}`)]\n\t\t.filter((node) => (node.parentElement?.closest(`.${parent}`) ?? null) === null)\n\t\t.map((node) => node.outerHTML)\n}\n\n/**\n * Collects the markup of every element carrying a non-empty `style` attribute and of every `<style>`\n * element, in document order, `root` included in both populations when it is an `Element`.\n *\n * @param root - The subtree to sweep. A detached element and a `DocumentFragment` both work.\n * @returns The `outerHTML` of each such element, in document order; an empty list when the markup\n * declares no style of its own.\n *\n * @remarks\n * These are the declarations the stylesheet never sees: an inline `style` attribute, wherever it\n * sits, and a `<style>` element, whatever it holds. Nothing else counts. A class and a `data-*`\n * attribute name something the cascade resolves, so neither is reported however unusual it looks;\n * an inline `style` on a `<path>` inside an SVG is reported, because a namespace changes nothing\n * about what an inline declaration is.\n *\n * A `style` attribute holding nothing but whitespace declares nothing, so it is not reported. A\n * `DocumentFragment` root contributes its descendants alone, because it is not an `Element`; a\n * `<style>` root and a root carrying an inline attribute are each reported, and an element that is a\n * `<style>` element and carries an inline attribute too is reported once.\n *\n * @example\n * ```ts\n * extractStyles(container) // []\n * ```\n */\nexport function extractStyles(root: ParentNode): readonly string[] {\n\tconst elements: Element[] = root instanceof Element ? [root] : []\n\telements.push(...root.querySelectorAll('*'))\n\tconst styled: string[] = []\n\tfor (const element of elements) {\n\t\tconst inline = element.getAttribute('style') ?? ''\n\t\tif (inline.trim() !== '' || element.localName === 'style') styled.push(element.outerHTML)\n\t}\n\treturn styled\n}\n\n/**\n * Reads one resolved CSS property from a real browser element.\n *\n * @param element - The element whose resolved style to inspect.\n * @param property - The CSS property name, registered or custom.\n * @returns The browser's resolved property value, trimmed; an empty string when the element resolves\n * none.\n *\n * @remarks\n * The value is trimmed, so what comes back is the value and never the whitespace around it. Internal\n * whitespace is kept: `--shadow: 0 0 2px` reads back with its spaces.\n *\n * @example\n * ```ts\n * readStyle(button, 'padding-left')\n * ```\n */\nexport function readStyle(element: Element, property: string): string {\n\treturn getComputedStyle(element).getPropertyValue(property).trim()\n}\n\n/**\n * Reads one custom property from an element's resolved style.\n *\n * @param element - The element whose resolved style to inspect.\n * @param name - The custom property name, with or without its leading dashes.\n * @returns The resolved value, trimmed; an empty string when the element inherits no such property.\n *\n * @remarks\n * The dashes are optional because a token is spoken about both ways — `--surface` in a stylesheet\n * and `surface` in prose — and a reader that accepted only one spelling would turn that into a silent\n * empty string. An absent token reads as `''`, which is what the CSSOM returns and is\n * indistinguishable from a token declared empty; assert on the value you expect rather than on\n * presence.\n *\n * Resolution is inheritance, so a token declared on `:root` reads from any mounted descendant and\n * from an unmounted element reads as `''`. Use {@link readRootToken} where the declaration is the\n * document's.\n *\n * @example\n * ```ts\n * readToken(panel, 'surface') // '#ffffff'\n * readToken(panel, '--surface') // '#ffffff'\n * ```\n */\nexport function readToken(element: Element, name: string): string {\n\treturn readStyle(element, name.startsWith('--') ? name : `--${name}`)\n}\n\n/**\n * Reads one custom property from the document element.\n *\n * @param name - The custom property name, with or without its leading dashes.\n * @returns The resolved value, trimmed; an empty string when the document declares no such property.\n *\n * @remarks\n * This is {@link readToken} against `document.documentElement`, which is where a theme declares its\n * tokens and where a `[data-theme]` switch retunes them. It exists as its own name because that\n * element is the one a token question is nearly always about, and naming it at every call site\n * buries the question.\n *\n * @example\n * ```ts\n * readRootToken('surface')\n * ```\n */\nexport function readRootToken(name: string): string {\n\treturn readToken(document.documentElement, name)\n}\n\n/**\n * Reads one resolved CSS length as a number of pixels.\n *\n * @param element - The element whose resolved style to inspect.\n * @param property - The CSS property name, registered or custom.\n * @returns The leading numeric part of the resolved value, and `0` when it carries none.\n *\n * @remarks\n * A resolved length is text with a unit — `'12px'` — so this reads the number in front of the unit\n * and discards the rest. The unit is not checked: the resolved value of a length is in pixels in\n * every case a browser hands back, and a property that resolves to something else is the caller's\n * mistake rather than this reader's.\n *\n * An unparsable value reads as `0` rather than as absence, because every caller of this is measuring\n * and `'auto'`, `'none'`, and `''` each contribute no pixels to what a reader sees. Where the\n * distinction matters, read the text with {@link readStyle} instead.\n *\n * @example\n * ```ts\n * readPixels(button, 'padding-left') // 12\n * readPixels(button, 'width') // 0 when the width resolves to `auto`\n * ```\n */\nexport function readPixels(element: Element, property: string): number {\n\tconst measured = Number.parseFloat(readStyle(element, property))\n\treturn Number.isFinite(measured) ? measured : 0\n}\n\n/**\n * Measures the row the document's own content ends on, in document coordinates.\n *\n * @returns The content edge, rounded up to a whole row.\n *\n * @remarks\n * The body's box is not the document's height: it is the larger of the content and the pane. A pane\n * taller than the document stretches it, and `document.body.getBoundingClientRect()`,\n * `body.scrollHeight`, `body.offsetHeight`, and `documentElement.scrollHeight` all read that pane\n * back rather than the content under it. So a caller that has staged a pane taller than the\n * document cannot find its way down again from any of them. This reading can, because it is taken\n * over the elements inside the body rather than over the box around them: a document of fixed\n * content answers the same number under a short pane and a tall one, and a document laid out\n * against the viewport answers what that viewport actually laid out.\n *\n * Each element contributes its client rectangle's bottom edge in document coordinates plus its own\n * bottom margin, which sits outside that rectangle, and the largest contribution wins. Taking the\n * largest is what handles a collapsed margin without asking whether it collapsed: a child margin\n * that collapses out through its parent is counted once, at the child, and one the parent's padding\n * holds in is counted once, at the parent. The body's and the root's own bottom padding and margin\n * sit under every child rather than beside them, so they are added after the walk.\n *\n * The sum is rounded up because a box can end part way through a row and a frame cannot hold part\n * of one.\n *\n * @example\n * ```ts\n * const covered = measureContent()\n * ```\n */\nexport function measureContent(): number {\n\tlet edge = 0\n\tfor (const element of document.body.querySelectorAll('*')) {\n\t\tconst bottom =\n\t\t\telement.getBoundingClientRect().bottom + window.scrollY + readPixels(element, 'margin-bottom')\n\t\tif (bottom > edge) edge = bottom\n\t}\n\treturn Math.ceil(\n\t\tedge +\n\t\t\treadPixels(document.body, 'padding-bottom') +\n\t\t\treadPixels(document.body, 'margin-bottom') +\n\t\t\treadPixels(document.documentElement, 'padding-bottom') +\n\t\t\treadPixels(document.documentElement, 'margin-bottom'),\n\t)\n}\n\n/**\n * Sets the tester's viewport and renders the runner's pane at the size that viewport claims.\n *\n * @param width - The viewport width in CSS pixels.\n * @param height - The viewport height in CSS pixels.\n * @returns A promise resolving after the resized pane has been painted.\n * @throws Thrown when the tester sits inside no pane a capture can size, and when the staged pane\n * does not render at the viewport it was given.\n *\n * @remarks\n * This depends on the runner's own tester layout, and that dependency is contract rather than an\n * accident: `vitest@4.1.11` lays its tester out inside a smaller page, fits it by scaling the pane\n * the tester sits in, and clips whatever overflows that pane. Layout inside the tester is\n * unaffected — the tester reports the viewport it was given and every breakpoint answers to it —\n * but a screenshot is taken off the page the runner painted, so a frame shot through that scale is\n * a thumbnail of the surface and a frame shot after only unscaling it is a sliver. The tester is\n * therefore unscaled and lifted to the window's own origin for the shot. The `iframe[data-vitest]`\n * selector and the `--tester-transform`, `--tester-margin-left`, `--viewport-width`, and\n * `--viewport-height` custom properties are the runner's, so a Vitest release that renames any of\n * them reddens the size check that follows rather than writing a wrong frame.\n *\n * Hand the pane straight back with {@link releasePane}. A tester pinned at a viewport taller than\n * the window puts its lower half beyond what a pointer can reach, so an ordinary press then fails\n * as a control outside the viewport, in a test that took no picture at all.\n *\n * This is a capture's staging alone. A suite that resizes the tester for a journey — a breakpoint\n * to drive, a variant to act at — calls `page.viewport` from `vitest/browser` and leaves the tester\n * there. Staging and releasing as a pair resizes and then undoes the resize, so the journey step\n * after it runs at the size the file started at.\n *\n * The rule is declared rather than written inline, because the runner writes its own scale onto the\n * pane as inline custom properties and rewrites them whenever the tester resizes. A declared rule\n * marked important outranks an inline value and survives every rewrite. It finds the pane by the\n * tester it contains as well as by {@link CAPTURE_PANE}, because a re-render between the staging and\n * the shot replaces the node and takes any attribute of ours with it.\n *\n * The wait is two frames rather than a delay: the first carries the resize into layout and the\n * second is the paint a screenshot reads.\n *\n * The viewport the tester had before this staging is written onto that rule element as the\n * {@link CAPTURE_PANE} value, in `<width>x<height>` form, and {@link releasePane} hands it back.\n * Staging an already-staged pane leaves that value alone, so a capture that stages a second time to\n * cover a taller document still releases to the viewport the tester started with.\n *\n * @example\n * ```ts\n * await stagePane(390, 844)\n * ```\n */\nexport async function stagePane(width: number, height: number): Promise<void> {\n\tconst viewport = `${String(window.innerWidth)}x${String(window.innerHeight)}`\n\tawait page.viewport(width, height)\n\tconst frame = window.frameElement\n\tconst pane = frame?.parentElement\n\tconst owner = pane?.ownerDocument\n\tif (frame === null || pane === null || pane === undefined || owner === undefined) {\n\t\tthrow new Error('Tester pane is unavailable for a capture')\n\t}\n\tpane.setAttribute(CAPTURE_PANE, '')\n\tif (owner.querySelector(`style[${CAPTURE_PANE}]`) === null) {\n\t\tconst rule = owner.createElement('style')\n\t\trule.setAttribute(CAPTURE_PANE, viewport)\n\t\trule.textContent = [\n\t\t\t`[${CAPTURE_PANE}],:has(>iframe[data-vitest])`,\n\t\t\t'{--tester-transform:none !important;--tester-margin-left:0px !important}',\n\t\t\t'iframe[data-vitest]',\n\t\t\t'{position:fixed !important;left:0 !important;top:0 !important;right:auto !important;',\n\t\t\t'bottom:auto !important;width:var(--viewport-width) !important;',\n\t\t\t'height:var(--viewport-height) !important;z-index:2147483647 !important}',\n\t\t].join('')\n\t\towner.head.append(rule)\n\t}\n\tawait waitForFrame()\n\tawait waitForFrame()\n\tconst box = frame.getBoundingClientRect()\n\tif (Math.round(box.width) !== width || Math.round(box.height) !== height) {\n\t\tthrow new Error(\n\t\t\t`Tester pane rendered ${String(Math.round(box.width))}x${String(Math.round(box.height))} for a ${String(width)}x${String(height)} viewport`,\n\t\t)\n\t}\n}\n\n/**\n * Hands the tester pane back to the runner's own layout, at the viewport it had before staging.\n *\n * @remarks\n * A staged pane is the runner's fitting scale suppressed, so a pane left staged outlives the capture\n * that needed it and every later act in the file happens on a surface the runner is no longer\n * fitting to its window. What that costs is not a wrong picture: it is a control whose page\n * coordinates fall outside the pane, which the runner's own layout then intercepts, so an ordinary\n * press fails with the voice of a control that is covered.\n *\n * The viewport goes back too, because a capture resizes the tester and the size it chose belongs to\n * the frame rather than to the file: a test that runs after one and reads a breakpoint would\n * otherwise read the last capture's variant. The size comes off the {@link CAPTURE_PANE} value\n * {@link stagePane} wrote onto the rule element, which is the reading taken before the first\n * staging. Calling this on an unstaged pane finds no such value, so it changes nothing and resizes\n * nothing.\n *\n * That hand-back is what makes {@link stagePane} and this pair a capture's staging rather than a\n * resize: the pair puts the tester back where it found it, so a suite that used it to reach a\n * breakpoint runs its next step at the old size. Call `page.viewport` from `vitest/browser` for a\n * journey's own size, and leave this pair to the capture.\n *\n * @example\n * ```ts\n * await releasePane()\n * ```\n */\nexport async function releasePane(): Promise<void> {\n\tconst pane = window.frameElement?.parentElement\n\tconst rule = pane?.ownerDocument.querySelector(`style[${CAPTURE_PANE}]`)\n\tconst viewport = rule?.getAttribute(CAPTURE_PANE)?.split('x') ?? []\n\tpane?.removeAttribute(CAPTURE_PANE)\n\trule?.remove()\n\tconst width = Number(viewport[0])\n\tconst height = Number(viewport[1])\n\tif (Number.isFinite(width) && Number.isFinite(height)) await page.viewport(width, height)\n}\n\n/**\n * Shoots one frame at one viewport size and proves the file on disk holds this run's bytes.\n *\n * @param options - The path to write, the viewport to shoot at, and the element to shoot.\n * @returns The absolute path of the written frame, after it has been read back and matched.\n * @throws Thrown when the pane cannot be staged, when the document's height never settles under\n * {@link CAPTURE_STAGINGS} restagings, when the provider wrote the frame somewhere else, and when\n * the bytes on disk are not the ones this shot produced.\n *\n * @remarks\n * The path a screenshot call returns is the path it meant to write, so it is not evidence a file\n * exists. The file is read back through the runner's built-in `readFile` command and compared with\n * the shot itself, which is what separates a frame this run wrote from one an earlier run left\n * behind. The provider resolves `options.path` against the calling test file and returns an absolute\n * path, so the two are compared by the segments that survive resolving `.` and `..` lexically — the\n * refusal is what a provider resolving that path against a different base would trip.\n *\n * The frame covers the whole document at `options.width`, whatever `options.height` is. The\n * provider shoots the tester's body in the top-level page's own coordinates, so a document taller\n * than the pane is painted for the pane's height and the rows below it are the runner's page rather\n * than the document — a frame that reads as the surface down to the fold and as bare canvas after\n * it. The document is therefore laid out at the declared viewport first and, where it is taller\n * than that, the pane is staged again at the height the document needs, for the shot alone.\n *\n * That height is {@link measureContent}, never less than `options.height`, because the declared\n * viewport is the smallest frame a variant asks for. The reading is the content's own edge rather\n * than the body's box: the box is the larger of the content and the pane, so it stretches with\n * every pane staged over it and a capture that staged too tall a pane could not read its way back\n * down. Rounding up is what covers a body ending part way through a row, which the box does and an\n * integer scroll height does not.\n *\n * The edge is read again after every staging, because a rule bound to the viewport height — a `vh`\n * length, a fixed footer, a full-height panel — lays the document out taller against the taller\n * pane, so a surface built out of those photographs as its scrolled-open self rather than as one\n * screen, and the reading taken before that staging is stale by exactly what the reflow added.\n * Restaging at the edge alone converges on such a document without arriving: each staging closes\n * the same fraction of what is left, so a rule keeping half the pane reads 1322, 1561, 1681, and\n * 1741 against a fixed point of 1800. Each staging therefore carries the growth the one before it\n * produced — the pane is the edge plus that growth — which lands on the fixed point rather than\n * creeping up to it. The first staging carries no growth, because nothing has grown yet, so a\n * document of fixed content is staged at its own edge and shot there rather than at a pane the\n * overshoot stretched.\n *\n * The re-reading stops when the pane and the edge agree, which is the pane the shot is taken at. A\n * rule that adds height with every pane never reaches that point, so the re-reading is bounded by\n * {@link CAPTURE_STAGINGS} and the shot is refused with\n * `Capture frame at <path> never settled after <n> restagings: <h> over a <h> pane` rather than\n * written at a height that is already wrong.\n *\n * Omit `options.element` to shoot the whole page. The pane is staged for the frame and released\n * before this returns, on the failing path as well as the passing one, which hands the tester back\n * the viewport it had before the first staging.\n *\n * @example\n * ```ts\n * await captureFrame({ path: '../../tmp/capture/start.png', width: 390, height: 844 })\n * ```\n */\nexport async function captureFrame(options: FrameOptions): Promise<string> {\n\ttry {\n\t\tawait stagePane(options.width, options.height)\n\t\tlet pane = options.height\n\t\tlet covered = Math.max(measureContent(), options.height)\n\t\tlet growth = 0\n\t\tfor (let staging = 0; pane !== covered; staging += 1) {\n\t\t\tif (staging === CAPTURE_STAGINGS) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Capture frame at ${options.path} never settled after ${String(CAPTURE_STAGINGS)} restagings: ${String(covered)} over a ${String(pane)} pane`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tpane = covered + growth\n\t\t\tawait stagePane(options.width, pane)\n\t\t\tconst reading = Math.max(measureContent(), options.height)\n\t\t\tgrowth = Math.max(0, reading - covered)\n\t\t\tcovered = reading\n\t\t}\n\t\tconst shot =\n\t\t\toptions.element === undefined\n\t\t\t\t? await page.screenshot({ path: options.path, base64: true })\n\t\t\t\t: await page.screenshot({ element: options.element, path: options.path, base64: true })\n\t\tconst segments: string[] = []\n\t\tfor (const segment of options.path.replaceAll('\\\\', '/').split('/')) {\n\t\t\tif (segment === '' || segment === '.') continue\n\t\t\tif (segment === '..') segments.pop()\n\t\t\telse segments.push(segment)\n\t\t}\n\t\tif (!shot.path.replaceAll('\\\\', '/').endsWith(segments.join('/'))) {\n\t\t\tthrow new Error(\n\t\t\t\t`Capture frame was written to ${shot.path} where ${options.path} was asked for`,\n\t\t\t)\n\t\t}\n\t\tif ((await commands.readFile(shot.path, 'base64')) !== shot.base64) {\n\t\t\tthrow new Error(`Capture frame at ${options.path} is not the one this run shot`)\n\t\t}\n\t\treturn shot.path\n\t} finally {\n\t\tawait releasePane()\n\t}\n}\n\n/**\n * Reads one written frame back and reports its size and the color its bottom row paints.\n *\n * @param path - The frame's absolute path, as `captureFrame` returns it.\n * @returns The frame's size in device pixels and its floor.\n * @throws Thrown when the runner cannot read the path, when the bytes there are not an image this\n * browser decodes, and when the browser hands out no 2D canvas to measure them on.\n *\n * @remarks\n * The reading comes off the written file rather than off the document that produced it, which is\n * what makes it evidence about a capture: the browser's own image decoding and an\n * `OffscreenCanvas` answer for the pixels a viewer would see, so a frame that ends on the runner's\n * canvas reports that canvas whatever the document's style resolves to. Pass the path the provider\n * resolved and `captureFrame` returned; the runner's `readFile` command resolves a relative path\n * against its own root rather than against the calling test file, so a relative path names a file\n * somewhere else.\n *\n * @example\n * ```ts\n * const reading = await readFrame(written)\n * ```\n */\nexport async function readFrame(path: string): Promise<FrameReading> {\n\tconst encoded = await commands.readFile(path, 'base64').catch((cause: unknown) => {\n\t\tthrow new Error(`Capture frame at ${path} could not be read`, { cause })\n\t})\n\tconst image = new Image()\n\timage.src = `data:image/png;base64,${encoded}`\n\tawait image.decode().catch((cause: unknown) => {\n\t\tthrow new Error(`Capture frame at ${path} is not an image this browser decodes`, { cause })\n\t})\n\tconst context = new OffscreenCanvas(image.width, image.height).getContext('2d')\n\tif (context === null) {\n\t\tthrow new Error(`Capture frame at ${path} cannot be measured without a 2D canvas`)\n\t}\n\tcontext.drawImage(image, 0, 0)\n\tconst row = context.getImageData(0, image.height - 1, image.width, 1).data\n\tconst red = row[0]\n\tconst green = row[1]\n\tconst blue = row[2]\n\tconst alpha = row[3]\n\tlet single = red !== undefined && green !== undefined && blue !== undefined\n\tfor (let pixel = 4; single && pixel < row.length; pixel += 4) {\n\t\tsingle =\n\t\t\trow[pixel] === red &&\n\t\t\trow[pixel + 1] === green &&\n\t\t\trow[pixel + 2] === blue &&\n\t\t\trow[pixel + 3] === alpha\n\t}\n\treturn {\n\t\twidth: image.width,\n\t\theight: image.height,\n\t\tfloor: single ? `rgb(${String(red)}, ${String(green)}, ${String(blue)})` : undefined,\n\t}\n}\n\n/**\n * Expands a capture registry across every variant into the filenames a complete portfolio holds.\n *\n * @param states - The registered state names.\n * @param variants - The variants the portfolio is rendered in.\n * @returns One `<state>--<variant>.png` name per pair, each state's variants together, in registry\n * order.\n *\n * @remarks\n * The expansion is the portfolio's own definition of complete, so a duplicate in it is a registry\n * defect a proof reads directly rather than a collision discovered on disk.\n *\n * @example\n * ```ts\n * expandCaptures(['start'], [{ name: 'dark-390', width: 390, height: 844 }])\n * // ['start--dark-390.png']\n * ```\n */\nexport function expandCaptures(\n\tstates: readonly string[],\n\tvariants: readonly CaptureVariant[],\n): readonly string[] {\n\tconst files: string[] = []\n\tfor (const state of states) {\n\t\tfor (const variant of variants) files.push(`${state}--${variant.name}.png`)\n\t}\n\treturn files\n}\n\n/**\n * Builds the refusal a host withholding a storage operation raises.\n *\n * @param operation - The withheld operation, named as the `Storage` interface names it.\n * @param key - The storage key the operation addressed. Omit it for an operation that takes none.\n * @returns The refusal, unthrown.\n *\n * @remarks\n * A browser with site data blocked, a sandboxed frame, and a hardened privacy mode all raise a\n * `DOMException` named `SecurityError` from the storage object rather than answering, so this is\n * the voice rather than a message of this package's. {@link createStorage} raises it from every\n * operation the permission withholds; it is exported because a fixture implementing `Storage` some\n * other way needs the same voice rather than a second spelling of it.\n *\n * @example\n * ```ts\n * buildDenial('getItem', 'theme').message // 'Access is denied for getItem \"theme\"'\n * buildDenial('length').name // 'SecurityError'\n * ```\n */\nexport function buildDenial(operation: string, key?: string): DOMException {\n\treturn new DOMException(\n\t\t`Access is denied for ${operation}${key === undefined ? '' : ` \"${key}\"`}`,\n\t\t'SecurityError',\n\t)\n}\n\n/**\n * Builds a detached translucent stack whose composited and flat contrast readings straddle one bar.\n *\n * @param bar - The contrast ratio `refused` and `accepted` must sit on opposite sides of.\n * @returns The opaque root carrying the tint, and the refused and accepted foregrounds under it.\n * @throws An `Error` when no grey foreground puts the two readings on opposite sides of the bar.\n *\n * @remarks\n * A contrast instrument that never composites still clears every fixture painting its own opaque\n * background, so this is the control that makes {@link readContrast}'s ancestor walk and alpha\n * blend the thing under test. The stack is an opaque floor, a translucent tint over it, and two\n * grey foregrounds inside the tint. `refused` reads under the bar composited and at or over it\n * flat, and `accepted` reads the other way about, so no single non-compositing reading satisfies\n * both.\n *\n * The greys are searched rather than written down, so the control follows the bar it was asked for.\n * A bar at or under `1` is refused because every contrast ratio reaches `1`, and a bar above what\n * the tinted surface can reach is refused because no foreground clears it — each refusal names the\n * bar rather than returning a stack that proves nothing.\n *\n * The nodes are detached, so nothing is mounted for you. Append `root` to the surface you are\n * reading, take both readings, and remove it: a computed color needs the document, and a fixture\n * left behind is the next test's resolver ambiguity.\n *\n * @example\n * ```ts\n * const control = buildContrast(4.5)\n * mount(control.root)\n * readContrast(control.refused) < 4.5 // true\n * readContrast(control.accepted) >= 4.5 // true\n * control.root.remove()\n * ```\n */\nexport function buildContrast(bar: number): ContrastFixture {\n\tconst tint: Color = [0, 0, 0, 0.06]\n\tconst backdrop = blendColor(tint, CANVAS_COLOR)\n\tconst flattened: Color = [tint[0], tint[1], tint[2], 1]\n\tlet refusedChannel: number | undefined\n\tlet acceptedChannel: number | undefined\n\tfor (let channel = 0; channel <= 255; channel += 1) {\n\t\tconst front: Color = [channel, channel, channel, 1]\n\t\tconst composited = measureContrast(front, backdrop)\n\t\tconst flat = measureContrast(front, flattened)\n\t\tif (refusedChannel === undefined && composited < bar && flat >= bar) refusedChannel = channel\n\t\tif (acceptedChannel === undefined && composited >= bar && flat < bar) acceptedChannel = channel\n\t}\n\tif (refusedChannel === undefined || acceptedChannel === undefined) {\n\t\tthrow new Error(`Contrast control cannot straddle the bar ${bar}`)\n\t}\n\tconst root = build('div', {\n\t\tattributes: {\n\t\t\tstyle: `background-color: rgb(${CANVAS_COLOR[0]}, ${CANVAS_COLOR[1]}, ${CANVAS_COLOR[2]})`,\n\t\t},\n\t})\n\tconst tinted = build('div', {\n\t\tattributes: {\n\t\t\tstyle: `background-color: rgba(${tint[0]}, ${tint[1]}, ${tint[2]}, ${tint[3]})`,\n\t\t},\n\t})\n\tconst refused = build('p', {\n\t\ttext: 'Composited contrast control',\n\t\tattributes: {\n\t\t\tstyle: `color: rgb(${refusedChannel}, ${refusedChannel}, ${refusedChannel})`,\n\t\t},\n\t})\n\tconst accepted = build('p', {\n\t\ttext: 'Composited contrast survivor',\n\t\tattributes: {\n\t\t\tstyle: `color: rgb(${acceptedChannel}, ${acceptedChannel}, ${acceptedChannel})`,\n\t\t},\n\t})\n\ttinted.append(refused, accepted)\n\troot.append(tinted)\n\treturn Object.freeze({ root, refused, accepted })\n}\n\n/**\n * Builds detached markup carrying one style escape of each kind, plus the sheet a project allows.\n *\n * @param permitted - The `id` the caller's reading exempts, placed on the third element.\n * @returns The detached root, the inline escape, the embedded escape, and the exempt sheet.\n *\n * @remarks\n * {@link extractStyles} has two branches — an inline `style` attribute and a `<style>` element —\n * and a reading fed only the first never exercises the second. The exempt sheet is the other half\n * of the control: a project that allows one standalone stylesheet writes an exemption for its id,\n * and a reading that passes by refusing every `<style>` element clears the two escapes and fails\n * that exemption.\n *\n * The declaration `inline`, `embedded`, and `permitted` carry is this package's, so assert on which\n * elements are reported rather than on what they declare.\n *\n * The nodes are detached and stay that way: `extractStyles` takes any `ParentNode`, so the reading\n * runs without mounting, and an embedded sheet that reached the document would join the cascade\n * every other reading measures against.\n *\n * @example\n * ```ts\n * const control = buildEscapes('project-stylesheet')\n * extractStyles(control.root).length // 3 — the inline escape, the embedded sheet, and the exempt one\n * ```\n */\nexport function buildEscapes(permitted: string): EscapeFixture {\n\tconst declaration = 'color: rgb(1, 2, 3)'\n\tconst root = build('div')\n\tconst inline = build('p', {\n\t\ttext: 'Inline escape control',\n\t\tattributes: { style: declaration },\n\t})\n\tconst embedded = build('style')\n\tembedded.textContent = `.escape-embedded { ${declaration} }`\n\tconst exempt = build('style', { attributes: { id: permitted } })\n\texempt.textContent = `#escape-permitted { ${declaration} }`\n\troot.append(inline, embedded, exempt)\n\treturn Object.freeze({ root, inline, embedded, permitted: exempt })\n}\n\n/**\n * Builds detached markup carrying one undeclared class token on HTML and another on SVG.\n *\n * @returns The detached root, the token the HTML element carries, and the one the SVG carries.\n *\n * @remarks\n * The SVG element is the trap a census has to survive: `className` on an SVG element is an\n * `SVGAnimatedString` rather than a string, so a reader splitting that value finds nothing and\n * reports one undeclared token where two are carried. {@link readCensus} reads every element\n * through `classList`, and this is the control that proves it.\n *\n * The two tokens are returned rather than written into a caller's expectation, so a cascade that\n * later declares one of these names moves the fixture and the assertion together. Each token also\n * carries a suffix drawn per call from `crypto.getRandomValues`, so a consumer cascade cannot\n * declare either of them in advance and two controls in one document never share a token.\n * `getRandomValues` rather than `randomUUID`, because that one answers outside a secure context\n * too, and a browser project served from a remote host is not one.\n *\n * @example\n * ```ts\n * const control = buildCensus()\n * readCensus(control.root).undeclared // [control.mark, control.token], sorted\n * ```\n */\nexport function buildCensus(): CensusFixture {\n\tconst suffix = crypto.getRandomValues(new Uint32Array(1)).join('')\n\tconst token = `census-authored-token-${suffix}`\n\tconst mark = `census-authored-mark-${suffix}`\n\tconst root = build('div')\n\troot.append(build('p', { classes: token, text: 'Authored class control' }))\n\tconst glyph = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n\tglyph.setAttribute('class', mark)\n\troot.append(glyph)\n\treturn Object.freeze({ root, token, mark })\n}\n","import type {\n\tHarnessInterface,\n\tHarnessOptions,\n\tJournalInterface,\n\tJournalStep,\n\tPortfolioInterface,\n\tPortfolioOptions,\n\tStorageOptions,\n\tWebStorageInterface,\n} from './types.js'\nimport { isError } from '@orkestrel/contract'\nimport {\n\tbuildRefusal,\n\texecuteScenario,\n\trequireValue,\n\tSTATECHART_ATTRIBUTES,\n\tSTATECHART_STATUSES,\n\twaitForDelay,\n} from '@src/core'\nimport { build, buildDenial, captureFrame, expandCaptures, mount } from './helpers.js'\n\n/**\n * Creates one real pointer event, ready to dispatch.\n *\n * @param name - The event type, such as `pointerdown`.\n * @param options - Any `PointerEventInit` member, each one overriding the default beneath it.\n * @returns A real `PointerEvent` of that type.\n *\n * @remarks\n * The defaults are what a browser's own pointer event carries and a hand-built one does not:\n * `bubbles` and `cancelable` are set, so a delegated listener hears it and a handler can prevent it,\n * and `pointerId`, `pointerType`, and `isPrimary` describe a single primary mouse, so a component\n * that branches on the pointer kind takes the branch a mouse takes. Override any of them by naming\n * it; a touch is `{ pointerType: 'touch' }` and nothing else has to be restated.\n *\n * The event is real rather than a shaped object, so `instanceof PointerEvent` holds and the\n * coordinate and modifier members a handler reads are the ones the platform defines.\n *\n * @example\n * ```ts\n * element.dispatchEvent(createPointerEvent('pointerdown', { clientX: 10, clientY: 20 }))\n * ```\n */\nexport function createPointerEvent(name: string, options?: PointerEventInit): PointerEvent {\n\treturn new PointerEvent(name, {\n\t\tbubbles: true,\n\t\tcancelable: true,\n\t\tpointerId: 1,\n\t\tpointerType: 'mouse',\n\t\tisPrimary: true,\n\t\t...options,\n\t})\n}\n\n/**\n * Creates one real drag event carrying a live data transfer, ready to dispatch.\n *\n * @param name - The event type, such as `dragstart`.\n * @param options - Any `DragEventInit` member, each one overriding the default beneath it.\n * @returns A real `DragEvent` of that type.\n *\n * @remarks\n * A drag event with no `dataTransfer` is the shape that makes a drop handler fail in a test and work\n * in a browser, so one is allocated. Pass your own to seed it: a `dataTransfer` given in `options`\n * replaces the allocated one, which is how a drop is driven with the payload the drag was supposed\n * to carry.\n *\n * The platform declares the `dataTransfer` member on the constructed event as nullable, so calling\n * code still narrows it even though this always supplies one.\n *\n * `bubbles` and `cancelable` are set, because a drop handler that never prevents the default event\n * is a drop the browser handles itself.\n *\n * @example\n * ```ts\n * const started = createDragEvent('dragstart')\n * started.dataTransfer?.setData('text/plain', 'row-3')\n * element.dispatchEvent(started)\n * ```\n */\nexport function createDragEvent(name: string, options?: DragEventInit): DragEvent {\n\treturn new DragEvent(name, {\n\t\tbubbles: true,\n\t\tcancelable: true,\n\t\tdataTransfer: new DataTransfer(),\n\t\t...options,\n\t})\n}\n\n/**\n * Creates the capture portfolio one run places its screenshots through.\n *\n * @param options - The state registry, the variant matrix, the variant this run renders, the\n * directory it writes into, and whether it writes at all.\n * @returns The portfolio: its registry expansion, what it has placed, and `place`.\n * @throws When no registered variant carries the name `variant` names.\n *\n * @remarks\n * A disabled portfolio is the ordinary run. `place` then resizes nothing, writes nothing, and\n * records nothing, so a journey calls it unconditionally and a suite with the flag unset pays for\n * none of it. The portfolio refuses an unregistered variant at creation. An enabled run refuses an\n * unregistered state name and a second placement of one state.\n *\n * An enabled `place` writes through `captureFrame`, so a placed state carries that helper's staged\n * pane and its byte readback: a path is recorded only after the file on disk has been proved to hold\n * this run's own frame.\n *\n * @example\n * ```ts\n * const portfolio = createPortfolio({\n * \tstates: ['start-empty'],\n * \tvariants: [{ name: 'dark-390', width: 390, height: 844 }],\n * \tvariant: 'dark-390',\n * \tdirectory: '../../tmp/capture/states',\n * })\n * await portfolio.place('start-empty')\n * ```\n */\nexport function createPortfolio(options: PortfolioOptions): PortfolioInterface {\n\tconst selected = options.variants.find((candidate) => candidate.name === options.variant)\n\tif (selected === undefined) {\n\t\tthrow new Error(`Capture variant \"${options.variant}\" is not registered`)\n\t}\n\tconst registry = [...options.states]\n\tconst files = expandCaptures(registry, options.variants)\n\tconst enabled = options.enabled ?? false\n\tconst placed: string[] = []\n\tconst paths: string[] = []\n\treturn {\n\t\tvariant: options.variant,\n\t\tfiles,\n\t\tget placements() {\n\t\t\treturn [...placed]\n\t\t},\n\t\tget paths() {\n\t\t\treturn [...paths]\n\t\t},\n\t\tasync place(state, element) {\n\t\t\tif (!enabled) return undefined\n\t\t\tif (!registry.includes(state)) {\n\t\t\t\tthrow new Error(`Capture state \"${state}\" is not registered`)\n\t\t\t}\n\t\t\tif (placed.includes(state)) {\n\t\t\t\tthrow new Error(`Capture state \"${state}\" is already placed`)\n\t\t\t}\n\t\t\tconst file = `${state}--${options.variant}.png`\n\t\t\tselected.apply?.()\n\t\t\tconst written = await captureFrame({\n\t\t\t\tpath: `${options.directory}/${file}`,\n\t\t\t\twidth: selected.width,\n\t\t\t\theight: selected.height,\n\t\t\t\telement,\n\t\t\t})\n\t\t\tplaced.push(state)\n\t\t\tpaths.push(written)\n\t\t\treturn written\n\t\t},\n\t}\n}\n\n/**\n * Creates one console channel that records every call it receives and hands that call on unchanged.\n *\n * @param name - The channel's name, which prefixes each line it records.\n * @param output - The list each call is recorded into, appended to in place.\n * @param forward - The channel every call is passed on to after it is recorded.\n * @returns A channel carrying the console's own call signature.\n *\n * @remarks\n * One call becomes one line. Every argument of that call is put through `String` and joined with a\n * space, so a call carrying several values reads as the one line the page printed rather than as\n * several entries.\n *\n * Nothing is swallowed. The record happens first and `forward` receives the arguments it would have\n * received, so a page recorded through this prints exactly what it printed without it. The list\n * belongs to the caller, so a channel writes into whatever it was handed and holds no state of its\n * own. {@link createJournal} builds one channel per console method over one list.\n *\n * @example\n * ```ts\n * const output: string[] = []\n * console.log = createChannel('log', output, console.log)\n * ```\n */\nexport function createChannel(\n\tname: string,\n\toutput: string[],\n\tforward: (...data: unknown[]) => void,\n): (...data: unknown[]) => void {\n\treturn (...data) => {\n\t\toutput.push(`${name}: ${data.map((value) => String(value)).join(' ')}`)\n\t\tforward(...data)\n\t}\n}\n\n/**\n * Creates the journal one scenario records its steps and the page's own output into.\n *\n * @returns A journal that records nothing until it is started.\n *\n * @remarks\n * The console is recorded rather than replaced: every intercepted call is forwarded to the channel\n * that was there when the journal started, so a run under a journal prints exactly what it printed\n * without one. `stop` puts those same function references back by identity.\n *\n * Uncaught errors and unhandled rejections are recorded too, through listeners the journal drops\n * when it stops. `steps` and `output` hand out snapshots, so a list read mid-scenario stays what it\n * was. Each journal owns its own recording, so a file that needs one per scenario creates one per\n * scenario.\n *\n * @example\n * ```ts\n * const journal = createJournal()\n * journal.start()\n * journal.record('click', 'Evaluate', 'alerts=0')\n * journal.stop()\n * journal.steps // [{ action: 'click', trigger: 'Evaluate', result: 'alerts=0' }]\n * ```\n */\nexport function createJournal(): JournalInterface {\n\tconst steps: JournalStep[] = []\n\tconst output: string[] = []\n\t// The channels the page was writing to when the journal started. Their presence is what \"started\"\n\t// means, so no second flag can disagree with it. The listeners are dropped through one signal,\n\t// which is why no handler reference has to be kept to take them off again.\n\tlet intercepted: Pick<Console, 'debug' | 'error' | 'info' | 'log' | 'warn'> | undefined\n\tlet listeners: AbortController | undefined\n\treturn {\n\t\tget steps() {\n\t\t\treturn [...steps]\n\t\t},\n\t\tget output() {\n\t\t\treturn [...output]\n\t\t},\n\t\tstart() {\n\t\t\tsteps.length = 0\n\t\t\toutput.length = 0\n\t\t\tif (intercepted !== undefined) return\n\t\t\tconst forwarded = {\n\t\t\t\tdebug: console.debug,\n\t\t\t\terror: console.error,\n\t\t\t\tinfo: console.info,\n\t\t\t\tlog: console.log,\n\t\t\t\twarn: console.warn,\n\t\t\t}\n\t\t\tintercepted = forwarded\n\t\t\tfor (const channel of ['debug', 'error', 'info', 'log', 'warn'] as const) {\n\t\t\t\tconsole[channel] = createChannel(channel, output, forwarded[channel])\n\t\t\t}\n\t\t\tconst dropped = new AbortController()\n\t\t\tlisteners = dropped\n\t\t\twindow.addEventListener(\n\t\t\t\t'error',\n\t\t\t\t(event) => {\n\t\t\t\t\toutput.push(`error: ${event.message}`)\n\t\t\t\t},\n\t\t\t\t{ signal: dropped.signal },\n\t\t\t)\n\t\t\twindow.addEventListener(\n\t\t\t\t'unhandledrejection',\n\t\t\t\t(event) => {\n\t\t\t\t\toutput.push(`rejection: ${String(event.reason)}`)\n\t\t\t\t},\n\t\t\t\t{ signal: dropped.signal },\n\t\t\t)\n\t\t},\n\t\tstop() {\n\t\t\tif (intercepted === undefined) return\n\t\t\tObject.assign(console, intercepted)\n\t\t\tintercepted = undefined\n\t\t\tlisteners?.abort()\n\t\t\tlisteners = undefined\n\t\t},\n\t\trecord(action, trigger, result) {\n\t\t\tif (intercepted === undefined) return\n\t\t\tsteps.push(Object.freeze({ action, trigger, result }))\n\t\t},\n\t}\n}\n\n/**\n * Creates an inert `Storage` a host can withhold, grant, and run out of room in.\n *\n * @param options - The seed, the read and write permissions, and the quota.\n * @returns A store carrying the Web Storage surface plus the grant.\n * @throws An `Error` when `quota` is not a non-negative safe integer. A quota above\n * `Number.MAX_SAFE_INTEGER` carries the same sentence, because a counter that cannot decrement past\n * that point bounds nothing.\n *\n * @remarks\n * Conditions a real origin produces are unreachable from a test otherwise: a browser with\n * site data blocked refuses every operation the permission withholds, an origin with no room left\n * refuses `setItem`, and a person allowing site data grants what was withheld. This makes each of\n * them reachable against a real `Storage` surface rather than a shaped object.\n *\n * The store answers through its methods and intercepts no named-property access, so drive a\n * consumer under test through `getItem` and `setItem`. `Storage` declares an index signature, so\n * `store.theme` typechecks and reads `undefined` while `getItem('theme')` answers, and a property\n * write lands on the object rather than in the store, consuming no quota and meeting no refusal.\n *\n * It is backed by a map of its own and patches nothing: `localStorage` and `sessionStorage` are\n * untouched, no `storage` event is dispatched, and the store is reached only by the code the test\n * hands it to. Reach for {@link clearStorage} where the real browser surfaces are the subject.\n *\n * `length`, `key`, and `getItem` are reads; `clear`, `removeItem`, and `setItem` are writes. A\n * withheld operation raises {@link buildDenial}'s `SecurityError`, and `permit` lifts both\n * permissions at once, the way a person allowing site data lifts them. Reads answer from what the\n * store actually accepted, so a journey reads what the application kept while the host was refusing.\n *\n * `quota` counts accepted `setItem` calls rather than bytes, because the number of writes is what a\n * journey scripts and a byte budget is the browser's own arithmetic. `removeItem` consumes none of\n * it, and `permit` replenishes none of it: room and permission are different refusals, and a test\n * that granted the permission still meets the full origin.\n *\n * @example\n * ```ts\n * const storage = createStorage({ values: { theme: 'dark' }, writes: false })\n * storage.getItem('theme') // 'dark'\n * storage.permit()\n * storage.setItem('theme', 'light')\n * ```\n */\nexport function createStorage(options?: StorageOptions): WebStorageInterface {\n\tconst quota = options?.quota\n\tif (quota !== undefined && (!Number.isSafeInteger(quota) || quota < 0)) {\n\t\tthrow new Error('Storage quota must be a non-negative integer')\n\t}\n\tconst values = new Map<string, string>(Object.entries(options?.values ?? {}))\n\tlet reads = options?.reads ?? true\n\tlet writes = options?.writes ?? true\n\tlet room = quota\n\treturn {\n\t\tget length() {\n\t\t\tif (!reads) throw buildDenial('length')\n\t\t\treturn values.size\n\t\t},\n\t\tpermit() {\n\t\t\treads = true\n\t\t\twrites = true\n\t\t},\n\t\tclear() {\n\t\t\tif (!writes) throw buildDenial('clear')\n\t\t\tvalues.clear()\n\t\t},\n\t\tgetItem(key) {\n\t\t\tif (!reads) throw buildDenial('getItem', key)\n\t\t\treturn values.get(key) ?? null\n\t\t},\n\t\tkey(index) {\n\t\t\tif (!reads) throw buildDenial('key')\n\t\t\treturn [...values.keys()][index] ?? null\n\t\t},\n\t\tremoveItem(key) {\n\t\t\tif (!writes) throw buildDenial('removeItem', key)\n\t\t\tvalues.delete(key)\n\t\t},\n\t\tsetItem(key, value) {\n\t\t\tif (!writes) throw buildDenial('setItem', key)\n\t\t\tif (room !== undefined) {\n\t\t\t\tif (room === 0) throw new DOMException(`No room is left for ${key}`, 'QuotaExceededError')\n\t\t\t\troom -= 1\n\t\t\t}\n\t\t\tvalues.set(key, value)\n\t\t},\n\t}\n}\n\n/**\n * Creates a mounted statechart harness that renders one transition table and drives it row by row.\n *\n * @typeParam TState - The states the entity moves between.\n * @typeParam TEvent - The events the entity accepts.\n * @typeParam TContext - The fixture each row drives.\n * @param options - The table, the fixture builder, the state reader, and the delay between rows.\n * @returns The mounted harness, standing idle with its tally at zero.\n * @throws An `Error` reading `Statechart harness mounted no transition` for an empty table, before\n * anything reaches the document.\n *\n * @remarks\n * A page cannot import this package, because the browser entry imports `vitest/browser` at module\n * scope. So the harness is test-side: the suite mounts it, a gate outside the page polls the\n * markup it renders, and `STATECHART_ATTRIBUTES` is the whole contract between the two. Nothing\n * here spells a `data-statechart-*` string of its own, and neither does a gate. That gate has no\n * rejection channel, so every exit writes a terminal status: a run that completes writes `passed` or\n * `failed`, and a run that a `state` reader or a non-`Error` phase throw ends writes `failed` and\n * then rejects with that value by identity, without counting the row as failed.\n *\n * The markup is framework-free. The root carries `status` and the tally; a `role=\"status\"`\n * announcer narrates each step in a sentence; one element carries `state` and renders what the\n * entity's own reader reports; and an ordered list carries one row per scenario, each labelled with\n * its `from`, its `event`, and its `to` and marked with the transition's name. The `state` element\n * mounts empty and takes its attribute from the first row that produces a context, because a state\n * is read from an entity and no entity exists until a row builds one.\n *\n * Construction writes `pending`, mounts the root, renders every row, then writes the row count and\n * `idle` — so a gate that reads `pending` has found a harness whose rows never mounted, and the\n * order is observable from outside through the mutations the document records.\n *\n * `execute` clears every rendered result and the rendered state, writes `running`, and drives each\n * row in order through {@link executeScenario} against a context of that row's own. It continues\n * past a failing row, so one run reports on the whole table rather than stopping at the first\n * finding, and a builder that throws counts as its row failing under {@link buildRefusal}'s\n * sentence, which is the one `executeScenarios` raises. What decides whether a row's phases run is\n * whether its builder returned, not what it returned, so a table whose context is `undefined` drives\n * every phase. A second `execute` runs the same table from a fresh tally and a cleared state.\n *\n * Every reading comes off the markup, so the object and the page cannot disagree, and `failures` is\n * the `scenario` name of each row whose rendered `result` reads `failed` rather than a second list\n * beside them.\n *\n * @example\n * ```ts\n * const harness = createHarness({ scenarios: SCENARIOS, build: buildDisclosure, state: readState })\n * await harness.execute()\n * harness.status // 'passed'\n * harness.destroy()\n * ```\n */\nexport function createHarness<TState extends string, TEvent extends string, TContext>(\n\toptions: HarnessOptions<TState, TEvent, TContext>,\n): HarnessInterface {\n\tconst scenarios = options.scenarios\n\tif (scenarios.length === 0) throw new Error('Statechart harness mounted no transition')\n\tconst root = mount(build('div', { attributes: { [STATECHART_ATTRIBUTES.status]: 'pending' } }))\n\tconst announcer = build('p', { attributes: { role: 'status' } })\n\tconst state = build('p')\n\tconst rows = build('ol')\n\troot.append(announcer, state, rows)\n\t// Each row's element is kept beside the scenario it renders, so a run reaches its own row by\n\t// identity rather than by an index into a live collection or by a name the table may repeat.\n\tconst table = scenarios.map((scenario) => ({\n\t\tscenario,\n\t\telement: build('li', {\n\t\t\ttext: `${scenario.transition.name}: ${scenario.transition.from} on ${scenario.transition.event} becomes ${scenario.transition.to}`,\n\t\t\tattributes: { [STATECHART_ATTRIBUTES.scenario]: scenario.transition.name },\n\t\t}),\n\t}))\n\tfor (const row of table) rows.append(row.element)\n\troot.setAttribute(STATECHART_ATTRIBUTES.total, String(table.length))\n\troot.setAttribute(STATECHART_ATTRIBUTES.passed, '0')\n\troot.setAttribute(STATECHART_ATTRIBUTES.failed, '0')\n\troot.setAttribute(STATECHART_ATTRIBUTES.status, 'idle')\n\tannouncer.textContent = `Statechart harness is idle, 0 passed and 0 failed of ${table.length}.`\n\treturn {\n\t\troot,\n\t\tget status() {\n\t\t\tconst written = root.getAttribute(STATECHART_ATTRIBUTES.status)\n\t\t\treturn requireValue(\n\t\t\t\tSTATECHART_STATUSES.find((member) => member === written),\n\t\t\t\t'Statechart harness carries no status',\n\t\t\t)\n\t\t},\n\t\tget total() {\n\t\t\treturn Number(root.getAttribute(STATECHART_ATTRIBUTES.total))\n\t\t},\n\t\tget passed() {\n\t\t\treturn Number(root.getAttribute(STATECHART_ATTRIBUTES.passed))\n\t\t},\n\t\tget failed() {\n\t\t\treturn Number(root.getAttribute(STATECHART_ATTRIBUTES.failed))\n\t\t},\n\t\tget failures() {\n\t\t\tconst names: string[] = []\n\t\t\tfor (const row of table) {\n\t\t\t\tif (row.element.getAttribute(STATECHART_ATTRIBUTES.result) !== 'failed') continue\n\t\t\t\tconst name = row.element.getAttribute(STATECHART_ATTRIBUTES.scenario)\n\t\t\t\tif (name !== null) names.push(name)\n\t\t\t}\n\t\t\treturn names\n\t\t},\n\t\tasync execute() {\n\t\t\tfor (const row of table) row.element.removeAttribute(STATECHART_ATTRIBUTES.result)\n\t\t\tstate.removeAttribute(STATECHART_ATTRIBUTES.state)\n\t\t\tstate.textContent = ''\n\t\t\tlet passed = 0\n\t\t\tlet failed = 0\n\t\t\troot.setAttribute(STATECHART_ATTRIBUTES.passed, '0')\n\t\t\troot.setAttribute(STATECHART_ATTRIBUTES.failed, '0')\n\t\t\troot.setAttribute(STATECHART_ATTRIBUTES.status, 'running')\n\t\t\tannouncer.textContent = `Statechart harness is running, 0 passed and 0 failed of ${table.length}.`\n\t\t\ttry {\n\t\t\t\tfor (const [index, row] of table.entries()) {\n\t\t\t\t\t// The box's presence is what \"the builder returned\" means, so a context of `undefined`\n\t\t\t\t\t// runs its phases like any other and only a refused build skips them.\n\t\t\t\t\tlet built: { readonly context: TContext } | undefined\n\t\t\t\t\tlet refusal: string | undefined\n\t\t\t\t\ttry {\n\t\t\t\t\t\tbuilt = { context: await options.build(row.scenario) }\n\t\t\t\t\t} catch (cause) {\n\t\t\t\t\t\trefusal = buildRefusal(row.scenario.transition.name, cause).message\n\t\t\t\t\t}\n\t\t\t\t\tif (built !== undefined) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait executeScenario(row.scenario, built.context)\n\t\t\t\t\t\t} catch (cause) {\n\t\t\t\t\t\t\t// `executeScenario` raises an `Error` for every failing phase, so anything else\n\t\t\t\t\t\t\t// came from outside this contract and is the caller's to see unchanged.\n\t\t\t\t\t\t\tif (!isError(cause)) throw cause\n\t\t\t\t\t\t\trefusal = cause.message\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst current = options.state(built.context)\n\t\t\t\t\t\tstate.setAttribute(STATECHART_ATTRIBUTES.state, current)\n\t\t\t\t\t\tstate.textContent = current\n\t\t\t\t\t}\n\t\t\t\t\tif (refusal === undefined) passed += 1\n\t\t\t\t\telse failed += 1\n\t\t\t\t\trow.element.setAttribute(\n\t\t\t\t\t\tSTATECHART_ATTRIBUTES.result,\n\t\t\t\t\t\trefusal === undefined ? 'passed' : 'failed',\n\t\t\t\t\t)\n\t\t\t\t\troot.setAttribute(STATECHART_ATTRIBUTES.passed, String(passed))\n\t\t\t\t\troot.setAttribute(STATECHART_ATTRIBUTES.failed, String(failed))\n\t\t\t\t\tannouncer.textContent = refusal ?? `${row.scenario.transition.name} passed.`\n\t\t\t\t\tif (options.pause !== undefined && index < table.length - 1) {\n\t\t\t\t\t\tawait waitForDelay(options.pause)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (cause) {\n\t\t\t\t// A gate outside the page has no rejection channel, so an exceptional exit publishes the\n\t\t\t\t// terminal reading before the value leaves by identity. The row is not counted as failed:\n\t\t\t\t// a reader's defect is not the entity's. A completed run never reaches this, which is why\n\t\t\t\t// the write is here rather than in a `finally`.\n\t\t\t\troot.setAttribute(STATECHART_ATTRIBUTES.status, 'failed')\n\t\t\t\tannouncer.textContent = `Statechart harness failed, ${passed} passed and ${failed} failed of ${table.length}.`\n\t\t\t\tthrow cause\n\t\t\t}\n\t\t\tconst outcome = failed === 0 ? 'passed' : 'failed'\n\t\t\troot.setAttribute(STATECHART_ATTRIBUTES.status, outcome)\n\t\t\tannouncer.textContent = `Statechart harness ${outcome}, ${passed} passed and ${failed} failed of ${table.length}.`\n\t\t},\n\t\tdestroy() {\n\t\t\troot.remove()\n\t\t},\n\t}\n}\n"],"mappings":"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"}
|