Skip to content

Stop polyfilling existing globals #3682

@kettanaito

Description

@kettanaito

Basic info:

  • Node.js version: v18+
  • jsdom version: any JSDOM version

Issue

JSDOM is polyfilling a bunch of already existing global APIs, which leads to all sorts of issues when the underlying code expects those APIs to be actual.

All the issues I'm describing are transient. They are likely not reproducible in an isolated JSDOM environment since JSDOM creates an illusion of "globals" working instead of actually relying on the environment's globals that already exist.

While JSDOM aims to emulate the browser, most of my (and others') pain of working with JSDOM rises from it ignoring that it's still being run in Node.js. It must respect Node.js globals to create a functional, complete environment.

Example 1: AbortSignal doesn't extend EventTarget

import { implementation as AbortSignal } from 'jsdom/lib/jsdom/living/aborting/AbortSignal-impl'

it('AbortSignal extends EventTarget', () => {
  expect(AbortSignal instanceof EventTarget).toBe(true)
})

Root cause: JSDOM extends its own EventTarget implementation. This is incorrect and harmful. No child classes of the custom EventTargetImpl in JSDOM will be treated as valid events in Node.js. It will throw right here, among other places:

Example 2: Custom Event

JSDOM implements a custom EventImpl instead of relying on the global Event class. No derives events will be considered valid events by Node.js.

Example: try dispatching an Event on an EventTarget instance.

import { implementation as Event } from 'jsdom/lib/jsdom/living/events/Event-impl'
// Valid global EventTarget in Node.js
const target = new EventTarget()

target.dispatchEvent(new Event('hello'))

This will throw right over here in Node.js:

Because custom Event implementation from JSDOM is not a valid Event in Node.js.

Minimal reproduction case

I've provided two reproduction cases above. Please see those. I can submit a test suite that fails with JSDOM due to it not respecting Node.js globals.

How does similar code behave in browsers?

Both browsers and Node.js correctly rely on and execute global functions. I expect JSDOM not to rob me of those either.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions