94

I'm implementing tests into an existing project that currently has no tests. My tests are failing to compile node_modules/ imports.

/Users/me/myproject/node_modules/lodash-es/lodash.js:10
export { default as add } from './add.js';
^^^^^^
SyntaxError: Unexpected token export
  
  at transformAndBuildScript (node_modules/jest-runtime/build/transform.js:320:12)
  at Object.<anonymous> (app/reducers/kind_reducer.js:2:43)
  at Object.<anonymous> (app/reducers/index.js:12:47)

The workaround I've found is to 'whitelist' node_modules in package.json jest config like this:

"jest": {
    "transformIgnorePatterns": [
      "!node_modules/"
    ]
  }

This seems like a hack because it takes over 1 minute to run a simple test that imports node_modules/lodash-es/lodash.js.

Zoe
  • 27,060
  • 21
  • 118
  • 148
Cory Robinson
  • 4,616
  • 4
  • 36
  • 53
  • 2
    A lot of node modules export ES5 so that jest can run it out of the box without transform. that's why by default jest doesn't transform node_modules. In this case, lodash-es specifically exports es modules, so you HAVE to let jest transform that code. You might be safe if you use `"!node_modules/lodash-es"` in your `transformIgnorePatterns` instead so that jest runs babel on lodash-es only. – Lewis Chung Feb 20 '17 at 20:19

7 Answers7

134

If none of the other solutions worked for you, you can try this in your jest

"moduleNameMapper": {
    "^lodash-es$": "lodash"
}

It will replace lodash-es with the commonjs version during testing runtime.

Chris Villa
  • 3,901
  • 1
  • 18
  • 10
Ozair Patel
  • 1,658
  • 1
  • 12
  • 17
  • 12
    I hate that this is the only answer that worked for me. There has to be a better way than having lodash as a dependency twice – jamesthollowell Apr 29 '19 at 18:02
  • 2
    @jamesthollowell you don't have to directly depend on it since chances are you are already depending on it deeply through another package. I don't really recommend doing it, but you can if you don't want another entry in your pkg.json. – Ozair Patel May 07 '19 at 17:18
  • 6
    Thanks, this is the only solution that worked for me. The `transformIgnorePatterns` approach did not work for me. – baumgarb Dec 09 '19 at 10:15
  • 5
    @jamesthollowell, you only need `lodash` in `devDependencies`, for tests. So it won't affect your bundle size. You can still use `lodash-es` imports throughout your application. – tao Jun 04 '20 at 10:06
  • 2
    This solution appears to be noticeably faster than `transformIgnorePatterns`. (My test suite takes about 17 seconds to run with this and about 23 seconds to run with `transformIgnorePatterns`.) – Josh Kelley Jul 03 '20 at 18:31
  • this worked best for me, and I don't really mind about bundle size for development/tests – James Wilson Aug 25 '20 at 08:37
  • 1
    Instead of using `lodash-es` imports, use `lodash` and alias that to `lodash-es`. This way, your build uses `lodash-es`, but your test runtime uses regular `lodash`, which is exported as CJS. These solutions should be become obsolete overtime, since newer versions of Node.js support ESM and Jest can and should leverage that. – adi518 Sep 27 '20 at 14:32
  • 1
    worked with minor changes: moduleNameMapper: { 'lodash-es': 'lodash', }, – dimson d Nov 24 '21 at 10:31
69

I had to add this into my .jestconfig:

