You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browse filesBrowse the repository at this point in the historyBrowse files
authored
feat: checkOption finds checkables by ARIA role (#5704)
* feat: checkOption finds checkables by ARIA role
`checkOption('Accept terms')` failed on every headless component library.
Radix renders a checkbox as `<button role="checkbox" aria-checked>`, Base UI
as `<span role="checkbox">`; neither is an `<input>`, and all three strategies
in `Locator.checkable` hard-code `.//input[@type='checkbox' or @type='radio']`.
Playwright's `findCheckable` now runs a `getByRole('checkbox'|'radio'|'switch',
{ name })` pass — exact across the three roles first, then substring — mirroring
what `findClickable` already does for `button`/`link`. Native inputs expose
those roles too, so the pass is a superset of the XPath strategies it precedes.
`seeCheckboxIsChecked` / `dontSeeCheckboxIsChecked` route through the same
lookup and are fixed by it.
WebDriver and Puppeteer already had an ARIA fallback but ran it *after* the
label XPath, which is too late. Base UI renders a hidden mirror `<input>`, moves
the author's id onto it and points `<label for>` at it, so the label XPath
succeeds and resolves a 1x1 `aria-hidden` input at x:-1,y:-1 — the click is then
intercepted or reported outside the viewport. `aria-hidden` keeps that input out
of the accessibility tree, so the ARIA lookup lands on the visible control
instead. Both fallbacks now run before the label XPath.
Adds Radix and Base UI fixtures under /form/checkable and a shared spec block
asserting `aria-checked` flips on the visible element. Radix checkables stay
skipped on WebDriver: webdriverio's `aria/` selector resolves `<label for>` to
input/textarea only, and a Radix `<button role=checkbox>` has no accessible name
of its own.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TcwzSXPnfaig8nBZD2Vxfi
* fix: role-restrict the hoisted ARIA checkable lookup
Moving the accessible-name lookup above the label XPath fixed Base UI but
widened the net: `aria/…` and `::-p-aria(…)` match on name alone, so a heading
sharing a checkbox label's text now won on document order where `byText`
previously reached the input. Measured on the new collision fixture, both
returned `[H2, INPUT#terms-box]`.
Puppeteer loops the three checkable roles as `::-p-aria([name][role])`,
following the buildRoleSelector convention already in the file. `::-p-aria`
matches names exactly and case-sensitively, so one pass per role is enough;
a name that cannot be parsed falls through to the XPath as before.
WebDriver has no attribute filter on `aria/`, so its results are post-filtered
to `input[type=checkbox|radio]` and `[role=checkbox|radio|switch]` in a single
`browser.execute` round trip regardless of match count, using the
`execute(fn, ...elements)` form already used in the file.
Both now resolve `[INPUT#terms-box]`, matching Playwright's role-scoped pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TcwzSXPnfaig8nBZD2Vxfi
---------
Co-authored-by: DavertMik <davert@testomat.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
0 commit comments