Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/react-native-gesture-handler/jestSetup.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jest.mock('./lib/commonjs/RNGestureHandlerModule', () =>
require('./lib/commonjs/mocks/mocks')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Can this be renamed from mocks?
  2. I don't think it should contain anything more than the module methods. The old gesture handlers, gesture-wrapped components, and host detector should be separate and mocked to the correct files, no?

I think the current setup dates back to the time when all of Gesture Handler was a single file, so it was correct to mock everything to a single file.

);
jest.mock('./lib/commonjs/components/GestureButtons', () =>
require('./lib/commonjs/mocks/mocks')
require('./lib/commonjs/mocks/GestureButtons')
);
jest.mock('./lib/commonjs/components/Pressable', () =>
require('./lib/commonjs/mocks/Pressable')
Expand All @@ -18,7 +18,7 @@ jest.mock('./lib/module/RNGestureHandlerModule', () =>
require('./lib/module/mocks/mocks')
);
jest.mock('./lib/module/components/GestureButtons', () =>
require('./lib/module/mocks/mocks')
require('./lib/module/mocks/GestureButtons')
);
jest.mock('./lib/module/components/Pressable', () =>
require('./lib/module/mocks/Pressable')
Expand Down
125 changes: 125 additions & 0 deletions packages/react-native-gesture-handler/src/__tests__/Errors.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import React from 'react';
import { render, cleanup } from '@testing-library/react-native';
import {
Gesture,
GestureDetector,
GestureHandlerRootView,
InterceptingGestureDetector,
useTapGesture,
} from '../index';
import { findNodeHandle, View } from 'react-native';
import { VirtualDetector } from '../v3/detectors/VirtualDetector/VirtualDetector';

beforeEach(() => cleanup());
jest.mock('react-native/Libraries/ReactNative/RendererProxy', () => ({
findNodeHandle: jest.fn(),
}));

describe('VirtualDetector', () => {
test('virtual detector must be under InterceptingGestureDetector', () => {
function VirtualDetectorWithNoBoundary() {
const tap = useTapGesture({});
return (
<GestureHandlerRootView>
<VirtualDetector gesture={tap}>
<View />
</VirtualDetector>
</GestureHandlerRootView>
);
}

expect(() => render(<VirtualDetectorWithNoBoundary />)).toThrow(
'VirtualGestureDetector must be a descendant of an InterceptingGestureDetector'
);
});
test('virtual detector does not handle animated events', () => {
(findNodeHandle as jest.Mock).mockReturnValue(123);

function VirtualDetectorAnimated() {
const tap = useTapGesture({ useAnimated: true });
return (
<GestureHandlerRootView>
<InterceptingGestureDetector>
<VirtualDetector gesture={tap}>
<View />
</VirtualDetector>
</InterceptingGestureDetector>
</GestureHandlerRootView>
);
}

expect(() => render(<VirtualDetectorAnimated />)).toThrow(
'VirtualGestureDetector cannot handle Animated events with native driver when used inside InterceptingGestureDetector. Use Reanimated or Animated events without native driver instead.'
);
});

test('intercepting detector cant handle multiple types of events', () => {
(findNodeHandle as jest.Mock).mockReturnValue(123);
const mockWorklet = () => undefined;
mockWorklet.__workletHash = 123;

function InterceptingDetectorMultipleTypes() {
const tap = useTapGesture({ useAnimated: true });
const tap2 = useTapGesture({ onActivate: mockWorklet });
return (
<GestureHandlerRootView>
<InterceptingGestureDetector gesture={tap}>
<VirtualDetector gesture={tap2}>
<View />
</VirtualDetector>
</InterceptingGestureDetector>
</GestureHandlerRootView>
);
}

expect(() => render(<InterceptingDetectorMultipleTypes />)).toThrow(
'InterceptingGestureDetector can only handle either Reanimated or Animated events.'
);
});
});

describe('Check if descendant of root view', () => {
test('gesture detector', () => {
function GestureDetectorNoRootView() {
const tap = useTapGesture({});
return (
<GestureDetector gesture={tap}>
<View />
</GestureDetector>
);
}
expect(() => render(<GestureDetectorNoRootView />)).toThrow(
'GestureDetector must be used as a descendant of GestureHandlerRootView. Otherwise the gestures will not be recognized. See https://docs.swmansion.com/react-native-gesture-handler/docs/fundamentals/installation for more details.'
);
});

test('intercepting detector', () => {
function GestureDetectorNoRootView() {
const tap = useTapGesture({});
return (
<InterceptingGestureDetector gesture={tap}>
<View />
</InterceptingGestureDetector>
);
}

expect(() => render(<GestureDetectorNoRootView />)).toThrow(
'GestureDetector must be used as a descendant of GestureHandlerRootView. Otherwise the gestures will not be recognized. See https://docs.swmansion.com/react-native-gesture-handler/docs/fundamentals/installation for more details.'
);
});

test('legacy detector', () => {
function GestureDetectorNoRootView() {
const tap = Gesture.Tap();
return (
<GestureDetector gesture={tap}>
<View />
</GestureDetector>
);
}

expect(() => render(<GestureDetectorNoRootView />)).toThrow(
'GestureDetector must be used as a descendant of GestureHandlerRootView. Otherwise the gestures will not be recognized. See https://docs.swmansion.com/react-native-gesture-handler/docs/fundamentals/installation for more details.'
);
});
});
10 changes: 10 additions & 0 deletions packages/react-native-gesture-handler/src/mocks/GestureButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { TouchableNativeFeedback, View } from 'react-native';
export const RawButton = ({ enabled, ...rest }: any) => (
<TouchableNativeFeedback disabled={enabled === false} {...rest}>
<View />
</TouchableNativeFeedback>
);
export const BaseButton = RawButton;
export const RectButton = RawButton;
export const BorderlessButton = TouchableNativeFeedback;
15 changes: 5 additions & 10 deletions packages/react-native-gesture-handler/src/mocks/mocks.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import {
TouchableHighlight,
TouchableNativeFeedback,
Expand All @@ -17,7 +16,7 @@ import { Directions } from '../Directions';
const NOOP = () => {
// Do nothing
};
const PanGestureHandler = View;

const attachGestureHandler = NOOP;
const createGestureHandler = NOOP;
const dropGestureHandler = NOOP;
Expand All @@ -26,21 +25,16 @@ const updateGestureHandlerConfig = NOOP;
const flushOperations = NOOP;
const configureRelations = NOOP;
const install = NOOP;

const PanGestureHandler = View;
const NativeViewGestureHandler = View;
const TapGestureHandler = View;
const ForceTouchGestureHandler = View;
const LongPressGestureHandler = View;
const PinchGestureHandler = View;
const RotationGestureHandler = View;
const FlingGestureHandler = View;
export const RawButton = ({ enabled, ...rest }: any) => (
<TouchableNativeFeedback disabled={enabled === false} {...rest}>
<View />
</TouchableNativeFeedback>
);
export const BaseButton = RawButton;
export const RectButton = RawButton;
export const BorderlessButton = TouchableNativeFeedback;
const HostGestureDetector = View;

export default {
TouchableHighlight,
Expand Down Expand Up @@ -68,6 +62,7 @@ export default {
configureRelations,
flushOperations,
install,
HostGestureDetector,
// Probably can be removed
Directions,
State,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { use } from 'react';
import { isTestEnv } from '../../utils';
import { Platform } from 'react-native';
import GestureHandlerRootViewContext from '../../GestureHandlerRootViewContext';

export function useEnsureGestureHandlerRootView() {
const rootViewContext = use(GestureHandlerRootViewContext);

if (__DEV__ && !rootViewContext && !isTestEnv() && Platform.OS !== 'web') {
if (__DEV__ && !rootViewContext && Platform.OS !== 'web') {
throw new Error(
'GestureDetector must be used as a descendant of GestureHandlerRootView. Otherwise the gestures will not be recognized. See https://docs.swmansion.com/react-native-gesture-handler/docs/fundamentals/installation for more details.'
);
Expand Down
Loading