Skip to content

fix(user-event): include selection in TextInput change event#1919

Merged
mdjastrzebski merged 1 commit into
callstack:mainfrom
nsbarsukov:fix/userevent-change-selection
Jun 22, 2026
Merged

fix(user-event): include selection in TextInput change event#1919
mdjastrzebski merged 1 commit into
callstack:mainfrom
nsbarsukov:fix/userevent-change-selection

Conversation

@nsbarsukov

@nsbarsukov nsbarsukov commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

React Native (>=0.85) reports the caret position via onChange's nativeEvent.selection (see commits from react-native repo 162627a and c1f5445).

userEvent.type() did not include selection in the change event's nativeEvent — it computed a selectionRange (caret at the end of the current text) and emitted it only via a separate selectionChange event. As a result, components that read the caret from event.nativeEvent.selection inside their onChange handler (e.g. input-masking libraries) could not be driven by userEvent.type(...): they saw no selection, mishandled every keystroke, and the value never updated.

This PR folds the already-computed selectionRange into the change event so it matches the real platform shape, while keeping the separate selectionChange event unchanged.

Changes:

  • buildTextChangeEvent(text, selection) now includes selection: { start, end } in the change event's nativeEvent.
  • type() (emitTypingEvents) and paste() pass the caret range (end of the current/inserted text) into the change event. clear() inherits this via emitTypingEvents.
  • submitEditing / endEditing are left as-is — the platform does not report a selection on those events.

Test plan

  • yarn test — all suites pass (snapshots for type, type-managed, paste, and clear regenerated to include selection).
  • yarn typecheck, yarn lint, yarn format:check — all pass.
  • New/updated unit tests in src/user-event/type/__tests__/type.test.tsx:
    • Asserts that after userEvent.type(input, 'Hello'), the onChange handler receives an event whose nativeEvent.selection equals { start: 5, end: 5 }.
    • Regression test mounting a masking-style TextInput that reads e.nativeEvent.selection in onChange and only updates its value when the caret is present — confirms it is now correctly driven by userEvent.type().
  • Updated src/event-builder/__tests__/text.test.ts to assert selection is present in the built change-event payload.

React Native (>=0.85) reports caret position via onChange's
nativeEvent.selection on all platforms, but userEvent.type only
emitted it on a separate selectionChange event. Components that read
the caret inside onChange (e.g. input masks) could not be driven by
userEvent. Fold the computed selectionRange into the change event.
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.40%. Comparing base (e5e8e37) to head (08b5fed).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1919   +/-   ##
=======================================
  Coverage   98.40%   98.40%           
=======================================
  Files          79       79           
  Lines        1501     1501           
  Branches      414      398   -16     
=======================================
  Hits         1477     1477           
  Misses         24       24           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mdjastrzebski mdjastrzebski merged commit e819f77 into callstack:main Jun 22, 2026
29 checks passed
@mdjastrzebski

Copy link
Copy Markdown
Member

@nsbarsukov thank you for spotting this and providing a fix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants