Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native Expo App: How to get it to run Jest tests

So Jest seems to be broken out of the box right now, when creating a React Native App with Expo.

Steps to reproduce:

  1. `expo init'
  2. Choose tabs.
  3. cd into your app.
  4. Run npm test 👉🏻 Fails

I googled and tried out the following fixes:

A) Add jest.config.js:

module.exports = {
  preset: 'jest-expo',
  transform: {
    '\\.js$': '<rootDir>/node_modules/react-native/jest/preprocessor.js',
  }
};

B) Copy react-natives preprocessor in your own `jest.preprcessor.js' file:

 transform: {
    /*
     * Stop jest from falling over on its face.
     * cf. https://github.com/expo/expo/issues/2595#issuecomment-440966998
     * cf. https://github.com/facebook/react-native/issues/22175#issuecomment-436959462
     */
    '\\.js$': '<rootDir>/jest.preprocessor.js',
  },

C) Changing the "test" scripts section

from:

"test": "node_modules/.bin/jest"

to:

"test": "node ./node_modules/jest/bin/jest.js"

So nothing works 😓 All approaches result in some or all tests failing.

Does anyone know how to get jest to work with Expo 32?

Edit: Bruno's answer works. Additionally, make sure to delete your node_modules and package-lock.json before running yarn. Furthermore, you don't need a jest.config.js. And you also don't need Bruno's babel.config.js. Here is mine:

module.exports = function(api) {
    api.cache(true);
    return {
        presets: ['babel-preset-expo'],
    };
};

It's so weird that it doesn't work for npm.

PS, here is the preprocessor code so you don't have to search it:

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
 */

/* eslint-env node */

'use strict';

const {transformSync: babelTransformSync} = require('@babel/core');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
 * found when Flow v0.54 was deployed. To see the error delete this comment and
 * run Flow. */
const babelRegisterOnly = require('metro-babel-register');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
 * found when Flow v0.54 was deployed. To see the error delete this comment and
 * run Flow. */
const createCacheKeyFunction = require('fbjs-scripts/jest/createCacheKeyFunction');
const generate = require('@babel/generator').default;

const nodeFiles = RegExp(
  [
    '/local-cli/',
    '/metro(?:-[^/]*)?/', // metro, metro-core, metro-source-map, metro-etc
  ].join('|'),
);
const nodeOptions = babelRegisterOnly.config([nodeFiles]);

babelRegisterOnly([]);

/* $FlowFixMe(site=react_native_oss) */
const transformer = require('metro/src/reactNativeTransformer');
module.exports = {
  process(src /*: string */, file /*: string */) {
    if (nodeFiles.test(file)) {
      // node specific transforms only
      return babelTransformSync(src, {
        filename: file,
        sourceType: 'script',
        ...nodeOptions,
        ast: false,
      }).code;
    }

    const {ast} = transformer.transform({
      filename: file,
      localPath: file,
      options: {
        ast: true, // needed for open source (?) https://github.com/facebook/react-native/commit/f8d6b97140cffe8d18b2558f94570c8d1b410d5c#r28647044
        dev: true,
        inlineRequires: true,
        minify: false,
        platform: '',
        projectRoot: '',
        retainLines: true,
        sourceType: 'unambiguous', // b7 required. detects module vs script mode
      },
      src,
      plugins: [
        [require('@babel/plugin-transform-block-scoping')],
        // the flow strip types plugin must go BEFORE class properties!
        // there'll be a test case that fails if you don't.
        [require('@babel/plugin-transform-flow-strip-types')],
        [
          require('@babel/plugin-proposal-class-properties'),
          // use `this.foo = bar` instead of `this.defineProperty('foo', ...)`
          {loose: true},
        ],
        [require('@babel/plugin-transform-computed-properties')],
        [require('@babel/plugin-transform-destructuring')],
        [require('@babel/plugin-transform-function-name')],
        [require('@babel/plugin-transform-literals')],
        [require('@babel/plugin-transform-parameters')],
        [require('@babel/plugin-transform-shorthand-properties')],
        [require('@babel/plugin-transform-react-jsx')],
        [require('@babel/plugin-transform-regenerator')],
        [require('@babel/plugin-transform-sticky-regex')],
        [require('@babel/plugin-transform-unicode-regex')],
        [
          require('@babel/plugin-transform-modules-commonjs'),
          {strict: false, allowTopLevelThis: true},
        ],
        [require('@babel/plugin-transform-classes')],
        [require('@babel/plugin-transform-arrow-functions')],
        [require('@babel/plugin-transform-spread')],
        [require('@babel/plugin-proposal-object-rest-spread')],
        [
          require('@babel/plugin-transform-template-literals'),
          {loose: true}, // dont 'a'.concat('b'), just use 'a'+'b'
        ],
        [require('@babel/plugin-transform-exponentiation-operator')],
        [require('@babel/plugin-transform-object-assign')],
        [require('@babel/plugin-transform-for-of'), {loose: true}],
        [require('@babel/plugin-transform-react-display-name')],
        [require('@babel/plugin-transform-react-jsx-source')],
      ],
    });

    return generate(
      ast,
      {
        code: true,
        comments: false,
        compact: false,
        filename: file,
        retainLines: true,
        sourceFileName: file,
        sourceMaps: true,
      },
      src,
    ).code;
  },

  getCacheKey: createCacheKeyFunction([
    __filename,
    require.resolve('metro/src/reactNativeTransformer'),
    require.resolve('@babel/core/package.json'),
  ]),
};

