Skip to content

Commit 5280125

Browse files
authored
Merge pull request #131 from preactjs/set-event-flags
Set default event flags appropriate for event type
2 parents 9ac53bb + 1816eee commit 5280125

3 files changed

Lines changed: 385 additions & 8 deletions

File tree

src/MountRenderer.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ import type { MountRenderer as AbstractMountRenderer, RSTNode } from 'enzyme';
22
import { VNode, h } from 'preact';
33
import { act } from 'preact/test-utils';
44

5-
import { getNode } from './preact10-rst.js';
6-
import { getDisplayName, withReplacedMethod } from './util.js';
75
import { render } from './compat.js';
8-
import { getLastVNodeRenderedIntoContainer } from './preact10-internals.js';
96
import {
107
installHook as installDebounceHook,
118
flushRenders,
129
} from './debounce-render-hook.js';
10+
import { eventMap } from './event-map.js';
11+
import { getLastVNodeRenderedIntoContainer } from './preact10-internals.js';
12+
import { getNode } from './preact10-rst.js';
13+
import { getDisplayName, withReplacedMethod } from './util.js';
1314

1415
type EventDetails = { [prop: string]: any };
1516

@@ -21,6 +22,15 @@ export interface Options {
2122
container?: HTMLElement;
2223
}
2324

