mirror of
https://github.com/pezkuwichain/pezkuwi-dev.git
synced 2026-10-22 11:46:18 +00:00
dev-test: UI events, getComputedStyle and the observers in the browser env
react-tooltip, on hover, called getComputedStyle, MutationObserver and ResizeObserver, none of which the browser env exposed. The env now also carries the UI event constructors (MouseEvent, KeyboardEvent, FocusEvent and the rest), DOMRect, MutationObserver and a bound getComputedStyle from JSDOM, grouped by kind. JSDOM has no ResizeObserver. It does no layout either, so no element ever changes size; the env's ResizeObserver accepts observe() and never calls back, which is what a real one would do on a page that never resizes.
This commit is contained in:
1 parent
4e3bf04010
commit
cb15405cfb
2 files changed
+89
-12
No files matched your search
+21
@@ -36,6 +36,27 @@ describe('browser', () => {
|
||||
expect(document).toBeInstanceOf(Document);
|
||||
});
|
||||
|
||||
it('contains the UI event constructors', () => {
|
||||
const div = document.createElement('div');
|
||||
|
||||
expect(() => div.dispatchEvent(new MouseEvent('click'))).not.toThrow();
|
||||
expect(() => div.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }))).not.toThrow();
|
||||
expect(new FocusEvent('focus')).toBeInstanceOf(UIEvent);
|
||||
});
|
||||
|
||||
it('contains getComputedStyle and the observers', () => {
|
||||
const div = document.createElement('div');
|
||||
|
||||
div.style.display = 'none';
|
||||
document.body.appendChild(div);
|
||||
|
||||
expect(getComputedStyle(div).display).toBe('none');
|
||||
expect(() => new MutationObserver(() => undefined).observe(div, { childList: true })).not.toThrow();
|
||||
expect(() => new ResizeObserver(() => undefined).observe(div)).not.toThrow();
|
||||
|
||||
div.remove();
|
||||
});
|
||||
|
||||
it('dispatches the global CustomEvent and Event on window', () => {
|
||||
expect(() => window.dispatchEvent(new CustomEvent('custom', { detail: 1 }))).not.toThrow();
|
||||
expect(() => window.dispatchEvent(new Event('plain'))).not.toThrow();
|
||||
|
||||
Vendored
+68
-12
@@ -1,6 +1,8 @@
|
||||
// Copyright 2017-2026 @pezkuwi/dev-test authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { DOMWindow } from 'jsdom';
|
||||
|
||||
import { JSDOM } from 'jsdom';
|
||||
|
||||
/**
|
||||
@@ -10,6 +12,69 @@ import { JSDOM } from 'jsdom';
|
||||
*/
|
||||
export const BROWSER_OVERRIDES: readonly string[] = ['CustomEvent', 'Event'];
|
||||
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
}
|
||||
|
||||
/** 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
|
||||
@@ -22,13 +87,9 @@ export function browser () {
|
||||
const { window } = new JSDOM('', { url: 'http://localhost' });
|
||||
|
||||
return {
|
||||
// The DOM node hierarchy, which libraries check with instanceof, and the
|
||||
// event constructors (Node has its own of these, see BROWSER_OVERRIDES)
|
||||
CustomEvent: window.CustomEvent,
|
||||
Document: window.Document,
|
||||
DocumentFragment: window.DocumentFragment,
|
||||
Element: window.Element,
|
||||
Event: window.Event,
|
||||
...nodes(window),
|
||||
...events(window),
|
||||
...layout(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
|
||||
@@ -103,11 +164,6 @@ export function browser () {
|
||||
HTMLUListElement: window.HTMLUListElement,
|
||||
HTMLUnknownElement: window.HTMLUnknownElement,
|
||||
HTMLVideoElement: window.HTMLVideoElement,
|
||||
// the rest of the node hierarchy
|
||||
Node: window.Node,
|
||||
SVGElement: window.SVGElement,
|
||||
ShadowRoot: window.ShadowRoot,
|
||||
Text: window.Text,
|
||||
// normal service resumes, the base top-level names
|
||||
crypto: window.crypto,
|
||||
document: window.document,
|
||||
|
||||
Reference in new issue
Block a user