feat: fillField works with role=combobox widgets - #5701
Closed
DavertMik wants to merge 1 commit into
Closed
Conversation
fillField now handles comboboxes whose trigger is not a text field — a `<button role="combobox">` (shadcn, Base UI), a `<div role="combobox">`, or a readonly input trigger. The widget is expanded, its search input is located, and the value is typed there, leaving the list filtered so an option can be picked with a following click. Locating the input walks: an editable descendant of the trigger, the `aria-controls`/`aria-owns` container, a visible dialog/listbox popup, then the focused element. Focus lands asynchronously after the click (~80ms in Base UI), so the search is polled to a 1s deadline rather than sampled once. The element focused before the click is excluded, so a previously focused field never receives the keystrokes. A combobox with no text input raises an error pointing at selectOption. Also fixes Locator.field matching an aria-hidden proxy input. Base UI points `<label for>` at a visually hidden form-value input rather than at the trigger, so fillField typed into an invisible field and passed while the app saw nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ut1rjeUiZmKU7V61CeYhns
This was referenced Sep 8, 2026
Contributor
Author
|
Absoltely terrible code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
I.fillField('Country', 'Ukr')does not work against comboboxes whose trigger is not a text field — the shadcn / Base UI pattern where a<button role="combobox">opens a popup containing the search input.Worse, against Base UI it silently passes while doing nothing. Base UI renders:
The
<label for>points at the aria-hidden form-value proxy, not at the trigger.Locator.field.labelEqualsis tried first infindFieldsand matches that proxy, sofillFieldtypes into a zero-size invisible input and the step resolves green while the app never sees the interaction.What changed
Locator.fieldskips aria-hidden proxies (lib/locator.js) — one predicate added to theinput | textarea | selectbranches of all four builders, so all three helpers are fixed in one place. With the proxy filtered, resolution falls through tolabelContains→aria-labelledby→ the trigger.fillFieldhandles combobox triggers (lib/helper/extras/comboBox.js) — a<button role="combobox">, a<div role="combobox">, or a readonly input trigger is expanded, its search input located, and the value typed there. The popup is left open and filtered so an option can be picked:Locating the input walks, in order: an editable descendant of the trigger (ARIA 1.1 wrapper, no click needed), the
aria-controls/aria-ownscontainer, a visible[role=dialog]/[role=listbox]popup, then the focused element. Two details are measured rather than assumed:click()resolves in Base UI (pointerdown t=0 → click t=3 → focusin t=82), so the search is polled to a 1s deadline instead of sampled once.A combobox exposing no text input raises
combobox exposes no text input to type into. Use I.selectOption() to pick one of its options.rather than typing into nothing.role="combobox"inputs (Base UI inline, MUI, Downshift) also route through this path, so they are typed with real keystrokes rather than a one-shotfill()— comboboxes that filter onkeydownneed that.Detection reuses the single
evaluatethatrichTextEditoralready runs perfillField, so no extra round-trip is added to ordinary fills.Tests
New belt in
test/helper/webapi.js, so it runs against Playwright, Puppeteer and WebDriver — mirroring the rich-editor belt. Fixtures load Base UI 1.0.0-rc.0 from CDN with no build step (test/data/app/view/form/combobox/), covering the button trigger, the inline input, andcustom_select.phpas the negative case.Each variant asserts: typing filters the options, the picked option submits, a pre-populated value is rewritten, and keystrokes do not leak to an outer focused input.
Locator.fieldgets unit tests intest/unit/locator_test.js.Local: 9/9 combobox belt on Playwright and Puppeteer, 75/75
fillFieldon Playwright (rich editors included, no regressions), 15/15selectOption, 772 unit tests. WebDriver has no local server here — relying on CI.Note for review:
test/data/app/view/form/combobox/*pull React and Base UI from esm.sh, a CDN this repo has not used before (existing fixtures use jsdelivr). Versions are pinned exactly.🤖 Generated with Claude Code
https://claude.ai/code/session_01Ut1rjeUiZmKU7V61CeYhns