Skip to content

Commit 5998eea

Browse files
authored
fix: [#2054] Throw error if event is not of type Event in dispatchEvent (#2092)
1 parent 7a11238 commit 5998eea

File tree

2 files changed

+89
-75
lines changed

2 files changed

+89
-75
lines changed

packages/happy-dom/src/event/EventTarget.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as PropertySymbol from '../PropertySymbol.js';
2-
import type Event from './Event.js';
2+
import Event from './Event.js';
33
import type IEventListenerOptions from './IEventListenerOptions.js';
44
import EventPhaseEnum from './EventPhaseEnum.js';
55
import WindowBrowserContext from '../window/WindowBrowserContext.js';
@@ -118,6 +118,12 @@ export default class EventTarget {
118118
* @returns The return value is false if event is cancelable and at least one of the event handlers which handled this event called Event.preventDefault().
119119
*/
120120
public dispatchEvent(event: Event): boolean {
121+
if (!(event instanceof Event)) {
122+
throw new this[PropertySymbol.window].TypeError(
123+
`Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.`
124+
);
125+
}
126+
121127
// The "load" event is a special case. It should not bubble up to the window from the document.
122128
if (
123129
!event[PropertySymbol.dispatching] &&

packages/happy-dom/test/event/EventTarget.test.ts

Lines changed: 82 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,20 @@ describe('EventTarget', () => {
1919

2020
describe('addEventListener()', () => {
2121
it('Adds an event listener and triggers it when calling dispatchEvent().', () => {
22-
let recievedEvent: Event | null = null;
23-
let recievedTarget: EventTarget | null = null;
24-
let recievedCurrentTarget: EventTarget | null = null;
22+
let receivedEvent: Event | null = null;
23+
let receivedTarget: EventTarget | null = null;
24+
let receivedCurrentTarget: EventTarget | null = null;
2525
const listener = (event: Event): void => {
26-
recievedEvent = event;
27-
recievedTarget = event.target;
28-
recievedCurrentTarget = event.currentTarget;
26+
receivedEvent = event;
27+
receivedTarget = event.target;
28+
receivedCurrentTarget = event.currentTarget;
2929
};
3030
const dispatchedEvent = new Event(EVENT_TYPE);
3131
eventTarget.addEventListener(EVENT_TYPE, listener);
3232
eventTarget.dispatchEvent(dispatchedEvent);
33-
expect(recievedEvent).toBe(dispatchedEvent);
34-
expect(recievedTarget).toBe(eventTarget);
35-
expect(recievedCurrentTarget).toBe(eventTarget);
33+
expect(receivedEvent).toBe(dispatchedEvent);
34+
expect(receivedTarget).toBe(eventTarget);
35+
expect(receivedCurrentTarget).toBe(eventTarget);
3636
});
3737

3838
it('Adds an event listener and set options once', () => {
@@ -69,46 +69,46 @@ describe('EventTarget', () => {
6969
});
7070

7171
it('Adds a custom event listener and triggers it when calling dispatchEvent().', () => {
72-
let recievedEvent: CustomEvent | null = null;
73-
let recievedTarget: EventTarget | null = null;
74-
let recievedCurrentTarget: EventTarget | null = null;
72+
let receivedEvent: CustomEvent | null = null;
73+
let receivedTarget: EventTarget | null = null;
74+
let receivedCurrentTarget: EventTarget | null = null;
7575
const DETAIL = {};
76-
const listener = (event): void => {
77-
recievedEvent = <CustomEvent>event;
78-
recievedTarget = event.target;
79-
recievedCurrentTarget = event.currentTarget;
76+
const listener = (event: Event): void => {
77+
receivedEvent = <CustomEvent>event;
78+
receivedTarget = event.target;
79+
receivedCurrentTarget = event.currentTarget;
8080
};
8181
const dispatchedEvent = new CustomEvent(EVENT_TYPE, { detail: DETAIL });
8282
eventTarget.addEventListener(EVENT_TYPE, listener);
8383
eventTarget.dispatchEvent(dispatchedEvent);
84-
expect(recievedEvent).toBe(dispatchedEvent);
85-
expect((<CustomEvent>(<unknown>recievedEvent)).detail).toBe(DETAIL);
86-
expect(recievedTarget).toBe(eventTarget);
87-
expect(recievedCurrentTarget).toBe(eventTarget);
84+
expect(receivedEvent).toBe(dispatchedEvent);
85+
expect((<CustomEvent>(<unknown>receivedEvent)).detail).toBe(DETAIL);
86+
expect(receivedTarget).toBe(eventTarget);
87+
expect(receivedCurrentTarget).toBe(eventTarget);
8888
});
8989

9090
it('Adds an event listener using object with handleEvent as property and triggers it when calling dispatchEvent().', () => {
91-
let recievedEvent: CustomEvent | null = null;
92-
let recievedTarget: EventTarget | null = null;
93-
let recievedCurrentTarget: EventTarget | null = null;
91+
let receivedEvent: CustomEvent | null = null;
92+
let receivedTarget: EventTarget | null = null;
93+
let receivedCurrentTarget: EventTarget | null = null;
9494
const listener = {
9595
handleEvent: (event: CustomEvent): void => {
96-
recievedEvent = event;
97-
recievedTarget = event.target;
98-
recievedCurrentTarget = event.currentTarget;
96+
receivedEvent = event;
97+
receivedTarget = event.target;
98+
receivedCurrentTarget = event.currentTarget;
9999
}
100100
};
101101
const dispatchedEvent = new Event(EVENT_TYPE);
102102
eventTarget.addEventListener(EVENT_TYPE, listener);
103103
eventTarget.dispatchEvent(dispatchedEvent);
104-
expect(recievedEvent).toBe(dispatchedEvent);
105-
expect(recievedTarget).toBe(eventTarget);
106-
expect(recievedCurrentTarget).toBe(eventTarget);
104+
expect(receivedEvent).toBe(dispatchedEvent);
105+
expect(receivedTarget).toBe(eventTarget);
106+
expect(receivedCurrentTarget).toBe(eventTarget);
107107
});
108108

109109
it('Event listener is called in the scope of the EventTarget when calling dispatchEvent().', () => {
110-
let scope = null;
111-
const listener = function (): void {
110+
let scope: any = null;
111+
const listener = function (this: any): void {
112112
scope = this;
113113
};
114114
const dispatchedEvent = new Event(EVENT_TYPE);
@@ -147,60 +147,60 @@ describe('EventTarget', () => {
147147

148148
describe('removeEventListener()', () => {
149149
it('Removes an event listener and does not call it when calling dispatchEvent().', () => {
150-
let recievedEvent: Event | null = null;
150+
let receivedEvent: Event | null = null;
151151
const listener = (event: Event): void => {
152-
recievedEvent = event;
152+
receivedEvent = event;
153153
};
154154
const dispatchedEvent = new Event(EVENT_TYPE);
155155
eventTarget.addEventListener(EVENT_TYPE, listener);
156156
eventTarget.removeEventListener(EVENT_TYPE, listener);
157157
eventTarget.dispatchEvent(dispatchedEvent);
158-
expect(recievedEvent).toBe(null);
158+
expect(receivedEvent).toBe(null);
159159
});
160160
});
161161

162162
describe('dispatchEvent()', () => {
163163
it('Triggers listener properties with "on" as prefix on DOM elements.', () => {
164164
// on* handlers should work on DOM elements (which have propertyEventListeners)
165165
const element = window.document.createElement('div');
166-
let recievedEvent: Event | null = null;
167-
let recievedTarget: EventTarget | null = null;
168-
let recievedCurrentTarget: EventTarget | null = null;
166+
let receivedEvent: Event | null = null;
167+
let receivedTarget: EventTarget | null = null;
168+
let receivedCurrentTarget: EventTarget | null = null;
169169
const listener = (event: Event): void => {
170-
recievedEvent = event;
171-
recievedTarget = event.target;
172-
recievedCurrentTarget = event.currentTarget;
170+
receivedEvent = event;
171+
receivedTarget = event.target;
172+
receivedCurrentTarget = event.currentTarget;
173173
};
174174
const dispatchedEvent = new Event(EVENT_TYPE);
175175
element[`on${EVENT_TYPE}`] = listener;
176176
element.dispatchEvent(dispatchedEvent);
177-
expect(recievedEvent).toBe(dispatchedEvent);
178-
expect(recievedTarget).toBe(element);
179-
expect(recievedCurrentTarget).toBe(element);
177+
expect(receivedEvent).toBe(dispatchedEvent);
178+
expect(receivedTarget).toBe(element);
179+
expect(receivedCurrentTarget).toBe(element);
180180
expect(dispatchedEvent.target).toBe(element);
181181
expect(dispatchedEvent.currentTarget).toBe(null);
182182
expect(dispatchedEvent.defaultPrevented).toBe(false);
183183
expect(dispatchedEvent[PropertySymbol.dispatching]).toBe(false);
184184
});
185185

186186
it('Triggers all listeners, even though listeners are removed while dispatching.', () => {
187-
let recievedEvent1: Event | null = null;
188-
let recievedTarget1: EventTarget | null = null;
189-
let recievedCurrentTarget1: EventTarget | null = null;
190-
let recievedEvent2: Event | null = null;
191-
let recievedTarget2: EventTarget | null = null;
192-
let recievedCurrentTarget2: EventTarget | null = null;
187+
let receivedEvent1: Event | null = null;
188+
let receivedTarget1: EventTarget | null = null;
189+
let receivedCurrentTarget1: EventTarget | null = null;
190+
let receivedEvent2: Event | null = null;
191+
let receivedTarget2: EventTarget | null = null;
192+
let receivedCurrentTarget2: EventTarget | null = null;
193193

194194
const listener1 = (event: Event): void => {
195-
recievedEvent1 = event;
196-
recievedTarget1 = event.target;
197-
recievedCurrentTarget1 = event.currentTarget;
195+
receivedEvent1 = event;
196+
receivedTarget1 = event.target;
197+
receivedCurrentTarget1 = event.currentTarget;
198198
eventTarget.removeEventListener(EVENT_TYPE, listener1);
199199
};
200200
const listener2 = (event: Event): void => {
201-
recievedEvent2 = event;
202-
recievedTarget2 = event.target;
203-
recievedCurrentTarget2 = event.currentTarget;
201+
receivedEvent2 = event;
202+
receivedTarget2 = event.target;
203+
receivedCurrentTarget2 = event.currentTarget;
204204
eventTarget.removeEventListener(EVENT_TYPE, listener2);
205205
};
206206
const dispatchedEvent = new Event(EVENT_TYPE);
@@ -210,52 +210,60 @@ describe('EventTarget', () => {
210210

211211
eventTarget.dispatchEvent(dispatchedEvent);
212212

213-
expect(recievedEvent1).toBe(dispatchedEvent);
214-
expect(recievedEvent2).toBe(dispatchedEvent);
213+
expect(receivedEvent1).toBe(dispatchedEvent);
214+
expect(receivedEvent2).toBe(dispatchedEvent);
215215

216-
expect(recievedTarget1).toBe(eventTarget);
217-
expect(recievedCurrentTarget1).toBe(eventTarget);
218-
expect(recievedTarget2).toBe(eventTarget);
219-
expect(recievedCurrentTarget2).toBe(eventTarget);
216+
expect(receivedTarget1).toBe(eventTarget);
217+
expect(receivedCurrentTarget1).toBe(eventTarget);
218+
expect(receivedTarget2).toBe(eventTarget);
219+
expect(receivedCurrentTarget2).toBe(eventTarget);
220220

221221
expect(dispatchedEvent.target).toBe(eventTarget);
222222
expect(dispatchedEvent.currentTarget).toBe(null);
223223
expect(dispatchedEvent.defaultPrevented).toBe(false);
224224
expect(dispatchedEvent[PropertySymbol.dispatching]).toBe(false);
225225
});
226+
227+
it('Throws a TypeError if the event is not an instance of Event.', () => {
228+
expect(() => {
229+
eventTarget.dispatchEvent(<Event>{});
230+
}).toThrowError(
231+
`Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.`
232+
);
233+
});
226234
});
227235

228236
describe('attachEvent()', () => {
229237
it('Adds an event listener in older browsers for backward compatibility.', () => {
230-
let recievedEvent: Event | null = null;
231-
let recievedTarget: EventTarget | null = null;
232-
let recievedCurrentTarget: EventTarget | null = null;
238+
let receivedEvent: Event | null = null;
239+
let receivedTarget: EventTarget | null = null;
240+
let receivedCurrentTarget: EventTarget | null = null;
233241
const listener = (event: Event): void => {
234-
recievedEvent = event;
235-
recievedTarget = event.target;
236-
recievedCurrentTarget = event.currentTarget;
242+
receivedEvent = event;
243+
receivedTarget = event.target;
244+
receivedCurrentTarget = event.currentTarget;
237245
};
238246
const dispatchedEvent = new Event(EVENT_TYPE);
239247
eventTarget.attachEvent(`on${EVENT_TYPE}`, listener);
240248
eventTarget.dispatchEvent(dispatchedEvent);
241-
expect(recievedEvent).toBe(dispatchedEvent);
242-
expect((<Event>(<unknown>recievedEvent)).type).toBe(EVENT_TYPE);
243-
expect(recievedTarget).toBe(eventTarget);
244-
expect(recievedCurrentTarget).toBe(eventTarget);
249+
expect(receivedEvent).toBe(dispatchedEvent);
250+
expect((<Event>(<unknown>receivedEvent)).type).toBe(EVENT_TYPE);
251+
expect(receivedTarget).toBe(eventTarget);
252+
expect(receivedCurrentTarget).toBe(eventTarget);
245253
});
246254
});
247255

248256
describe('detachEvent()', () => {
249257
it('Removes an event listener in older browsers for backward compatibility.', () => {
250-
let recievedEvent: Event | null = null;
258+
let receivedEvent: Event | null = null;
251259
const listener = (event: Event): void => {
252-
recievedEvent = event;
260+
receivedEvent = event;
253261
};
254262
const dispatchedEvent = new Event('click');
255263
eventTarget.attachEvent('onclick', listener);
256264
eventTarget.detachEvent('onclick', listener);
257265
eventTarget.dispatchEvent(dispatchedEvent);
258-
expect(recievedEvent).toBe(null);
266+
expect(receivedEvent).toBe(null);
259267
});
260268
});
261269

0 commit comments

Comments
 (0)