Skip to content

Commit bd78a26

Browse files
fix: RN Gesture Handler Pressable support (#1746)
1 parent a9c056b commit bd78a26

File tree

10 files changed

+222
-72
lines changed

10 files changed

+222
-72
lines changed

examples/basic/components/__tests__/AnimatedView.test.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('AnimatedView', () => {
2020
);
2121
expect(screen.root).toHaveStyle({ opacity: 0 });
2222

23-
await act(() => jest.advanceTimersByTime(250));
23+
act(() => jest.advanceTimersByTime(250));
2424
expect(screen.root).toHaveStyle({ opacity: 1 });
2525
});
2626

@@ -32,7 +32,7 @@ describe('AnimatedView', () => {
3232
);
3333
expect(screen.root).toHaveStyle({ opacity: 0 });
3434

35-
await act(() => jest.advanceTimersByTime(250));
35+
act(() => jest.advanceTimersByTime(250));
3636
expect(screen.root).toHaveStyle({ opacity: 1 });
3737
});
3838
});

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"chalk": "^4.1.2",
5151
"jest-matcher-utils": "^29.7.0",
5252
"pretty-format": "^29.7.0",
53+
"react-native-gesture-handler": "^2.23.1",
5354
"redent": "^3.0.0"
5455
},
5556
"peerDependencies": {

src/__tests__/react-native-animated.test.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -43,28 +43,28 @@ describe('AnimatedView', () => {
4343
jest.useRealTimers();
4444
});
4545

46-
it('should use native driver when useNativeDriver is true', async () => {
46+
it('should use native driver when useNativeDriver is true', () => {
4747
render(
4848
<AnimatedView fadeInDuration={250} useNativeDriver={true}>
4949
Test
5050
</AnimatedView>,
5151
);
5252
expect(screen.root).toHaveStyle({ opacity: 0 });
5353

54-
await act(() => jest.advanceTimersByTime(250));
54+
act(() => jest.advanceTimersByTime(250));
5555
// This stopped working in tests in RN 0.77
5656
// expect(screen.root).toHaveStyle({ opacity: 0 });
5757
});
5858

59-
it('should not use native driver when useNativeDriver is false', async () => {
59+
it('should not use native driver when useNativeDriver is false', () => {
6060
render(
6161
<AnimatedView fadeInDuration={250} useNativeDriver={false}>
6262
Test
6363
</AnimatedView>,
6464
);
6565
expect(screen.root).toHaveStyle({ opacity: 0 });
6666

67-
await act(() => jest.advanceTimersByTime(250));
67+
act(() => jest.advanceTimersByTime(250));
6868
expect(screen.root).toHaveStyle({ opacity: 1 });
6969
});
7070
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import 'react-native-gesture-handler/jestSetup.js';
2+
import React from 'react';
3+
import { View } from 'react-native';
4+
import { Pressable } from 'react-native-gesture-handler';
5+
6+
import { fireEvent, render, screen, userEvent } from '..';
7+
import { createEventLogger, getEventsNames } from '../test-utils';
8+
9+
test('fireEvent can invoke press events for RNGH Pressable', () => {
10+
const onPress = jest.fn();
11+
const onPressIn = jest.fn();
12+
const onPressOut = jest.fn();
13+
const onLongPress = jest.fn();
14+
15+
render(
16+
<View>
17+
<Pressable
18+
testID="pressable"
19+
onPress={onPress}
20+
onPressIn={onPressIn}
21+
onPressOut={onPressOut}
22+
onLongPress={onLongPress}
23+
/>
24+
</View>,
25+
);
26+
27+
const pressable = screen.getByTestId('pressable');
28+
29+
fireEvent.press(pressable);
30+
expect(onPress).toHaveBeenCalled();
31+
32+
fireEvent(pressable, 'pressIn');
33+
expect(onPressIn).toHaveBeenCalled();
34+
35+
fireEvent(pressable, 'pressOut');
36+
expect(onPressOut).toHaveBeenCalled();
37+
38+
fireEvent(pressable, 'longPress');
39+
expect(onLongPress).toHaveBeenCalled();
40+
});
41+
42+
test('userEvent can invoke press events for RNGH Pressable', async () => {
43+
const { events, logEvent } = createEventLogger();
44+
const user = userEvent.setup();
45+
46+
render(
47+
<View>
48+
<Pressable
49+
testID="pressable"
50+
onPress={logEvent('press')}
51+
onPressIn={logEvent('pressIn')}
52+
onPressOut={logEvent('pressOut')}
53+
onLongPress={logEvent('longPress')}
54+
/>
55+
</View>,
56+
);
57+
58+
const pressable = screen.getByTestId('pressable');
59+
await user.press(pressable);
60+
expect(getEventsNames(events)).toEqual(['pressIn', 'pressOut', 'press']);
61+
});

src/user-event/press/__tests__/longPress.test.tsx

+33-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
2-
import { Pressable, Text, TouchableHighlight, TouchableOpacity } from 'react-native';
2+
import { Pressable, Text, TouchableHighlight, TouchableOpacity, View } from 'react-native';
3+
import type { ReactTestInstance } from 'react-test-renderer';
34

45
import { render, screen } from '../../..';
56
import { createEventLogger, getEventsNames } from '../../../test-utils';
@@ -152,4 +153,35 @@ describe('userEvent.longPress with fake timers', () => {
152153

153154
expect(mockOnLongPress).toHaveBeenCalled();
154155
});
156+
157+
test('longPress accepts custom duration', async () => {
158+
const { events, logEvent } = createEventLogger();
159+
const user = userEvent.setup();
160+
161+
render(
162+
<Pressable
163+
onPress={logEvent('press')}
164+
onPressIn={logEvent('pressIn')}
165+
onPressOut={logEvent('pressOut')}
166+
onLongPress={logEvent('longPress')}
167+
testID="pressable"
168+
/>,
169+
);
170+
171+
await user.longPress(screen.getByTestId('pressable'), { duration: 50 });
172+
expect(getEventsNames(events)).toEqual(['pressIn', 'press', 'pressOut']);
173+
});
174+
175+
it('longPress throws on composite components', async () => {
176+
render(<View testID="view" />);
177+
const user = userEvent.setup();
178+
179+
const compositeView = screen.getByTestId('view').parent as ReactTestInstance;
180+
await expect(user.longPress(compositeView)).rejects.toThrowErrorMatchingInlineSnapshot(`
181+
"longPress() works only with host elements. Passed element has type "function Component() {
182+
(0, _classCallCheck2.default)(this, Component);
183+
return _callSuper(this, Component, arguments);
184+
}"."
185+
`);
186+
});
155187
});

src/user-event/press/__tests__/press.real-timers.test.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ describe('userEvent.press with real timers', () => {
3434
);
3535

3636
await user.press(screen.getByTestId('pressable'));
37+
// Typical event order is pressIn, pressOut, press
38+
// But sometimes due to a race condition, the order is pressIn, press, pressOut.
3739
const eventSequence = getEventsNames(events).join(', ');
3840
expect(
3941
eventSequence === 'pressIn, pressOut, press' || eventSequence === 'pressIn, press, pressOut',
@@ -201,11 +203,11 @@ describe('userEvent.press with real timers', () => {
201203
);
202204
await user.press(screen.getByTestId('pressable'));
203205

204-
const eventsNames = getEventsNames(events).join(', ');
206+
const eventSequence = getEventsNames(events).join(', ');
205207
// Typical event order is pressIn, pressOut, press
206208
// But sometimes due to a race condition, the order is pressIn, press, pressOut.
207209
expect(
208-
eventsNames === 'pressIn, pressOut, press' || eventsNames === 'pressIn, press, pressOut',
210+
eventSequence === 'pressIn, pressOut, press' || eventSequence === 'pressIn, press, pressOut',
209211
).toBe(true);
210212
});
211213

src/user-event/press/__tests__/press.test.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
TouchableOpacity,
99
View,
1010
} from 'react-native';
11+
import type { ReactTestInstance } from 'react-test-renderer';
1112

1213
import { render, screen } from '../../..';
1314
import { createEventLogger, getEventsNames } from '../../../test-utils';
@@ -331,6 +332,19 @@ describe('userEvent.press with fake timers', () => {
331332
expect(mockOnPress).toHaveBeenCalled();
332333
});
333334

335+
it('press throws on composite components', async () => {
336+
render(<View testID="view" />);
337+
const user = userEvent.setup();
338+
339+
const compositeView = screen.getByTestId('view').parent as ReactTestInstance;
340+
await expect(user.press(compositeView)).rejects.toThrowErrorMatchingInlineSnapshot(`
341+
"press() works only with host elements. Passed element has type "function Component() {
342+
(0, _classCallCheck2.default)(this, Component);
343+
return _callSuper(this, Component, arguments);
344+
}"."
345+
`);
346+
});
347+
334348
test('disables act environmennt', async () => {
335349
// In this test there is state update during await when typing
336350
// Since wait is not wrapped by act there would be a warning

0 commit comments

Comments
 (0)