Search code examples
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:

    • Wait until Jest supports package exports, they are doing a great job with ESM support and I don't think it will take long.
    • Upvote my proposal in the uuid package that they also export a default, like export default uuid in wrapper.mjs, which would allow you to use the snippet I put above.