My dependencies:

"dependencies": {
    "@expo/samples": "2.1.1",
    "expo": "^32.0.0",
    "formik": "^1.5.0",
    "i18n-js": "^3.2.1",
    "prop-types": "^15.7.1",
    "react": "16.5.0",
    "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
    "react-navigation": "^3.0.9",
    "yup": "^0.26.10"
  },
  "devDependencies": {
    "babel-eslint": "^10.0.1",
    "babel-preset-expo": "^5.0.0",
    "eslint": "^5.13.0",
    "eslint-plugin-import": "^2.16.0",
    "eslint-plugin-jsx-a11y": "^6.2.1",
    "eslint-plugin-react": "^7.12.4",
    "eslint-plugin-react-native": "^3.6.0",
    "eslint-plugin-react-native-a11y": "^1.2.0",
    "eslint-plugin-simple-import-sort": "^3.0.0",
    "jest-expo": "^32.0.0",
    "react-native-elements": "^1.0.0",
    "react-native-testing-library": "^1.5.0"
  },

like image 546
J. Hesters Avatar asked Feb 13 '19 17:02

J. Hesters


People also ask

How do you use the Jest app to test expo?

To do so, run yarn add jest-expo --dev or npm i jest-expo --save-dev depending on which package manager you prefer. Then, install the test renderer library: yarn add react-test-renderer --dev or npm i react-test-renderer --save-dev . That's it! ?

How do you run Jest test cases in React Native?

Setup​ Run yarn test to run tests with Jest. If you are upgrading your react-native application and previously used the jest-react-native preset, remove the dependency from your package. json file and change the preset to react-native instead.

How do you mock native modules Jest?

Mocking native modules​Make sure that the path to the file in setupFiles is correct. Jest will run these files before running your tests, so it's the best place to put your global mocks. If you're not using Jest, then you'll need to mock these modules according to the test framework you are using.


1 Answers

Your dependecies and devDependencies seem fine.

  • First thing, install yarn. Follow this link for instructions.
  • Second, you must alter a few things in your package.json. Like this:
"scripts": {
    "test": "jest",
    ...
  },
"jest": {
    "preset": "jest-expo",
    "transform": {
      "^.+\\.js$": "babel-jest"
  },
}
  • Third, ensure your babel.config.js is setup correctly. Here's the one from my project running Expo's SDK 32:
module.exports = function (api) {
  api.cache(true);
  return {
    presets: [
      'babel-preset-expo',
      'module:react-native-dotenv',
    ],
    sourceMaps: true,
    plugins: [
      '@babel/transform-react-jsx-source',
    ],
  };
};
  • Lastly, use yarn to install your packages yarn install and to run your tests yarn test.
like image 199
Bruno Eduardo Avatar answered Oct 10 '22 03:10

Bruno Eduardo