"ReferenceError: structuredClone is not defined" using jest with nodejs & typescript

44k Views Asked by At

I'm running tests with jest in a simple NodeJS app that uses typescript. My test is throwing an error: ReferenceError: structuredClone is not defined.

I'm not getting any linter errors and the code compiles fine normally.

  const variableForValidation = structuredClone(variableForValidationUncloned);

package.json:

  "dependencies": {
    ...
  },
  "devDependencies": {
    "@types/jest": "^29.0.0",
    "@types/node": "^18.7.15",
    "@typescript-eslint/eslint-plugin": "^5.36.1",
    "@typescript-eslint/parser": "^5.36.1",
    "eslint": "^8.23.0",
    "jest": "^28.0.1",
    "nodemon": "^2.0.19",
    "serverless-plugin-typescript": "^2.1.2",
    "ts-jest": "^28.0.8",
    "ts-node": "^10.9.1",
    "typescript": "^4.8.2"
  }

This github issue suggests to me that the issue has been resolved: https://github.com/facebook/jest/issues/12628 - or perhaps I'm misunderstanding?

I've seen a similar Stack question but using Mocha: mocha not recognizing structuredClone is not defined

8

There are 8 best solutions below

4
On BEST ANSWER

structuredClone was added in Node 17.

If you can't update, the JSON hack (stringify then parse) works, but has some shortcomings that might be relevant to you:

  • Recursive data structures: JSON.stringify() will throw when you give it a recursive data structure. This can happen quite easily when working with linked lists or trees.
  • Built-in types: JSON.stringify() will throw if the value contains other JS built-ins like Map, Set, Date, RegExp or ArrayBuffer.
  • Functions: JSON.stringify() will quietly discard functions.

Edit:

I recently learned about the json-stringify-safe, that helps with the circular issue.

0
On

Had the same issue with jsdom. They have no structuredClone global in current ([email protected]) version, and the issue seems stale: https://github.com/jsdom/jsdom/issues/3363.

In addition to the workarounds discussed, I would provide my approach based on setupFiles jest setting:

// global.mock.js
global.structuredClone = v => JSON.parse(JSON.stringify(v));
// jest.config.js
module.exports = {
  testEnvironment: "jsdom",
  ...
  roots: ["./__tests__"],
  setupFiles: ["<rootDir>/global.mock.js"]
};

0
On

For anyone who has already updated Jest and Node and still can't get structuredClone to work, try running:

console.log(`Node Version: ${process.version}`);

And verify that the logged version number supports structuredClone.

IDE misconfigurations can cause Jest to be run using a different version of Node. When I ran my project it used Node v17, but when I ran tests my IDE decided to use Node v16. Took hours to figure out what was happening.


After running into this problem again, jest 27 combined with ts-jest 27 seems to not be able to use structuredClone even if you are on Node v17. I solved this by updating to jest 29 and ts-jest 29.

0
On

Update the version of your node to the most recent one.

4
On

I couldn't figure it out, so I set my own global:

// globals.ts
if(!global.structuredClone){
    global.structuredClone = function structuredClone(objectToClone: any) {
          const stringified = JSON.stringify(objectToClone);
          const parsed = JSON.parse(stringified);
          return parsed;
        }
}
// entry point of app, eg index.ts:
import './globals.ts'
// ...

I think it might be because the target in my tsconfig is converting my typescript files to a javascript/node version before structuredClone was added?

5
On

For the same error, having the code below in the test file fixed the issue for me.

global.structuredClone = (val) => JSON.parse(JSON.stringify(val))

Reference

0
On

I had the same issue with testEnvironment set to jest-environment-jsdom in my Jest config file.

@fservantdev has linked to this issue (currently open at the time of writing) regarding this: https://github.com/jsdom/jsdom/issues/3363

There are several possible workarounds suggested in that thread - the following worked for me:

  1. npm install @ungap/structured-clone
  2. npm i --save-dev @types/ungap__structured-clone
  3. Add the following line at the top of all the files where structuredClone is being used: import structuredClone from "@ungap/structured-clone";.

UPDATE: This suggestion from tkrotoff might be a better one. In short, this is a hot topic at the time of writing so worth reading the thread to stay up to date...

1
On

A polyfill of structuredClone is available in core-js. Add it to your jest.config.js.

import 'core-js' or require('core-js')

Note: Don't forget to add core-js to your babel exclude pattern.