Metro: Couldn't find preset "module:metro-react-native-babel-preset" when running jest

Created on 12 Sep 2018  ·  45Comments  ·  Source: facebook/metro

Do you want to request a feature or report a bug?
bugreport

What is the current behavior?
I updated a react-native codebase from 0.56 to 0.57 and migrated from "babel-preset-react-native": "^2.1.0" to the current version of "metro-react-native-babel-preset". The app itself compiles and runs for iOS and android but all of the jest tests crash immediately on my mac and on our linux ci.

Test suite failed to run
Couldn't find preset "module:metro-react-native-babel-preset" relative to directory "/Users/michaelknoch/dev/repos/JestCrashReproduction"

If the current behavior is a bug, please provide the steps to reproduce and a minimal repository on GitHub that we can yarn install and yarn test.

I created this repo with react-native init. To run Jest we need at leat one file with pattern *.test.js
So i ended up running this: react-native init JestMetroCrash --version 0.57.0 && cd JestMetroCrash && touch App.test.js

Its worth to mention that the test suite also breaks when .babelrc with explicit "presets": ["module:metro-react-native-babel-preset"] is provided.

What is the expected behavior?
Jest should resolve the preset and transpile files correctly.

Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system.
node v8.11.3
npm 6.4.1
metro latest release

Most helpful comment

For your jest configuration, can you also add transform: { '^.+\\.js$': '<rootDir>/node_modules/react-native/jest/preprocessor.js' }?

All 45 comments

For your jest configuration, can you also add transform: { '^.+\\.js$': '<rootDir>/node_modules/react-native/jest/preprocessor.js' }?

@mjesun do you know why jest is not able to pick up the preset?

I have found the same problem today.
Open the file .babelrc, you will find it in the root of the project, and replace:

{ "presets": ["module:metro-react-native-babel-preset"] }

to

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

Replacing with { "presets": ["react-native"] } can't be the solution for the existing set of tests, as it breaks loading babel-jest and fails to mock of files that test import using ES6.

I confirm that @ajcrites's solution works, event with TypeScript.
My jest config in package.json is following:

    ...
    "transform": {
      "^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js",
      "\\.(ts|tsx)$": "ts-jest"
    },
   ...

the solution from @ajcrites seems to work, but now everything mocked with jest.mock seems to break for some reasons. Is there any known breaking change related to that?

@ajcrites I tried your solution it works great locally but for some reason my CI is throwing this error.

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/react-native/jest/preprocessor.js:45
...nodeOptions,
^^^

SyntaxError: Unexpected token ...

at ScriptTransformer._getTransformer (node_modules/jest-runtime/build/script_transformer.js:231:19)

Now we're using TypeScript, if that matters. The above configuration, as suggested, does work. But also yields warning:

ts-jest][DEPRECATED] - replace any occurrences of "ts-jest/dist/preprocessor.js" or "/node_modules/ts-jest/preprocessor.js" in the 'transform' section of you
r Jest config with just "ts-jest".

However, just using ts-jest has the error come back.

 "transform": {
      "\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js",
      "^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js"
    },

Yes, you can just do "\\.(ts|tsx)$": "ts-jest",

I'm running into the same issue as @michaelknoch

Edit: scratch that, just found you have to put the transform inside the jest config, lol. Maybe the full message is useful to somebody though.

Getting the same issue as OP, even with the transform. Here's the full error as I can't see it above:

Couldn't find preset "module:metro-react-native-babel-preset" relative to directory "Q:\\Path\\to\\REPO-NAME"

      at node_modules/babel-core/lib/transformation/file/options/option-manager.js:293:19
          at Array.map (<anonymous>)
      at OptionManager.resolvePresets (node_modules/babel-core/lib/transformation/file/options/option-manager.js:275:20)
      at OptionManager.mergePresets (node_modules/babel-core/lib/transformation/file/options/option-manager.js:264:10)
      at OptionManager.mergeOptions (node_modules/babel-core/lib/transformation/file/options/option-manager.js:249:14)
      at OptionManager.init (node_modules/babel-core/lib/transformation/file/options/option-manager.js:368:12)
      at File.initOptions (node_modules/babel-core/lib/transformation/file/index.js:212:65)
      at new File (node_modules/babel-core/lib/transformation/file/index.js:135:24)
      at Pipeline.transform (node_modules/babel-core/lib/transformation/pipeline.js:46:16)

@michaelknoch I had to install babel-jest as per https://jestjs.io/docs/en/getting-started#using-babel. I also had to rename my .babelrc to babel.config.js (and add module.exports = to the top since the json file is now a regular js file). Here is my final list of babel depencies:

"@babel/core": "^7.1.0",
"@babel/runtime": "^7.0.0",
"babel-core": "7.0.0-bridge.0",
"babel-jest": "^23.6.0",

Looks like version 0.47 of metro-react-native-babel-preset is available now. Testing now works for me with this new version including jest.mock.

I finally resolved the issue I was having by bringing in https://www.npmjs.com/package/babel-plugin-jest-hoist to my project.

My dependencies:

    "react": "16.5.1",
    "react-native": "^0.57.1",
.. 
    "@babel/core": "^7.1.0",
    "@babel/runtime": "^7.0.0",
    "babel-core": "^6.26.3",
    "babel-eslint": "^8.1.1",
    "babel-jest": "^23.6.0",
    "babel-plugin-jest-hoist": "^23.2.0",
    "babel-plugin-relay": "^1.5.0",
    "jest": "^23.6.0",
    "metro-react-native-babel-preset": "^0.47.0",

and my babel.config.js:

module.exports = {
  "presets": ["module:metro-react-native-babel-preset", "module:react-native-dotenv"],
  "plugins": [
    "relay",
    "jest-hoist"
  ]
}

EDIT: my tests are now passing locally but failing on CI 🙇‍♂️

still running into Couldn't find preset "module:metro-react-native-babel-preset" with 0.47.0

Hey @michaelknoch. I have the following versions:

"react": "16.5.1",
"react-native": "^0.57.1",
...
"@babel/cli": "^7.0.0",
"@babel/core": "^7.0.0",
"babel-core": "^7.0.0-bridge.0",
"jest": "^23.6.0",
"metro-react-native-babel-preset": "^0.45.0",

And it works just fine. Just had to change my .babelrc to babelrc.js and install babel-core (npm i -D babel-core@bridge).

I had the same issue and adding this to jest config made test work
"^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js",
But then my jest.mock() statements were not working. It seems all the jest.mock() calls need to be hoisted before all import statements in the test.

@hernancorigliano try what I said above

I've also been following this issue trying to track the jest.mock breakage

https://github.com/facebook/react-native/issues/20876#issuecomment-426643455

I fixed most of my tests by moving mocks to __MOCKS__ directory instead of mocking dynamically in the test itself. @hanford

@hernancorigliano try what I said above

Sorry I forgot to mention that I tried using the plugin to hoist the calls, but for some reason does not seem to be working. I did exactly the same as you. I might have a problem with babel somewhere else.

looks like I've set

"jest": {
    "preset": "react-native",

and it works, even if I have installed only metro-react-native-babel-preset and react-native: 0.57.1. Not sure why...

inside my react-native-vector-icons folder, in node_modules, there was a bablerc file which was like this

{
  "presets": ["module:metro-react-native-babel-preset"]
}

I manually changed it to this :

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

I hope this can help

  1. Go to new module folder (ex: node_module/react-native-vector-icons)
  2. Open .babelrc
  3. replace "presets": ["module:metro-react-native-babel-preset"]
  4. with "presets": ["react-native"]
  5. and rebuild project

trims

And it works just fine. Just had to change my .babelrc to babelrc.js and install babel-core (npm i -D babel-core@bridge).

Can confirm this works for me!

Hey @michaelknoch. I have the following versions:

"react": "16.5.1",
"react-native": "^0.57.1",
...
"@babel/cli": "^7.0.0",
"@babel/core": "^7.0.0",
"babel-core": "^7.0.0-bridge.0",
"jest": "^23.6.0",
"metro-react-native-babel-preset": "^0.45.0",

And it works just fine. Just had to change my .babelrc to babelrc.js and install babel-core (npm i -D babel-core@bridge).

It works for me. I didn't change my '.babelrc' though. Just installed the 'babel-core'

After I added the custom transform mocks stopped working as well. These are the steps I completed to fix it.

1) I added 'babel-core@^7.0.0-bridge'
2) removed the custom transform (transform: { '^.+\\.js$': '<rootDir>/node_modules/react-native/jest/preprocessor.js' })
3) changed from .babelrc to babel.config.js

babel.config.js

module.exports = function (api) {
  api.cache(true)
  return {
    "presets": ["module:metro-react-native-babel-preset"]
  };
}

now my tests are running and mocks are working as usual :-) hope it can help somebody

After spending a couple of hours trying to make everything work, I noticed there is some official documentation for ts-jest to run on react-native 0.57 and babel 7:

https://kulshekhar.github.io/ts-jest/user/react-native/

Solved my problem

After I added the custom transform mocks stopped working as well. These are the steps I completed to fix it.

1. I added `'babel-core@^7.0.0-bridge'`

2. **removed** the custom transform (`transform: { '^.+\\.js$': '<rootDir>/node_modules/react-native/jest/preprocessor.js' }`)

3. changed from `.babelrc` to `babel.config.js`

babel.config.js

module.exports = function (api) {
  api.cache(true)
  return {
    "presets": ["module:metro-react-native-babel-preset"]
  };
}

now my tests are running and mocks are working as usual :-) hope it can help somebody

This solution worked for me but I also had to bring @babel/plugin-proposal-class-properties to my devDependencies
https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-class-properties

@makabde It worked for me too, without adding @babel/plugin-proposal-class-properties

one thing I noticed and was taken aback by was, that jest is caching tests.
So if you think "why aren't my babel config changes doing anything", chances are, that jest is running the tests out of it's cache without considering the config changes.

Make sure to run jest --clearCache when trying to test config changes.

@esbenp's suggestion worked for me. Thanks, man !

I was facing the same issue and while implementing detox e2e test.
fixed it by adding the following code in the e2e/config.json

"transform": {
"^.+\\.js$": "<rootDir>/../node_modules/react-native/jest/preprocessor.js"
}

under the main {}.
my final config.json file looks like this:

{
    "setupTestFrameworkScriptFile": "./init.js",
    "testEnvironment": "node",
    "transform": {
        "^.+\\.js$": "<rootDir>/../node_modules/react-native/jest/preprocessor.js"
      }
}

@esbenp's suggestion worked for me as well.

@esbenp, you rock!!

Thank you!

@esbenp solution works for me, except of missed transform:
transform: { '^.+\\.(js|jsx)$': '<rootDir>/node_modules/react-native/jest/preprocessor.js', },

I've returned it to be able to use ES6 syntax in my test files.

Can confirm @esbenp solution works, in fact the only one here that works. Thanks!

@esbenp solution works for me. I am wondering why it doesn't work out of the box....

This issue occur even on a newly fresh installed version of an react-native application:

cd /tmp
react-native init test
cd test
react-native-git-upgrade

gives

git-upgrade ERR! An error occurred during upgrade:
git-upgrade ERR! Error: Couldn't find preset "module:metro-react-native-babel-preset" relative to directory "/private/tmp/test"
at /usr/local/lib/node_modules/react-native-git-upgrade/node_modules/babel-core/lib/transformation/file/options/option-manager.js:293:19
at Array.map ()

Getting same issue
Error: Couldn't find preset "module:metro-react-native-babel-preset" relative to directory
and also tried
For your jest configuration, can you also add transform: { '^.+\.js$': '/node_modules/react-native/jest/preprocessor.js' }?

But, still its not working

I was getting this error when running tests with detox
@esbenp s solution worked for me to remove the error with not finding metro bundler. However I started getting the error
ReferenceError: regeneratorRuntime is not defined.

On removing the line disableBabelRuntime: true from react-native/jest/preprocessor.js this error goes away. This change was introduced by this commit

To fix it temporarily, I copied react-native/jest/preprocessor.js to <project_root>/jest-preprocessor.js and removing disableBabelRuntime: true and directing the path to transform to this file.

so i choose to use the old version

I didn't test with jest, but this lets me run npm start:

npm i metro-react-native-babel-preset --save-dev

Just echoing other solutions above... depending on your use case, use only one:
.babelrc or babel.config.js (as per documentation)

For me, I was in the process of migrating my code and had both files present by accident, so the bundler was confused. I removed .babelrc and kept babel.config.js and the error went away.

Hey @michaelknoch. I have the following versions:

"react": "16.5.1",
"react-native": "^0.57.1",
...
"@babel/cli": "^7.0.0",
"@babel/core": "^7.0.0",
"babel-core": "^7.0.0-bridge.0",
"jest": "^23.6.0",
"metro-react-native-babel-preset": "^0.45.0",

And it works just fine. Just had to change my .babelrc to babelrc.js and install babel-core (npm i -D babel-core@bridge).

Thanks a ton, man

I have found the same problem today.
Open the file .babelrc, you will find it in the root of the project, and replace:

{ "presets": ["module:metro-react-native-babel-preset"] }

to

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

It worked only react-native version <=0.61 but for version 0.63 it doesn't work.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aleclarson picture aleclarson  ·  4Comments

acamenhas picture acamenhas  ·  5Comments

IljaDaderko picture IljaDaderko  ·  5Comments

MattFoley picture MattFoley  ·  5Comments

peterp picture peterp  ·  3Comments