fix(userEvent): add unfocused tab fallbacks for keyboard(), clear() and blur#210
Merged
Merged
Conversation
…nd blur
In unfocused/hidden browser tabs (common during twd-relay AI runs),
userEvent.keyboard() was a no-op for all non-Tab keys and blur validation
never fired after Tab, causing flaky test failures like the combobox
pointer-events: none cascade.
Two root causes fixed:
1. typingFallback now explicitly dispatches focus/focusin after
element.focus(). Browsers suppress these events in unfocused tabs, so
React's event delegation (which relies on bubbling focusin) never
registered the element as focused — meaning focusout from keyboard("{Tab}")
produced no synthetic onBlur and validation never ran.
2. keyboard() fallback now handles the full key string instead of only "{Tab}":
- Regular characters are buffered and flushed via typingFallback
(native setter + input/change events)
- Arrow keys, Enter, Escape etc. dispatch real keydown/keyup events
- Backspace trims the current value
This fixes combobox patterns like keyboard("Spain{arrowdown}{enter}")
that were silently dropped, leaving dropdowns open and blocking clicks.
Covered by:
- 3 new Vitest unit tests (verified RED before fix, GREEN after)
- 2 new twd-test-app integration scenarios using window.blur() to reproduce
the unfocused condition: blur-validation (Tab case) and combobox-select
(arrow+enter case)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
Summary
typingFallbacknow explicitly dispatchesfocus/focusinafterelement.focus(). Browsers suppress these events in unfocused tabs so React's event delegation never registered the element as focused — meaningfocusoutfromkeyboard("{Tab}")produced no syntheticonBlurand blur-triggered validation (e.g. React Hook Form) never ran.keyboard()fallback now handles the full key string instead of only{Tab}: regular characters are buffered and flushed viatypingFallback(native setter +input/changeevents); arrow keys,Enter,Escapeetc. dispatch realkeydown/keyupevents;{Backspace}trims the value. This fixes combobox patterns likekeyboard("Spain{arrowdown}{enter}")that were silently dropped, leaving dropdowns open and blocking subsequent clicks (pointer-events: nonecascade).Test Plan
npm test src/tests/proxies/userEvent.spec.ts)npm run test:ci)examples/twd-test-app: new/blur-validationpage + test —window.blur()→type→clear→keyboard("{Tab}")→ validatesaria-describedbyis setexamples/twd-test-app: new/combobox-selectpage + test —window.blur()→clicktrigger →keyboard("Spain{arrowdown}{enter}")→ validates selected country shown🤖 Generated with Claude Code