Jest设置问题:"SyntaxError: Unexpected token export"

97

我正在将测试集成到一个目前没有测试的现有项目中。我的测试无法编译node_modules/引入。

/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)
我找到的解决方法是在 package.json 的 jest 配置中“白名单”node_modules,如下所示:

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


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

这似乎是一个黑客行为,因为运行导入 node_modules/lodash-es/lodash.js 的简单测试需要超过1分钟。


2
很多节点模块导出ES5,以便jest可以直接运行而无需转换。这就是为什么默认情况下jest不会转换node_modules的原因。在这种情况下,lodash-es特别导出es模块,所以您必须让jest转换该代码。如果您在transformIgnorePatterns中使用"!node_modules/lodash-es",那么您可能是安全的,因此jest仅在lodash-es上运行babel。 - Lewis Chung
8个回答

139
如果其他解决方案都不适用于您,您可以尝试在jest中使用这个。
"moduleNameMapper": {
    "^lodash-es$": "lodash"
}

在测试运行期间,它将使用commonjs版本替换lodash-es


13
很讨厌这是我唯一可用的答案。肯定有更好的方法,而不是重复依赖 lodash。 - jamesthollowell
2
@jamesthollowell,你不必直接依赖它,因为很有可能你已经通过另一个包深度依赖它了。我并不是很推荐这样做,但如果你不想在你的pkg.json中再添加另一个条目,那么你可以这样做。 - Ozair Patel
6
谢谢,这是唯一对我有效的解决方案。transformIgnorePatterns方法对我没有起作用。 - baumgarb
5
@jamesthollowell,你只需要将lodash放在devDependencies中,用于测试。这样不会影响你的打包大小。你仍然可以在应用程序中使用lodash-es导入。 - tao
2
这个解决方案似乎比 transformIgnorePatterns 快得多。(我的测试套件使用此方法运行大约需要17秒,而使用 transformIgnorePatterns 则需要大约23秒。) - Josh Kelley
显示剩余3条评论

69

我必须将这个添加到我的.jestconfig中:

"transformIgnorePatterns": [
  "<rootDir>/node_modules/(?!lodash-es)"
]

5
这个方法可行,但我需要安装 babel-jestbabel-preset-envbabel-preset-react,然后在 "transform": { "^.+\\.(js|jsx|mjs)$": "<rootDir>/node_modules/babel-jest" } 中添加,因为 ts 和 js 文件需要不同的转换。 - FisNaN
6
如果你有多个,你可能需要在正则表达式中包含相同的内容,比如 (?!lodash-es|my-module)。由于某些原因,如果它们分别在不同的条目中,它们会互相抵消。 - Jazzy
3
由于 jest 文档中的这个声明,它们必须在同一个条目中。“如果测试路径与任何模式匹配,则不会进行转换。”所以当 my-module 被测试时,它对?!lodash-es 正则表达式测试为真,并被忽略。 - joeycozza
5
扩展Jazzy的评论:如果您已经有了一个transformIgnorePatterns: [ 'node_modules/(?!foo|bar)' ]条目,则必须将lodash-es添加到该列表中;您不能在transformIgnorePatterns数组中添加单独的条目,因为现有条目已经意味着“忽略除foo和bar之外的所有node_modules文件夹”,因此node_modules/lodash-es将被忽略。//提示(来自github issue comment):如果使用jest.config.js,则可以执行const esModules = ['foo', 'bar', 'lodash-es'],然后执行esModules.join('|') - Daryn
6
注意:如果你已经在运行 jest --watch,你需要退出并重新运行 jest,才能使 transformIgnorePatterns 的更改生效。 - Daryn
显示剩余3条评论

34

在此发布更完整的答案:

Jest默认不转换 node_modules 的代码,因为 node_modules 很大。大多数 Node 模块都是打包成 ES5 代码以便无需进一步转换(并且在很大程度上向后兼容)。

在你的情况下,lodash-es 具体公开了 ES 模块,这将需要 Jest 通过 babel 进行构建。

你可以尝试缩小白名单范围,这样 Jest 就不会尝试通过 babel 处理 node_modules 中的每个 JavaScript 文件。

我认为在你的情况下正确的配置是:

"jest": {
  "transformIgnorePatterns": [
    "/!node_modules\\/lodash-es/"
  ]
}

2
似乎正则表达式不正确,因此Babel将转换不仅是lodash-es文件夹,而且是node_modules文件夹中的所有模块。这并不理想。我认为正确的正则表达式应该是“<rootDir>/node_modules/(?!lodash-es)”。 - vikingmute

12
对于使用create-react-app 的用户正在寻求解决方法,这是对我有效的解决方法:
// package.json
...
  "jest": {
    "transformIgnorePatterns": [
      "<rootDir>/node_modules/(?!lodash-es)"
    ]
  },
...

我尝试在jest.config.js文件中覆盖选项,但没成功。请注意,并非所有选项都可以被覆盖,以下是支持覆盖的选项列表:https://create-react-app.dev/docs/running-tests#configuration


1
谢谢,解决了我的问题。 - newbie
1
这对我有用。我将其添加到package.json文件中。 - Bhushan Patil

7

也许有些人会发现这很有用:

在我的情况下,我有一个使用lodash-es包的Angular应用程序。在测试期间,我遇到了与作者相同的错误。

OPatel的答案对我来说很有效,只需要稍微调整一下(将其添加到您的jest.config.ts中):

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

在进行更改后,我还需要将"esModuleInterop": true添加到我的tsconfig.spec.json中的compilerOptions属性中,以摆脱TypeError: cloneDeep_1.default is not a function

更新:

在上述解决方法之后,所有的lodash方法返回的都是LodashWrapper而不是实际值,例如:

const clone = cloneDeep(object); // LodashWrapper

为了解决这个问题,我使用了以下解决方案:https://github.com/nrwl/nx/issues/812#issuecomment-787141835
moduleNameMapper: {
    "^lodash-es/(.*)$": "<rootDir>/node_modules/lodash/$1",
}

7

这是使其正常工作的关键,结合transformIgnorePatterns - Flavian Hautbois

2

我使用pnpm,因此我必须在模式中考虑符号链接,即

transformIgnorePatterns: ['/node_modules/.pnpm/(?!lodash-es)']

-1
我通过阅读https://docs.expo.dev/develop/unit-testing/中的文档解决了这个问题,所以我将我的jest.config.js更改如下,并最终解决了它。如果你遇到任何模块导入抛出错误的情况,只需将其添加到"transformIgnorePatterns"字段中。
module.exports = {
  preset: 'jest-expo',
  "transformIgnorePatterns": [
    "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg|@rneui/base)"
  ]
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接