【问题标题】: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 proposal 在uuid 包中,它们还导出默认值,例如wrapper.mjs 中的export default uuid,这将允许您使用我在上面放置的sn-p。

    【讨论】:

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

    问题是Jest 和uuid 之间的版本不兼容。 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
    相关资源
    最近更新 更多