jest: babel-jest does not transpile import/export in node_modules when Babel 7 is used

šŸ› Bug Report

I started getting the dreaded SyntaxError: Unexpected token import error again for lodash-es. And I spent hours debugging it, because I already had .babelrc and package.json:jest configured properly ("modules": "commonjs", a jest.transform for babel-jest, and transformIgnorePatterns set to not ignore node_modules/lodash-es).

After a lot of debugging and a little searching, it appears that Babel 7 has stopped using the projectā€™s .babelrc code in node_modules. This means that all the previous suggestions to just tell transformIgnorePatterns to transpile certain packages in node_modules and set "modules": "commonjs" in the test env to make WebPack import work with jest no longer work.

To Reproduce

Steps to reproduce the behavior:

  • Import an es-modules using library like lodash-es into your project
  • Write a Jest test that imports the file you import the es-modules using package
  • Setup a recent version of Babel 7
  • Configure .babelrc to use the env preset to transpile ES6 modules to CommonJS
  • Configure Jest to transform .js files with babel-jest and transformIgnorePatterns to not ignore the es-modules using package

Expected behavior

When babel-jest is used to transpile ES-modules using packages like lodash-es it should transpile the imports to CommonJS so they work with Jest.

Practically I believe it should be sufficient to add transform-modules-commonjs to the plugins list that babel-jest uses when the filename is a node_modules file and Babel 7 is used. This would also fix the fact that itā€™s not good practice for the projectā€™s .babelrc (which may also include plugins for non-standard things like JSX and flow) to be used just to transpile ES6 / modules code in packages.

Link to repl or repo (highly encouraged)

https://gist.github.com/dantman/820f6232acc6f53bd1e57d21b09e1f89

Run npx envinfo --preset jest

Paste the results here:

  System:
    OS: macOS Sierra 10.12.6
    CPU: x64 Intel(R) Core(TM) i5-7267U CPU @ 3.10GHz
  Binaries:
    Node: 9.11.1 - ~/.nvm/versions/node/v9.11.1/bin/node
    Yarn: 1.6.0 - /usr/local/bin/yarn
    npm: 5.6.0 - ~/.nvm/versions/node/v9.11.1/bin/npm
  npmPackages:
    jest: ^22.4.4 => 22.4.4

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 136
  • Comments: 58 (6 by maintainers)

Commits related to this issue

Most upvoted comments

For the record, I was able to fix the issue of my module in the node_modules folder not compiling properly by:

  1. Changing the filename .babelrc to babel.config.js and module.exports the config object
  2. Adding transformIgnorePatterns to my Jest config:
"transformIgnorePatterns": [
  // Change MODULE_NAME_HERE to your module that isn't being compiled
  "/node_modules/(?!MODULE_NAME_HERE).+\\.js$"
]

Renaming .babelrc to babel.config.js worked for me

I had the same issue and I found this comment. So you should rename the .babelrc file to babel.config.js which will export .babelrc object.

This didnā€™t work for me until I added the env.test key to babel.config.js. Iā€™m not using any transform anything.

module.exports = {
  presets: ['@babel/preset-env'],
  env: {
    test: {
      presets: [['@babel/preset-env']]
    }
  }
};

I love Jest. I love Babel. But installing this suuuuucks. And all the docs are out of date.

@master-7 , i had similar problem, my advice to u is the followings:

  1. itā€™s better to have a separate jest.config.js
  2. yarn add --dev babel-jest babel-core@^7.0.0-bridge.0 @babel/core regenerator-runtime (look at https://jestjs.io/docs/en/getting-started.html#using-babel )
  3. create a babel.config.js file, and put the following code inside.
  presets: [
    '@babel/preset-env',
    '@babel/preset-react',
  ],
  env: {
    test: {
      presets: [
        '@babel/preset-env',
        '@babel/preset-react',
      ],
      plugins: [
        '@babel/plugin-proposal-class-properties',
        'transform-es2015-modules-commonjs',
        'babel-plugin-dynamic-import-node',
      ],
    },
  },
};
  1. npm test again. make sure your package.json test:, is scripted correctly.

See https://github.com/facebook/jest/issues/6053#issuecomment-383632515, it explains the need for babel.config.js. I donā€™t think Jest should do anything special here, open to being convinced otherwise, though.

  ā— Test suite failed to run

    ~/internals/jest/settings.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import Enzyme from 'enzyme'
                                                                                                    ^^^^^^

    SyntaxError: Unexpected identifier

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)

package.json

"jest": {
    "transform": {
      "^.+\\.(js|jsx|ts)$": "babel-jest",
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/internals/jest/fileTransform.js",
      "\\.(css|less)$": "<rootDir>/internals/jest/cssTransform.js"
    },
    "setupTestFrameworkScriptFile": "<rootDir>/internals/jest/settings.js",
    "testURL": "http://localhost/"
  }

