slhck
slhck

Reputation: 38652

React Native tests failing, missing babel transforms

I want to test a React Native application that I've created based on the default guides, so it's very simple and has not had any changes w.r.t. the initial test configuration. The only difference seems to be that it's using npm instead of yarn (so it has a package-lock.json).

Here is the package.json:

{
  "name": "foo",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  },
  "dependencies": {
    "react": "16.9.0",
    "react-native": "0.61.5",
    "react-native-gesture-handler": "^1.5.2",
    "react-navigation": "^4.0.10",
    "react-navigation-stack": "^1.10.3"
  },
  "devDependencies": {
    "@babel/core": "^7.7.4",
    "@babel/runtime": "^7.7.4",
    "@react-native-community/eslint-config": "^0.0.5",
    "babel-jest": "^24.9.0",
    "eslint": "^6.7.1",
    "jest": "^24.9.0",
    "license-checker": "^25.0.1",
    "metro-react-native-babel-preset": "^0.57.0",
    "react-test-renderer": "16.9.0"
  },
  "jest": {
    "preset": "react-native"
  }
}

The test file __tests__/App-test.js is very simple (and auto-generated):

import 'react-native';
import React from 'react';
import App from '../App';

// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';

it('renders correctly', () => {
  renderer.create(<App />);
});

I get this error:

➜ npm test
> jest

 FAIL  __tests__/App-test.js
  ● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    /node_modules/@foo/bar/src/main.js:24
    export function milliseconds(timeoutInMilliseconds) {
    ^^^^^^

    SyntaxError: Unexpected token 'export'

Now, I don't really understand why it wouldn't work "out of the box". Other guides mention the same steps, too.

Adding a .babelrc with:

{ 
  "presets": ["react-native"]
}

produces the error:

Cannot find module 'babel-preset-react-native' from '/'
    - If you want to resolve "react-native", use "module:react-native"

      at Function.module.exports [as sync] (node_modules/resolve/lib/sync.js:74:15)
      at resolveStandardizedName (node_modules/@babel/core/lib/config/files/plugins.js:101:31)
      at resolvePreset (node_modules/@babel/core/lib/config/files/plugins.js:58:10)
      at loadPreset (node_modules/@babel/core/lib/config/files/plugins.js:77:20)
      at createDescriptor (node_modules/@babel/core/lib/config/config-descriptors.js:154:9)
      at node_modules/@babel/core/lib/config/config-descriptors.js:109:50
          at Array.map (<anonymous>)
      at createDescriptors (node_modules/@babel/core/lib/config/config-descriptors.js:109:29)
      at createPresetDescriptors (node_modules/@babel/core/lib/config/config-descriptors.js:101:10)
      at presets (node_modules/@babel/core/lib/config/config-descriptors.js:47:19)

There is already a babel.config.js file with the following contents (as suggested here):

module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
};

What should I do? I've seen this question but the React App has not been upgraded and is not missing anything, AFAICT. Note that when I create a completely new app with the init script, the tests run fine.

Upvotes: 2

Views: 937

Answers (1)

Christos Lytras
Christos Lytras

Reputation: 37288

You are using "react-navigation": "^4.0.10" which uses react-native-gesture-handler. Jest does not know about it. You have to mock react-native-gesture-handler and add react-navigation to transformIgnorePatterns or use react-native-jest-mocks.

Some examples of mocking react-native-gesture-handler can be found here: https://github.com/software-mansion/react-native-gesture-handler/issues/344

Add "files": ["jest/setup.js"]," inside package.json. Also transformIgnorePatterns must include react-navigation-stack, @react-native-community, react-native-gesture-handler and react-navigation.

package.json:

"files": [
  "jest/setup.js"
],
"jest": {
  "preset": "react-native",
  "transform": {
    "^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js"
  },
  "setupFiles": ["./jest/setup.js"],
  "testPathIgnorePatterns": [
    "/node_modules/"
  ],
  "transformIgnorePatterns": [
    "node_modules/(?!(jest-)?react-native|react-navigation-stack|@react-native-community|react-native-gesture-handler|react-navigation|@react-navigation/.*)"
  ]
}

jest/setup.js:

import { NativeModules as RNNativeModules } from "react-native";
RNNativeModules.UIManager = RNNativeModules.UIManager || {};
RNNativeModules.UIManager.RCTView = RNNativeModules.UIManager.RCTView || {};
RNNativeModules.RNGestureHandlerModule = RNNativeModules.RNGestureHandlerModule || {
  State: { BEGAN: "BEGAN", FAILED: "FAILED", ACTIVE: "ACTIVE", END: "END" },
  attachGestureHandler: jest.fn(),
  createGestureHandler: jest.fn(),
  dropGestureHandler: jest.fn(),
  updateGestureHandler: jest.fn(),

};
RNNativeModules.PlatformConstants = RNNativeModules.PlatformConstants || {
  forceTouchAvailable: false
};

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

Now run jest and it should pass the test. I have created a repo with an example RN 0.61 app using react-navigation that has jest test passing: https://github.com/clytras/RNJestTest

Or you can try react-native-jest-mocks but I haven't tried it with RN 0.61 yet.

Upvotes: 2

Related Questions