// What an e2e locator SELECTS, as a value, plus the one in-page expression that resolves it. // `locator`/`getByRole`/`getByText` are lazy handles, so the selection has to survive as data // until something asks a question about it — and only then does it become a string the browser // can run. /** Where the driver parks its click target. Removed again as soon as the click has been made. */ export const MARK_ATTRIBUTE = 'data-x-e2e'; /** One selection, exactly as the test spelled it. `first` is `.first()`, applied at resolve time. */ export type E2eSelection = | { readonly kind: 'css'; readonly selector: string; readonly first: boolean } | { readonly kind: 'role'; readonly role: string; readonly name?: string | undefined; readonly level?: number | undefined; readonly first: boolean; } | { readonly kind: 'text'; readonly text: string; readonly first: boolean }; /** * What the page answers for one selection. `count` is how many elements matched AFTER `first` * narrowed it, `visible` is about the first match alone, and `marked` says the click target now * carries `MARK_ATTRIBUTE` — three facts in one round trip, because a locator that asked twice * could be answered about two different renders. */ export interface E2eResolution { readonly count: number; readonly visible: boolean; readonly marked: boolean; } /** * The elements that carry a role IMPLICITLY, so `getByRole('button')` finds a `