笑话:节点模块依赖使用导入语句并导致测试崩溃

Posted

技术标签:

【中文标题】笑话:节点模块依赖使用导入语句并导致测试崩溃【英文标题】:Jest: node_module dependency uses import statement and crashes the test 【发布时间】:2021-04-27 15:17:08 【问题描述】:

TL;DR

我的 Jest 测试崩溃了

    SyntaxError: Cannot use import statement outside a module

因为node_module 使用import 语句。我该如何解决这个错误?

上下文

我正在编写一个 Next.js 应用程序,使用 Jest 作为我的测试运行程序并使用 Magic 进行身份验证。我安装了 ts-node 以在 TypeScript 中运行我的 Jest 测试。

我想测试一个使用 @magic-sdk/admin 包的无服务器函数,该包又使用 ethereum-cryptography 进行其 keccak 哈希算法。

当我运行测试时它崩溃了,因为 ethereum-cryptography 包使用了 import 语句。

 FAIL  src/features/user-authentication/login-handler.test.ts
  ● Test suite failed to run

    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:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
     • 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:

    /Users/my-computer/dev/my-app/node_modules/ethereum-cryptography/src/keccak.ts:1
    ("Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest)import  createHashFunction  from "./hash-utils";
                                                                                             ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1350:14)
      at Object.<anonymous> (node_modules/ethereum-cryptography/src/keccak.ts:3:26)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        2.292 s
Ran all test suites related to changed files.

我的tsconfig.json


  "compilerOptions": 
    "allowJs": true,
    "baseUrl": "./src",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "lib": ["dom", "dom.iterable", "esnext"],
    "module": "esnext",
    "moduleResolution": "node",
    "noEmit": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strict": true,
    "target": "es5"
  ,
  "exclude": ["node_modules"],
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]

我的jest.config.ts 看起来像这样。

export default 
  moduleDirectories: ['node_modules', 'src'],
  moduleNameMapper: 
    '\\.(css|less)$': '<rootDir>/src/tests/mocks/style-mock.js',
  ,
  setupFilesAfterEnv: ['./jest.setup.ts'],
  setupFiles: ['<rootDir>/src/tests/setup-environment-variables.js'],
;

我尝试了什么

这似乎是大量 Google 搜索结果中的常见错误,但没有一个有效。这是我尝试过的。

我尝试在transformIgnorePatterns 中包含该文件夹。

const esModules = ['ethereum-cryptography', '@magic-sdk/admin'].join('|');

export default 
  moduleDirectories: ['node_modules', 'src'],
  moduleNameMapper: 
    '\\.(css|less)$': '<rootDir>/src/tests/mocks/style-mock.js',
  ,
  setupFilesAfterEnv: ['./jest.setup.ts'],
  setupFiles: ['<rootDir>/src/tests/setup-environment-variables.js'],
  transformIgnorePatterns: [`/node_modules/(?!$esModules)`],
;

没有用。

我尝试使用transformts-jest 对其进行显式转换。

transform:  '^.+\\.(ts|tsx|js|jsx)?$': 'ts-jest' ,

我也试过把tsconfig.json中的模块改成commonjs,也没用。

如何解决这个问题并让测试运行?

【问题讨论】:

当前版本的@magic-sdk/admin 没有提到以太坊密码学。这两个软件包都有不会导致此类问题的入口点,因此不知道它为什么会在那里。请提供可以重现问题的***.com/help/mcve,这包括确切的包版本和负责此导入的所有代码。你应该做相反的事情并防止从 src 导入任何东西,最好不要自定义 transformIgnorePatterns,因为转译一个不属于你的包是一个兔子洞。 @EstusFlask @magic-sdk/admin 使用以太坊实用程序,而后者又使用 ethereum-cryptograhy 包。好的将创建一个代码框???? 基本上,您需要找出模块从什么时候开始从 /src/ 导入而不是编译文件,并使用 moduleNameMapper 或其他方式解决此问题。 这不是以太坊问题,而是 Javascript 问题。删除“以太坊”标签 我无法在 Next.js 项目之外重现它????真的很奇怪。 【参考方案1】:

我发现了我的错误。我的jest.config.tsmoduleDirectories 中有src,因为我将Next.js 配置为支持绝对导入。

  moduleDirectories: ['node_modules', 'src'], // ? fails

当我将它明确地从 rootDir 更改为它时,它起作用了?

export default 
  moduleDirectories: ['node_modules', '<rootDir>/src'],
  moduleNameMapper: 
    '\\.(css|less)$': '<rootDir>/src/tests/mocks/style-mock.js',
  ,
  setupFilesAfterEnv: ['./jest.setup.ts'],
  setupFiles: ['<rootDir>/src/tests/setup-environment-variables.js'],
;

【讨论】:

很高兴你把它整理出来。请注意,“失败”是一个已经修复的 sn-p 我遇到了类似的错误,我的问题是 .babelrcbabel.config.js 文件冲突。一旦我清除了它,一切都很好,与你的设置相似。感谢您提出的出色问题 + 事后回答。

以上是关于笑话:节点模块依赖使用导入语句并导致测试崩溃的主要内容,如果未能解决你的问题,请参考以下文章

笑话 - 语法错误:不能在模块外使用 import 语句

无法在模块外使用导入语句 - Vuex 测试类星体

Node12/next9 SyntaxError:无法在模块外使用导入语句

Mocha + TypeScript:不能在模块外使用导入语句

由 AWS SDK 导致的环境被破坏后尝试导入的笑话

在 NestJS 中使用依赖注入导入 TypeScript 模块