Versions:

"jest": "^23.5.0",
"babel-jest": "^23.4.2"

/internals/jest/settings.js

import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

Enzyme.configure({ adapter: new Adapter() })

Could you please help?

this happend to me when i updated a react-native project to 0.56.0. Since then, jest test canā€™t be run anymore. transformIgnorePatterns seems to be completly ignored.

Seems like jest-babel just doesnā€™t load babel.config.js. Updating previously proposed solution:

  1. Create custom transformer under the tests/transform.js path:
const config = require("../babel.config.js")
module.exports = require("babel-jest").createTransformer(config)
  1. Modify your jest.config.js file:
  moduleFileExtensions: ["js", "jsx", "ts", "tsx"],
  transform: {
    "^.+\\.(js|jsx|ts|tsx)$": "./tests/transform.js"
  },
  1. Configure whatever transforms you need in babel.config.js:
module.exports = {
  presets: [
    ["@babel/preset-env", { targets: "node 8", modules: "commonjs" }],
    "@babel/preset-react",
    ["@babel/preset-typescript", { isTSX: true, allExtensions: true }]
  ],
  plugins: [
    "@babel/proposal-class-properties",
    "@babel/proposal-object-rest-spread",
  ]
}

NOTE: ts-jest is not needed with new @babel/preset-typescript

Any updates on this? This is behaviour which was working before and is now not, which seems to be to be a clear regression. Fair enough if the behaviour is to be removed, but lacking any clear documentation indicating that, this just feels like a bug.

The error handling for this issue needs to be updated with a direct link to the solution unless a fix is going to be implemented as itā€™s quite absurd how obscure and nonsensical this issue is still ongoing in 2020. On second thought, if you consider itā€™s 2020 itā€™s quite the norm. Good day

Also worked with setting negate regex intransformIgnorePatterns and creating custom babel transformer file:

"transformIgnorePatterns": [
      "/node_modules/(?!<MODULE_NAME>).+\\.js$"
    ],
"transform": {
      "^.+\\.(js|ts|tsx)?$": "./jest/transform.js"
    }

transform.js:

const config = {
  babelrc: false,
  presets: ['@babel/env', '@babel/react', '@babel/typescript'],
  plugins: [
    ['@babel/plugin-proposal-class-properties', { loose: true }],
    '@babel/plugin-transform-runtime',
    '@babel/plugin-syntax-dynamic-import',
    '@babel/plugin-proposal-object-rest-spread'
  ]
};
module.exports = require('babel-jest').createTransformer(config);

It was frustrating to deal with. When Iā€™ve started using the lodash-es package, suddenly it started complaining. Iā€™ve solved this issue with the help of this thread. However, I see that it lacks one universal, well explained solution, so I will try to provide one. Hope it will help others.

So it appears that @eugeneoshepkovā€™s solution is the best one but there are some changes that Iā€™ve done to make it work.

  1. Install all the required packages:
npm i -D @babel/core @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spread @babel/plugin-syntax-dynamic-import @babel/plugin-transform-runtime @babel/preset-env @babel/preset-react babel-core babel-jest regenerator-runtime ts-jest
  1. Create custom transformer under the tests/transform.js path:
const config = {
  babelrc: false,
  presets: ["@babel/preset-env", "@babel/preset-react"],
  plugins: [
    ["@babel/plugin-proposal-class-properties", { loose: true }],
    "@babel/plugin-transform-runtime",
    "@babel/plugin-syntax-dynamic-import",
    "@babel/plugin-proposal-object-rest-spread",
  ],
};
module.exports = require("babel-jest").createTransformer(config);
  1. Modify your jest.config.js file:
module.exports = {
  verbose: true,
  transform: {
    // Use official TypeScript Jest transformer
    "\\.(ts|tsx)?$": "ts-jest",
    // Use our custom transformer only for the *.js and *.jsx files
    "\\.(js|jsx)?$": "./tests/transform.js",
    // I'm also transforming GraphQL files with my own transformer (remove this line if you don't need it)
    "\\.(gql|graphql)$": "@jagi/jest-transform-graphql",
  },
  // As I've mentioned the package that was causing errors in my case is `lodash-es`
  // so I'm including it in the next line.
  // Notice that if you have more than one package you should use `|` (pipe) i.e.
  // transformIgnorePatterns: ["/node_modules/(?!(lodash-es|other-package|next-es-pkg)/)"]
  transformIgnorePatterns: ["/node_modules/(?!(lodash-es)/)"],
  moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
  /* ... */
};

Hope, it will help.

I have a problem on Mac also. When I updated node modules cannot run tests anymore. It fails to transpile from node_modules package even tough I set transformIgnorePatterns (did not change them since it worked).

faced the same issue, followed this steps to resolve

  1. install babel-jest
  2. in jest config add this configuration
transform: {
       '^.+\\.js?$': require.resolve('babel-jest')
   }
  1. make sure you have babel.config.js present (your config might be different than provided below)
module.exports = {
  "env": {
    "test": {
      presets: [
        [
          '@babel/preset-env',
          {
            targets: {
              node: 'current',
            },
          },
        ],
      ]
    }
  }
};

Although I added @babel/plugin-transform-modules-commonjs plugin, I was getting SyntaxError: Unexpected identifier on imports. For me, it was happening because I added all babel configuration in a .babelrc file, but thereā€™s a new concept of configuration in babel 7, babel.config.js.

So, I added all the configuration in an object on babel.config.js file and exported the object.

It worked.

Solution found. I fought with this same issue for a couple of days.

    /projectRoot/client/tests/unit/example.spec.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import { shallowMount } from '@vue/test-utils';
                                                                                                  ^

    SyntaxError: Unexpected token {

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)

I found the solution. When I updated the package.json babel-jest the project broke. Changing babel-jest back to an earlier version, removing node modules, install and the project REMAINS BROKEN.

To reproduce. Put "babel-jest": "^23.6.0", into your devDependencies. Verify unit tests work. Upgrade to ā€œbabel-jestā€: ā€œ^24.8.0ā€, the unit tests will fail. Revert to 23.6.0 and remove all node_modules, npm install, run the unit tests and they continue to fail.

To fix

  1. rm -rf node_modules
  2. downgrade to babel-jest 23.6
  3. IMPORTANT rm package-lock.json
  4. run npm install

Without step 3 the tests will continue to fail with the same error.

in babelrc, if you set the env of presets as [ā€˜@babel/preset-envā€™,{modules: false}], the import would not work. so let the modules of env not be false would solve this problem.

Thanks @austinkelleher

We had something similar but a bit different,

your fix didnā€™t work first - but then we realized that we were missing the .+\\.js$ at the end of the line, which worked just fine with jest and babel 6 but doesnā€™t with babel 7.

Iā€™ve got the same issue as @marcelerz. Ever since updating to React Native 56.0, transformIgnorePatterns seems to be ignored.

Thanks for the suggestion @mpospelov. Unfortunately, it didnā€™t seem to work for me.

SimenB, that solution is not working for vue-cli.

https://github.com/vuejs/vue-cli/issues/1584

We donā€™t have .babelrc, or .babel.config.js. I tried creating a basic one, it didnā€™t work.

Thanks a lot to everyone who tried to help!

@Chethannp @ghasemikasra39, I have an advice to resolve this problem. Please, donā€™t try to use every babel plugin to solve your problem, thisā€™s not a good deal.

Minimal config to make your transformation works as well

First step is to install the dependencies

npm i babel-jest @babel/core @babel/preset-env -D

Second step - RTFM and follow the configs bellow

babel.config.js

module.exports = {
  "presets": [
    ['@babel/preset-env', { targets: { node: 'current' } }],
    "@babel/preset-react",
    "@babel/preset-typescript" // if you want to have typescript in your project
  ]
}

jest.config.js

// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html

module.exports = {
  clearMocks: true,
  coverageDirectory: "coverage",
  testEnvironment: "node",
  transform: {
    "^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest"
  },
};

good luck!

Same issue šŸ˜¦

same issue? any solution ?

Seems like it needs to be updated to respect package.json babel config, as this is a valid location according to babel.

We use @babel/core to load the config using https://babeljs.io/docs/en/babel-core#loadpartialconfig. If babel doesnā€™t find your config, thatā€™s not an issue with jest.

Why does rename work at all?

Because thatā€™s how Babel works: https://babeljs.io/docs/en/configuration#what-s-your-use-case. You need babel.config.js to transpile from node_modules.

For those who had been struggling like me, listen to this man @SimenB here!

Before you try anything else, copy your babel config and jest config into separate babel.config.js and jest.config.js. This may save you from several hours, maybe days of googling, debugging and frustration.

Iā€™ve been trying these ways:

  • Modify the versions of babel/jest/babel-jest
  • Modify the configs of babel/jest in package.json
  • Scratching my head to come up with another possible way

It turns out that none of the above is necessary.

Here is a glimpse of those key configuration files:

package.json

Pay attention that Iā€™m using Babel@7 and jest@23. Babel@7 barely requires any configuration.

{
  "dependencies": {
    "@babel/core": "7.1.0",
    "babel-core": "7.0.0-bridge.0",
    "babel-jest": "23.6.0",
    "babel-preset-react-app": "^6.1.0",
    "jest": "23.6.0",
    "jest-pnp-resolver": "1.0.1",
    "jest-resolve": "23.6.0"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "devDependencies": {
    "@types/jest": "^23.3.10"
  }
}

babel.config.js

NOTHING fancy at all. Doesnā€™t even have to explicitly set configs for test environment.

module.exports = {
  "presets": [
    "react-app"
  ]
};

jest.config.js

Most of the content is copied from "jest": {...} in package.json. This is a ejected create-react-app project(with TypeScript), so most of the configs below were generated automatically while ā€œejectingā€. Iā€™ve add comments to the lines which need to be noticed.

module.exports = {
  "collectCoverageFrom": [
    "src/**/*.{js,jsx,ts,tsx}",
    "!src/**/*.d.ts"
  ],
  "resolver": "jest-pnp-resolver",
  "setupFiles": [
    "react-app-polyfill/jsdom"
  ],
  "testMatch": [
    "<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
    "<rootDir>/src/**/?(*.)(spec|test).{js,jsx,ts,tsx}"
  ],
  "testEnvironment": "jsdom",
  "testURL": "http://localhost",
  "transform": {
    "^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
    "^.+\\.(css|less)$": "<rootDir>/config/jest/cssTransform.js",
    "^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
  },
  "transformIgnorePatterns": [
    "^.+\\.module\\.(css|sass|scss)$",
    "node_modules/(?!(reactjs-click-outside|@babel/runtime)/)", // The modules that need to be transpiled. You might not need this.
    // "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$", // This line is no longer needed.
  ],
  "moduleNameMapper": {
    // "^react-native$": "react-native-web", // This was generated while "ejecting", not necessary.
    "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy",
    "\\.(css|less)$": "identity-obj-proxy", // If you are importing css/less in JS files
  },
  "moduleDirectories": [
    "node_modules" // This is required
  ],
  "moduleFileExtensions": [
    "web.js",
    "js",
    "web.ts",
    "ts",
    "web.tsx",
    "tsx",
    "json",
    "web.jsx",
    "jsx",
    "node"
  ]
}

Hope this is helpful.

Renaming .babelrc to babel.config.js worked for me

Iā€™m not sure why, but this worked.

Iā€™ve done everything I could for solving this, and still no luck.

I totally agree with @AndrewRayCode about the outdated docs, the one in jestjs.io itā€™s different from the instructions given here in Github. In particular:

yarn add --dev babel-jest @babel/core

Is it necessary to install the bridge to babel 7 or not?

This was all I needed to fix the issue:

module.exports = {
  "presets": [
    ['@babel/preset-env', { targets: { node: 'current' } }],
    "@babel/preset-react",
    "@babel/preset-typescript" // if you want to have typescript in your project
  ]
}

@nickovchinnikov is right. Simpler is better.

Man I spent countless hours trying to figure out why transformIgnorePatterns wasnā€™t working, and this was the cause all along? That I wasnā€™t explicitly using babel.config.js? I understand why, but dang. I was using "babel": in package.js.

Maybe the error thatā€™s displayed below when thereā€™s an unexpected token should explicitly state that it only works with babel.config.js?

Hereā€™s what you can do: ā€¢ To have some of your ā€œnode_modulesā€ files transformed, you can specify a custom ā€œtransformIgnorePatternsā€ in your config.

Seems like it needs to be updated to respect package.json babel config, as this is a valid location according to babel.

We use @babel/core to load the config using https://babeljs.io/docs/en/babel-core#loadpartialconfig. If babel doesnā€™t find your config, thatā€™s not an issue with jest.

Why does rename work at all?

Because thatā€™s how Babel works: https://babeljs.io/docs/en/configuration#what-s-your-use-case. You need babel.config.js to transpile from node_modules.

I donā€™t think Jest should add babel transforms, beyond the ones it needs for its own purposes.

That said, Jest should load your babel config itself, so weird that it doesnā€™t workā€¦

I ran into a similar error when trying to import a package from node_modules whose index.js is an ES Module. After a lot of painful debugging, I was able to resolve it by moving my babel configuration out of package.json, into babel.config.js, as described here: https://github.com/facebook/jest/issues/6053#issuecomment-383632515 Combined with a custom transformIgnorePatterns (see here), this allowed babel-jest to correctly transform the file in node_modules.

@sormy: Your note about ts-jest vs @babel/preset-typescript caught my attention. While @babel/preset-typescript actually can be used instead of ts-jest, ts-jest offers some advantages. See e.g. here.

babel-jest doesnā€™t load the confic, it reads it and uses it for caching, but to my knowledge it leaves babelrc handling up to Babel as it should.

Oh, youā€™re correct, I confused it with the merge done by the createTransformer factory.

This seems more like a Babel issue rather than Jest, though. Is there an issue over there about it, and discussing the use case of transpiling node_modules?

I was mistaken. After clearing the cache, I realize you donā€™t need the custom transform. All jest seems to want is the transformIgnorePatterns to be correct, and to have the babel.config.js in the ROOT directory. Seems like it needs to be updated to respect package.json babel config, as this is a valid location according to babel.