Jest和Babel转译 - SyntaxError: Cannot use import statement outside a module

10

在某些测试中,我使用JEST时遇到困难,在运行测试时出现以下错误:

测试套件无法运行

...node_modules\p-retry\index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import retry from 'retry';
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

    > 1 | import pRetry from 'p-retry';
        | ^
      2 |
      3 | export function Retry(tries: number) {

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
      at Object.<anonymous> (src/common/Retry.ts:1:1)

同时,我的webpack构建与typescript和babel很好地配合使用。我尝试了许多方法(请参见下文),但没有成功,并且实际上无法理解发生了什么。从我的观点来看 - 虽然转换的东西对我来说是一个黑盒子,但我尝试启用Jest使用ESModules并提供代码以及尝试提供commonJS模块代码。
因此,我正在寻找替代选项和进一步调查的方法。特别是有一件事引起了我的注意:错误中的Retry.ts文件是我的文件之一,它导入了pRetry(一个以ESModule风格编写的node_module),在其代码中从第一行开始就执行“import retry from'retry'”(另一个以commonJS风格编写的node-module)。
所以在我看来,似乎发生的是pRetry没有从其ESModule代码(pRetry源代码以“import retry from'retry';”开头)进行转换,而只是在语法正确的情况下用一些commonJS代码包装起来。
因此,我的下一步可能是调查babel-jest真正生成了什么,并检查那里面的问题并进行推断。有人知道如何实现���一点(尤其是了解babel-jest生成的内容)或者有其他想法吗?
我尝试过的事情-全部失败了(有时会出现略微不同的错误)
1. 在babel.config.js中使用plugins: ["@babel/plugin-transform-runtime"] 2. 在tsconfig.json中更改target和module为es5 3. 在jest.config.ts中添加以下内容transformIgnorePatterns: ["node_modules/?!(p-retry)"] 4. 在jest.config.ts中使用以下内容,或者对于两者均使用ts-jest或babel-jest:

preset: "ts-jest",
transform: { '^.+\.(ts|tsx)?$': 'ts-jest', "^.+\.(js|jsx)$": "babel-jest"}

5. 按照一篇文章的建议从.babelrc文件迁移到babel.config.js 6. 在tscfonfig.json中使用AllowJS:true和在jest中使用transformIgnorePatterns组合 7. 将["@babel/plugin-transform-runtime",{"regenerator":true}]添加到babel.config中 8. 在jest.config中使用如下:

preset: "ts-jest",
testEnvironment: "node", transform: {"node_modules/p-retry/.+\.(j|t)sx?$": "ts-jest"},
transformIgnorePatterns: ["node_modules/(?!p-retry/.\*)"]

  1. 在 babel.config 中使用 "transform-es2015-modules-commonjs"
  2. 在 babel.config 中使用 @babel/plugin-transform-modules-commonjs
  3. 按照以下步骤进行操作,如 https://dev59.com/vlsV5IYBdhLWcg3w0hlU 所建议的:
  • 确保不要通过设置 transform: {} 在配置文件中转换 import 语句
  • 使用 --experimental-vm-modules 标志运行 node@^12.16.0 || >=13.2.0
  • 使用 jest-environment-node 或 jest-environment-jsdom-sixteen 运行测试
  1. 在 jest.config.ts 中尝试使用类似于 jest-environment-node、node 或 jsdom 的测试环境

jest-config.ts:

const tsconfig = require("./tsconfig.json");
const moduleNameMapper = require("tsconfig-paths-jest")(tsconfig)

export default {
   collectCoverage: true,
   coverageDirectory: "analysis/coverage",
   coveragePathIgnorePatterns: ["/node_modules/"],
   collectCoverageFrom: ["src/**/*.{js,jsx,ts}"],
   coverageReporters: ["json", "lcov", "text", "clover"],
   coverageThreshold: {
      global: {
         branches: 0,
         functions: 0,
         lines: 0,
         statements: 0
      },
   },
   clearMocks: true,
   coverageProvider: "babel",
   moduleNameMapper,
   roots: ["<rootDir>/src/", "<rootDir>/test/"],
   testEnvironment: 'jest-environment-node', 
   testPathIgnorePatterns: [
      "\\\\node_modules\\\\"
   ],
   "transform": {
      "^.+\\.(js|ts|jsx)$": "babel-jest"
   }
};

babel.config.js:

    module.exports = {
   presets: ['@babel/preset-typescript',
      ['@babel/preset-env', {
         targets: { node: "current" }
      }],
      '@babel/preset-flow',

   ],
   plugins: [["@babel/plugin-transform-modules-commonjs"], ["@babel/plugin-proposal-decorators", { "legacy": true }], ["@babel/plugin-proposal-class-properties"]]
}

从package.json中提取

"@babel/core": "^7.16.12",
"@babel/plugin-proposal-decorators": "^7.16.5",
"@babel/plugin-transform-modules-commonjs": "^7.16.8",
"@babel/plugin-transform-runtime": "^7.16.10",
"@babel/preset-env": "^7.14.4",
"@babel/preset-flow": "^7.16.7",
"@babel/preset-typescript": "^7.13.0",
"@babel/runtime": "^7.16.7",
"babel-jest": "^27.4.6",
"babel-plugin-transform-regenerator": "^6.26.0",         
"jest": "^27.0.4",
"jest-config": "^27.4.5",
"jest-esm-transformer": "^1.0.0",
"ts-jest": "^27.1.3",
"tsconfig-paths-jest": "^0.0.1",
"core-js": "^3.20.0",

只是额外的一点说明:自从使用Jest 29后,我再次遇到了同样的错误问题,但之前的解决方案不起作用,而且过去我一直在使用Jest时也遇到了问题,所以我迁移到了Vitest。Api似乎非常符合Jest的要求,在我的情况下迁移很容易。也许对其他人来说也是一个选择。 - TomFree
4个回答

2
你可以在jest.config.js中添加以下内容,让Jest不忽略对的转换,这对我很有效。请注意保留HTML标签。
  "transformIgnorePatterns": [
    "node_modules/(?!(p-retry)/)",
  ],

如果这个库需要更多的库,并且这会导致更多的错误,那该怎么办? - VityaSchel

2

我的解决方案使用了"jest": "^28.1.0"

package.json中:

  1. devDependencies下添加:
"@babel/preset-env": "^7.18.10"

2. 并且,
"jest": {
  "transform": {
    "^.+\\.[t|j]sx?$": "babel-jest"
  }
},

babel.config.json中添加:

{
  "presets": ["@babel/preset-env"]
}

2
原来我很接近了。
通过在babel.config.ts中添加esmodules: false就可以完成了:-)
module.exports = {
   presets: ['@babel/preset-typescript',
      ['@babel/preset-env', {
         targets: { esmodules: false, node: "current" }
      }],
      '@babel/preset-flow',
    
   ],
   plugins: [["@babel/plugin-transform-modules-commonjs"], ["@babel/plugin-proposal-decorators", { "legacy": true }], ["@babel/plugin-proposal-class-properties"]]
}

我不是给你的解决方案点的踩,但它对我不起作用。我还在努力想办法修复它。 - Robin Elvin
1
对我来说也是一样的...没有一个全局解决方案非常令人恼火。 - La pach'

0
在我的情况下,我不得不按照这里的详细说明添加特定的模块映射: https://dev59.com/SlIH5IYBdhLWcg3wYtAS#65250052
这将强制Jest加载CommonJS版本的模块,因为测试是在Node中运行,即使最终目标是浏览器。

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