25+
function constructEvent(type: string, init: EventInit) {
26+
const meta = eventMap[type];
27+
const defaultInit = meta?.defaultInit ?? {};
28+
return new Event(type, {
29+
...defaultInit,
30+
...init,
31+
});
32+
}
33+
2434
export default class MountRenderer implements AbstractMountRenderer {
2535
private _container: HTMLElement;
2636
private _getNode: typeof getNode;
@@ -92,11 +102,17 @@ export default class MountRenderer implements AbstractMountRenderer {
92102
// constructor for the event type. This implementation is good enough for
93103
// many components though.
94104
const { bubbles, composed, cancelable, ...extra } = args;
95-
const event = new Event(eventName, {
96-
bubbles,
97-
composed,
98-
cancelable,
99-
});
105+
const init = {} as EventInit;
106+
if (typeof bubbles === 'boolean') {
107+
init.bubbles = bubbles;
108+
}
109+
if (typeof composed === 'boolean') {
110+
init.composed = composed;
111+
}
112+
if (typeof cancelable === 'boolean') {
113+
init.cancelable = cancelable;
114+
}
115+
const event = constructEvent(eventName, init);
100116
Object.assign(event, extra);
101117

102118
act(() => {

src/event-map.ts

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
export interface EventData {
2+
EventType: string;
3+
defaultInit: EventInit;
4+
}
5+
6+
/**
7+
* Metadata for events which have different flags set by default than the
8+
* `Event` constructor defaults or which use a subclass of `Event`.
9+
*
10+
* Adapted from `event-map.js` in https://github.com/testing-library/dom-testing-library,
11+
* but changed to lower-case event names to match the actual values that would
12+
* be seen in the `Event.type` field.
13+
*/
14+
export const eventMap: Record<string, EventData> = {
15+
// Clipboard Events
16+
copy: {
17+
EventType: 'ClipboardEvent',
18+
defaultInit: { bubbles: true, cancelable: true, composed: true },
19+
},
20+
cut: {
21+
EventType: 'ClipboardEvent',
22+
defaultInit: { bubbles: true, cancelable: true, composed: true },
23+
},
24+
paste: {
25+
EventType: 'ClipboardEvent',
26+
defaultInit: { bubbles: true, cancelable: true, composed: true },
27+
},
28+
29+
// Composition Events
30+
compositionend: {
31+
EventType: 'CompositionEvent',
32+
defaultInit: { bubbles: true, cancelable: true, composed: true },
33+
},
34+
compositionstart: {
35+
EventType: 'CompositionEvent',
36+
defaultInit: { bubbles: true, cancelable: true, composed: true },
37+
},
38+
compositionupdate: {
39+
EventType: 'CompositionEvent',
40+
defaultInit: { bubbles: true, cancelable: true, composed: true },
41+
},
42+
43+
// Keyboard Events
44+
keydown: {
45+
EventType: 'KeyboardEvent',
46+
defaultInit: {
47+
bubbles: true,
48+
cancelable: true,
49+
composed: true,
50+
},
51+
},
52+
keypress: {
53+
EventType: 'KeyboardEvent',
54+
defaultInit: {
55+
bubbles: true,
56+
cancelable: true,
57+
composed: true,
58+
},
59+
},
60+
keyup: {
61+
EventType: 'KeyboardEvent',
62+
defaultInit: {
63+
bubbles: true,
64+
cancelable: true,
65+
composed: true,
66+
},
67+
},
68+
69+
// Focus Events
70+
focus: {
71+
EventType: 'FocusEvent',
72+
defaultInit: { bubbles: false, cancelable: false, composed: true },
73+
},
74+
blur: {
75+
EventType: 'FocusEvent',
76+
defaultInit: { bubbles: false, cancelable: false, composed: true },
77+
},
78+
focusin: {
79+
EventType: 'FocusEvent',
80+
defaultInit: { bubbles: true, cancelable: false, composed: true },
81+
},
82+
focusout: {
83+
EventType: 'FocusEvent',
84+
defaultInit: { bubbles: true, cancelable: false, composed: true },
85+
},
86+
87+
// Form Events
88+
change: {
89+
EventType: 'Event',
90+
defaultInit: { bubbles: true, cancelable: false },
91+
},
92+
input: {
93+
EventType: 'InputEvent',
94+
defaultInit: { bubbles: true, cancelable: false, composed: true },
95+
},
96+
invalid: {
97+
EventType: 'Event',
98+
defaultInit: { bubbles: false, cancelable: true },
99+
},
100+
submit: {
101+
EventType: 'Event',
102+
defaultInit: { bubbles: true, cancelable: true },
103+
},
104+
reset: {
105+
EventType: 'Event',
106+
defaultInit: { bubbles: true, cancelable: true },
107+
},
108+
109+
// Mouse Events
110+
click: {
111+
EventType: 'MouseEvent',
112+
defaultInit: { bubbles: true, cancelable: true, composed: true },
113+
},
114+
contextmenu: {
115+
EventType: 'MouseEvent',
116+
defaultInit: { bubbles: true, cancelable: true, composed: true },
117+
},
118+
dblclick: {
119+
EventType: 'MouseEvent',
120+
defaultInit: { bubbles: true, cancelable: true, composed: true },
121+
},
122+
drag: {
123+
EventType: 'DragEvent',
124+
defaultInit: { bubbles: true, cancelable: true, composed: true },
125+
},
126+
dragend: {
127+
EventType: 'DragEvent',
128+
defaultInit: { bubbles: true, cancelable: false, composed: true },
129+
},
130+
dragenter: {
131+
EventType: 'DragEvent',
132+
defaultInit: { bubbles: true, cancelable: true, composed: true },
133+
},
134+
dragexit: {
135+
EventType: 'DragEvent',
136+
defaultInit: { bubbles: true, cancelable: false, composed: true },
137+
},
138+
dragleave: {
139+
EventType: 'DragEvent',
140+
defaultInit: { bubbles: true, cancelable: false, composed: true },
141+
},
142+
dragover: {
143+
EventType: 'DragEvent',
144+
defaultInit: { bubbles: true, cancelable: true, composed: true },
145+
},
146+
dragstart: {
147+
EventType: 'DragEvent',
148+
defaultInit: { bubbles: true, cancelable: true, composed: true },
149+
},
150+
drop: {
151+
EventType: 'DragEvent',
152+
defaultInit: { bubbles: true, cancelable: true, composed: true },
153+
},
154+
mousedown: {
155+
EventType: 'MouseEvent',
156+
defaultInit: { bubbles: true, cancelable: true, composed: true },
157+
},
158+
mouseenter: {
159+
EventType: 'MouseEvent',
160+
defaultInit: { bubbles: false, cancelable: false, composed: true },
161+
},
162+
mouseleave: {
163+
EventType: 'MouseEvent',
164+
defaultInit: { bubbles: false, cancelable: false, composed: true },
165+
},
166+
mousemove: {
167+
EventType: 'MouseEvent',
168+
defaultInit: { bubbles: true, cancelable: true, composed: true },
169+
},
170+
mouseout: {
171+
EventType: 'MouseEvent',
172+
defaultInit: { bubbles: true, cancelable: true, composed: true },
173+
},
174+
mouseover: {
175+
EventType: 'MouseEvent',
176+
defaultInit: { bubbles: true, cancelable: true, composed: true },
177+
},
178+
mouseup: {
179+
EventType: 'MouseEvent',
180+
defaultInit: { bubbles: true, cancelable: true, composed: true },
181+
},
182+
183+
// Selection Events
184+
select: {
185+
EventType: 'Event',
186+
defaultInit: { bubbles: true, cancelable: false },
187+
},
188+
189+
// Touch Events
190+
touchcancel: {
191+
EventType: 'TouchEvent',
192+
defaultInit: { bubbles: true, cancelable: false, composed: true },
193+
},
194+
touchend: {
195+
EventType: 'TouchEvent',
196+
defaultInit: { bubbles: true, cancelable: true, composed: true },
197+
},
198+
touchmove: {
199+
EventType: 'TouchEvent',
200+
defaultInit: { bubbles: true, cancelable: true, composed: true },
201+
},
202+
touchstart: {
203+
EventType: 'TouchEvent',
204+
defaultInit: { bubbles: true, cancelable: true, composed: true },
205+
},
206+
207+
// UI Events
208+
resize: {
209+
EventType: 'UIEvent',
210+
defaultInit: { bubbles: false, cancelable: false },
211+
},
212+
scroll: {
213+
EventType: 'UIEvent',
214+
defaultInit: { bubbles: false, cancelable: false },
215+
},
216+
217+
// Wheel Events
218+
wheel: {
219+
EventType: 'WheelEvent',
220+
defaultInit: { bubbles: true, cancelable: true, composed: true },
221+
},
222+
223+
// Media Events
224+
// (nb. These are currently incomplete)
225+
loadstart: {
226+
EventType: 'ProgressEvent',
227+
defaultInit: { bubbles: false, cancelable: false },
228+
},
229+
progress: {
230+
EventType: 'ProgressEvent',
231+
defaultInit: { bubbles: false, cancelable: false },
232+
},
233+
234+
// Image Events
235+
load: {
236+
EventType: 'UIEvent',
237+
defaultInit: { bubbles: false, cancelable: false },
238+
},
239+
error: {
240+
EventType: 'Event',
241+
defaultInit: { bubbles: false, cancelable: false },
242+
},
243+
244+
// Animation Events
245+
animationstart: {
246+
EventType: 'AnimationEvent',
247+
defaultInit: { bubbles: true, cancelable: false },
248+
},
249+
animationend: {
250+
EventType: 'AnimationEvent',
251+
defaultInit: { bubbles: true, cancelable: false },
252+
},
253+
animationiteration: {
254+
EventType: 'AnimationEvent',
255+
defaultInit: { bubbles: true, cancelable: false },
256+
},
257+
258+
// Transition Events
259+
transitioncancel: {
260+
EventType: 'TransitionEvent',
261+
defaultInit: { bubbles: true, cancelable: false },
262+
},
263+
transitionend: {
264+
EventType: 'TransitionEvent',
265+
defaultInit: { bubbles: true, cancelable: true },
266+
},
267+
transitionrun: {
268+
EventType: 'TransitionEvent',
269+
defaultInit: { bubbles: true, cancelable: false },
270+
},
271+
transitionstart: {
272+
EventType: 'TransitionEvent',
273+
defaultInit: { bubbles: true, cancelable: false },
274+
},
275+
276+
// Pointer events
277+
pointerover: {
278+
EventType: 'PointerEvent',
279+
defaultInit: { bubbles: true, cancelable: true, composed: true },
280+
},
281+
pointerenter: {
282+
EventType: 'PointerEvent',
283+
defaultInit: { bubbles: false, cancelable: false },
284+
},
285+
pointerdown: {
286+
EventType: 'PointerEvent',
287+
defaultInit: { bubbles: true, cancelable: true, composed: true },
288+
},
289+
pointermove: {
290+
EventType: 'PointerEvent',
291+
defaultInit: { bubbles: true, cancelable: true, composed: true },
292+
},
293+
pointerup: {
294+
EventType: 'PointerEvent',
295+
defaultInit: { bubbles: true, cancelable: true, composed: true },
296+
},
297+
pointercancel: {
298+
EventType: 'PointerEvent',
299+
defaultInit: { bubbles: true, cancelable: false, composed: true },
300+
},
301+
pointerout: {
302+
EventType: 'PointerEvent',
303+
defaultInit: { bubbles: true, cancelable: true, composed: true },
304+
},
305+
pointerleave: {
306+
EventType: 'PointerEvent',
307+
defaultInit: { bubbles: false, cancelable: false },
308+
},
309+
gotpointercapture: {
310+
EventType: 'PointerEvent',
311+
defaultInit: { bubbles: true, cancelable: false, composed: true },
312+
},
313+
lostpointercapture: {
314+
EventType: 'PointerEvent',
315+
defaultInit: { bubbles: true, cancelable: false, composed: true },
316+
},
317+
318+
// History events
319+
popstate: {
320+
EventType: 'PopStateEvent',
321+
defaultInit: { bubbles: true, cancelable: false },
322+
},
323+
};

0 commit comments

Comments
 (0)