Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop polyfilling existing globals #3682

Closed
kettanaito opened this issue Feb 12, 2024 · 8 comments
Closed

Stop polyfilling existing globals #3682

kettanaito opened this issue Feb 12, 2024 · 8 comments

Comments

@kettanaito
Copy link

kettanaito commented Feb 12, 2024

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.

@kettanaito
Copy link
Author

Please consider removing custom implementations of things that already exist in Node.js. Those are harmful, and they are already causing real issues, and will cause more and more issues as Node.js aims to align itself with the browser APIs.

Instead, properly rely on the globals that implement the same specification in both the browser and Node.js. That includes Event and EventTarget just as two specific examples. This has to be adopted globally to prevent runtime incompatibilities, which are plentiful with JSDOM.

@domenic
Copy link
Member

domenic commented Feb 12, 2024

You seem to have misunderstood the purpose of the jsdom project.

@domenic domenic closed this as completed Feb 12, 2024
@kettanaito
Copy link
Author

@domenic, apologies if that's the case. I just see little value in polyfilling global APIs that exist in both the browser and Node.js. If only those polyfills weren't harmful in practice, wasting quite a bit of time on things that mustn't require time at all.

@stevenpollack
Copy link

You seem to have misunderstood the purpose of the jsdom project.

Asking for a friend: what is the purpose of this project, again?

@lennerd
Copy link

lennerd commented Jun 6, 2024

So JSdom really has no way to disable some of the polyfills to use the ones in Node? This makes some tests very difficualt or even impossible to write.

@victorhahncastell
Copy link

I agree with the reporter that this behaviour is unexpected and makes life hell in testing -- which is obviously a major use case of JSDOM and usually performed using NodeJS.

The fact that JSDOM's Buffers are neither compatible with NodeJS' nor even based on Uint8Array basically means I need to introduce extra code just to ensure that JSDOM's strange Buffers never sneak into my objects.

@badams-atlas
Copy link

badams-atlas commented Jan 7, 2025

Hey @kettanaito

How did you work a round this issue? I'm running into a similar problem.

TypeError: The "event" argument must be an instance of Event. Received an instance of MessageEvent

Note: I'm using vitest rather than jest.

@kettanaito
Copy link
Author

@badams-atlas I stopped using jsdom and tested that functionality in a Node.js environment instead. You can also test it in the real browser, using tools like Vitest Browser Mode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants