testing-library / native-testing-library

🐳 Simple and complete React Native testing utilities that encourage good testing practices.
https://native-testing-library.com
MIT License
516 stars 44 forks source link

Unable to trigger onPress() prop for a TouchableOpacity via fireEvent.press() #107

Closed alekhinen closed 4 years ago

alekhinen commented 4 years ago

Relevant code or config:

OpacityExample.tsx

import { TouchableOpacity } from 'react-native-gesture-handler';
import React, { useState } from 'react';
import { Text, View } from 'react-native';

export default function OpacityExample(): JSX.Element {
  const [amount, setAmount] = useState<number>(0);

  const handlePress = () => {
    setAmount(amount + 1);
  };

  return (
    <View>
      <Text testID="test-amount">{amount}</Text>
      <TouchableOpacity testID="test-foo" onPress={handlePress} />
    </View>
  );
}

OpacityExample.test.tsx

import React from 'react';
import { cleanup, render, fireEvent } from '@testing-library/react-native';

import OpacityExample from 'src/OpacityExample';

describe('<OpacityExample />', () => {
  afterEach(cleanup);

  it('should increment the value', () => {
    const component = render(<OpacityExample />);

    const amountEl = component.getByTestId('test-amount');
    expect(amountEl.props.children).toBe(0);

    const touchableEl = component.getByTestId('test-foo');
    fireEvent.press(touchableEl);
    expect(amountEl.props.children).toBe(1);
  });
});

What you did:

My team is working on a feature where we want to increment/decrement an input value via some touchable elements. We've run into an issue where firing a press event doesn't trigger the event handler in this instance – though we've been able to get the onPress handler to trigger in other scenarios for some reason. In our codebase, the other working fireEvent.press() are being selected via getByText() not getByTestId().

What happened:

  ● <OpacityExample /> › should increment the value

    expect(received).toBe(expected) // Object.is equality

    Expected: 1
    Received: 0

      15 |     const touchableEl = component.getByTestId('test-foo');
      16 |     fireEvent.press(touchableEl);
    > 17 |     expect(amountEl.props.children).toBe(1);
         |                                     ^
      18 |   });
      19 | });
      20 | 

Reproduction:

The above code is all that is needed to repro the issue.

Problem description:

We are assuming that invoking fireEvent.press(touchableEl) will trigger that element's onPress handler and subsequently increment the value we are rendering out into the JSX tree.

Suggested solution:

N/A

Can you help us fix this issue by submitting a pull request?

N/A

bcarroll22 commented 4 years ago

Hey there, thanks for using Testing Library!

Unfortunately I don’t have time to run/debug this right now, but I think I see the issue. Unlike React/DOM Testing Library, the results of queries saved to variables aren’t live references, only saved instances. Because of that, after you fire the press event, you’ll have to query for the text element again to get the updated text value of 1.

Hope that helps!

alekhinen commented 4 years ago

Hey @bcarroll22 thanks for the quick response!

So it turns out that the same code all works when we swapped the import of TouchableOpacity from the react-native-gesture-handler to react-native 😓

So making the imports for the above example as the following fixed the issue:

import React, { useState } from 'react';
import { TouchableOpacity, Text, View } from 'react-native';

I'm unfamiliar with the internal mechanics of react-native-gesture-handler but there is definitely an issue where this testing library's fireEvent()s do not trigger the event handlers for the components exported from that lib.