Forward press handlers as testOnly_* in PressableWithTouchable - #4416
Conversation
`Pressable` dispatches to `StatefulPressable` when a relation prop is passed and to `PressableWithTouchable` otherwise. Only the former sets `testOnly_onPress`/`onPressIn`/`onPressOut`/`onLongPress` on the button, so in the common case (no relation props) React Native Testing Library finds no handler and `fireEvent(element, 'press')` silently does nothing. The press state machine runs natively, so a test environment has no other way to reach the handlers. Forward them from `PressableWithTouchable` too, guarded by `isTestEnv()`, exactly as `StatefulPressable` does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughSummary by CodeRabbit
WalkthroughChangesPressable test callback forwarding
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR fixes a testing regression in the v3 Pressable implementation where the common (relation-free) engine (PressableWithTouchable) did not forward press handlers via testOnly_* props, preventing React Native Testing Library from reaching user handlers in a Jest environment.
Changes:
- Forward
onPress/onPressIn/onPressOut/onLongPressfromPressableWithTouchableonto the underlying button astestOnly_*props, gated byisTestEnv(). - Add a Jest regression test asserting these
testOnly_*props are present for a relation-free v3Pressable.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| packages/react-native-gesture-handler/src/v3/components/PressableWithTouchable.tsx | Adds isTestEnv() gating and forwards testOnly_* handler props in the Touchable-based v3 Pressable engine. |
| packages/react-native-gesture-handler/src/tests/mocks.test.tsx | Adds a regression test verifying v3 Pressable exposes the four testOnly_* handler props on the rendered button. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
## Description Follow-up to #4416. None of the `Pressable` engines forwarded hover handlers as `testOnly_*` props, so `fireEvent(element, 'hoverIn')` from React Native Testing Library had no way to reach `onHoverIn`/`onHoverOut`. RNTL resolves `testOnly_on{EventName}` generically for any event, so exposing the props is all that's needed. This adds `testOnly_onHoverIn`/`testOnly_onHoverOut` to the button props and forwards them, guarded by `isTestEnv()`, from all three engines: legacy `Pressable`, `StatefulPressable` and `PressableWithTouchable`. Also widens the relation props (`simultaneousWith`/`requireToFail`/`block`) from `AnyGesture` to `AnyGesture | AnyGesture[]`. The JSDoc already promises a gesture object or an array of gesture objects and the runtime handles arrays in both directions (`relationUtils` flattens them into handler tags and pushes the symmetric relation onto each array element), only the prop type was narrowed. ## Test plan Added tests in `src/__tests__/mocks.test.tsx` asserting the hover props are wired on the button for both v3 engines — relation-free and routed to `StatefulPressable` via `simultaneousWith={[]}` (which the type widening makes legal). Both fail without the engine changes. In `packages/react-native-gesture-handler`: `yarn test`, `yarn ts-check` and `yarn lint:js` pass.
…4416) ## Description Fixes #4417. Since 3.2.0, `Pressable` dispatches between two engines: `StatefulPressable` when one of the relation props (`simultaneousWith` / `requireToFail` / `block`) is passed, and `PressableWithTouchable` otherwise — the common case. Only `StatefulPressable` sets `testOnly_onPress` / `testOnly_onPressIn` / `testOnly_onPressOut` / `testOnly_onLongPress` on the button. `PressableWithTouchable` doesn't, so for a plain `<Pressable onPress={...}>` React Native Testing Library finds no handler and `fireEvent(element, 'press')` silently does nothing. The press state machine runs natively, so in a test environment those props are the only way to reach the handlers. This makes the regression silent and fairly wide-reaching: no error is thrown, tests just stop observing presses. On 3.1.0 the single v3 `Pressable` always forwarded them, so this is a 3.1.0 → 3.2.0 regression for any app whose Jest suite drives a `Pressable`. The fix forwards the four handlers from `PressableWithTouchable` too, guarded by `isTestEnv()`, exactly as `StatefulPressable` does. `Touchable` spreads its remaining props onto `GestureHandlerButton`, which already declares them in `ButtonProps`, so nothing else needed to change and the props stay stripped outside a test environment. Note this is unrelated to #4414, which fixed the `testOnly_pressed` display state. ## Test plan Added a regression test in `src/__tests__/mocks.test.tsx` asserting the four `testOnly_*` props are wired on the button for a relation-free `Pressable`. It fails on `main` and passes with the fix. The test asserts the props rather than calling `fireEvent(element, 'press')` because this repo is on `@testing-library/react-native@12.9`, which predates the `testOnly_*` handler lookup (added in v13). Asserting the props keeps the test meaningful on the pinned version and independent of the RNTL version. In `packages/react-native-gesture-handler`: - `yarn test` — 16 suites, 135 tests passing - `yarn ts-check` — clean - `yarn lint:js` — 0 errors - `yarn format:js` — clean Also verified end-to-end in a real app (Expo 57 / RN 0.86, RNTL 14.0.1) that had ~3 suites broken by the 3.1.0 → 3.2.0 bump: with this change applied as a patch, the full suite is green again (136 suites, 1663 tests, 73 snapshots). Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
## Description Follow-up to #4416. None of the `Pressable` engines forwarded hover handlers as `testOnly_*` props, so `fireEvent(element, 'hoverIn')` from React Native Testing Library had no way to reach `onHoverIn`/`onHoverOut`. RNTL resolves `testOnly_on{EventName}` generically for any event, so exposing the props is all that's needed. This adds `testOnly_onHoverIn`/`testOnly_onHoverOut` to the button props and forwards them, guarded by `isTestEnv()`, from all three engines: legacy `Pressable`, `StatefulPressable` and `PressableWithTouchable`. Also widens the relation props (`simultaneousWith`/`requireToFail`/`block`) from `AnyGesture` to `AnyGesture | AnyGesture[]`. The JSDoc already promises a gesture object or an array of gesture objects and the runtime handles arrays in both directions (`relationUtils` flattens them into handler tags and pushes the symmetric relation onto each array element), only the prop type was narrowed. ## Test plan Added tests in `src/__tests__/mocks.test.tsx` asserting the hover props are wired on the button for both v3 engines — relation-free and routed to `StatefulPressable` via `simultaneousWith={[]}` (which the type widening makes legal). Both fail without the engine changes. In `packages/react-native-gesture-handler`: `yarn test`, `yarn ts-check` and `yarn lint:js` pass.
…867) Bumps \[react-native-gesture-handler\](https://github.com/software-mansion/react-native-gesture-handler) from 2.32.0 to 3.2.1. Release notes _Sourced from [react-native-gesture-handler's releases](https://github.com/software-mansion/react-native-gesture-handler/releases)._ > v3.2.1 > ------ > > 🐛 Bug fixes > ------------ > > * Forward press handlers as `testOnly_*` in `PressableWithTouchable` by [`@huextrat`](https://github.com/huextrat) in [software-mansion/react-native-gesture-handler#4416](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4416) > > 🔢 Miscellaneous > ---------------- > > * Update `Pressable` props by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4421](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4421) > > **Full Changelog**: [https://github.com/software-mansion/react-native-gesture-handler/compare/v3.2.0...v3.2.1](https://github.com/software-mansion/react-native-gesture-handler/compare/v3.2.0...v3.2.1) > > v3.2.0 > ------ > > ❗ Important changes > ------------------- > > * feat: Adopt AGP v9 by [`@hurali97`](https://github.com/hurali97) in [software-mansion/react-native-gesture-handler#4263](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4263) > * Implement `Pressable` based on `Touchable` by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4411](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4411) > * \[Android\] Add hover callbacks to Touchable by [`@j-piasecki`](https://github.com/j-piasecki) in [software-mansion/react-native-gesture-handler#4396](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4396) > * \[iOS\] Add hover callbacks to Touchable by [`@j-piasecki`](https://github.com/j-piasecki) in [software-mansion/react-native-gesture-handler#4397](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4397) > * \[Web\] Add hover callbacks to Touchable by [`@j-piasecki`](https://github.com/j-piasecki) in [software-mansion/react-native-gesture-handler#4398](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4398) > * \[Web\] Refactor `Touchable` not to rely on `GestureDetector` by [`@j-piasecki`](https://github.com/j-piasecki) in [software-mansion/react-native-gesture-handler#4344](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4344) > * \[iOS\] Refactor `Touchable` not to rely on `GestureDetector` by [`@j-piasecki`](https://github.com/j-piasecki) in [software-mansion/react-native-gesture-handler#4343](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4343) > * \[Android\] Refactor `Touchable` not to rely on `GestureDetector` by [`@j-piasecki`](https://github.com/j-piasecki) in [software-mansion/react-native-gesture-handler#4342](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4342) > * Fix fatal crash `Cannot read property 'translationX' of undefined` when a touch event is serialized without `allTouches` by [`@huextrat`](https://github.com/huextrat) in [software-mansion/react-native-gesture-handler#4316](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4316) > > 👍 Improvements > --------------- > > * \[Android\] Skip the underlay drawable when it can never be visible by [`@j-piasecki`](https://github.com/j-piasecki) in [software-mansion/react-native-gesture-handler#4359](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4359) > * \[Android\] Apply the button's managed handler config once per prop transaction by [`@j-piasecki`](https://github.com/j-piasecki) in [software-mansion/react-native-gesture-handler#4357](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4357) > * \[Android\] Configure the button's handler directly instead of through a `ReadableMap` by [`@j-piasecki`](https://github.com/j-piasecki) in [software-mansion/react-native-gesture-handler#4358](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4358) > > 🐛 Bug fixes > ------------ > > * \[Android\] Guard update events to only be dispatched in ACTIVE state by [`@j-piasecki`](https://github.com/j-piasecki) in [software-mansion/react-native-gesture-handler#4332](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4332) > * Pass empty callbacks to UI when `runOnJS` is `true` by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4326](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4326) > * \[Web\] Fix incorrectly calculated `timeDelta` by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4329](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4329) > * \[Web\] Fix incorrect `Tap` offset by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4330](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4330) > * Fix `minVelocity` props behavior by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4327](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4327) > * \[Android\] Fix `minDistance` being reset by partial config updates by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4347](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4347) > * Move Interceptor on `ScrollView`, not its content by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4331](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4331) > * \[iOS\] Re-sync layer opacity and transform from retained props when recycling buttons by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4360](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4360) > * \[Android\] Properly handle `requestDisallowInterceptTouchEvent` for v3 by [`@j-piasecki`](https://github.com/j-piasecki) in [software-mansion/react-native-gesture-handler#4367](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4367) > * Fix `Touchable` not respecting `keyboardShouldPersistTaps="handled"` by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4372](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4372) > * \[macOS\] Fix touch events never being delivered by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4390](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4390) > * fix: crash when mount listener fires after GestureDetector unmount by [`@kosmydel`](https://github.com/kosmydel) in [software-mansion/react-native-gesture-handler#4268](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4268) > * \[macOS\] Fix `Pan` activation criteria being ignored by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4387](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4387) > * \[macOS\] Fix `manualActivation` never blocking gesture activation by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4389](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4389) > * \[iOS\] Fix touch events never being delivered to `VirtualDetector` handlers by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4392](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4392) > * \[iOS\] Fix gestures attached via `VirtualGestureDetector` never recognizing continuous gestures by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4393](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4393) > * \[macOS\] Fix `Fling` not sending touch events and begin/end states consistently by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4395](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4395) > * \[Android\] Fix handlers cancelled while awaiting leaking in the orchestrator by [`@m-bert`](https://github.com/m-bert) in [software-mansion/react-native-gesture-handler#4402](https://redirect.github.com/software-mansion/react-native-gesture-handler/pull/4402) ... (truncated) Commits * [`62f0f7d`](software-mansion/react-native-gesture-handler@62f0f7d) Release v3.2.1 * [`4716425`](software-mansion/react-native-gesture-handler@4716425) Merge branch '3.2-stable' of github.com:software-mansion/react-native-gesture... * [`f0ae48c`](software-mansion/react-native-gesture-handler@f0ae48c) Update `Pressable` props ([#4421](https://redirect.github.com/software-mansion/react-native-gesture-handler/issues/4421)) * [`5f0f0d8`](software-mansion/react-native-gesture-handler@5f0f0d8) Forward press handlers as `testOnly_*` in `PressableWithTouchable` ([#4416](https://redirect.github.com/software-mansion/react-native-gesture-handler/issues/4416)) * [`0a91db7`](software-mansion/react-native-gesture-handler@0a91db7) Release v3.2.0 * [`44046a6`](software-mansion/react-native-gesture-handler@44046a6) \[Android\] Resolve the button event dispatcher by react tag ([#4415](https://redirect.github.com/software-mansion/react-native-gesture-handler/issues/4415)) * [`2469c1d`](software-mansion/react-native-gesture-handler@2469c1d) Derive `Pressable` pressed state from `testOnly_pressed` ([#4414](https://redirect.github.com/software-mansion/react-native-gesture-handler/issues/4414)) * [`3f1bf74`](software-mansion/react-native-gesture-handler@3f1bf74) Clear pending timers on unmount in StatefulPressable ([#4413](https://redirect.github.com/software-mansion/react-native-gesture-handler/issues/4413)) * [`50ae6a1`](software-mansion/react-native-gesture-handler@50ae6a1) \[General\] Default GestureDetector moduleId to -1 ([#4412](https://redirect.github.com/software-mansion/react-native-gesture-handler/issues/4412)) * [`8b661c9`](software-mansion/react-native-gesture-handler@8b661c9) Implement `Pressable` based on `Touchable` ([#4411](https://redirect.github.com/software-mansion/react-native-gesture-handler/issues/4411)) * Additional commits viewable in [compare view](software-mansion/react-native-gesture-handler@v2.32.0...v3.2.1)
Description
Fixes #4417.
Since 3.2.0,
Pressabledispatches between two engines:StatefulPressablewhen one of therelation props (
simultaneousWith/requireToFail/block) is passed, andPressableWithTouchableotherwise — the common case.Only
StatefulPressablesetstestOnly_onPress/testOnly_onPressIn/testOnly_onPressOut/testOnly_onLongPresson the button.PressableWithTouchabledoesn't, so for a plain<Pressable onPress={...}>React Native Testing Library finds no handler andfireEvent(element, 'press')silently does nothing.The press state machine runs natively, so in a test environment those props are the only way to
reach the handlers. This makes the regression silent and fairly wide-reaching: no error is
thrown, tests just stop observing presses. On 3.1.0 the single v3
Pressablealways forwardedthem, so this is a 3.1.0 → 3.2.0 regression for any app whose Jest suite drives a
Pressable.The fix forwards the four handlers from
PressableWithTouchabletoo, guarded byisTestEnv(),exactly as
StatefulPressabledoes.Touchablespreads its remaining props ontoGestureHandlerButton, which already declares them inButtonProps, so nothing else needed tochange and the props stay stripped outside a test environment.
Note this is unrelated to #4414, which fixed the
testOnly_presseddisplay state.Test plan
Added a regression test in
src/__tests__/mocks.test.tsxasserting the fourtestOnly_*propsare wired on the button for a relation-free
Pressable. It fails onmainand passes with thefix.
The test asserts the props rather than calling
fireEvent(element, 'press')because this repo ison
@testing-library/react-native@12.9, which predates thetestOnly_*handler lookup (added inv13). Asserting the props keeps the test meaningful on the pinned version and independent of the
RNTL version.
In
packages/react-native-gesture-handler:yarn test— 16 suites, 135 tests passingyarn ts-check— cleanyarn lint:js— 0 errorsyarn format:js— cleanAlso verified end-to-end in a real app (Expo 57 / RN 0.86, RNTL 14.0.1) that had ~3 suites broken
by the 3.1.0 → 3.2.0 bump: with this change applied as a patch, the full suite is green again
(136 suites, 1663 tests, 73 snapshots).