node.jsjestjsnode-uuid

Can't use uuid module when running tests with Jest


I have a very simple Node.js (12.16.3) application that uses Express 4.17.1. I'm trying to use Jest 26.0.1 to run the test suite, but the same is failing due to some issue with the uuid module (version 8.1.0) used across the entire project:

[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.

I'm importing the module like: import { v4 } from "uuid"; and on the other hand, the application runs successfully:

[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

...and everything works fine. I'm puzzled... I don't understand why this fails with Jest only. Is there something else I need to do to make it work?


Solution

  • TL;DR: Jest not yet supports the field "exports" in package.json.

    The problem is that Node.js uses the ESM version since it understands the "exports" field in the package.json, but since Jest does not yet support it, Jest uses the "main" field in package.json which exports the CommonJS version. See the relevant package.json section:

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

    What this does it:

    1. The default export is main, as always.
    2. If the exports is understood, that overwrites the "main" exports
    3. The default exports "." defines a require and import, so Node.js uses the "import"
    4. But the problem is that the Jest issue indicates that it does not yet understand "Package Exports", so Jest is trying to load the CommonJS file (from "main") while Node.js loads the ESM file.

    I found the exact same issue and documented it here. As an experiment, this should work with Jest:

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

    But that will not work with Node.js since UUID does not define a default export.

    You have two realistic options: