Skip to content

Solving "ReferenceError: structuredClone is not defined" in Jest Tests

Current Status

structuredClone() was added in Node.js 17.0.0 (Sept 2021). If you're using older Node versions or Jest environments like jsdom, manual solutions are needed.

Problem Overview

When running Jest tests in Node.js/TypeScript environments, you might encounter:

bash
ReferenceError: structuredClone is not defined

This occurs because:

  1. structuredClone() is unavailable in Node.js versions below 17
  2. jsdom (used by Jest for browser-like environments) lacks its implementation
  3. Your production environment supports it, but testing environment doesn't

1. Update Node.js Version (Ideal Solution)

Upgrade to Node.js v17+:

bash
# Check current version
node --version

# Update using nvm (recommended)
nvm install 18
nvm use 18

# Or via package manager (e.g., macOS Homebrew)
brew update && brew upgrade node

Verify support:

js
console.log('Native structuredClone support:', typeof structuredClone !== 'undefined');

Minimum Version Note

Ensure all team members and CI/CD pipelines update simultaneously to prevent environment inconsistencies.

2. Global Polyfill in Jest Configuration

For older Node versions or jsdom environments:

js
module.exports = {
  setupFiles: ['<rootDir>/jest.setup.ts'],
  // Other configurations...
};
ts
declare global {
  function structuredClone<T>(obj: T): T;
}

// Add polyfill implementation
global.structuredClone = <T>(obj: T): T => {
  if (typeof globalThis.structuredClone === 'function') {
    return globalThis.structuredClone(obj);
  }
  return JSON.parse(JSON.stringify(obj)) as T;
};

3. Robust Polyfill Library

For complete feature support (Dates, Maps, custom classes, circular refs):

bash
npm install @ungap/structured-clone
npm install -D @types/ungap__structured-clone
ts
import structuredClone from '@ungap/structured-clone';

export const deepClone = <T>(obj: T): T => structuredClone(obj);
ts
import { deepClone } from './utils/clone';

test('cloning test', () => {
  const original = new Map([['key', { value: 123 }]]);
  const cloned = deepClone(original);
  // Assertions...
});

Polyfill Limitations

While libraries provide better coverage, they can't perfectly replicate native browser behavior. Profile performance for large objects.

Environment-Specific Fixes

Fixing jsdom Environments

When using jest-environment-jsdom, add this to your setup file:

js
// Only define if missing in jsdom
if (!global.structuredClone) {
  global.structuredClone = function (obj) {
    return new Promise((resolve) => {
      const { port1, port2 } = new MessageChannel();
      port2.onmessage = (ev) => resolve(ev.data);
      port1.postMessage(obj);
    });
  };
}

Jest Version Conflicts

If you've updated Node but still see errors:

  1. Upgrade Jest and related tools:
bash
npm install --save-dev jest@29 ts-jest@29
  1. Verify actual Node version in tests:
ts
test('debug env', () => {
  console.log(`Test Node version: ${process.version}`);
});

Alternative: Switch to Vitest

For modern projects, consider Vitest (Jest-compatible API):

bash
npm remove jest ts-jest @types/jest
npm install -D vitest happy-dom @vitest/coverage-v8
js
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    environment: 'happy-dom',
    setupFiles: './vitest.setup.ts',
    coverage: { provider: 'v8' },
  },
});
ts
import { expect, test } from 'vitest';

test('structuredClone works', () => {
  const original = { date: new Date() };
  const cloned = structuredClone(original);
  expect(cloned.date instanceof Date).toBe(true);
});

When to Use Which Solution?

SolutionBest ForNode Version RequiredComplexity
Update Node.jsGreenfield projects, team alignmentv17+★☆☆☆☆
Global PolyfillLegacy projects, quick fixesAny★★☆☆☆
Polyfill LibraryComplex objects, circular referencesAny★★★☆☆
Switch to VitestPerformance-critical tests, modern stacksv14+★★★★☆

Historical Context

  • structuredClone() entered browser specs in 2021 (MDN Docs)
  • Node.js implemented it in v17.0.0 (September 2021)
  • jsdom support is still pending as of 2024 (GitHub Issue)

Always prioritize upgrading Node.js where possible. For constrained environments, choose polyfills based on your data complexity and testing needs. Remember to document your solution for team awareness!