"transformIgnorePatterns": [
  "<rootDir>/node_modules/(?!lodash-es)"
]
Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
Yangshun Tay
  • 49,270
  • 33
  • 114
  • 141
  • 5
    This works, but I have to install `babel-jest`, `babel-preset-env`, `babel-preset-react`, and then `"transform": { "^.+\\.(js|jsx|mjs)$": "/node_modules/babel-jest" }`, since ts and js files require different transform. – FisNaN Jun 29 '18 at 00:48
  • 6
    If you have more than one, you might need to include in same regex like `(?!lodash-es|my-module)`. For some reason, if they are in separate entries, they cancel each other out. – Jazzy Mar 20 '20 at 23:06
  • 3
    They have to be in the same entry because of this statement in jest's docs. "If the test path matches any of the patterns, it will not be transformed." So when my-module is getting tested, it tests true for the ?!lodash-es regex, and it is ignored. – joeycozza Apr 16 '20 at 19:47
  • 5
    To expand on Jazzy's comment: if you _already_ have a `transformIgnorePatterns: [ 'node_modules/(?!foo|bar)' ]` entry, then you **have to add `lodash-es` to that list**; you can't add a separate entry in the transformIgnorePatterns array, because the existing entry already means "ignore all folders under node_modules except foo and bar", so node_modules/lodash-es will be ignored. // Tip (from [github issue comment](https://github.com/nrwl/nx/issues/812#issuecomment-429420861)): If using jest.config.js, you can do `const esModules = ['foo', 'bar', 'lodash-es']` and then `esModules.join('|')` – Daryn Jan 02 '21 at 13:47
  • 6
    Note: if you already have `jest --watch` running, you have to quit and rerun jest before you'll see the `transformIgnorePatterns` changes take effect. – Daryn Jan 02 '21 at 13:48
  • Do we need to add this in package.json file? I added it and it worked – Bhushan Patil Aug 18 '22 at 11:03
  • 2
    @BhushanPatil This is to be added to your Jest config file, which can be defined within your package.json or in a separate jest.config.js file (and its variations). Where to change depends on where your Jest config is located. – Yangshun Tay Aug 19 '22 at 06:40
  • 1
    On an older project, besides adding `transformIgnorePatterns`, I had to rename `.babelrc.js` to `babel.config.js` for it to work. – Yong Jie Wong Nov 12 '22 at 17:57
34

Posting a more complete answer here:

Jest by default does not transform node_modules because node_modules is huge. Most node modules are packaged to expose ES5 code because this is runnable without any further transformation (and largely backwards compatible).

In your case, lodash-es specifically exposes ES modules, which will need to be built by Jest via babel.

You can try narrowing your whitelist down so Jest doesn't try to pass every JavaScript file within node_modules through babel.

I think the correct configuration in your case is:

"jest": {
  "transformIgnorePatterns": [
    "/!node_modules\\/lodash-es/"
  ]
}
Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
Lewis Chung
  • 2,307
  • 1
  • 20
  • 16
  • 2
    It seems the regex is not correct, so babel will transform not just the lodash-es folder, but all the modules inside node_modules folder. This is not ideal. I think the correct regex should be "/node_modules/(?!lodash-es)" – vikingmute May 31 '22 at 02:06
12

For create-react-app users who are looking for a fix, here's what worked for me:

// package.json
...
  "jest": {
    "transformIgnorePatterns": [
      "<rootDir>/node_modules/(?!lodash-es)"
    ]
  },
...

Overriding options in jest.config.js file didn't work for me. Keep in mind that not every option can be overridden, here's a list of supported options: https://create-react-app.dev/docs/running-tests#configuration

8bitjoey
  • 769
  • 7
  • 17
7

Renaming .babelrc to babel.config.js and adding transformIgnorePatterns worked for me.

module.exports = {
  "presets": ["@babel/preset-env"]
}

P.S. My Jest version is:

"jest": "24.9.0"

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

Flavian Hautbois
  • 2,940
  • 6
  • 28
  • 45
Sandeep Sharma
  • 1,855
  • 3
  • 19
  • 34
7

Probably someone finds this useful:

In my case, I have an Angular application that uses lodash-es package. During the testing, I am having the same error as the author.

OPatel's answer worked fine for me with a little tweak (add it to your jest.config.ts):

"moduleNameMapper": {
    "lodash-es": "lodash"
}

After the changes I also needed to add the "esModuleInterop": true into my tsconfig.spec.json within the compilerOptions property to get rid of the TypeError: cloneDeep_1.default is not a function.

UPDATE:

After the solution above all the lodash methods return LodashWrapper instead of actual values e.g.

const clone = cloneDeep(object); // LodashWrapper

To get rid of this issue I used this solution: https://github.com/nrwl/nx/issues/812#issuecomment-787141835

moduleNameMapper: {
    "^lodash-es/(.*)$": "<rootDir>/node_modules/lodash/$1",
}
Andrew Kicha
  • 143
  • 2
  • 6
2

I use pnpm, so I had to account for the symlink in the pattern, i.e.

transformIgnorePatterns: ['/node_modules/.pnpm/(?!lodash-es)']
momotaro
  • 135
  • 1
  • 5