, only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Fail When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
+Pass When clicking child of parent , only child should be activated.
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-target-moved.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-target-moved.txt
new file mode 100644
index 00000000000..cceb9dc7198
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-target-moved.txt
@@ -0,0 +1,11 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 1 tests
+
+1 Fail
+Details
+Result Test Name MessageFail Event propagation path when an element in it is moved within the DOM
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-target-removed.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-target-removed.txt
new file mode 100644
index 00000000000..f18dda177e6
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-target-removed.txt
@@ -0,0 +1,11 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 1 tests
+
+1 Fail
+Details
+Result Test Name MessageFail Event propagation path when an element in it is removed from the DOM
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-throwing-multiple-globals.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-throwing-multiple-globals.txt
new file mode 100644
index 00000000000..a4f93ed089c
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-throwing-multiple-globals.txt
@@ -0,0 +1,12 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 2 tests
+
+2 Fail
+Details
+Result Test Name MessageFail exception thrown in event listener function should result in error event on listener's global
+Fail exception thrown in event listener interface object should result in error event on listener's global
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-throwing.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-throwing.txt
new file mode 100644
index 00000000000..a6bbba7e660
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-dispatch-throwing.txt
@@ -0,0 +1,12 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 2 tests
+
+2 Pass
+Details
+Result Test Name MessagePass Throwing in event listener with a single listeners
+Pass Throwing in event listener with multiple listeners
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-init-while-dispatching.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-init-while-dispatching.txt
new file mode 100644
index 00000000000..4157cb77678
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-init-while-dispatching.txt
@@ -0,0 +1,16 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 5 tests
+
+4 Pass
+1 Fail
+Details
+Result Test Name MessagePass Calling initKeyboardEvent while dispatching.
+Pass Calling initMouseEvent while dispatching.
+Pass Calling initCustomEvent while dispatching.
+Fail Calling initUIEvent while dispatching. Not an object of type Window
+Pass Calling initEvent while dispatching.
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-initEvent.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-initEvent.txt
new file mode 100644
index 00000000000..bcf06522919
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-initEvent.txt
@@ -0,0 +1,22 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 12 tests
+
+12 Pass
+Details
+Result Test Name MessagePass Properties of initEvent(type, true, true)
+Pass Properties of initEvent(type, true, false)
+Pass Properties of initEvent(type, false, true)
+Pass Properties of initEvent(type, false, false)
+Pass Calling initEvent multiple times (getting type).
+Pass Calling initEvent multiple times (not getting type).
+Pass Calling initEvent must not have an effect during dispatching.
+Pass Calling initEvent must unset the stop propagation flag.
+Pass Calling initEvent must unset the stop immediate propagation flag.
+Pass Calling initEvent during propagation.
+Pass First parameter to initEvent should be mandatory.
+Pass Tests initEvent's default parameter values.
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-propagation.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-propagation.txt
new file mode 100644
index 00000000000..75d1379ad02
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-propagation.txt
@@ -0,0 +1,17 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 7 tests
+
+7 Pass
+Details
+Result Test Name MessagePass Newly-created Event
+Pass After stopPropagation()
+Pass Reinitialized after stopPropagation()
+Pass After stopImmediatePropagation()
+Pass Reinitialized after stopImmediatePropagation()
+Pass After cancelBubble=true
+Pass Reinitialized after cancelBubble=true
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-returnValue.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-returnValue.txt
new file mode 100644
index 00000000000..f3b612ca034
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-returnValue.txt
@@ -0,0 +1,17 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 7 tests
+
+7 Pass
+Details
+Result Test Name MessagePass When an event is created, returnValue should be initialized to true.
+Pass preventDefault() should not change returnValue if cancelable is false.
+Pass returnValue=false should have no effect if cancelable is false.
+Pass preventDefault() should change returnValue if cancelable is true.
+Pass returnValue should change returnValue if cancelable is true.
+Pass initEvent should unset returnValue.
+Pass returnValue=true should have no effect once the canceled flag was set.
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-stopImmediatePropagation.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-stopImmediatePropagation.txt
new file mode 100644
index 00000000000..2856f7b3c93
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-stopImmediatePropagation.txt
@@ -0,0 +1,11 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 1 tests
+
+1 Pass
+Details
+Result Test Name MessagePass Event's stopImmediatePropagation
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-stopPropagation-cancel-bubbling.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-stopPropagation-cancel-bubbling.txt
new file mode 100644
index 00000000000..304976625fb
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-stopPropagation-cancel-bubbling.txt
@@ -0,0 +1,11 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 1 tests
+
+1 Pass
+Details
+Result Test Name MessagePass Event-stopPropagation-cancel-bubbling
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-subclasses-constructors.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-subclasses-constructors.txt
new file mode 100644
index 00000000000..fa23229c0ef
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-subclasses-constructors.txt
@@ -0,0 +1,60 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 49 tests
+
+43 Pass
+6 Fail
+Details
+Result Test Name MessagePass Event constructor (no argument)
+Pass Event constructor (undefined argument)
+Pass Event constructor (null argument)
+Pass Event constructor (empty argument)
+Pass Event constructor (argument with default values)
+Pass Event constructor (argument with non-default values)
+Pass UIEvent constructor (no argument)
+Pass UIEvent constructor (undefined argument)
+Pass UIEvent constructor (null argument)
+Pass UIEvent constructor (empty argument)
+Pass UIEvent constructor (argument with default values)
+Fail UIEvent constructor (argument with non-default values) Not an object of type Window
+Pass FocusEvent constructor (no argument)
+Pass FocusEvent constructor (undefined argument)
+Pass FocusEvent constructor (null argument)
+Pass FocusEvent constructor (empty argument)
+Pass FocusEvent constructor (argument with default values)
+Fail FocusEvent constructor (argument with non-default values) Not an object of type Window
+Pass MouseEvent constructor (no argument)
+Pass MouseEvent constructor (undefined argument)
+Pass MouseEvent constructor (null argument)
+Pass MouseEvent constructor (empty argument)
+Pass MouseEvent constructor (argument with default values)
+Fail MouseEvent constructor (argument with non-default values) Not an object of type Window
+Pass WheelEvent constructor (no argument)
+Pass WheelEvent constructor (undefined argument)
+Pass WheelEvent constructor (null argument)
+Pass WheelEvent constructor (empty argument)
+Pass WheelEvent constructor (argument with default values)
+Fail WheelEvent constructor (argument with non-default values) Not an object of type Window
+Pass KeyboardEvent constructor (no argument)
+Pass KeyboardEvent constructor (undefined argument)
+Pass KeyboardEvent constructor (null argument)
+Pass KeyboardEvent constructor (empty argument)
+Pass KeyboardEvent constructor (argument with default values)
+Fail KeyboardEvent constructor (argument with non-default values) Not an object of type Window
+Pass CompositionEvent constructor (no argument)
+Pass CompositionEvent constructor (undefined argument)
+Pass CompositionEvent constructor (null argument)
+Pass CompositionEvent constructor (empty argument)
+Pass CompositionEvent constructor (argument with default values)
+Fail CompositionEvent constructor (argument with non-default values) Not an object of type Window
+Pass SubclassedEvent constructor (no argument)
+Pass SubclassedEvent constructor (undefined argument)
+Pass SubclassedEvent constructor (null argument)
+Pass SubclassedEvent constructor (empty argument)
+Pass SubclassedEvent constructor (argument with default values)
+Pass SubclassedEvent constructor (argument with non-default values)
+Pass UIEvent constructor (view argument with wrong type)
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-cross-realm-getter.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-cross-realm-getter.txt
new file mode 100644
index 00000000000..1ceb23a64f3
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-cross-realm-getter.txt
@@ -0,0 +1,11 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 1 tests
+
+1 Pass
+Details
+Result Test Name MessagePass event.timeStamp is initialized using event's relevant global object
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-high-resolution.https.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-high-resolution.https.txt
new file mode 100644
index 00000000000..1e9b3d18239
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-high-resolution.https.txt
@@ -0,0 +1,11 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 1 tests
+
+1 Fail
+Details
+Result Test Name MessageFail Constructed GamepadEvent timestamp should be high resolution and have the same time origin as performance.now() undefined is not a constructor (evaluated from 'window[]')
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-high-resolution.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-high-resolution.txt
new file mode 100644
index 00000000000..21feddbc99e
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-high-resolution.txt
@@ -0,0 +1,14 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 4 tests
+
+4 Pass
+Details
+Result Test Name MessagePass Constructed MouseEvent timestamp should be high resolution and have the same time origin as performance.now()
+Pass Constructed KeyboardEvent timestamp should be high resolution and have the same time origin as performance.now()
+Pass Constructed WheelEvent timestamp should be high resolution and have the same time origin as performance.now()
+Pass Constructed FocusEvent timestamp should be high resolution and have the same time origin as performance.now()
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-safe-resolution.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-safe-resolution.txt
new file mode 100644
index 00000000000..8a8fe297ea8
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-timestamp-safe-resolution.txt
@@ -0,0 +1,11 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 1 tests
+
+1 Fail
+Details
+Result Test Name MessageFail Event timestamp should not have a resolution better than 5 microseconds
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-type-empty.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-type-empty.txt
new file mode 100644
index 00000000000..c08935b362e
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-type-empty.txt
@@ -0,0 +1,12 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 2 tests
+
+2 Pass
+Details
+Result Test Name MessagePass initEvent
+Pass Constructor
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-type.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-type.txt
new file mode 100644
index 00000000000..e815e26a159
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/Event-type.txt
@@ -0,0 +1,13 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 3 tests
+
+3 Pass
+Details
+Result Test Name MessagePass Event.type should initially be the empty string
+Pass Event.type should be initialized by initEvent
+Pass Event.type should be initialized by the constructor
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventListener-handleEvent.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventListener-handleEvent.txt
new file mode 100644
index 00000000000..6cc70959fd0
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventListener-handleEvent.txt
@@ -0,0 +1,16 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 6 tests
+
+6 Pass
+Details
+Result Test Name MessagePass calls `handleEvent` method of `EventListener`
+Pass performs `Get` every time event is dispatched
+Pass doesn't call `handleEvent` method on callable `EventListener`
+Pass rethrows errors when getting `handleEvent`
+Pass throws if `handleEvent` is falsy and not callable
+Pass throws if `handleEvent` is thruthy and not callable
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventListenerOptions-capture.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventListenerOptions-capture.txt
new file mode 100644
index 00000000000..1f15aa46994
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventListenerOptions-capture.txt
@@ -0,0 +1,14 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 4 tests
+
+4 Pass
+Details
+Result Test Name MessagePass Capture boolean should be honored correctly
+Pass Capture option should be honored correctly
+Pass Supports capture option
+Pass Equivalence of option values
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-add-listener-platform-object.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-add-listener-platform-object.txt
new file mode 100644
index 00000000000..b4612687f9f
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-add-listener-platform-object.txt
@@ -0,0 +1,11 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 1 tests
+
+1 Pass
+Details
+Result Test Name MessagePass addEventListener with a platform object
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-dispatchEvent-returnvalue.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-dispatchEvent-returnvalue.txt
new file mode 100644
index 00000000000..3577f2e256d
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-dispatchEvent-returnvalue.txt
@@ -0,0 +1,12 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 2 tests
+
+2 Pass
+Details
+Result Test Name MessagePass Return value of EventTarget.dispatchEvent() affected by preventDefault().
+Pass Return value of EventTarget.dispatchEvent() affected by returnValue.
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-dispatchEvent.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-dispatchEvent.txt
new file mode 100644
index 00000000000..00a5de00784
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-dispatchEvent.txt
@@ -0,0 +1,35 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 25 tests
+
+25 Pass
+Details
+Result Test Name MessagePass Calling dispatchEvent(null).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (BeforeUnloadEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (CompositionEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (CustomEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (DeviceMotionEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (DeviceOrientationEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (DragEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (Event).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (Events).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (FocusEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (HashChangeEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (HTMLEvents).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (KeyboardEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (MessageEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (MouseEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (MouseEvents).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (StorageEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (SVGEvents).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (TextEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (UIEvent).
+Pass If the event's initialized flag is not set, an InvalidStateError must be thrown (UIEvents).
+Pass If the event's dispatch flag is set, an InvalidStateError must be thrown.
+Pass Exceptions from event listeners must not be propagated.
+Pass Event listeners added during dispatch should be called
+Pass Capturing event listeners should be called before non-capturing ones
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-this-of-listener.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-this-of-listener.txt
new file mode 100644
index 00000000000..9b7ab8896b1
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/EventTarget-this-of-listener.txt
@@ -0,0 +1,16 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 6 tests
+
+6 Pass
+Details
+Result Test Name MessagePass the this value inside the event listener callback should be the node
+Pass the this value inside the event listener object handleEvent should be the object
+Pass dispatchEvent should invoke the current handleEvent method of the object
+Pass addEventListener should not require handleEvent to be defined on object listeners
+Pass handleEvent properties added to a function before addEventListener are not reached
+Pass handleEvent properties added to a function after addEventListener are not reached
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/KeyEvent-initKeyEvent.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/KeyEvent-initKeyEvent.txt
new file mode 100644
index 00000000000..1820c075d8b
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/KeyEvent-initKeyEvent.txt
@@ -0,0 +1,13 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 3 tests
+
+3 Pass
+Details
+Result Test Name MessagePass KeyboardEvent.initKeyEvent shouldn't be defined (created by createEvent("KeyboardEvent")
+Pass KeyboardEvent.initKeyEvent shouldn't be defined (created by constructor)
+Pass KeyboardEvent.prototype.initKeyEvent shouldn't be defined
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/event-disabled-dynamic.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/event-disabled-dynamic.txt
new file mode 100644
index 00000000000..06acb7012c5
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/event-disabled-dynamic.txt
@@ -0,0 +1,11 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 1 tests
+
+1 Pass
+Details
+Result Test Name MessagePass disabled is honored properly in presence of dynamic changes
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/event-global.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/event-global.txt
new file mode 100644
index 00000000000..f2cc61b872f
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/event-global.txt
@@ -0,0 +1,19 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 8 tests
+
+7 Pass
+1 Fail
+Details
+Result Test Name MessagePass event exists on window, which is initially set to undefined
+Pass window.event is only defined during dispatch
+Pass window.event is undefined if the target is in a shadow tree (event dispatched outside shadow tree)
+Pass window.event is undefined if the target is in a shadow tree (event dispatched inside shadow tree)
+Fail window.event is undefined inside window.onerror if the target is in a shadow tree (ErrorEvent dispatched inside shadow tree)
+Pass window.event is set to the current event during dispatch
+Pass window.event is set to the current event, which is the event passed to dispatch
+Pass window.event is set to the current event, which is the event passed to dispatch (2)
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/mouse-event-retarget.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/mouse-event-retarget.txt
new file mode 100644
index 00000000000..1d8c46f179f
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/mouse-event-retarget.txt
@@ -0,0 +1,11 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 1 tests
+
+1 Fail
+Details
+Result Test Name MessageFail offsetX is correctly adjusted
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/passive-by-default.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/passive-by-default.txt
new file mode 100644
index 00000000000..ebcc2067da0
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/passive-by-default.txt
@@ -0,0 +1,111 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 100 tests
+
+68 Pass
+32 Fail
+Details
+Result Test Name MessageFail touchstart listener is passive by default for Window
+Fail touchstart listener is passive with {passive:undefined} for Window
+Pass touchstart listener is non-passive with {passive:false} for Window
+Pass touchstart listener is passive with {passive:true} for Window
+Fail touchstart listener is passive by default for HTMLDocument
+Fail touchstart listener is passive with {passive:undefined} for HTMLDocument
+Pass touchstart listener is non-passive with {passive:false} for HTMLDocument
+Pass touchstart listener is passive with {passive:true} for HTMLDocument
+Fail touchstart listener is passive by default for HTMLHtmlElement
+Fail touchstart listener is passive with {passive:undefined} for HTMLHtmlElement
+Pass touchstart listener is non-passive with {passive:false} for HTMLHtmlElement
+Pass touchstart listener is passive with {passive:true} for HTMLHtmlElement
+Fail touchstart listener is passive by default for HTMLBodyElement
+Fail touchstart listener is passive with {passive:undefined} for HTMLBodyElement
+Pass touchstart listener is non-passive with {passive:false} for HTMLBodyElement
+Pass touchstart listener is passive with {passive:true} for HTMLBodyElement
+Pass touchstart listener is non-passive by default for HTMLDivElement
+Pass touchstart listener is non-passive with {passive:undefined} for HTMLDivElement
+Pass touchstart listener is non-passive with {passive:false} for HTMLDivElement
+Pass touchstart listener is passive with {passive:true} for HTMLDivElement
+Fail touchmove listener is passive by default for Window
+Fail touchmove listener is passive with {passive:undefined} for Window
+Pass touchmove listener is non-passive with {passive:false} for Window
+Pass touchmove listener is passive with {passive:true} for Window
+Fail touchmove listener is passive by default for HTMLDocument
+Fail touchmove listener is passive with {passive:undefined} for HTMLDocument
+Pass touchmove listener is non-passive with {passive:false} for HTMLDocument
+Pass touchmove listener is passive with {passive:true} for HTMLDocument
+Fail touchmove listener is passive by default for HTMLHtmlElement
+Fail touchmove listener is passive with {passive:undefined} for HTMLHtmlElement
+Pass touchmove listener is non-passive with {passive:false} for HTMLHtmlElement
+Pass touchmove listener is passive with {passive:true} for HTMLHtmlElement
+Fail touchmove listener is passive by default for HTMLBodyElement
+Fail touchmove listener is passive with {passive:undefined} for HTMLBodyElement
+Pass touchmove listener is non-passive with {passive:false} for HTMLBodyElement
+Pass touchmove listener is passive with {passive:true} for HTMLBodyElement
+Pass touchmove listener is non-passive by default for HTMLDivElement
+Pass touchmove listener is non-passive with {passive:undefined} for HTMLDivElement
+Pass touchmove listener is non-passive with {passive:false} for HTMLDivElement
+Pass touchmove listener is passive with {passive:true} for HTMLDivElement
+Fail wheel listener is passive by default for Window
+Fail wheel listener is passive with {passive:undefined} for Window
+Pass wheel listener is non-passive with {passive:false} for Window
+Pass wheel listener is passive with {passive:true} for Window
+Fail wheel listener is passive by default for HTMLDocument
+Fail wheel listener is passive with {passive:undefined} for HTMLDocument
+Pass wheel listener is non-passive with {passive:false} for HTMLDocument
+Pass wheel listener is passive with {passive:true} for HTMLDocument
+Fail wheel listener is passive by default for HTMLHtmlElement
+Fail wheel listener is passive with {passive:undefined} for HTMLHtmlElement
+Pass wheel listener is non-passive with {passive:false} for HTMLHtmlElement
+Pass wheel listener is passive with {passive:true} for HTMLHtmlElement
+Fail wheel listener is passive by default for HTMLBodyElement
+Fail wheel listener is passive with {passive:undefined} for HTMLBodyElement
+Pass wheel listener is non-passive with {passive:false} for HTMLBodyElement
+Pass wheel listener is passive with {passive:true} for HTMLBodyElement
+Pass wheel listener is non-passive by default for HTMLDivElement
+Pass wheel listener is non-passive with {passive:undefined} for HTMLDivElement
+Pass wheel listener is non-passive with {passive:false} for HTMLDivElement
+Pass wheel listener is passive with {passive:true} for HTMLDivElement
+Fail mousewheel listener is passive by default for Window
+Fail mousewheel listener is passive with {passive:undefined} for Window
+Pass mousewheel listener is non-passive with {passive:false} for Window
+Pass mousewheel listener is passive with {passive:true} for Window
+Fail mousewheel listener is passive by default for HTMLDocument
+Fail mousewheel listener is passive with {passive:undefined} for HTMLDocument
+Pass mousewheel listener is non-passive with {passive:false} for HTMLDocument
+Pass mousewheel listener is passive with {passive:true} for HTMLDocument
+Fail mousewheel listener is passive by default for HTMLHtmlElement
+Fail mousewheel listener is passive with {passive:undefined} for HTMLHtmlElement
+Pass mousewheel listener is non-passive with {passive:false} for HTMLHtmlElement
+Pass mousewheel listener is passive with {passive:true} for HTMLHtmlElement
+Fail mousewheel listener is passive by default for HTMLBodyElement
+Fail mousewheel listener is passive with {passive:undefined} for HTMLBodyElement
+Pass mousewheel listener is non-passive with {passive:false} for HTMLBodyElement
+Pass mousewheel listener is passive with {passive:true} for HTMLBodyElement
+Pass mousewheel listener is non-passive by default for HTMLDivElement
+Pass mousewheel listener is non-passive with {passive:undefined} for HTMLDivElement
+Pass mousewheel listener is non-passive with {passive:false} for HTMLDivElement
+Pass mousewheel listener is passive with {passive:true} for HTMLDivElement
+Pass touchend listener is non-passive by default for Window
+Pass touchend listener is non-passive with {passive:undefined} for Window
+Pass touchend listener is non-passive with {passive:false} for Window
+Pass touchend listener is passive with {passive:true} for Window
+Pass touchend listener is non-passive by default for HTMLDocument
+Pass touchend listener is non-passive with {passive:undefined} for HTMLDocument
+Pass touchend listener is non-passive with {passive:false} for HTMLDocument
+Pass touchend listener is passive with {passive:true} for HTMLDocument
+Pass touchend listener is non-passive by default for HTMLHtmlElement
+Pass touchend listener is non-passive with {passive:undefined} for HTMLHtmlElement
+Pass touchend listener is non-passive with {passive:false} for HTMLHtmlElement
+Pass touchend listener is passive with {passive:true} for HTMLHtmlElement
+Pass touchend listener is non-passive by default for HTMLBodyElement
+Pass touchend listener is non-passive with {passive:undefined} for HTMLBodyElement
+Pass touchend listener is non-passive with {passive:false} for HTMLBodyElement
+Pass touchend listener is passive with {passive:true} for HTMLBodyElement
+Pass touchend listener is non-passive by default for HTMLDivElement
+Pass touchend listener is non-passive with {passive:undefined} for HTMLDivElement
+Pass touchend listener is non-passive with {passive:false} for HTMLDivElement
+Pass touchend listener is passive with {passive:true} for HTMLDivElement
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/preventDefault-during-activation-behavior.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/preventDefault-during-activation-behavior.txt
new file mode 100644
index 00000000000..856c3fa0d42
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/preventDefault-during-activation-behavior.txt
@@ -0,0 +1,11 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 1 tests
+
+1 Pass
+Details
+Result Test Name MessagePass behavior of preventDefault during activation behavior
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/remove-all-listeners.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/remove-all-listeners.txt
new file mode 100644
index 00000000000..619c33ed3a7
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/remove-all-listeners.txt
@@ -0,0 +1,13 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 2 tests
+
+1 Pass
+1 Fail
+Details
+Result Test Name MessagePass Removing all listeners and then adding a new one should work.
+Fail Nested usage of once listeners should work.
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/events/shadow-relatedTarget.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/events/shadow-relatedTarget.txt
new file mode 100644
index 00000000000..58eb8b39e0b
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/events/shadow-relatedTarget.txt
@@ -0,0 +1,12 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 2 tests
+
+2 Fail
+Details
+Result Test Name MessageFail relatedTarget should not leak at capturing phase, at window object.
+Fail relatedTarget should not leak at target.
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/AddEventListenerOptions-once.any.js b/Tests/LibWeb/Text/input/wpt-import/dom/events/AddEventListenerOptions-once.any.js
new file mode 100644
index 00000000000..b4edd4345c5
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/AddEventListenerOptions-once.any.js
@@ -0,0 +1,96 @@
+// META: title=AddEventListenerOptions.once
+
+"use strict";
+
+test(function() {
+ var invoked_once = false;
+ var invoked_normal = false;
+ function handler_once() {
+ invoked_once = true;
+ }
+ function handler_normal() {
+ invoked_normal = true;
+ }
+
+ const et = new EventTarget();
+ et.addEventListener('test', handler_once, {once: true});
+ et.addEventListener('test', handler_normal);
+ et.dispatchEvent(new Event('test'));
+ assert_equals(invoked_once, true, "Once handler should be invoked");
+ assert_equals(invoked_normal, true, "Normal handler should be invoked");
+
+ invoked_once = false;
+ invoked_normal = false;
+ et.dispatchEvent(new Event('test'));
+ assert_equals(invoked_once, false, "Once handler shouldn't be invoked again");
+ assert_equals(invoked_normal, true, "Normal handler should be invoked again");
+ et.removeEventListener('test', handler_normal);
+}, "Once listener should be invoked only once");
+
+test(function() {
+ const et = new EventTarget();
+ var invoked_count = 0;
+ function handler() {
+ invoked_count++;
+ if (invoked_count == 1)
+ et.dispatchEvent(new Event('test'));
+ }
+ et.addEventListener('test', handler, {once: true});
+ et.dispatchEvent(new Event('test'));
+ assert_equals(invoked_count, 1, "Once handler should only be invoked once");
+
+ invoked_count = 0;
+ function handler2() {
+ invoked_count++;
+ if (invoked_count == 1)
+ et.addEventListener('test', handler2, {once: true});
+ if (invoked_count <= 2)
+ et.dispatchEvent(new Event('test'));
+ }
+ et.addEventListener('test', handler2, {once: true});
+ et.dispatchEvent(new Event('test'));
+ assert_equals(invoked_count, 2, "Once handler should only be invoked once after each adding");
+}, "Once listener should be invoked only once even if the event is nested");
+
+test(function() {
+ var invoked_count = 0;
+ function handler() {
+ invoked_count++;
+ }
+
+ const et = new EventTarget();
+
+ et.addEventListener('test', handler, {once: true});
+ et.addEventListener('test', handler);
+ et.dispatchEvent(new Event('test'));
+ assert_equals(invoked_count, 1, "The handler should only be added once");
+
+ invoked_count = 0;
+ et.dispatchEvent(new Event('test'));
+ assert_equals(invoked_count, 0, "The handler was added as a once listener");
+
+ invoked_count = 0;
+ et.addEventListener('test', handler, {once: true});
+ et.removeEventListener('test', handler);
+ et.dispatchEvent(new Event('test'));
+ assert_equals(invoked_count, 0, "The handler should have been removed");
+}, "Once listener should be added / removed like normal listeners");
+
+test(function() {
+ const et = new EventTarget();
+
+ var invoked_count = 0;
+
+ for (let n = 4; n > 0; n--) {
+ et.addEventListener('test', (e) => {
+ invoked_count++;
+ e.stopImmediatePropagation();
+ }, {once: true});
+ }
+
+ for (let n = 4; n > 0; n--) {
+ et.dispatchEvent(new Event('test'));
+ }
+
+ assert_equals(invoked_count, 4, "The listeners should be invoked");
+}, "Multiple once listeners should be invoked even if the stopImmediatePropagation is set");
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/AddEventListenerOptions-passive.any.js b/Tests/LibWeb/Text/input/wpt-import/dom/events/AddEventListenerOptions-passive.any.js
new file mode 100644
index 00000000000..8e59cf5b379
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/AddEventListenerOptions-passive.any.js
@@ -0,0 +1,134 @@
+// META: title=AddEventListenerOptions.passive
+
+test(function() {
+ var supportsPassive = false;
+ var query_options = {
+ get passive() {
+ supportsPassive = true;
+ return false;
+ },
+ get dummy() {
+ assert_unreached("dummy value getter invoked");
+ return false;
+ }
+ };
+
+ const et = new EventTarget();
+ et.addEventListener('test_event', null, query_options);
+ assert_true(supportsPassive, "addEventListener doesn't support the passive option");
+
+ supportsPassive = false;
+ et.removeEventListener('test_event', null, query_options);
+ assert_false(supportsPassive, "removeEventListener supports the passive option when it should not");
+}, "Supports passive option on addEventListener only");
+
+function testPassiveValue(optionsValue, expectedDefaultPrevented, existingEventTarget) {
+ var defaultPrevented = undefined;
+ var handler = function handler(e) {
+ assert_false(e.defaultPrevented, "Event prematurely marked defaultPrevented");
+ e.preventDefault();
+ defaultPrevented = e.defaultPrevented;
+ }
+ const et = existingEventTarget || new EventTarget();
+ et.addEventListener('test', handler, optionsValue);
+ var uncanceled = et.dispatchEvent(new Event('test', {bubbles: true, cancelable: true}));
+
+ assert_equals(defaultPrevented, expectedDefaultPrevented, "Incorrect defaultPrevented for options: " + JSON.stringify(optionsValue));
+ assert_equals(uncanceled, !expectedDefaultPrevented, "Incorrect return value from dispatchEvent");
+
+ et.removeEventListener('test', handler, optionsValue);
+}
+
+test(function() {
+ testPassiveValue(undefined, true);
+ testPassiveValue({}, true);
+ testPassiveValue({passive: false}, true);
+ testPassiveValue({passive: true}, false);
+ testPassiveValue({passive: 0}, true);
+ testPassiveValue({passive: 1}, false);
+}, "preventDefault should be ignored if-and-only-if the passive option is true");
+
+function testPassiveValueOnReturnValue(test, optionsValue, expectedDefaultPrevented) {
+ var defaultPrevented = undefined;
+ var handler = test.step_func(e => {
+ assert_false(e.defaultPrevented, "Event prematurely marked defaultPrevented");
+ e.returnValue = false;
+ defaultPrevented = e.defaultPrevented;
+ });
+ const et = new EventTarget();
+ et.addEventListener('test', handler, optionsValue);
+ var uncanceled = et.dispatchEvent(new Event('test', {bubbles: true, cancelable: true}));
+
+ assert_equals(defaultPrevented, expectedDefaultPrevented, "Incorrect defaultPrevented for options: " + JSON.stringify(optionsValue));
+ assert_equals(uncanceled, !expectedDefaultPrevented, "Incorrect return value from dispatchEvent");
+
+ et.removeEventListener('test', handler, optionsValue);
+}
+
+async_test(t => {
+ testPassiveValueOnReturnValue(t, undefined, true);
+ testPassiveValueOnReturnValue(t, {}, true);
+ testPassiveValueOnReturnValue(t, {passive: false}, true);
+ testPassiveValueOnReturnValue(t, {passive: true}, false);
+ testPassiveValueOnReturnValue(t, {passive: 0}, true);
+ testPassiveValueOnReturnValue(t, {passive: 1}, false);
+ t.done();
+}, "returnValue should be ignored if-and-only-if the passive option is true");
+
+function testPassiveWithOtherHandlers(optionsValue, expectedDefaultPrevented) {
+ var handlerInvoked1 = false;
+ var dummyHandler1 = function() {
+ handlerInvoked1 = true;
+ };
+ var handlerInvoked2 = false;
+ var dummyHandler2 = function() {
+ handlerInvoked2 = true;
+ };
+
+ const et = new EventTarget();
+ et.addEventListener('test', dummyHandler1, {passive:true});
+ et.addEventListener('test', dummyHandler2);
+
+ testPassiveValue(optionsValue, expectedDefaultPrevented, et);
+
+ assert_true(handlerInvoked1, "Extra passive handler not invoked");
+ assert_true(handlerInvoked2, "Extra non-passive handler not invoked");
+
+ et.removeEventListener('test', dummyHandler1);
+ et.removeEventListener('test', dummyHandler2);
+}
+
+test(function() {
+ testPassiveWithOtherHandlers({}, true);
+ testPassiveWithOtherHandlers({passive: false}, true);
+ testPassiveWithOtherHandlers({passive: true}, false);
+}, "passive behavior of one listener should be unaffected by the presence of other listeners");
+
+function testOptionEquivalence(optionValue1, optionValue2, expectedEquality) {
+ var invocationCount = 0;
+ var handler = function handler(e) {
+ invocationCount++;
+ }
+ const et = new EventTarget();
+ et.addEventListener('test', handler, optionValue1);
+ et.addEventListener('test', handler, optionValue2);
+ et.dispatchEvent(new Event('test', {bubbles: true}));
+ assert_equals(invocationCount, expectedEquality ? 1 : 2, "equivalence of options " +
+ JSON.stringify(optionValue1) + " and " + JSON.stringify(optionValue2));
+ et.removeEventListener('test', handler, optionValue1);
+ et.removeEventListener('test', handler, optionValue2);
+}
+
+test(function() {
+ // Sanity check options that should be treated as distinct handlers
+ testOptionEquivalence({capture:true}, {capture:false, passive:false}, false);
+ testOptionEquivalence({capture:true}, {passive:true}, false);
+
+ // Option values that should be treated as equivalent
+ testOptionEquivalence({}, {passive:false}, true);
+ testOptionEquivalence({passive:true}, {passive:false}, true);
+ testOptionEquivalence(undefined, {passive:true}, true);
+ testOptionEquivalence({capture: true, passive: false}, {capture: true, passive: true}, true);
+
+}, "Equivalence of option values");
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/AddEventListenerOptions-signal.any.js b/Tests/LibWeb/Text/input/wpt-import/dom/events/AddEventListenerOptions-signal.any.js
new file mode 100644
index 00000000000..e6a34261594
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/AddEventListenerOptions-signal.any.js
@@ -0,0 +1,143 @@
+'use strict';
+
+test(function() {
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ et.addEventListener('test', handler, { signal: controller.signal });
+ et.dispatchEvent(new Event('test'));
+ assert_equals(count, 1, "Adding a signal still adds a listener");
+ et.dispatchEvent(new Event('test'));
+ assert_equals(count, 2, "The listener was not added with the once flag");
+ controller.abort();
+ et.dispatchEvent(new Event('test'));
+ assert_equals(count, 2, "Aborting on the controller removes the listener");
+ et.addEventListener('test', handler, { signal: controller.signal });
+ et.dispatchEvent(new Event('test'));
+ assert_equals(count, 2, "Passing an aborted signal never adds the handler");
+}, "Passing an AbortSignal to addEventListener options should allow removing a listener");
+
+test(function() {
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ et.addEventListener('test', handler, { signal: controller.signal });
+ et.removeEventListener('test', handler);
+ et.dispatchEvent(new Event('test'));
+ assert_equals(count, 0, "The listener was still removed");
+}, "Passing an AbortSignal to addEventListener does not prevent removeEventListener");
+
+test(function() {
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ et.addEventListener('test', handler, { signal: controller.signal, once: true });
+ controller.abort();
+ et.dispatchEvent(new Event('test'));
+ assert_equals(count, 0, "The listener was still removed");
+}, "Passing an AbortSignal to addEventListener works with the once flag");
+
+test(function() {
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ et.addEventListener('test', handler, { signal: controller.signal, once: true });
+ et.removeEventListener('test', handler);
+ et.dispatchEvent(new Event('test'));
+ assert_equals(count, 0, "The listener was still removed");
+}, "Removing a once listener works with a passed signal");
+
+test(function() {
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ et.addEventListener('first', handler, { signal: controller.signal, once: true });
+ et.addEventListener('second', handler, { signal: controller.signal, once: true });
+ controller.abort();
+ et.dispatchEvent(new Event('first'));
+ et.dispatchEvent(new Event('second'));
+ assert_equals(count, 0, "The listener was still removed");
+}, "Passing an AbortSignal to multiple listeners");
+
+test(function() {
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ et.addEventListener('test', handler, { signal: controller.signal, capture: true });
+ controller.abort();
+ et.dispatchEvent(new Event('test'));
+ assert_equals(count, 0, "The listener was still removed");
+}, "Passing an AbortSignal to addEventListener works with the capture flag");
+
+test(function() {
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ et.addEventListener('test', () => {
+ controller.abort();
+ }, { signal: controller.signal });
+ et.addEventListener('test', handler, { signal: controller.signal });
+ et.dispatchEvent(new Event('test'));
+ assert_equals(count, 0, "The listener was still removed");
+}, "Aborting from a listener does not call future listeners");
+
+test(function() {
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ et.addEventListener('test', () => {
+ et.addEventListener('test', handler, { signal: controller.signal });
+ controller.abort();
+ }, { signal: controller.signal });
+ et.dispatchEvent(new Event('test'));
+ assert_equals(count, 0, "The listener was still removed");
+}, "Adding then aborting a listener in another listener does not call it");
+
+test(function() {
+ const et = new EventTarget();
+ const ac = new AbortController();
+ let count = 0;
+ et.addEventListener('foo', () => {
+ et.addEventListener('foo', () => {
+ count++;
+ if (count > 5) ac.abort();
+ et.dispatchEvent(new Event('foo'));
+ }, { signal: ac.signal });
+ et.dispatchEvent(new Event('foo'));
+ }, { once: true });
+ et.dispatchEvent(new Event('foo'));
+}, "Aborting from a nested listener should remove it");
+
+test(function() {
+ const et = new EventTarget();
+ assert_throws_js(TypeError, () => { et.addEventListener("foo", () => {}, { signal: null }); });
+}, "Passing null as the signal should throw");
+
+test(function() {
+ const et = new EventTarget();
+ assert_throws_js(TypeError, () => { et.addEventListener("foo", null, { signal: null }); });
+}, "Passing null as the signal should throw (listener is also null)");
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Body-FrameSet-Event-Handlers.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Body-FrameSet-Event-Handlers.html
new file mode 100644
index 00000000000..16d13815b1b
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Body-FrameSet-Event-Handlers.html
@@ -0,0 +1,123 @@
+
+
+HTMLBodyElement and HTMLFrameSetElement Event Handler Tests
+
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/CustomEvent.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/CustomEvent.html
new file mode 100644
index 00000000000..cce9e915ddb
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/CustomEvent.html
@@ -0,0 +1,35 @@
+
+CustomEvent
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-cancelBubble.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-cancelBubble.html
new file mode 100644
index 00000000000..63fae65c33d
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-cancelBubble.html
@@ -0,0 +1,132 @@
+
+
+
+
+ Event.cancelBubble
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-constants.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-constants.html
new file mode 100644
index 00000000000..608be04737f
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-constants.html
@@ -0,0 +1,23 @@
+
+Event constants
+
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-constructors.any.js b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-constructors.any.js
new file mode 100644
index 00000000000..faa623ea929
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-constructors.any.js
@@ -0,0 +1,120 @@
+// META: title=Event constructors
+
+test(function() {
+ assert_throws_js(
+ TypeError,
+ () => Event(""),
+ "Calling Event constructor without 'new' must throw")
+})
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new Event()
+ })
+})
+test(function() {
+ var test_error = { name: "test" }
+ assert_throws_exactly(test_error, function() {
+ new Event({ toString: function() { throw test_error; } })
+ })
+})
+test(function() {
+ var ev = new Event("")
+ assert_equals(ev.type, "")
+ assert_equals(ev.target, null)
+ assert_equals(ev.srcElement, null)
+ assert_equals(ev.currentTarget, null)
+ assert_equals(ev.eventPhase, Event.NONE)
+ assert_equals(ev.bubbles, false)
+ assert_equals(ev.cancelable, false)
+ assert_equals(ev.defaultPrevented, false)
+ assert_equals(ev.returnValue, true)
+ assert_equals(ev.isTrusted, false)
+ assert_true(ev.timeStamp > 0)
+ assert_true("initEvent" in ev)
+})
+test(function() {
+ var ev = new Event("test")
+ assert_equals(ev.type, "test")
+ assert_equals(ev.target, null)
+ assert_equals(ev.srcElement, null)
+ assert_equals(ev.currentTarget, null)
+ assert_equals(ev.eventPhase, Event.NONE)
+ assert_equals(ev.bubbles, false)
+ assert_equals(ev.cancelable, false)
+ assert_equals(ev.defaultPrevented, false)
+ assert_equals(ev.returnValue, true)
+ assert_equals(ev.isTrusted, false)
+ assert_true(ev.timeStamp > 0)
+ assert_true("initEvent" in ev)
+})
+test(function() {
+ assert_throws_js(TypeError, function() { Event("test") },
+ 'Calling Event constructor without "new" must throw');
+})
+test(function() {
+ var ev = new Event("I am an event", { bubbles: true, cancelable: false})
+ assert_equals(ev.type, "I am an event")
+ assert_equals(ev.bubbles, true)
+ assert_equals(ev.cancelable, false)
+})
+test(function() {
+ var ev = new Event("@", { bubblesIGNORED: true, cancelable: true})
+ assert_equals(ev.type, "@")
+ assert_equals(ev.bubbles, false)
+ assert_equals(ev.cancelable, true)
+})
+test(function() {
+ var ev = new Event("@", { "bubbles\0IGNORED": true, cancelable: true})
+ assert_equals(ev.type, "@")
+ assert_equals(ev.bubbles, false)
+ assert_equals(ev.cancelable, true)
+})
+test(function() {
+ var ev = new Event("Xx", { cancelable: true})
+ assert_equals(ev.type, "Xx")
+ assert_equals(ev.bubbles, false)
+ assert_equals(ev.cancelable, true)
+})
+test(function() {
+ var ev = new Event("Xx", {})
+ assert_equals(ev.type, "Xx")
+ assert_equals(ev.bubbles, false)
+ assert_equals(ev.cancelable, false)
+})
+test(function() {
+ var ev = new Event("Xx", {bubbles: true, cancelable: false, sweet: "x"})
+ assert_equals(ev.type, "Xx")
+ assert_equals(ev.bubbles, true)
+ assert_equals(ev.cancelable, false)
+ assert_equals(ev.sweet, undefined)
+})
+test(function() {
+ var called = []
+ var ev = new Event("Xx", {
+ get cancelable() {
+ called.push("cancelable")
+ return false
+ },
+ get bubbles() {
+ called.push("bubbles")
+ return true;
+ },
+ get sweet() {
+ called.push("sweet")
+ return "x"
+ }
+ })
+ assert_array_equals(called, ["bubbles", "cancelable"])
+ assert_equals(ev.type, "Xx")
+ assert_equals(ev.bubbles, true)
+ assert_equals(ev.cancelable, false)
+ assert_equals(ev.sweet, undefined)
+})
+test(function() {
+ var ev = new CustomEvent("$", {detail: 54, sweet: "x", sweet2: "x", cancelable:true})
+ assert_equals(ev.type, "$")
+ assert_equals(ev.bubbles, false)
+ assert_equals(ev.cancelable, true)
+ assert_equals(ev.sweet, undefined)
+ assert_equals(ev.detail, 54)
+})
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-defaultPrevented-after-dispatch.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-defaultPrevented-after-dispatch.html
new file mode 100644
index 00000000000..c3557759bd8
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-defaultPrevented-after-dispatch.html
@@ -0,0 +1,44 @@
+
+
+Event.defaultPrevented is not reset after dispatchEvent()
+
+
+
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-defaultPrevented.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-defaultPrevented.html
new file mode 100644
index 00000000000..c4221925e43
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-defaultPrevented.html
@@ -0,0 +1,55 @@
+
+Event.defaultPrevented
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-bubble-canceled.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-bubble-canceled.html
new file mode 100644
index 00000000000..f34f22426c0
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-bubble-canceled.html
@@ -0,0 +1,59 @@
+
+
+
+Setting cancelBubble=true prior to dispatchEvent()
+
+
+
+
+
+
+
+
+
+
Shady Grove
+
Aeolian
+
+
+
Over the river, Charlie
+
Dorian
+
+
+
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-bubbles-false.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-bubbles-false.html
new file mode 100644
index 00000000000..de8532a18be
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-bubbles-false.html
@@ -0,0 +1,98 @@
+
+
+ Event.bubbles attribute is set to false
+
+
+
+
+
+
+
+
+
Shady Grove
+
Aeolian
+
+
+
Over the river, Charlie
+
Dorian
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-bubbles-true.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-bubbles-true.html
new file mode 100644
index 00000000000..35784254b4d
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-bubbles-true.html
@@ -0,0 +1,108 @@
+
+
+ Event.bubbles attribute is set to false
+
+
+
+
+
+
+
+
+
Shady Grove
+
Aeolian
+
+
+
Over the river, Charlie
+
Dorian
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-click.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-click.html
new file mode 100644
index 00000000000..3f34fbc810c
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-click.html
@@ -0,0 +1,425 @@
+
+Synthetic click event "magic"
+
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-click.tentative.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-click.tentative.html
new file mode 100644
index 00000000000..d9ff0fdc82f
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-click.tentative.html
@@ -0,0 +1,78 @@
+
+Clicks on input element
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-detached-click.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-detached-click.html
new file mode 100644
index 00000000000..a9080f16444
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-detached-click.html
@@ -0,0 +1,20 @@
+
+Click event on an element not in the document
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-detached-input-and-change.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-detached-input-and-change.html
new file mode 100644
index 00000000000..a2fb6d75d84
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-detached-input-and-change.html
@@ -0,0 +1,190 @@
+
+
+
+input and change events for detached checkbox and radio elements
+
+
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-handlers-changed.html b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-handlers-changed.html
new file mode 100644
index 00000000000..323c13bff0c
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/events/Event-dispatch-handlers-changed.html
@@ -0,0 +1,91 @@
+
+
+ Dispatch additional events inside an event listener
+
+
+
+
+
+