Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot read property 'Direction' of undefined, tests only

Tags:

react-native

I just added TouchableOpacity to a component and the app is working fine, but my tests, using react-native-testing-library, fail to run:

  ● Test suite failed to run

    TypeError: Cannot read property 'Direction' of undefined

      at Object.Direction (node_modules/react-native-gesture-handler/Directions.js:3:39)
      at Object.<anonymous> (node_modules/react-native-gesture-handler/GestureHandler.js:2:1)

I just removed and re-added react-native-gesture-handler with yarn, and ran pod install. Again, the app is working, but the tests fail to run.

I actually get the same error when using <Text onPress={() => onOptionPress(opt)} /> rather than TouchableOpacity.

component:

const SelectOptions = ({ field, dismissOverlay, onOptionPress }) => {
  return (
    <Overlay
      isVisible
      overlayStyle={styles.overlay}
      height={"auto"}
      onBackdropPress={dismissOverlay}
    >
      <View>
        {field.options.map((opt, i) => (
          <TouchableOpacity
            style={styles.option}
            key={i}
            onPress={() => onOptionPress(opt)}
          >
            <Text>{opt}</Text>
          </TouchableOpacity>
        ))}
      </View>
    </Overlay>
  );
};

test:

describe("CardFormView", () => {
  let wrapper, birthdayField;

  beforeEach(() => {
    wrapper = render(
      <React.Fragment>
        <CardFormView form={form} />
      </React.Fragment>
    );
    birthdayField = wrapper.getByText("Add a Birthday Gift Card");
  });

  const message1 =
    "...";
  const message2 =
    "...";

  it("shows the options for a birthday card when clicked", () => {
    fireEvent.press(birthdayField);
    expect(wrapper.getByText(message1)).toBeDefined();
  });

  it("sets an option when clicked", () => {
    fireEvent.press(birthdayField);
    const firstOption = wrapper.getByText(message1);
    fireEvent.press(firstOption);
    expect(wrapper.queryByText(message2)).toBeNull();
    expect(wrapper.getByText(message1)).toBeDefined();
  });
});
like image 653
Jonathan Tuzman Avatar asked Aug 21 '19 15:08

Jonathan Tuzman


4 Answers

This is because you are not mocking the react-navigation-gesture-handler

To use mock of react-navigation-gesture-handler you should add jestSetup.js from node_modules in jest.config.json or jest.config.js

setupFiles: [
  "./node_modules/react-native-gesture-handler/jestSetup.js"
]

I found a reference from the following link and It's working for me.

https://github.com/software-mansion/react-native-gesture-handler/issues/344#issuecomment-489547513

like image 186
Sahil Shikalgar Avatar answered Oct 20 '22 02:10

Sahil Shikalgar


For me just adding the setupFiles didn't work. I added setupFiles and transformIgnorePatterns at "jest" in package.json

Here the code to make the gestureHandler work, but I tested it with AsyncStorage and the storage stopped work. If you aren't using AsyncStorage I presume this code will work very well!

"setupFiles": [
     "./node_modules/react-native-gesture-handler/jestSetup.js"
],
"transformIgnorePatterns": [
     "/node_modules/(?!native-base)/"
]

My reference: https://github.com/software-mansion/react-native-gesture-handler/issues/344

like image 28
Samtapes Avatar answered Oct 20 '22 02:10

Samtapes


Updating package.json and reinstalling npm package worked for me.

"jest": {
    "preset": "react-native",
    "transformIgnorePatterns": ["node_modules/(?!(jest-)?react-native|@?react-navigation)"],
    "setupFiles": ["./node_modules/react-native-gesture-handler/jestSetup.js"]
}
like image 41
Amit Kumar Trivedi Avatar answered Oct 20 '22 01:10

Amit Kumar Trivedi


This is happening because you have to mock the NativeModules module from react-native. It can happen with several modules but it was happening to me specifically with the ImagePicker, Linking and @react-navigation/native. This is what I did to mock the native modules.

/src/testSetup.ts

import {NativeModules} from 'react-native';

NativeModules.RNGestureHandlerModule= {
    attachGestureHandler: jest.fn(),
    createGestureHandler: jest.fn(),
    dropGestureHandler: jest.fn(),
    updateGestureHandler: jest.fn(),
    State: {},
    Directions: {},
},

NativeModules.ImagePickerManager = {
    showImagePicker: jest.fn(),
}

NativeModules.Linking = {
    canOpenUrl: jest.fn().mockResolvedValue(true),
    openUrl: jest.fn().mockResolvedValue(true)
}

NativeModules.Platform = {
    OS: 'iOS'
}

jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper');
jest.mock('react-native/Libraries/Animated/src/animations/TimingAnimation');


const mockNavigation = () => {
    const mockedNavigate = jest.fn();
    const mockedAddListener = jest.fn();

    jest.mock('@react-navigation/native', () => ({ // @ts-ignore
        ...(jest.requireActual('@react-navigation/native')),
        useNavigation: () => ({
          navigate: mockedNavigate,
          addListener: mockedAddListener
        })
      }));
    
    return {mockedNavigate, mockedAddListener}
}

in your tests

import { fireEvent, act, render } = '@testing-library/react-native'

const {mockedNavigate, mockedAddListener} = mockNavigation()

test('Should navigate', () => {
  const { queryByText } = render(<Component />)

  fireEvent.press(getByText('View Page Button'))

  expect(mockedNavigate).toHaveBeenCalledWith('Your Page Name')
  expect(mockedAddListener).toHaveBeenCalled()
})

like image 1
Miguel Coder Avatar answered Oct 20 '22 00:10

Miguel Coder