Skip to content

fix: preserve native Event/dispatchEvent in jsdom setup for Deno compatibility#9

Merged
Lojhan merged 1 commit into
mainfrom
fix/jsdom-deno-event-compatibility
Apr 5, 2026
Merged

fix: preserve native Event/dispatchEvent in jsdom setup for Deno compatibility#9
Lojhan merged 1 commit into
mainfrom
fix/jsdom-deno-event-compatibility

Conversation

@Lojhan
Copy link
Copy Markdown
Collaborator

@Lojhan Lojhan commented Apr 5, 2026

Problem

When running tests under Deno with happy-dom, the process exited with:

TypeError: Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.
    at GlobalWindow.dispatchEvent (happy-dom/src/event/EventTarget.ts:122:10)
    at dispatchBeforeUnloadEvent (ext:runtime_main/js/99_main.js:469:22)

With jsdom + isolation:process, each per-test subprocess exited with:

TypeError: Cannot set properties of undefined (setting 'target')
    at setTarget (ext:deno_web/02_event.js:97:29)
    at dispatchEvent (ext:deno_web/02_event.js:1055:7)
    at dispatchLoadEvent (ext:runtime_main/js/99_main.js:466:15)

Both errors share the same root cause: dom-env.ts was overwriting globalThis.Event, globalThis.CustomEvent, and globalThis.dispatchEvent with the DOM library's own implementations. When Deno's runtime teardown fires dispatchLoadEvent() on exit it uses its own native Event constructor, which is no longer present on globalThis.

isolation:none was unaffected because no subprocess teardown occurs.

Fix

In both setupHappyDomEnvironment() and setupJsdomEnvironment() in dom-env.ts:

  1. Capture the runtime's native Event, CustomEvent, and dispatchEvent before installing the DOM library globals.
  2. After installation, restore them so Deno's exit handlers see the original constructors.

This leaves full DOM functionality intact while keeping Deno's shutdown path working.

Compatibility matrix after fix

All 24 combinations now pass (Node × Bun × Deno) × (happy-dom × jsdom) × (isolation:none × isolation:process) — 24/24 ✅.

…atibility

Under isolation:process, Deno spawns a per-test subprocess and fires
dispatchLoadEvent() on exit using its own native Event constructor.
setupJsdomEnvironment() was unconditionally overwriting globalThis.Event
with jsdom's implementation, causing setTarget() to receive undefined:

  TypeError: Cannot set properties of undefined (setting 'target')
    at setTarget (ext:deno_web/02_event.js:97:29)

Apply the same save/restore pattern already present in
setupHappyDomEnvironment(): capture the runtime's native Event,
CustomEvent, and dispatchEvent before constructing JSDOM, then
restore them after. isolation:none is unaffected as no subprocess
teardown occurs. Fixes all 24 matrix combinations (24/24 ✅).
@Lojhan Lojhan merged commit 3e734f6 into main Apr 5, 2026
9 checks passed
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

Successfully merging this pull request may close these issues.

1 participant