Skip to content

Jest: with the hook API, raw touch events fired under a GestureDetector don't reach ancestors under Testing Library 14 #4656

Open

Description

@jrmsayag

Description

This happens only in Jest: it's an interaction between Gesture Handler 3's test stand-in and React Native Testing Library, not a bug in the runtime.

Under Jest, jestSetup.js replaces HostGestureDetector with a plain View (src/mocks/hostDetector.tsx at v3.3.0). For a hook gesture, NativeDetector passes that View its onStartShouldSetResponder (NativeDetector.tsx#L76 at v3.3.0), which declines the responder.

Testing Library 14 treats a declining responder as blocking every event for the ancestors above it, raw touch events included. So fireEvent(child, 'touchStart') under a hook gesture's GestureDetector no longer reaches a parent's onTouchStart. On a device it does. (Once a gesture activates on a device, the ancestors get touchCancel, as expected: that isn't what this is about. In Jest, touchStart and the moves before activation never reach them.) With a builder-API gesture, no such View is rendered and the touch gets through, so tests that passed on 2.x start failing after moving to the hooks.

The root cause appears to be on Testing Library's side: on a device, raw touch events reach every ancestor whatever the responder does, and Testing Library applies the responder rule to them anyway. I've reported it there as callstack/react-native-testing-library#1957. I'm raising it here too because Gesture Handler 3 users will run into it when they move tests from the builder API to the hooks, so you may want to do something about it on your side, or at least be aware of it.

Steps to reproduce

  1. Clone https://github.com/jrmsayag/rntl-touch-bubbling-repro-demo and run npm ci.
  2. Run npx jest.
  3. "with a hook-API gesture (usePanGesture())" fails: the parent's onTouchStart gets 0 calls. "with a builder-API gesture (Gesture.Pan())" passes.
function Pannable() {
  const gesture = usePanGesture({});
  return (
    <GestureDetector gesture={gesture}>
      <View testID="child" />
    </GestureDetector>
  );
}

it('a raw touchStart under a hook gesture reaches the parent', async () => {
  const onTouchStart = jest.fn();
  await render(
    <GestureHandlerRootView>
      <View onTouchStart={onTouchStart}>
        <Pannable />
      </View>
    </GestureHandlerRootView>,
  );

  await fireEvent(screen.getByTestId('child'), 'touchStart');

  expect(onTouchStart).toHaveBeenCalledTimes(1); // fails: 0 calls
});

A link to a Gist, an Expo Snack or a link to a repository

https://github.com/jrmsayag/rntl-touch-bubbling-repro-demo

Gesture Handler version

3.3.0

React Native version

0.88.1

Platforms

Android, iOS (it happens in Jest, whatever the platform)

JavaScript runtime

Hermes (not relevant: Jest runs on Node)

Workflow

Using Expo Prebuild or an Expo development build (the repro itself is plain React Native with @react-native/jest-preset)

Build type

Debug mode

Device

Not applicable (Jest); pick any.

Device model

Not applicable (Jest, Node 22). @testing-library/react-native 14.1.0, Jest 30.5.2.

Acknowledgements

Yes

Activity

  1. aliassar commented on Nov 2, 2026

    @aliassar

    Can I work on this?

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Platform: AndroidThis issue is specific to AndroidPlatform: iOSThis issue is specific to iOS

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions