Skip to content

Commit 3e4497e

Browse files
authored
Update Pressable props (#4421)
## 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.
1 parent 4bc2dec commit 3e4497e

7 files changed

Lines changed: 88 additions & 6 deletions

File tree

packages/react-native-gesture-handler/src/__tests__/mocks.test.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,51 @@ test('Pressable exposes its press handlers to testing-library', () => {
173173
expect(button.props.testOnly_onPressOut).toBe(onPressOut);
174174
expect(button.props.testOnly_onLongPress).toBe(onLongPress);
175175
});
176+
177+
test('Pressable exposes its hover handlers to testing-library', () => {
178+
const onHoverIn = jest.fn();
179+
const onHoverOut = jest.fn();
180+
181+
render(
182+
<GestureHandlerRootView>
183+
<Pressable
184+
testID="pressable"
185+
onHoverIn={onHoverIn}
186+
onHoverOut={onHoverOut}>
187+
<Text>Hover Me</Text>
188+
</Pressable>
189+
</GestureHandlerRootView>
190+
);
191+
192+
const button = screen.getByTestId('pressable');
193+
194+
expect(button.props.testOnly_onHoverIn).toBe(onHoverIn);
195+
expect(button.props.testOnly_onHoverOut).toBe(onHoverOut);
196+
});
197+
198+
test('StatefulPressable exposes its press and hover handlers to testing-library', () => {
199+
// A relation prop routes `Pressable` to the `StatefulPressable` engine,
200+
// which has to forward the same `testOnly_*` props as the default engine.
201+
const onPress = jest.fn();
202+
const onHoverIn = jest.fn();
203+
const onHoverOut = jest.fn();
204+
205+
render(
206+
<GestureHandlerRootView>
207+
<Pressable
208+
testID="pressable"
209+
simultaneousWith={[]}
210+
onPress={onPress}
211+
onHoverIn={onHoverIn}
212+
onHoverOut={onHoverOut}>
213+
<Text>Press Me</Text>
214+
</Pressable>
215+
</GestureHandlerRootView>
216+
);
217+
218+
const button = screen.getByTestId('pressable');
219+
220+
expect(button.props.testOnly_onPress).toBe(onPress);
221+
expect(button.props.testOnly_onHoverIn).toBe(onHoverIn);
222+
expect(button.props.testOnly_onHoverOut).toBe(onHoverOut);
223+
});

packages/react-native-gesture-handler/src/components/GestureButtonsProps.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,20 @@ export interface LegacyRawButtonProps
9393
*/
9494
// eslint-disable-next-line @typescript-eslint/ban-types
9595
testOnly_onLongPress?: Function | null | undefined;
96+
97+
/**
98+
* Used for testing-library compatibility, not passed to the native component.
99+
* @deprecated test-only props are deprecated and will be removed in the future.
100+
*/
101+
// eslint-disable-next-line @typescript-eslint/ban-types
102+
testOnly_onHoverIn?: Function | null | undefined;
103+
104+
/**
105+
* Used for testing-library compatibility, not passed to the native component.
106+
* @deprecated test-only props are deprecated and will be removed in the future.
107+
*/
108+
// eslint-disable-next-line @typescript-eslint/ban-types
109+
testOnly_onHoverOut?: Function | null | undefined;
96110
}
97111
interface ButtonWithRefProps {
98112
innerRef?: React.Ref<React.ComponentType<any>> | undefined;

packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,20 @@ export interface ButtonProps extends ViewProps, AccessibilityProps {
264264
*/
265265
// eslint-disable-next-line @typescript-eslint/ban-types
266266
testOnly_onLongPress?: Function | null | undefined;
267+
268+
/**
269+
* Used for testing-library compatibility, not passed to the native component.
270+
* @deprecated test-only props are deprecated and will be removed in the future.
271+
*/
272+
// eslint-disable-next-line @typescript-eslint/ban-types
273+
testOnly_onHoverIn?: Function | null | undefined;
274+
275+
/**
276+
* Used for testing-library compatibility, not passed to the native component.
277+
* @deprecated test-only props are deprecated and will be removed in the future.
278+
*/
279+
// eslint-disable-next-line @typescript-eslint/ban-types
280+
testOnly_onHoverOut?: Function | null | undefined;
267281
}
268282

269283
export const ButtonComponent =

packages/react-native-gesture-handler/src/components/Pressable/Pressable.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,9 @@ const LegacyPressable = (props: LegacyPressableProps) => {
399399
testOnly_onPress={IS_TEST_ENV ? onPress : undefined}
400400
testOnly_onPressIn={IS_TEST_ENV ? onPressIn : undefined}
401401
testOnly_onPressOut={IS_TEST_ENV ? onPressOut : undefined}
402-
testOnly_onLongPress={IS_TEST_ENV ? onLongPress : undefined}>
402+
testOnly_onLongPress={IS_TEST_ENV ? onLongPress : undefined}
403+
testOnly_onHoverIn={IS_TEST_ENV ? onHoverIn : undefined}
404+
testOnly_onHoverOut={IS_TEST_ENV ? onHoverOut : undefined}>
403405
{childrenProp}
404406
{__DEV__ ? (
405407
<PressabilityDebugView color="red" hitSlop={normalizedHitSlop} />

packages/react-native-gesture-handler/src/components/Pressable/PressableProps.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,19 @@ export interface PressableProps extends CommonPressableProps {
5858
* A gesture object or an array of gesture objects containing the configuration and callbacks to be
5959
* used with the Pressable's gesture handlers.
6060
*/
61-
simultaneousWith?: AnyGesture;
61+
simultaneousWith?: AnyGesture | AnyGesture[];
6262

6363
/**
6464
* A gesture object or an array of gesture objects containing the configuration and callbacks to be
6565
* used with the Pressable's gesture handlers.
6666
*/
67-
requireToFail?: AnyGesture;
67+
requireToFail?: AnyGesture | AnyGesture[];
6868

6969
/**
7070
* A gesture object or an array of gesture objects containing the configuration and callbacks to be
7171
* used with the Pressable's gesture handlers.
7272
*/
73-
block?: AnyGesture;
73+
block?: AnyGesture | AnyGesture[];
7474
}
7575

7676
interface CommonPressableProps

packages/react-native-gesture-handler/src/v3/components/PressableWithTouchable.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,9 @@ const PressableWithTouchable = (props: PressableProps) => {
321321
testOnly_onPress={IS_TEST_ENV ? onPress : undefined}
322322
testOnly_onPressIn={IS_TEST_ENV ? onPressIn : undefined}
323323
testOnly_onPressOut={IS_TEST_ENV ? onPressOut : undefined}
324-
testOnly_onLongPress={IS_TEST_ENV ? onLongPress : undefined}>
324+
testOnly_onLongPress={IS_TEST_ENV ? onLongPress : undefined}
325+
testOnly_onHoverIn={IS_TEST_ENV ? onHoverIn : undefined}
326+
testOnly_onHoverOut={IS_TEST_ENV ? onHoverOut : undefined}>
325327
{resolvedChildren}
326328
{__DEV__ ? (
327329
<PressabilityDebugView color="red" hitSlop={normalizedHitSlop} />

packages/react-native-gesture-handler/src/v3/components/StatefulPressable.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,9 @@ const StatefulPressable = (props: PressableProps) => {
463463
testOnly_onPress={IS_TEST_ENV ? onPress : undefined}
464464
testOnly_onPressIn={IS_TEST_ENV ? onPressIn : undefined}
465465
testOnly_onPressOut={IS_TEST_ENV ? onPressOut : undefined}
466-
testOnly_onLongPress={IS_TEST_ENV ? onLongPress : undefined}>
466+
testOnly_onLongPress={IS_TEST_ENV ? onLongPress : undefined}
467+
testOnly_onHoverIn={IS_TEST_ENV ? onHoverIn : undefined}
468+
testOnly_onHoverOut={IS_TEST_ENV ? onHoverOut : undefined}>
467469
{childrenProp}
468470
{__DEV__ ? (
469471
<PressabilityDebugView color="red" hitSlop={normalizedHitSlop} />

0 commit comments

Comments
 (0)