【问题标题】:Can't use uuid module when running tests with Jest使用 Jest 运行测试时无法使用 uuid 模块
【发布时间】:2020-09-21 16:15:59
【问题描述】:

我有一个非常简单的 Node.js (12.16.3) 应用程序,它使用 Express 4.17.1。我正在尝试使用 Jest 26.0.1 来运行测试套件,但由于整个项目中使用的 uuid 模块(版本 8.1.0)的一些问题,同样失败了:

[x80486@uplink:~/Workshop/node-guacamole]$ npm run test 

> node-guacamole@0.3.0 test /home/x80486/Workshop/node-guacamole
> node --experimental-modules --experimental-vm-modules ./node_modules/.bin/jest --coverage --detectOpenHandles --forceExit --verbose

(node:71155) ExperimentalWarning: The ESM module loader is experimental.
 FAIL  src/domain/customer.test.js
  ● Test suite failed to run

    SyntaxError: The requested module 'uuid' does not provide an export named 'v4'

      at jasmine2 (node_modules/jest-jasmine2/build/index.js:228:5)

 FAIL  src/service/customer.service.test.js
  ● Test suite failed to run

    SyntaxError: The requested module 'uuid' does not provide an export named 'v4'

          at async Promise.all (index 4)
      at jasmine2 (node_modules/jest-jasmine2/build/index.js:228:5)

 FAIL  src/handler/customer.handler.test.js
  ● Test suite failed to run

    SyntaxError: The requested module 'uuid' does not provide an export named 'v4'

          at async Promise.all (index 2)
          at async Promise.all (index 7)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |       0 |        0 |       0 |       0 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 3 failed, 3 total
Tests:       0 total
Snapshots:   0 total
Time:        0.63 s
Ran all test suites.

我正在导入模块,例如:import { v4 } from "uuid";另一方面,应用程序运行成功:

[x80486@uplink:~/Workshop/node-guacamole]$ npm run start:dev 

> node-guacamole@0.3.0 start:dev /home/x80486/Workshop/node-guacamole
> nodemon --experimental-modules --experimental-vm-modules ./src/main.js

[nodemon] 2.0.4
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node --experimental-modules --experimental-vm-modules ./src/main.js`
(node:74672) ExperimentalWarning: The ESM module loader is experimental.
2020-06-03T03:28:48.889Z [debug] - Server running at http://localhost:8080
2020-06-03T03:28:48.889Z [info] - Press CTRL-C to stop

...一切正常。我很困惑......我不明白为什么只有 Jest 会失败。我还需要做些什么才能让它发挥作用吗?

【问题讨论】:

    标签: node.js jestjs node-uuid


    【解决方案1】:

    TL;DR:Jest 还不支持 "exports" 中的字段 package.json

    问题是 Node.js 使用 ESM 版本,因为它理解 package.json 中的“exports”字段,但由于 Jest 还不支持它,Jest 使用 package.json 中的“main”字段来导出CommonJS 版本。见the relevant package.json section

    ...
    "main": "./dist/index.js",
    "exports": {
      "./package.json": "./package.json",
      ".": {
        "require": "./dist/index.js",
        "import": "./wrapper.mjs"
      }
    },
    ...
    

    这是做什么的:

    1. 与往常一样,默认导出为main
    2. 如果 exports 被理解,则会覆盖 "main" 导出
    3. 默认导出"."定义了一个require和import,所以Node.js使用了“import”
    4. 但问题是 the Jest issue 表示它还不理解“包导出”,因此 Jest 正在尝试加载 CommonJS 文件(从“main”),而 Node.js 加载 ESM 文件。

    found the exact same issue and documented it here。作为一个实验,这应该适用于 Jest:

    import uuid from 'uuid';
    const { v4 } = uuid;
    

    但这不适用于 Node.js since UUID does not define a default export

    你有两个现实的选择:

    • 等到 Jest 支持包导出,他们在 ESM 支持方面做得很好,我认为不会花很长时间。
    • Upvote my proposaluuid 包中,它们还导出默认值,例如wrapper.mjs 中的export default uuid,这将允许您使用我在上面放置的sn-p。

    【讨论】:

    • 我想你已经确定了这个,因为我在最初失败时使用这种方式来import 包,但后来应用程序不起作用,所以我回去了,因为我最初拥有的(现在已经)是uuid 开发人员推荐的方式。谢谢你的解释!
    • 我认为弗朗西斯科做对了。作为uuid 的维护者,我只想指出,这些都是实验性的Node.js API(因此有--experimental-modules --experimental-vm-modules 标志),因此会出现问题。我宁愿不添加默认导出只是为了解决当前的 jest 缺陷,该缺陷将很快得到修复。这只会使测试正确的pkg.exports 支持更难。
    【解决方案2】:

    问题是Jestuuid 之间的版本不兼容。 uuid 版本 8 支持原生 ES 模块,而 Jest 版本 26 不支持。

    您始终可以使用以下语法 uuid 版本 3.x.x:

    const uuid = require('uuid/v4');
    uuid(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
    

    【讨论】:

    • 我不完全遵循那个。 Jest 需要支持一些“ES 模块”特性,对吧?否则我什至无法执行任何操作。如果我只是删除那个uuid 模块,一切都很好。问题仅在于 Jest,我可以在使用 uuid 模块时正确执行应用程序。
    • 你能发布你的配置文件吗?您还使用了哪些其他库与导入语法,它们是否与 Jest 一起使用?
    • Alim,Jest 还不支持字段"exports";查看弗朗西斯科的答案。
    【解决方案3】:

    我的回答是附注,但我怀疑问题的本质与 import { v4 } from "uuid" 的导入语法有关。

    例如那里有一个相关的警告:

    (node:74672) ExperimentalWarning: E​​SM 模块加载器是实验性的。

    通常捆绑的 JavaScript 与将模块加载到 Jest 系统中的方式之间可能存在细微的不一致。因此,解决方案可能涉及到配置文件的添加——这样 Jest 可以理解 ESM 语法。例如这里有一个有趣的答案:ts-jest does not recognize es6 imports

    相关MDN:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

    import 语句不能用于嵌入式脚本,除非此类脚本具有 type="module"。导入的绑定称为实时绑定,因为它们由导出绑定的模块更新。

    作为测试,您可以看看像这样导入它是否会有所不同:

    const { v4: uuidv4 } = require('uuid');
    const v4 = uuidv4;
    

    const v4 = require('uuid').v4 // might work as well
    

    如果它有效,我不建议使用它,但它应该将其范围缩小到绝对的语法。

    问题源于这里的文件:https://github.com/uuidjs/uuid/blob/master/src/index.js 在我看来,因为该文件是一个传递文件(大致类似于符号链接),所以 Jest 正在尝试导入导出的导出。

    这可能与 Babel 和缺少转换装置有关。正确修复它应该可以缓解与“ESM loader”相关的所有问题。

    【讨论】:

    • 所以import 语法应该没问题,我正在正确使用应用程序;尝试通过 Jest 运行测试时会出现问题。我尝试了你的建议,但由于我在package.json 中有"type": "module",我想它不会让我使用它。
    • 这是一个有趣的问题。很高兴您找到了解决方案。
    猜你喜欢
    • 2021-05-30
    • 2021-10-15
    • 2021-02-22
    • 1970-01-01
    • 2017-02-13
    • 2020-05-07
    • 2020-05-30
    • 2022-11-09
    • 2021-04-23
    相关资源
    最近更新 更多