mirror of
https://github.com/pezkuwichain/pezkuwi-dev.git
synced 2026-10-22 19:56:18 +00:00
The browser environment replaces Node's Event with JSDOM's. Node's WebSocket dispatches through Node's EventTarget, which rejects that Event, so no open, message or error reached a listener and no connection ever came up: an ApiPromise against a live node never became ready. JSDOM's WebSocket now replaces Node's, as Event and CustomEvent already do. A spec completes a handshake with a local server and receives a frame.
189 lines
6.9 KiB
TypeScript
189 lines
6.9 KiB
TypeScript
// Copyright 2017-2026 @pezkuwi/dev-test authors & contributors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import type { DOMWindow } from 'jsdom';
|
|
|
|
import { JSDOM } from 'jsdom';
|
|
|
|
/**
|
|
* Constructors that Node defines as well. A DOM node only accepts an event
|
|
* created in its own realm, so in the browser environment the JSDOM ones
|
|
* replace Node's, as they do under jest-environment-jsdom.
|
|
*
|
|
* WebSocket follows from that: Node's own dispatches its events through
|
|
* Node's EventTarget, which rejects the JSDOM Event that replaced Node's, so
|
|
* no open, message or error ever reaches a listener and a connection never
|
|
* comes up. JSDOM's WebSocket dispatches events from its own realm.
|
|
*/
|
|
export const BROWSER_OVERRIDES: readonly string[] = ['CustomEvent', 'Event', 'WebSocket'];
|
|
|
|
/**
|
|
* JSDOM does no layout, so no element ever changes size and the callback
|
|
* never runs. JSDOM has no ResizeObserver of its own.
|
|
*/
|
|
class ResizeObserver {
|
|
observe (): void {
|
|
// nothing is ever resized
|
|
}
|
|
|
|
unobserve (): void {
|
|
// nothing is being watched
|
|
}
|
|
|
|
disconnect (): void {
|
|
// nothing is being watched
|
|
}
|
|
}
|
|
|
|
/** The DOM node hierarchy, which libraries check with instanceof */
|
|
function nodes (window: DOMWindow) {
|
|
return {
|
|
CharacterData: window.CharacterData,
|
|
Comment: window.Comment,
|
|
Document: window.Document,
|
|
DocumentFragment: window.DocumentFragment,
|
|
Element: window.Element,
|
|
Node: window.Node,
|
|
NodeList: window.NodeList,
|
|
SVGElement: window.SVGElement,
|
|
ShadowRoot: window.ShadowRoot,
|
|
Text: window.Text
|
|
};
|
|
}
|
|
|
|
/** Event constructors. Node has its own Event and CustomEvent, see BROWSER_OVERRIDES */
|
|
function events (window: DOMWindow) {
|
|
return {
|
|
CompositionEvent: window.CompositionEvent,
|
|
CustomEvent: window.CustomEvent,
|
|
Event: window.Event,
|
|
FocusEvent: window.FocusEvent,
|
|
InputEvent: window.InputEvent,
|
|
KeyboardEvent: window.KeyboardEvent,
|
|
MouseEvent: window.MouseEvent,
|
|
TouchEvent: window.TouchEvent,
|
|
UIEvent: window.UIEvent,
|
|
WheelEvent: window.WheelEvent
|
|
};
|
|
}
|
|
|
|
/** Network, see BROWSER_OVERRIDES for why WebSocket is JSDOM's */
|
|
function network (window: DOMWindow) {
|
|
return {
|
|
WebSocket: window.WebSocket
|
|
};
|
|
}
|
|
|
|
/** Styles, geometry and the observers */
|
|
function layout (window: DOMWindow) {
|
|
return {
|
|
// present on the JSDOM window, absent from its DOMWindow type
|
|
DOMRect: window['DOMRect'] as typeof DOMRect,
|
|
DOMRectReadOnly: window['DOMRectReadOnly'] as typeof DOMRectReadOnly,
|
|
MutationObserver: window.MutationObserver,
|
|
MutationRecord: window.MutationRecord,
|
|
ResizeObserver,
|
|
getComputedStyle: window.getComputedStyle.bind(window)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Export a very basic JSDom environment - this is just enough so we have
|
|
* @testing-environment/react tests passing in this repo
|
|
*
|
|
* FIXME: This approach is actually _explicitly_ discouraged by JSDOM - when
|
|
* using window you should run the tests inside that context, instead of just
|
|
* blindly relying on the globals as we do here
|
|
*/
|
|
export function browser () {
|
|
const { window } = new JSDOM('', { url: 'http://localhost' });
|
|
|
|
return {
|
|
...nodes(window),
|
|
...events(window),
|
|
...layout(window),
|
|
...network(window),
|
|
// All HTML Elements that are defined on the JSDOM window object.
|
|
// (we copied as-is from the types definition). We cannot get this
|
|
// via Object.keys(window).filter(...) so we have to specify explicitly
|
|
HTMLAnchorElement: window.HTMLAnchorElement,
|
|
HTMLAreaElement: window.HTMLAreaElement,
|
|
HTMLAudioElement: window.HTMLAudioElement,
|
|
HTMLBRElement: window.HTMLBRElement,
|
|
HTMLBaseElement: window.HTMLBaseElement,
|
|
HTMLBodyElement: window.HTMLBodyElement,
|
|
HTMLButtonElement: window.HTMLButtonElement,
|
|
HTMLCanvasElement: window.HTMLCanvasElement,
|
|
HTMLDListElement: window.HTMLDListElement,
|
|
HTMLDataElement: window.HTMLDataElement,
|
|
HTMLDataListElement: window.HTMLDataListElement,
|
|
HTMLDetailsElement: window.HTMLDetailsElement,
|
|
HTMLDialogElement: window.HTMLDialogElement,
|
|
HTMLDirectoryElement: window.HTMLDirectoryElement,
|
|
HTMLDivElement: window.HTMLDivElement,
|
|
HTMLElement: window.HTMLElement,
|
|
HTMLEmbedElement: window.HTMLEmbedElement,
|
|
HTMLFieldSetElement: window.HTMLFieldSetElement,
|
|
HTMLFontElement: window.HTMLFontElement,
|
|
HTMLFormElement: window.HTMLFormElement,
|
|
HTMLFrameElement: window.HTMLFrameElement,
|
|
HTMLFrameSetElement: window.HTMLFrameSetElement,
|
|
HTMLHRElement: window.HTMLHRElement,
|
|
HTMLHeadElement: window.HTMLHeadElement,
|
|
HTMLHeadingElement: window.HTMLHeadingElement,
|
|
HTMLHtmlElement: window.HTMLHtmlElement,
|
|
HTMLIFrameElement: window.HTMLIFrameElement,
|
|
HTMLImageElement: window.HTMLImageElement,
|
|
HTMLInputElement: window.HTMLInputElement,
|
|
HTMLLIElement: window.HTMLLIElement,
|
|
HTMLLabelElement: window.HTMLLabelElement,
|
|
HTMLLegendElement: window.HTMLLegendElement,
|
|
HTMLLinkElement: window.HTMLLinkElement,
|
|
HTMLMapElement: window.HTMLMapElement,
|
|
HTMLMarqueeElement: window.HTMLMarqueeElement,
|
|
HTMLMediaElement: window.HTMLMediaElement,
|
|
HTMLMenuElement: window.HTMLMenuElement,
|
|
HTMLMetaElement: window.HTMLMetaElement,
|
|
HTMLMeterElement: window.HTMLMeterElement,
|
|
HTMLModElement: window.HTMLModElement,
|
|
HTMLOListElement: window.HTMLOListElement,
|
|
HTMLObjectElement: window.HTMLObjectElement,
|
|
HTMLOptGroupElement: window.HTMLOptGroupElement,
|
|
HTMLOptionElement: window.HTMLOptionElement,
|
|
HTMLOutputElement: window.HTMLOutputElement,
|
|
HTMLParagraphElement: window.HTMLParagraphElement,
|
|
HTMLParamElement: window.HTMLParamElement,
|
|
HTMLPictureElement: window.HTMLPictureElement,
|
|
HTMLPreElement: window.HTMLPreElement,
|
|
HTMLProgressElement: window.HTMLProgressElement,
|
|
HTMLQuoteElement: window.HTMLQuoteElement,
|
|
HTMLScriptElement: window.HTMLScriptElement,
|
|
HTMLSelectElement: window.HTMLSelectElement,
|
|
HTMLSlotElement: window.HTMLSlotElement,
|
|
HTMLSourceElement: window.HTMLSourceElement,
|
|
HTMLSpanElement: window.HTMLSpanElement,
|
|
HTMLStyleElement: window.HTMLStyleElement,
|
|
HTMLTableCaptionElement: window.HTMLTableCaptionElement,
|
|
HTMLTableCellElement: window.HTMLTableCellElement,
|
|
HTMLTableColElement: window.HTMLTableColElement,
|
|
HTMLTableElement: window.HTMLTableElement,
|
|
HTMLTableRowElement: window.HTMLTableRowElement,
|
|
HTMLTableSectionElement: window.HTMLTableSectionElement,
|
|
HTMLTemplateElement: window.HTMLTemplateElement,
|
|
HTMLTextAreaElement: window.HTMLTextAreaElement,
|
|
HTMLTimeElement: window.HTMLTimeElement,
|
|
HTMLTitleElement: window.HTMLTitleElement,
|
|
HTMLTrackElement: window.HTMLTrackElement,
|
|
HTMLUListElement: window.HTMLUListElement,
|
|
HTMLUnknownElement: window.HTMLUnknownElement,
|
|
HTMLVideoElement: window.HTMLVideoElement,
|
|
// normal service resumes, the base top-level names
|
|
crypto: window.crypto,
|
|
document: window.document,
|
|
localStorage: window.localStorage,
|
|
navigator: window.navigator,
|
|
// window...
|
|
window
|
|
};
|
|
}
|