3

I added nanoid to a package in my monorepo, and a jest test in a downstream package is failing with this error message:

   Details:

    /Users/mikehogan/repos/personal/docsndata-monorepo/node_modules/.pnpm/nanoid@4.0.0/node_modules/nanoid/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { randomFillSync } from 'crypto'
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

       9 | const model_types_2 = require("@docsndata/model-types");
      10 | const model_types_3 = require("@docsndata/model-types");
    > 11 | const nanoid_1 = require("nanoid");
         |                  ^
      12 | const uuid_1 = require("uuid");
      13 | function emptyStringMatchesRegexCondition() {
      14 |     return { _type: 'string.matches.regex', regex: "" };

      at Runtime.createScriptFromCode (../../node_modules/.pnpm/jest-runtime@28.1.3/node_modules/jest-runtime/build/index.js:1796:14)
      at Object.<anonymous> (../../model/core2/dist/cjs/property_types.js:11:18)

I tried the suggestions in this answer: How to use Jest to test functions using crypto or window.msCrypto

Specifically, when I paste this suggested snippet into my test case:

import crypto from 'crypto'

Object.defineProperty(global, 'crypto', {
  value: {
    getRandomValues: (arr:any) => crypto.randomBytes(arr.length)
  }
});

My IDE tells me I need to install the crypto package, but that is deprecated according to its npm registry, in favour of a built in module. My ide also tells me that "global" is undefined. I am using node 16 and Typescript with the following tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ES2020",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist/esm",
    "declaration": true,
    "moduleResolution": "node"
  },
  "include": [
    "./src"
  ]
}

and the following jest.config.js:

module.exports = {
    globals: {
        'ts-jest': {
            packageJson: 'package.json',
        },
    },
    "roots": [
        "<rootDir>/src",
        "<rootDir>/test",
    ],
    "testMatch": [
        "**/__tests__/**/*.+(ts)",
        "**/?(*.)+(spec|test).+(ts)"
    ],
    "transform": {
        "^.+\\.(ts)$": "ts-jest"
    },
};


So if crypto is now in-build, I added "@types/node": "^18.7.14" to my package.json. THAT has no crypto export, so I took a guess and did this:

import {webcrypto} from "crypto";

Object.defineProperty(global.self, "crypto", {
  value: {
    subtle: webcrypto.subtle,
  },
});

Test fails with the same error. So confused and out of my depth here. Can someone please explain:

  • Why jest is effected by what my production code imports?
  • Is jest effected in this way by the crypto package specifically, or is it a more general issue?
  • How do I fix it in a centralised way, for 1000s of jest tests in a large monorepo?

Edit #1: Reading up some more, it seems the version of nanoid I am using (4.0.0) removed support for CJS modules, as per https://github.com/ai/nanoid/blob/main/CHANGELOG.md#40 . Switching to nanoid 3.3.4 works, so at least I can move forward for now, but I still need to solve this.

Mike Hogan
  • 9,933
  • 9
  • 41
  • 71

0 Answers0