summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/uievents
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/uievents')
-rw-r--r--testing/web-platform/tests/uievents/META.yml4
-rw-r--r--testing/web-platform/tests/uievents/README.md3
-rw-r--r--testing/web-platform/tests/uievents/click/auxclick_event.html81
-rw-r--r--testing/web-platform/tests/uievents/click/click_event_target_child_parent.html85
-rw-r--r--testing/web-platform/tests/uievents/click/click_event_target_siblings.html102
-rw-r--r--testing/web-platform/tests/uievents/click/click_events_on_input.html62
-rw-r--r--testing/web-platform/tests/uievents/click/contextmenu_event.html51
-rw-r--r--testing/web-platform/tests/uievents/click/dblclick_event_mouse.html44
-rw-r--r--testing/web-platform/tests/uievents/constructors/README.md4
-rw-r--r--testing/web-platform/tests/uievents/constructors/inputevent-constructor.html25
-rw-r--r--testing/web-platform/tests/uievents/hierarchy/README.md34
-rw-r--r--testing/web-platform/tests/uievents/historical.html15
-rw-r--r--testing/web-platform/tests/uievents/idlharness.window.js21
-rw-r--r--testing/web-platform/tests/uievents/interface/README.md13
-rw-r--r--testing/web-platform/tests/uievents/interface/click-event-manual.htm21
-rw-r--r--testing/web-platform/tests/uievents/interface/click-event.htm32
-rw-r--r--testing/web-platform/tests/uievents/interface/dblclick-event-manual.htm21
-rw-r--r--testing/web-platform/tests/uievents/interface/keyboard-accesskey-click-event.html56
-rw-r--r--testing/web-platform/tests/uievents/interface/keyboard-click-event.html50
-rw-r--r--testing/web-platform/tests/uievents/keyboard/README.md3
-rw-r--r--testing/web-platform/tests/uievents/keyboard/key-101en-us-manual.html91
-rw-r--r--testing/web-platform/tests/uievents/keyboard/key-102fr-fr-manual.html93
-rw-r--r--testing/web-platform/tests/uievents/keyboard/key.css118
-rw-r--r--testing/web-platform/tests/uievents/keyboard/key.js671
-rw-r--r--testing/web-platform/tests/uievents/keyboard/modifier-keys-combinations.html43
-rw-r--r--testing/web-platform/tests/uievents/keyboard/modifier-keys.html35
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/Status.html26
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/approved/ProcessingInstruction.DOMCharacterDataModified.html32
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/approved/dispatchEvent.click.checkbox.html80
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/approved/domnodeinserted.html26
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/approved/stopImmediatePropagation.effect.html71
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/approved/stopPropagation.deferred.effect.html70
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/approved/support/ProcessingInstruction.DOMCharacterDataModified.xml32
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/CompositionEvent.html69
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.attrChange.html65
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.attrName.html66
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.html66
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.newValue.html65
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.prevValue.html65
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.relatedNode.html66
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMCharacterDataModified.html62
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMNodeInserted.html64
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMNodeRemoved.html62
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMSubtreeModified.html72
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.defaultPrevented.html68
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.eventPhase.html77
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.stopPropagation.html85
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.key.html56
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.location.html74
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.modifiers.html66
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.button.html65
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.image.map.area.html70
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.preventDefault.html94
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.hasFeature.html67
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.initMutationEvent.html72
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.relatedNode.html76
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.fail.html18
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.xml63
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.hasFeature.html60
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.initTextEvent.html66
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.IME.html69
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.drop.html71
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.keyboard.html67
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.paste.html71
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.script.html63
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/UIEvent.load.stylesheet.html59
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.Capture.Bubble.html90
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.ctrlKey.zoom.html93
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.deltaMode.html76
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.hasFeature.html60
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.initWheelEvent.html76
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.preventDefault.scroll.html91
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/abort.img.html74
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/abort.testresult.html30
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/blur.html57
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.data.html66
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.keydown.html76
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.preventDefault.html73
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/converted/EventListener.dispatch.new.event.html77
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/converted/support/ProcessingInstruction.DOMCharacterDataModified.xml32
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/dispatchEvent.click.checkbox.html93
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/error.image.html65
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusin.html61
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusin.relatedTarget.html64
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusout.relatedTarget.html64
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/hasFeature.Events.html52
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/hasFeature.feature.string.html80
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/load.image.html82
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseenter.ctrlKey.html64
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseenter.relatedTarget.html69
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseleave.relatedTarget.html69
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/16kb.js140
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/InvalidBitMap.png1
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/iepreview.pngbin0 -> 76515 bytes
-rw-r--r--testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/style01.css3
-rw-r--r--testing/web-platform/tests/uievents/legacy/Event-subclasses-init.html17
-rw-r--r--testing/web-platform/tests/uievents/mouse/attributes.html61
-rw-r--r--testing/web-platform/tests/uievents/mouse/cancel-mousedown-in-subframe.html64
-rw-r--r--testing/web-platform/tests/uievents/mouse/layout_change_should_fire_mouseover.html97
-rw-r--r--testing/web-platform/tests/uievents/mouse/mouse_boundary_events_after_removing_last_over_element.html153
-rw-r--r--testing/web-platform/tests/uievents/mouse/mouse_buttons_back_forward.html56
-rw-r--r--testing/web-platform/tests/uievents/mouse/mouseenter-mouseleave-on-drag.html187
-rw-r--r--testing/web-platform/tests/uievents/mouse/mouseevent_move_button.html102
-rw-r--r--testing/web-platform/tests/uievents/mouse/mousemove_prevent_default_action.tentative.html98
-rw-r--r--testing/web-platform/tests/uievents/mouse/mouseover-at-removing-mousedown-target.html81
-rw-r--r--testing/web-platform/tests/uievents/mouse/resources/mouse-event-reporter-subframe.html37
-rw-r--r--testing/web-platform/tests/uievents/mouse/resources/utils.js35
-rw-r--r--testing/web-platform/tests/uievents/mouse/synthetic-mouse-enter-leave-over-out-button-state-after-target-removed.tentative.html240
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/README.md15
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/focus-events/focus-automated-blink-webkit.html159
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/focus-events/focus-contained.html94
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/focus-events/focus-management-expectations.html48
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/focus-events/focus.html94
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/focus-events/legacy-manual.html84
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/mouse-events/click-cancel.html37
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-body.html57
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-div.html47
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-html.html67
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/mouse-events/click-order.html86
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/mouse-events/mouseevents-mousemove.htm92
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/mouse-events/mousemove-across.html162
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/mouse-events/mousemove-between.html132
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/mouse-events/mouseover-out.html141
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/mouse-events/wheel-basic.html91
-rw-r--r--testing/web-platform/tests/uievents/order-of-events/mouse-events/wheel-scrolling.html109
-rw-r--r--testing/web-platform/tests/uievents/resources/eventrecorder.js315
126 files changed, 9250 insertions, 0 deletions
diff --git a/testing/web-platform/tests/uievents/META.yml b/testing/web-platform/tests/uievents/META.yml
new file mode 100644
index 0000000000..3c490cdc55
--- /dev/null
+++ b/testing/web-platform/tests/uievents/META.yml
@@ -0,0 +1,4 @@
+spec: https://w3c.github.io/uievents/
+suggested_reviewers:
+ - jdm
+ - NavidZ
diff --git a/testing/web-platform/tests/uievents/README.md b/testing/web-platform/tests/uievents/README.md
new file mode 100644
index 0000000000..a5112c52a2
--- /dev/null
+++ b/testing/web-platform/tests/uievents/README.md
@@ -0,0 +1,3 @@
+To run the UIEvents tests, go to:
+
+http://wpt.live/uievents/order-of-events/mouse-events/
diff --git a/testing/web-platform/tests/uievents/click/auxclick_event.html b/testing/web-platform/tests/uievents/click/auxclick_event.html
new file mode 100644
index 0000000000..8bb2e137f5
--- /dev/null
+++ b/testing/web-platform/tests/uievents/click/auxclick_event.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Clicking with primary vs non-primary buttons</title>
+ <link rel="help" href="https://wicg.github.io/auxclick/">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <style>
+#target {
+ background-color: green;
+ height: 200px;
+ width: 200px;
+}
+ </style>
+ </head>
+ <body>
+ <h1>Clicking with primary vs non-primary buttons</h1>
+ <p>Double-click on the green box with a non-primary button. When using mouse any button other than the left button is non-primary. If a "PASS" result appears, the test passes; otherwise, it fails.</p>
+ <div id="target"></div>
+ <script>
+ var test_auxclick = async_test("auxclick event sequence received.");
+ var actions_promise;
+ var target = document.querySelector('#target');
+ document.addEventListener('contextmenu', event => { event.preventDefault(); });
+ ['click', 'dblclick'].forEach(eventName => {
+ target.addEventListener(eventName, () => {
+ test_auxclick.step(() => {
+ assert_unreached(eventName + ' event should not be dispatched for non-primary buttons.');
+ });
+ });
+ document.addEventListener(eventName, () => {
+ test_auxclick.step(() => {
+ assert_unreached('document should not receive ' + eventName + ' for non-primary buttons.');
+ });
+ }, true);
+ });
+ var click_count = 0;
+ var events = [];
+ ['mousedown', 'mouseup'].forEach(eventName => {
+ target.addEventListener(eventName, event => {
+ events.push(event.type);
+ });
+ });
+ target.addEventListener('auxclick', event => {
+ events.push(event.type);
+ click_count++;
+ if (click_count==1) {
+ test (() => {
+ assert_equals(event.detail, click_count, 'detail attribute of auxclick should be the click count.');
+ }, "First auxclick should have detail=1 indicating the fire click");
+ } else {
+ test (() => {
+ assert_equals(event.detail, click_count, 'detail attribute of auxclick should be the click count.');
+ }, "Second auxclick should have detail=2 indicating the fire click");
+ test_auxclick.step(() => {
+ assert_array_equals(events, ['mousedown', 'mouseup', 'auxclick', 'mousedown', 'mouseup', 'auxclick'],
+ 'There should be two auxclick events for a non-primary button double click each preceded by one mousemove and one mouseup');
+ assert_equals(event.detail, click_count, 'detail attribute of auxclick should be the click count.');
+ });
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ test_auxclick.done();
+ });
+ }
+ });
+
+ // Inject mouse double click events.
+ var actions = new test_driver.Actions();
+ actions_promise = actions.pointerMove(0, 0, {origin: target})
+ .pointerDown({button: actions.ButtonType.MIDDLE})
+ .pointerUp({button: actions.ButtonType.MIDDLE})
+ .pointerDown({button: actions.ButtonType.MIDDLE})
+ .pointerUp({button: actions.ButtonType.MIDDLE})
+ .send();
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/click/click_event_target_child_parent.html b/testing/web-platform/tests/uievents/click/click_event_target_child_parent.html
new file mode 100644
index 0000000000..a09e5532af
--- /dev/null
+++ b/testing/web-platform/tests/uievents/click/click_event_target_child_parent.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Click targets the nearest common ancestor</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <style>
+ div {
+ padding: 10px;
+ margin: 5px;
+ }
+ a {
+ background: grey;
+ }
+ </style>
+ </head>
+ <body id='body'>
+ <h1>Click targeting when targets of down and up are child and parents</h1>
+ This test verifies that click event always goes to the first common ancestor of down and up event targets.
+
+ <ul>
+ <li>Press down the primary button on link 1 and move onto green container and release.</li>
+ <li>Press down the primary button on red container and move onto link 2 and release.</li>
+ <li>Click done.</li>
+ </ul>
+
+ <div id="link_container1" style="background: green">
+ <a id="link1" href="#">link1</a>
+ </div>
+
+ <div id="link_container2" style="background: red">
+ <a id="link2" href="#">link2</a>
+ </div>
+ <button id="done">Done</button>
+ <script>
+ var test_click_target = async_test("Click targets the nearest common ancestor");
+ var actions_promise;
+
+ // Prevent drag to avoid interfering with the click.
+ document.addEventListener('dragstart', (e) => e.preventDefault());
+
+ var events = [];
+ var nodes = ['link_container1', 'link1', 'link_container2', 'link2', 'body'];
+
+ for (var i = 0; i < nodes.length; i++) {
+ ['mousedown', 'mouseup', 'click'].forEach((eventName) => {
+ document.getElementById(nodes[i]).addEventListener(eventName, (e) => {
+ if (e.eventPhase == Event.AT_TARGET)
+ events.push(e.type + '@' + e.target.id);
+ });
+ });
+ }
+ document.getElementById('done').addEventListener('click', () => {
+ test_click_target.step(() => {
+ assert_equals (events.join(','),
+ "mousedown@link1,mouseup@link_container1,click@link_container1,mousedown@link_container2,mouseup@link2,click@link_container2",
+ "Click should be sent to the nearest common ancestor");
+ });
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ test_click_target.done();
+ });
+ });
+
+ // Inject mouse events.
+ var actions = new test_driver.Actions();
+ actions_promise = actions.pointerMove(0, 0, {origin: document.getElementById('link1')})
+ .pointerDown()
+ .pointerMove(0, 0, {origin: document.getElementById('link_container1')})
+ .pointerUp()
+ .pointerMove(0, 0, {origin: document.getElementById('link_container2')})
+ .pointerDown()
+ .pointerMove(0, 0, {origin: document.getElementById('link2')})
+ .pointerUp()
+ .pointerMove(0, 0, {origin: document.getElementById('done')})
+ .pointerDown()
+ .pointerUp()
+ .send();
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/click/click_event_target_siblings.html b/testing/web-platform/tests/uievents/click/click_event_target_siblings.html
new file mode 100644
index 0000000000..24d64dc9ac
--- /dev/null
+++ b/testing/web-platform/tests/uievents/click/click_event_target_siblings.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Click targets the nearest common ancestor</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <style>
+ div {
+ padding: 10px;
+ margin: 5px;
+ }
+ </style>
+ </head>
+ <body id='body'>
+ <h1>Click targeting when targets of down and up are sibling elements</h1>
+ This test verifies that click event always goes to the first common ancestor of down and up event targets.
+
+ <ul>
+ <li>Press down the primary button on red div and move to blue box and release.</li>
+ <li>Press down the primary button on button b1 and move to button b2 and release.</li>
+ <li>Press down the primary button on input i1 and move to input i2 and release.</li>
+ <li>Press down the primary button on link 1 and move to link 2 and release.</li>
+ <li>Click done.</li>
+ </ul>
+
+ <div id="div_container" style="background: green">
+ <div id="red_div" style="background: red"></div>
+ <div id="blue_div" style="background: blue"></div>
+ </div>
+
+ <div id="button_container" style="background: green">
+ <button id="button1">b1</button>
+ <button id="button2">b2</button>
+ </div>
+
+ <div id="input_container" style="background: green">
+ <input id="input1" value="i1">
+ <input id="input2" value="i2">
+ </div>
+
+ <div id="link_container" style="background: green">
+ <a id="link1" href="#">link1</a>
+ <br/>
+ <a id="link2" href="#">link2</a>
+ </div>
+
+ <button id="done">Done</button>
+ <script>
+ var test_click_target = async_test("Click targets the nearest common ancestor");
+ var actions_promise;
+
+ // Prevent drag to avoid interfering with the click.
+ document.addEventListener('dragstart', (e) => e.preventDefault());
+
+ var events = [];
+ var nodes = ['div_container', 'red_div', 'blue_div', 'button_container', 'button1', 'button2', 'input_container', 'input1', 'input2', 'link_container', 'link1', 'link2', 'body'];
+
+ for (var i = 0; i < nodes.length; i++) {
+ ['mousedown', 'mouseup', 'click'].forEach((eventName) => {
+ document.getElementById(nodes[i]).addEventListener(eventName, (e) => {
+ if (e.eventPhase == Event.AT_TARGET)
+ events.push(e.type + '@' + e.target.id);
+ });
+ });
+ }
+ document.getElementById('done').addEventListener('click', () => {
+ test_click_target.step(() => {
+ assert_equals (events.join(','),
+ "mousedown@red_div,mouseup@blue_div,click@div_container,mousedown@button1,mouseup@button2,click@button_container,mousedown@link1,mouseup@link2,click@link_container",
+ "Click should be sent to the nearest common ancestor");
+ });
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ test_click_target.done();
+ });
+ });
+
+ // Inject mouse events.
+ var actions = new test_driver.Actions();
+ actions_promise = actions.pointerMove(0, 0, {origin: document.getElementById('red_div')})
+ .pointerDown()
+ .pointerMove(0, 0, {origin: document.getElementById('blue_div')})
+ .pointerUp()
+ .pointerMove(0, 0, {origin: document.getElementById('button1')})
+ .pointerDown()
+ .pointerMove(0, 0, {origin: document.getElementById('button2')})
+ .pointerUp()
+ .pointerMove(0, 0, {origin: document.getElementById('link1')})
+ .pointerDown()
+ .pointerMove(0, 0, {origin: document.getElementById('link2')})
+ .pointerUp()
+ .pointerMove(0, 0, {origin: document.getElementById('done')})
+ .pointerDown()
+ .pointerUp()
+ .send();
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/click/click_events_on_input.html b/testing/web-platform/tests/uievents/click/click_events_on_input.html
new file mode 100644
index 0000000000..2f380eb451
--- /dev/null
+++ b/testing/web-platform/tests/uievents/click/click_events_on_input.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Clicking with primary vs non-primary buttons</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ </head>
+ <body>
+ <h1>Clicking on input type=text element when placeholder changes</h1>
+ <input id="target" onfocus="this.placeholder = ++focusCount;" placeholder="initial">
+ <input id="other">
+ <script>
+ var focusCount = 0;
+ var target = document.querySelector('#target');
+ document.addEventListener('contextmenu', event => { event.preventDefault(); });
+
+ var test_click = async_test("Test click and auxclick on input element");
+
+ // The test is on purpose rather vague, since auxclick handling on
+ // touchscreens isn't well defined.
+ // But at least there should be 'click'
+ var didGetClick = false;
+ async function testClick(type, mouseButton) {
+ return new Promise((resolve) => {
+ target.addEventListener(type, event => {
+ event.preventDefault();
+ didGetClick = didGetClick || event.type == "click";
+ test_click.step(() => {
+ assert_equals(event.type, type, 'Should have got an event.');
+ });
+ }, {once: true});
+
+ // Inject mouse click events.
+ var actions = new test_driver.Actions();
+ document.getElementById("other").focus();
+ actions.pointerMove(0, 0, {origin: target})
+ .pointerDown({button: mouseButton})
+ .pointerUp({button: mouseButton})
+ .send()
+ .then(resolve);
+ });
+ }
+
+ async function testClicks() {
+ var buttonType = test_driver.Actions.prototype.ButtonType;
+ await testClick("click", buttonType.LEFT);
+ await testClick("auxclick", buttonType.MIDDLE);
+ await testClick("auxclick", buttonType.RIGHT);
+ test_click.step(() => {
+ assert_true(didGetClick, 'Should have got at least "click".');
+ });
+ test_click.done();
+ }
+
+ testClicks();
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/click/contextmenu_event.html b/testing/web-platform/tests/uievents/click/contextmenu_event.html
new file mode 100644
index 0000000000..7a33d0aa38
--- /dev/null
+++ b/testing/web-platform/tests/uievents/click/contextmenu_event.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Contextmenu event</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+</head>
+<body>
+ <h1>Test contextmenu event</h1>
+ <p>Tests that right-clicking fires a contextmenu event.</p>
+ <ol id="instructions">
+ <li>Right-click here.
+ </ol>
+ <script>
+ let event_log = [];
+
+ function cancel_and_log_event(ename) {
+ return new Promise(resolve => {
+ document.body.addEventListener(ename, e => {
+ e.preventDefault();
+ event_log.push(e.type);
+ resolve(e);
+ }, {once: true});
+ });
+ }
+
+ promise_test(async () => {
+ const event_promises = ["mousedown", "mouseup", "contextmenu"]
+ .map(ename => cancel_and_log_event(ename));
+
+ let target = document.getElementById("instructions");
+ let actions = new test_driver.Actions();
+ actions.pointerMove(0, 0, {origin: target})
+ .pointerDown({button: actions.ButtonType.RIGHT})
+ .pointerUp({button: actions.ButtonType.RIGHT})
+ .send();
+
+ await Promise.all(event_promises);
+
+ assert_equals(event_log.length, 3, "Three events are received");
+ assert_true(event_log.includes("contextmenu"), "contextmenu event is received");
+ assert_true(event_log.includes("mouseup"), "mouseup event is received");
+ assert_equals(event_log[0], "mousedown", "mousedown event is the first event received");
+ }, "Test contextmenu dispatched after mousedown");
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/click/dblclick_event_mouse.html b/testing/web-platform/tests/uievents/click/dblclick_event_mouse.html
new file mode 100644
index 0000000000..50324f6dfd
--- /dev/null
+++ b/testing/web-platform/tests/uievents/click/dblclick_event_mouse.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>dblclick event for the mouse pointer type</title>
+ <link rel="author" title="Google" href="http://www.google.com/" />
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <style>
+ #target
+ {
+ background-color: green;
+ width: 200px;
+ height: 200px;
+ }
+ </style>
+ </head>
+ <body>
+ <p>Double-click on the green box with the left mouse button.</p>
+ <div id="target"></div>
+ <script>
+ promise_test(async (t) => {
+ const target = document.getElementById("target");
+ const event_watcher = new EventWatcher(t, target, ["click", "dblclick"]);
+ const actions_promise = new test_driver.Actions()
+ .pointerMove(0, 0, {origin: target})
+ .pointerDown()
+ .pointerUp()
+ .pointerDown()
+ .pointerUp()
+ .send();
+ // Make sure the test finishes after all the input actions are completed.
+ t.add_cleanup(() => actions_promise);
+ const event = await event_watcher.wait_for(["click", "click", "dblclick"]);
+ assert_equals(event.type, "dblclick");
+ assert_equals(event.target, target);
+ assert_equals(event.detail, 2);
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/constructors/README.md b/testing/web-platform/tests/uievents/constructors/README.md
new file mode 100644
index 0000000000..097a510395
--- /dev/null
+++ b/testing/web-platform/tests/uievents/constructors/README.md
@@ -0,0 +1,4 @@
+Constructors and States tests
+==============================
+
+These test that each of the defined interfaces can be constructed synthetically, and that all attributes can be set to the appropriate state via the constructors.
diff --git a/testing/web-platform/tests/uievents/constructors/inputevent-constructor.html b/testing/web-platform/tests/uievents/constructors/inputevent-constructor.html
new file mode 100644
index 0000000000..3876abcd43
--- /dev/null
+++ b/testing/web-platform/tests/uievents/constructors/inputevent-constructor.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>InputEvent Constructor Tests</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+ var e = new InputEvent('type');
+ assert_equals(e.data, null, '.data');
+ assert_false(e.isComposing, '.isComposing');
+}, 'InputEvent constructor without InputEventInit.');
+
+test(function() {
+ var e = new InputEvent('type', { data: null, isComposing: true });
+ assert_equals(e.data, null, '.data');
+ assert_true(e.isComposing, '.isComposing');
+}, 'InputEvent construtor with InputEventInit where data is null');
+
+test(function() {
+ assert_equals(new InputEvent('type', { data: ''}).data, '', '.data');
+}, 'InputEvent construtor with InputEventInit where data is empty string');
+
+test(function() {
+ assert_equals(new InputEvent('type', { data: 'data' }).data, 'data', '.data');
+}, 'InputEvent construtor with InputEventInit where data is non empty string');
+</script>
diff --git a/testing/web-platform/tests/uievents/hierarchy/README.md b/testing/web-platform/tests/uievents/hierarchy/README.md
new file mode 100644
index 0000000000..3bf23b4c23
--- /dev/null
+++ b/testing/web-platform/tests/uievents/hierarchy/README.md
@@ -0,0 +1,34 @@
+Verify the Class Hierarchy
+==========================
+
+Make sure the events inherit from the correct interfaces:
+ e.g., UIEvent > MouseEvent
+
+Requires manual and automated tests
+* manually create event and verify hierarchy
+* WebDriver create the event and verify hierarchy
+
+UIEvent
+ * load, unload, abort, error, select, resize, scroll
+ * Note: some event types may be dropped given that they don't appear to be UIEvents by other specs that define them.
+
+FocusEvent
+ * blur, focus, focusin, focusout
+ * blur and focus are handled in HTML5
+ * but they aren't sure if focusin/out are needed: see bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=25877
+
+MouseEvent
+ * click, dblclick, mousedown, mouseenter, mouseleave, mousemove, mouseout, mouseover, mouseup
+
+WheelEvent
+ * wheel
+
+KeyboardEvent
+ * keydown, keyup
+ * need to show interaction with beforeinput and input, which are in the Editing spec
+
+CompositionEvent
+ * compositionstart
+ * compositionupdate
+ * compositionend
+ * need to show interaction with the keyboard events: keydown, keyup
diff --git a/testing/web-platform/tests/uievents/historical.html b/testing/web-platform/tests/uievents/historical.html
new file mode 100644
index 0000000000..5aa76f41ac
--- /dev/null
+++ b/testing/web-platform/tests/uievents/historical.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Historical UI events features</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+ assert_false("initWheelEvent" in WheelEvent.prototype,
+ "Should not be supported on the prototype");
+}, "WheelEvent#initWheelEvent");
+test(function() {
+ assert_false("initWebKitWheelEvent" in WheelEvent.prototype,
+ "Should not be supported on the prototype");
+}, "WheelEvent#initWebKitWheelEvent");
+</script>
diff --git a/testing/web-platform/tests/uievents/idlharness.window.js b/testing/web-platform/tests/uievents/idlharness.window.js
new file mode 100644
index 0000000000..c3919e3558
--- /dev/null
+++ b/testing/web-platform/tests/uievents/idlharness.window.js
@@ -0,0 +1,21 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: timeout=long
+
+'use strict';
+
+idl_test(
+ ['uievents'],
+ ['html', 'dom'],
+ idl_array => {
+ idl_array.add_objects({
+ FocusEvent: ['new FocusEvent("event")'],
+ MouseEvent: ['new MouseEvent("event")'],
+ WheelEvent: ['new WheelEvent("event")'],
+ KeyboardEvent: ['new KeyboardEvent("event")'],
+ CompositionEvent: ['new CompositionEvent("event")'],
+ UIEvent: ['new UIEvent("event")'],
+ InputEvent: ['new InputEvent("event")'],
+ });
+ }
+);
diff --git a/testing/web-platform/tests/uievents/interface/README.md b/testing/web-platform/tests/uievents/interface/README.md
new file mode 100644
index 0000000000..970fdd4df3
--- /dev/null
+++ b/testing/web-platform/tests/uievents/interface/README.md
@@ -0,0 +1,13 @@
+Interface tests
+==============================
+
+These test that the basic UI Events interfaces exist, specifically:
+
+1. Does the interface exist
+2. Are all the members defined on the interface accounted for:
+ * UIEvent
+ * MouseEvent
+ * FocusEvent
+ * KeyboardEvent
+ * WheelEvent
+ * CompositionEvent
diff --git a/testing/web-platform/tests/uievents/interface/click-event-manual.htm b/testing/web-platform/tests/uievents/interface/click-event-manual.htm
new file mode 100644
index 0000000000..88db98d591
--- /dev/null
+++ b/testing/web-platform/tests/uievents/interface/click-event-manual.htm
@@ -0,0 +1,21 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Click event is a MouseEvent</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <style>#clicktarget { width: 100px; height: 100px; background-color: red; }</style>
+ </head>
+ <body>
+ <div id='clicktarget'>Click in this box.</div>
+ <div id="log"></div>
+ <script type="text/javascript">
+var t = async_test('click event generated from user action "click" is a MouseEvent');
+document.querySelector("#clicktarget").addEventListener('click', t.step_func(function (e) {
+ assert_equals(e.constructor, window.MouseEvent);
+ document.querySelector("#clicktarget").style.backgroundColor = "green";
+ t.done();
+}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/interface/click-event.htm b/testing/web-platform/tests/uievents/interface/click-event.htm
new file mode 100644
index 0000000000..b45dc29063
--- /dev/null
+++ b/testing/web-platform/tests/uievents/interface/click-event.htm
@@ -0,0 +1,32 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Click event is a PointerEvent</title>
+ <link rel="help" href="https://github.com/w3c/pointerevents/pull/317">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <div id='clicktarget'></div>
+ <div id="log"></div>
+ <script type="text/javascript">
+ var clicktarget = document.querySelector("#clicktarget");
+ var t = async_test("synthetic click event is a PointerEvent");
+ clicktarget.addEventListener('click', t.step_func(function (e) {
+ assert_equals(e.constructor, window.PointerEvent, "Click is a PointerEvent");
+ assert_true(e instanceof window.PointerEvent, "Click is an instance of PointerEvent");
+ // Since this click is not generated by a pointing device, pointerId must have
+ // the reserved value -1, and pointerType must have the default empty string
+ assert_equals(e.pointerId, -1, "Click's pointerId has the default value of -1");
+ assert_equals(e.pointerType, "", "Click's pointerType has the default value of empty string");
+ assert_equals(e.screenX, 0, "Click's screenX coordinate should not be set.");
+ assert_equals(e.screenY, 0, "Click's screenY coordinate should not be set.");
+ assert_equals(e.clientX, 0, "Click's clientX coordinate should not be set.");
+ assert_equals(e.clientY, 0, "Click's clientY coordinate should not be set.");
+ assert_equals(e.detail, 0, "element.click click event should not populate click count");
+ t.done();
+ }));
+ document.querySelector('#clicktarget').click();
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/interface/dblclick-event-manual.htm b/testing/web-platform/tests/uievents/interface/dblclick-event-manual.htm
new file mode 100644
index 0000000000..7ea0bdbf13
--- /dev/null
+++ b/testing/web-platform/tests/uievents/interface/dblclick-event-manual.htm
@@ -0,0 +1,21 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Double click (dblclick) event is a MouseEvent</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <style>#clicktarget { width: 100px; height: 100px; background-color: red; }</style>
+ </head>
+ <body>
+ <div id='clicktarget'>Double Click in this box.</div>
+ <div id="log"></div>
+ <script type="text/javascript">
+var t = async_test('click event generated from user action "click" is a MouseEvent');
+document.querySelector("#clicktarget").addEventListener('dblclick', t.step_func(function (e) {
+ assert_equals(e.constructor, window.MouseEvent);
+ document.querySelector("#clicktarget").style.backgroundColor = "green";
+ t.done();
+}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/interface/keyboard-accesskey-click-event.html b/testing/web-platform/tests/uievents/interface/keyboard-accesskey-click-event.html
new file mode 100644
index 0000000000..f90101e31e
--- /dev/null
+++ b/testing/web-platform/tests/uievents/interface/keyboard-accesskey-click-event.html
@@ -0,0 +1,56 @@
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/accesskey.js"></script>
+
+<p>Tests that a keyboard access key to press a button will fire only the click event</p>
+<button id="button" accesskey="g">Click Me with Shift+Alt+g or on Mac with Control+Option+g</button>
+<input id="inputbutton" type="button" accesskey="b" value="Click me with Shift+Alt+b or on Mac with Control+Option+b">
+<label id="label" accesskey="l">Click Me with Shift+Alt+l or on Mac with Control+Option+l</label>
+
+<script>
+let button = document.getElementById("button");
+let inputbutton = document.getElementById("inputbutton");
+let radiobutton = document.getElementById("radiobutton");
+let label = document.getElementById("label");
+let elementList = [button, inputbutton, label];
+let eventLog = [];
+const eventList = ["pointerdown", "pointerup", "mousedown", "mouseup", "click"];
+elementList.forEach((el)=>{eventList.forEach((ev)=>el.addEventListener(ev, (e)=>{
+ eventLog.push(`${ev}_${el.id}`);
+ if(ev === "click" && currentTest){
+ currentTest.step(()=>{
+ if(e instanceof PointerEvent){
+ // We want the test to run on all browsers even if click is not a PointerEvent.
+ assert_equals(e.pointerId, 0, "Click's pointerId has default value");
+ assert_equals(e.pointerType, "", "Click's pointerType has default value");
+ }
+ assert_equals(e.screenX, 0, "Click's screenX has default value");
+ assert_equals(e.screenY, 0, "Click's screenY has default value");
+ assert_equals(e.clientX, 0, "Click's clientX has default value");
+ assert_equals(e.clientY, 0, "Click's clientY has default value");
+ assert_equals(e.pageX, 0, "Click's pageX has default value");
+ assert_equals(e.pageY, 0, "Click's pageY has default value");
+ // https://github.com/w3c/csswg-drafts/issues/1070
+ assert_equals(e.offsetX, 0, "Click's offsetX should have default value");
+ assert_equals(e.offsetY, 0, "Click's offsetY should have default value");
+ });
+ }
+}));});
+let currentTest;
+let testElements = [button, inputbutton, label];
+let accesskeyMap = new Map([[button, "g"], [inputbutton, "b"], [label, "l"]]);
+testElements.forEach((el)=>promise_test((test)=> new Promise(async (resolve,reject)=>{
+ currentTest = test;
+ eventLog = [];
+ var eventWatcher = new EventWatcher(test, el, ['click']);
+ let waitForClick = eventWatcher.wait_for('click');
+ await pressAccessKey(accesskeyMap.get(el));
+ await waitForClick;
+
+ assert_array_equals(eventLog, [`click_${el.id}`], "The Keyboard generated click only sends the click event.");
+ resolve();
+}), `Test that the Keyboard generated click does not fire pointer or mouse events for ${el.id}`));
+</script>
diff --git a/testing/web-platform/tests/uievents/interface/keyboard-click-event.html b/testing/web-platform/tests/uievents/interface/keyboard-click-event.html
new file mode 100644
index 0000000000..2b5e06d9c1
--- /dev/null
+++ b/testing/web-platform/tests/uievents/interface/keyboard-click-event.html
@@ -0,0 +1,50 @@
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<p>Tests that a button pressed by using Space or Enter will fire only the click event</p>
+<button id="button">Click Me by pressing Enter or Space</button>
+<input id="inputbutton" type="button" value="Click me by pressing Enter or Space">
+
+<script>
+let button = document.getElementById("button");
+let inputbutton = document.getElementById("inputbutton");
+let radiobutton = document.getElementById("radiobutton");
+let elementList = [button, inputbutton];
+let eventLog = [];
+const enterKey = '\uE006';
+const spaceKey = ' ';
+let keys = [spaceKey, enterKey];
+const eventList = ["pointerdown", "pointerup", "mousedown", "mouseup", "click"];
+elementList.forEach((el)=>{eventList.forEach((ev)=>el.addEventListener(ev, (e)=>{
+ eventLog.push(`${ev}_${el.id}`);
+ if(ev === "click" && currentTest){
+ currentTest.step(()=>{
+ if(e instanceof PointerEvent){
+ // We want the test to run on all browsers even if click is not a PointerEvent.
+ assert_equals(e.pointerId, -1, "Click's pointerId has reserved value");
+ assert_equals(e.pointerType, "", "Click's pointerType has default value");
+ }
+ });
+ }
+}));});
+let currentTest;
+let testElements = [button, inputbutton];
+let keyNameMap = new Map([[spaceKey, "space"], [enterKey, "enter"]]);
+keys.forEach((key)=>testElements.forEach((el)=>promise_test((test)=> new Promise(async (resolve,reject)=>{
+ currentTest = test;
+ eventLog = [];
+ var eventWatcher = new EventWatcher(test, el, ['click']);
+ let waitForClick = eventWatcher.wait_for('click');
+ el.focus();
+ let actions = new test_driver.Actions();
+ await test_driver
+ .send_keys(el, key);
+ await waitForClick;
+
+ assert_array_equals(eventLog, [`click_${el.id}`], "The Keyboard generated click only sends the click event.");
+ resolve();
+}), `Test that the Keyboard generated click does not fire pointer or mouse events for ${el.id} when pressing ${keyNameMap.get(key)} key`)));
+</script>
diff --git a/testing/web-platform/tests/uievents/keyboard/README.md b/testing/web-platform/tests/uievents/keyboard/README.md
new file mode 100644
index 0000000000..38c454dd7c
--- /dev/null
+++ b/testing/web-platform/tests/uievents/keyboard/README.md
@@ -0,0 +1,3 @@
+# Keyboard event tests
+
+These tests focus on testing the |key|, |code| and other attributes of KeyboardEvents.
diff --git a/testing/web-platform/tests/uievents/keyboard/key-101en-us-manual.html b/testing/web-platform/tests/uievents/keyboard/key-101en-us-manual.html
new file mode 100644
index 0000000000..3228c65a83
--- /dev/null
+++ b/testing/web-platform/tests/uievents/keyboard/key-101en-us-manual.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+<title>Keyboard Event Manual Test</title>
+<meta http-equiv="content-type" content="text/html;charset=utf-8" />
+<script type="text/javascript" src="key.js" ></script>
+<link rel="stylesheet" type="text/css" href="key.css" />
+
+</head>
+
+<body>
+
+<script language="javascript">
+var KeyTable101 = [
+ // Code Row Type Width KeyCap Key Shift
+ ["Backquote", 0, 0, 0, "`", "`", "~"],
+ ["Digit1", 0, 0, 0, "1", "1", "!"],
+ ["Digit2", 0, 0, 0, "2", "2", "@"],
+ ["Digit3", 0, 0, 0, "3", "3", "#"],
+ ["Digit4", 0, 0, 0, "4", "4", "$"],
+ ["Digit5", 0, 0, 0, "5", "5", "%"],
+ ["Digit6", 0, 0, 0, "6", "6", "^"],
+ ["Digit7", 0, 0, 0, "7", "7", "&"],
+ ["Digit8", 0, 0, 0, "8", "8", "*"],
+ ["Digit9", 0, 0, 0, "9", "9", "("],
+ ["Digit0", 0, 0, 0, "0", "0", ")"],
+ ["Minus", 0, 0, 0, "-", "-", "_"],
+ ["Equal", 0, 0, 0, "=", "=", "+"],
+ ["Backspace", 0, 0, 2, "Backspace", "Backspace", "Backspace"],
+
+ ["Tab", 1, 0, 1, "Tab", "Tab", "Tab"],
+ ["KeyQ", 1, 0, 0, "Q", "q", "Q"],
+ ["KeyW", 1, 0, 0, "W", "w", "W"],
+ ["KeyE", 1, 0, 0, "E", "e", "E"],
+ ["KeyR", 1, 0, 0, "R", "r", "R"],
+ ["KeyT", 1, 0, 0, "T", "t", "T"],
+ ["KeyY", 1, 0, 0, "Y", "y", "Y"],
+ ["KeyU", 1, 0, 0, "U", "u", "U"],
+ ["KeyI", 1, 0, 0, "I", "i", "I"],
+ ["KeyO", 1, 0, 0, "O", "o", "O"],
+ ["KeyP", 1, 0, 0, "P", "p", "P"],
+ ["BracketLeft", 1, 0, 0, "[", "[", "{"],
+ ["BracketRight", 1, 0, 0, "]", "]", "}"],
+ ["Backslash", 1, 0, 1, "\\", "\\", "|"],
+
+ ["CapsLock", 2, 1, 2, "CapsLock", "CapsLock", "CapsLock"],
+ ["KeyA", 2, 0, 0, "A", "a", "A"],
+ ["KeyS", 2, 0, 0, "S", "s", "S"],
+ ["KeyD", 2, 0, 0, "D", "d", "D"],
+ ["KeyF", 2, 0, 0, "F", "f", "F"],
+ ["KeyG", 2, 0, 0, "G", "g", "G"],
+ ["KeyH", 2, 0, 0, "H", "h", "H"],
+ ["KeyJ", 2, 0, 0, "J", "j", "J"],
+ ["KeyK", 2, 0, 0, "K", "k", "K"],
+ ["KeyL", 2, 0, 0, "L", "l", "L"],
+ ["Semicolon", 2, 0, 0, ";", ";", ":"],
+ ["Quote", 2, 0, 0, "'", "'", "\""],
+ ["Enter", 2, 0, 3, "Enter", "Enter", "Enter"],
+
+ ["ShiftLeft", 3, 3, 3, "Shift", "Shift", "Shift"],
+ ["KeyZ", 3, 0, 0, "Z", "z", "Z"],
+ ["KeyX", 3, 0, 0, "X", "x", "X"],
+ ["KeyC", 3, 0, 0, "C", "c", "C"],
+ ["KeyV", 3, 0, 0, "V", "v", "V"],
+ ["KeyB", 3, 0, 0, "B", "b", "B"],
+ ["KeyN", 3, 0, 0, "N", "n", "N"],
+ ["KeyM", 3, 0, 0, "M", "m", "M"],
+ ["Comma", 3, 0, 0, ",", ",", "<"],
+ ["Period", 3, 0, 0, ".", ".", ">"],
+ ["Slash", 3, 0, 0, "/", "/", "?"],
+ ["ShiftRight", 3, 3, 4, "Shift", "Shift", "Shift"],
+
+ ["ControlLeft", 4, 3, 1, "Control", "Control", "Control"],
+ ["MetaLeft", 4, 3, 1, "Meta", "Meta", "Meta"],
+ ["AltLeft", 4, 3, 1, "Alt", "Alt", "Alt"],
+ ["Space", 4, 0, 5, "Space", " ", " "],
+ ["AltRight", 4, 3, 1, "Alt", "Alt", "Alt"],
+ ["MetaRight", 4, 3, 1, "Meta", "Meta", "Meta"],
+ ["ContextMenu", 4, 0, 1, "Menu", "", ""],
+ ["ControlRight", 4, 3, 1, "Control", "Control", "Control"],
+
+ ["END", 0, 2, 0, "", "", ""],
+];
+
+init("101en-us", KeyTable101);
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/keyboard/key-102fr-fr-manual.html b/testing/web-platform/tests/uievents/keyboard/key-102fr-fr-manual.html
new file mode 100644
index 0000000000..c5b51c47bd
--- /dev/null
+++ b/testing/web-platform/tests/uievents/keyboard/key-102fr-fr-manual.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+<title>Keyboard Event Manual Test</title>
+<meta http-equiv="content-type" content="text/html;charset=utf-8" />
+<script type="text/javascript" src="key.js" ></script>
+<link rel="stylesheet" type="text/css" href="key.css" />
+
+</head>
+
+<body>
+
+<script language="javascript">
+var KeyTable102 = [
+ // Code Row Type Width KeyCap Key Shift
+ ["Backquote", 0, 0, 0, "²", "²", ""],
+ ["Digit1", 0, 0, 0, "&", "&", "1"],
+ ["Digit2", 0, 0, 0, "é", "é", "2"],
+ ["Digit3", 0, 0, 0, "\"", "\"", "3"],
+ ["Digit4", 0, 0, 0, "'", "'", "4"],
+ ["Digit5", 0, 0, 0, "(", "(", "5"],
+ ["Digit6", 0, 0, 0, "-", "-", "6"],
+ ["Digit7", 0, 0, 0, "è", "è", "7"],
+ ["Digit8", 0, 0, 0, "_", "_", "8"],
+ ["Digit9", 0, 0, 0, "ç", "ç", "9"],
+ ["Digit0", 0, 0, 0, "à", "à", "0"],
+ ["Minus", 0, 0, 0, ")", ")", "°"],
+ ["Equal", 0, 0, 0, "=", "=", "+"],
+ ["Backspace", 0, 0, 2, "Backspace", "Backspace", "Backspace"],
+
+ ["Tab", 1, 0, 1, "Tab", "Tab", "Tab"],
+ ["KeyQ", 1, 0, 0, "A", "a", "A"],
+ ["KeyW", 1, 0, 0, "Z", "z", "Z"],
+ ["KeyE", 1, 0, 0, "E", "e", "E"],
+ ["KeyR", 1, 0, 0, "R", "r", "R"],
+ ["KeyT", 1, 0, 0, "T", "t", "T"],
+ ["KeyY", 1, 0, 0, "Y", "y", "Y"],
+ ["KeyU", 1, 0, 0, "U", "u", "U"],
+ ["KeyI", 1, 0, 0, "I", "i", "I"],
+ ["KeyO", 1, 0, 0, "O", "o", "O"],
+ ["KeyP", 1, 0, 0, "P", "p", "P"],
+ ["BracketLeft", 1, 0, 0, "^", "^", "¨"],
+ ["BracketRight", 1, 0, 0, "$", "$", "£"],
+ ["Enter", 1, 0, 1, "Enter", "Enter", "Enter"],
+
+ ["CapsLock", 2, 1, 2, "CapsLock", "CapsLock", "CapsLock"],
+ ["KeyA", 2, 0, 0, "Q", "q", "Q"],
+ ["KeyS", 2, 0, 0, "S", "s", "S"],
+ ["KeyD", 2, 0, 0, "D", "d", "D"],
+ ["KeyF", 2, 0, 0, "F", "f", "F"],
+ ["KeyG", 2, 0, 0, "G", "g", "G"],
+ ["KeyH", 2, 0, 0, "H", "h", "H"],
+ ["KeyJ", 2, 0, 0, "J", "j", "J"],
+ ["KeyK", 2, 0, 0, "K", "k", "K"],
+ ["KeyL", 2, 0, 0, "L", "l", "L"],
+ ["Semicolon", 2, 0, 0, "M", "m", "M"],
+ ["Quote", 2, 0, 0, "ù", "ù", "%"],
+ ["IntlHash", 2, 0, 0, "*", "*", "µ"],
+ ["Enter", 2, 1, 0, "Enter", "Enter", "Enter"],
+
+ ["ShiftLeft", 3, 3, 1, "Shift", "Shift", "Shift"],
+ ["IntlBackslash",3, 0, 0, "<", "<", ">"],
+ ["KeyZ", 3, 0, 0, "W", "w", "W"],
+ ["KeyX", 3, 0, 0, "X", "x", "X"],
+ ["KeyC", 3, 0, 0, "C", "c", "C"],
+ ["KeyV", 3, 0, 0, "V", "v", "V"],
+ ["KeyB", 3, 0, 0, "B", "b", "B"],
+ ["KeyN", 3, 0, 0, "N", "n", "N"],
+ ["KeyM", 3, 0, 0, ",", ",", "?"],
+ ["Comma", 3, 0, 0, ";", ";", "."],
+ ["Period", 3, 0, 0, ":", ":", "/"],
+ ["Slash", 3, 0, 0, "!", "!", "§"],
+ ["ShiftRight", 3, 3, 4, "Shift", "Shift", "Shift"],
+
+ ["ControlLeft", 4, 3, 1, "Control", "Control", "Control"],
+ ["MetaLeft", 4, 3, 1, "Meta", "Meta", "Meta"],
+ ["AltLeft", 4, 3, 1, "Alt", "Alt", "Alt"],
+ ["Space", 4, 0, 5, "Space", " ", " "],
+ ["AltRight", 4, 3, 1, "Alt", "Alt", "Alt"],
+ ["MetaRight", 4, 3, 1, "Meta", "Meta", "Meta"],
+ ["ContextMenu", 4, 0, 1, "Menu", "", ""],
+ ["ControlRight", 4, 3, 1, "Control", "Control", "Control"],
+
+ ["END", 0, 2, 0, "", "", ""],
+];
+
+init("102fr-fr", KeyTable102);
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/keyboard/key.css b/testing/web-platform/tests/uievents/keyboard/key.css
new file mode 100644
index 0000000000..b2add2a754
--- /dev/null
+++ b/testing/web-platform/tests/uievents/keyboard/key.css
@@ -0,0 +1,118 @@
+.keyboard {
+ display: table;
+ border-collapse: separate;
+ border-spacing: 2px;
+ width: 800px;
+ border: 2px solid black;
+ border-radius: 10px;
+ padding: 5px;
+}
+
+.key-row {
+ display: table;
+ margin: 0;
+ padding: 0;
+}
+
+.key {
+ display: table-cell;
+ border: 2px solid black;
+ border-radius: 8px;
+ width: 50px;
+ height: 40px;
+ vertical-align: middle;
+ text-align: center;
+ margin: 0;
+ padding: 0;
+}
+
+.wide1 {
+ width: 70px;
+}
+
+.wide2 {
+ width: 90px;
+}
+
+.wide3 {
+ width: 110px;
+}
+
+.wide4 {
+ width: 130px;
+}
+
+.wide5 {
+ width: 300px;
+}
+
+.nextKey {
+ background-color: yellow;
+}
+
+.goodKey {
+ background-color: #80ff08;
+}
+
+.badKey {
+ background-color: #ff8080;
+}
+
+.activeModifierKey {
+ background-color: #a0a0ff;
+}
+
+.skippedKey {
+ background-color: #e0e0e0;
+}
+
+#options {
+ display: none;
+ margin: 20px;
+}
+
+#optionstoggle, #helptoggle {
+ font-size: 10pt;
+}
+
+.opttable {
+ border: 1px solid black;
+}
+
+.optcell {
+ vertical-align: top;
+ padding: 0 10px;
+}
+
+.opttitle {
+ font-weight: bold;
+}
+
+.error {
+ border: 1px solid red;
+ margin: 5px;
+ padding: 5px;
+}
+
+.error1 {
+ font-size: 12pt;
+ margin: 0 0 0 10px;
+ padding: 0;
+}
+
+.error2 {
+ font-size: 10pt;
+ margin: 0 0 0 20px;
+ padding: 0;
+}
+
+.help {
+ font-size: 11pt;
+ margin: 0 0 5px 20px;
+ padding: 0;
+}
+
+body {
+ margin: 10px;
+ padding: 0 20px;
+}
diff --git a/testing/web-platform/tests/uievents/keyboard/key.js b/testing/web-platform/tests/uievents/keyboard/key.js
new file mode 100644
index 0000000000..175258bd88
--- /dev/null
+++ b/testing/web-platform/tests/uievents/keyboard/key.js
@@ -0,0 +1,671 @@
+var _testing = false;
+
+// The index into _keyTable of the key currently being tested.
+var _currKey = 0;
+
+var _keysTotal = 0;
+var _keysGood = 0;
+var _keysBad = 0;
+var _keysSkipped = 0;
+
+var _modifierMode = "None";
+
+var _keydownCapture = [];
+var _keyupCapture = [];
+
+var CAPTURE_KEYCODE = 0;
+var CAPTURE_CODE = 1;
+var CAPTURE_KEY = 2;
+var CAPTURE_SHIFTKEY = 3;
+var CAPTURE_CONTROLKEY = 4;
+var CAPTURE_ALTKEY = 5;
+var CAPTURE_METAKEY = 6;
+
+// An array of KeyInfo for each key to be tested.
+var _keyTable = [];
+
+// KeyInfo fields.
+var KEYINFO_CODE = 0; // |code| for this key
+var KEYINFO_ROW = 1; // Keyboard row
+var KEYINFO_TYPE = 2; // Key type (see below)
+var KEYINFO_WIDTH = 3; // Width of key: 0=normal
+var KEYINFO_KEYCAP = 4; // Keycap string to display
+var KEYINFO_KEY = 5; // Unmodified key value
+var KEYINFO_KEY_SHIFT = 6; // Shifted key value
+
+var KEYTYPE_NORMAL = 0;
+var KEYTYPE_DISABLED = 1; // Key cannot be tested: e.g., CapsLock
+var KEYTYPE_END = 2; // Used to mark end of KeyTable
+var KEYTYPE_MODIFIER = 3; // Modifer key
+
+function clearChildren(e) {
+ while (e.firstChild !== null) {
+ e.removeChild(e.firstChild);
+ }
+}
+
+function setText(e, text) {
+ clearChildren(e);
+ e.appendChild(document.createTextNode(text));
+}
+
+function setUserAgent() {
+ var userAgent = navigator.userAgent;
+ uaDiv = document.getElementById("useragent");
+ setText(uaDiv, userAgent);
+}
+
+function addEventListener(obj, etype, handler) {
+ if (obj.addEventListener) {
+ obj.addEventListener(etype, handler, false);
+ } else if (obj.attachEvent) {
+ obj.attachEvent("on"+etype, handler);
+ } else {
+ obj["on"+etype] = handler;
+ }
+}
+
+function addClass(obj, className) {
+ obj.classList.add(className);
+}
+
+function removeClass(obj, className) {
+ obj.classList.remove(className);
+}
+
+function addInnerText(obj, text) {
+ obj.appendChild(document.createTextNode(text));
+}
+
+function calcLocation(loc) {
+ if (loc == 1) return "LEFT";
+ if (loc == 2) return "RIGHT";
+ if (loc == 3) return "NUMPAD";
+ return loc;
+}
+
+function isModifierKey(e) {
+ // Shift, Control, Alt
+ if (e.keyCode >= 16 && e.keyCode <= 18) {
+ return true;
+ }
+ // Windows, Command or Meta key.
+ if (e.keyCode == 224 // Right/Left: Gecko
+ || e.keyCode == 91 // Left: WebKit/Blink
+ || e.keyCode == 93 // Right: WebKit/Blink
+ ) {
+ return true;
+ }
+ return false;
+}
+
+function init(title, keytable) {
+ _keyTable = keytable;
+
+ createBody(title, keytable);
+
+ setUserAgent();
+
+ var input = document.getElementById("input");
+ input.disabled = true;
+ addEventListener(input, "keydown", onKeyDown);
+ addEventListener(input, "keyup", onKeyUp);
+ //addEventListener(input, "beforeInput", onBeforeInput);
+ //addEventListener(input, "input", onInput);
+}
+
+function onKeyDown(e) {
+ // Ignore modifier keys when checking modifier combinations.
+ if (_modifierMode != "None" && isModifierKey(e)) {
+ return;
+ }
+
+ _keydownInfo = [e.keyCode, e.code, e.key, e.shiftKey, e.ctrlKey, e.altKey, e.metaKey];
+ if (e.keyCode == 9 || e.code == "Tab") {
+ e.preventDefault();
+ }
+}
+
+function onKeyUp(e) {
+ // Ignore modifier keys when checking modifier combinations.
+ if (_modifierMode != "None" && isModifierKey(e)) {
+ return;
+ }
+
+ _keyupInfo = [e.keyCode, e.code, e.key, e.shiftKey, e.ctrlKey, e.altKey, e.metaKey];
+
+ if (_testing) {
+ verifyKey();
+ nextKey();
+ }
+}
+
+function onBeforeInput(e) {
+}
+
+function onInput(e) {
+}
+
+function addError(elem, str) {
+ var p = document.createElement('p');
+ p.classList.add("error2");
+ p.textContent = str;
+ elem.appendChild(p);
+}
+
+function addErrorIncorrect(elem, eventName, attrName, keyEventInfo, attr, expected) {
+ addError(elem, "Incorrect " + eventName
+ + " |" + attrName + "| = " + keyEventInfo[attr]
+ + " - Expected " + expected);
+}
+
+function verifyKeyEventFields(eventName, keyEventInfo, code, key, error) {
+ var verifyCode = document.getElementById("opt_attr_code").checked;
+ var verifyKey = document.getElementById("opt_attr_key").checked;
+ var verifyModifiers = document.getElementById("opt_attr_modifiers").checked;
+ var good = true;
+
+ if (!verifyCode && !verifyKey && !verifyModifiers) {
+ good = false;
+ addError(error, "Invalid test: At least one attribute must be selected for testing.");
+ }
+ if (verifyCode && keyEventInfo[CAPTURE_CODE] != code) {
+ good = false;
+ addErrorIncorrect(error, eventName, "code", keyEventInfo, CAPTURE_CODE, code);
+ }
+ if (verifyKey && keyEventInfo[CAPTURE_KEY] != key) {
+ good = false;
+ addErrorIncorrect(error, eventName, "key", keyEventInfo, CAPTURE_KEY, key);
+ }
+ if (verifyModifiers) {
+ if (keyEventInfo[CAPTURE_SHIFTKEY] != (_modifierMode == "Shift")) {
+ good = false;
+ addErrorIncorrect(error, eventName, "shiftKey", keyEventInfo, CAPTURE_SHIFTKEY, false);
+ }
+ if (keyEventInfo[CAPTURE_CONTROLKEY]) {
+ good = false;
+ addErrorIncorrect(error, eventName, "controlKey", keyEventInfo, CAPTURE_CONTROLKEY, false);
+ }
+ if (keyEventInfo[CAPTURE_ALTKEY]) {
+ good = false;
+ addErrorIncorrect(error, eventName, "altKey", keyEventInfo, CAPTURE_ALTKEY, false);
+ }
+ if (keyEventInfo[CAPTURE_METAKEY]) {
+ good = false;
+ addErrorIncorrect(error, eventName, "metaKey", keyEventInfo, CAPTURE_METAKEY, false);
+ }
+ }
+
+ return good;
+}
+
+function verifyKey() {
+ _keysTotal++;
+
+ var keyInfo = _keyTable[_currKey];
+ var code = keyInfo[KEYINFO_CODE];
+ var key = keyInfo[KEYINFO_KEY];
+ var keyShift = keyInfo[KEYINFO_KEY_SHIFT];
+
+ var keyCheck = key;
+ if (_modifierMode == "Shift") {
+ keyCheck = keyShift;
+ }
+
+ var verifyKeydown = document.getElementById("opt_event_keydown").checked;
+ var verifyKeyup = document.getElementById("opt_event_keyup").checked;
+
+ var error = document.createElement('div');
+ error.classList.add("error");
+ var good = true;
+
+ if (verifyKeydown) {
+ good = verifyKeyEventFields("keydown", _keydownInfo, code, keyCheck, error);
+ }
+ if (verifyKeyup) {
+ good = verifyKeyEventFields("keyup", _keyupInfo, code, keyCheck, error);
+ }
+
+ if (!verifyKeydown && !verifyKeyup) {
+ good = false;
+ addError(error, "Invalid test: At least one event must be selected for testing.");
+ }
+
+ // Allow Escape key to skip the current key.
+ var skipped = false;
+ if (_keydownInfo[CAPTURE_KEYCODE] == 27 || _keydownInfo[CAPTURE_CODE] == "Escape") {
+ good = true;
+ skipped = true;
+ }
+
+ if (!good) {
+ var p = document.createElement('p');
+ p.classList.add("error1");
+ p.textContent = "Error : " + code;
+ error.insertBefore(p, error.firstChild);
+ }
+
+ removeNextKeyHilight();
+ if (skipped) {
+ _keysSkipped++;
+ document.getElementById(code).classList.add("skippedKey")
+ } else if (good) {
+ _keysGood++;
+ document.getElementById(code).classList.add("goodKey")
+ } else {
+ _keysBad++;
+ document.getElementById(code).classList.add("badKey")
+ }
+ updateTestSummary(good ? null : error);
+}
+
+function updateTestSummary(error) {
+ document.getElementById("keys-total").textContent = _keysTotal;
+ document.getElementById("keys-good").textContent = _keysGood;
+ document.getElementById("keys-bad").textContent = _keysBad;
+ document.getElementById("keys-skipped").textContent = _keysSkipped;
+
+ if (error) {
+ var errors = document.getElementById("errors");
+ errors.insertBefore(error, errors.firstChild);
+ }
+}
+
+function resetTest() {
+ _keysTotal = 0;
+ _keysGood = 0;
+ _keysBad = 0;
+
+ _currKey = -1;
+ nextKey();
+
+ updateTestSummary();
+
+ // Remove previous test results.
+ clearChildren(document.getElementById("errors"));
+
+ // Remove highlighting from keys.
+ for (var i = 0; i < _keyTable.length; i++) {
+ var code = _keyTable[i][KEYINFO_CODE];
+ var type = _keyTable[i][KEYINFO_TYPE];
+ if (type != KEYTYPE_END) {
+ var key = document.getElementById(code);
+ key.classList.remove("goodKey");
+ key.classList.remove("badKey");
+ key.classList.remove("skippedKey");
+ }
+ }
+}
+
+function startTest() {
+ if (_testing) {
+ // Cancel the currently running test.
+ endTest();
+ return;
+ }
+
+ resetTest();
+ _testing = true;
+ document.getElementById("start").value = "Stop Test"
+
+ var input = document.getElementById("input");
+ input.value = "";
+ input.disabled = false;
+ input.focus();
+
+ // Show test instructions and info.
+ document.getElementById("test-info").style.display = 'block';
+ document.getElementById("instructions").style.display = 'block';
+ document.getElementById("test-done").style.display = 'none';
+}
+
+function endTest() {
+ _testing = false;
+ removeNextKeyHilight();
+ document.getElementById("start").value = "Restart Test"
+ document.getElementById("input").disabled = true;
+ document.getElementById("instructions").style.display = 'none';
+ document.getElementById("test-done").style.display = 'block';
+}
+
+function removeNextKeyHilight() {
+ var curr = document.getElementById(_keyTable[_currKey][KEYINFO_CODE]);
+ if (curr) {
+ removeClass(curr, "nextKey")
+ }
+}
+
+function addNextKeyHilight() {
+ var curr = document.getElementById(_keyTable[_currKey][KEYINFO_CODE]);
+ if (curr) {
+ addClass(curr, "nextKey")
+ }
+}
+
+function nextKey() {
+ var keyInfo;
+ var keepLooking = true;
+ do {
+ _currKey++;
+ keyInfo = _keyTable[_currKey];
+ var type = keyInfo[KEYINFO_TYPE];
+
+ // Skip over disabled keys.
+ keepLooking = (type == KEYTYPE_DISABLED);
+
+ // Skip over modifier keys if we're testing modifier combinations.
+ if (_modifierMode != "None" && type == KEYTYPE_MODIFIER) {
+ keepLooking = true;
+ }
+
+ // Skip over keys in disabled rows.
+ if (type != KEYTYPE_END) {
+ var row = keyInfo[KEYINFO_ROW];
+ var rowEnabled = document.getElementById("opt_row_" + row).checked;
+ keepLooking = keepLooking || !rowEnabled;
+ }
+ } while (keepLooking);
+
+ if (keyInfo[KEYINFO_TYPE] == KEYTYPE_END) {
+ endTest();
+ } else {
+ addNextKeyHilight();
+ }
+}
+
+function toggleOptions() {
+ var link = document.getElementById("optionstoggle");
+ var options = document.getElementById("options");
+ clearChildren(link);
+ if (options.style.display == "block") {
+ options.style.display = "none";
+ addInnerText(link, "Show Options");
+ }
+ else {
+ options.style.display = "block";
+ addInnerText(link, "Hide Options");
+ }
+}
+
+function toggleHelp() {
+ var link = document.getElementById("helptoggle");
+ var help = document.getElementById("help");
+ clearChildren(link);
+ if (help.style.display == "block") {
+ help.style.display = "none";
+ addInnerText(link, "Show Help");
+ }
+ else {
+ help.style.display = "block";
+ addInnerText(link, "Hide Help");
+ }
+}
+
+function createBody(title, keytable) {
+ var body = document.getElementsByTagName("body")[0];
+ var p;
+ var span;
+
+ var h1 = document.createElement('h1');
+ h1.textContent = "Keyboard Event Manual Test - " + title;
+ body.appendChild(h1);
+
+ // Display useragent.
+ p = document.createElement('p');
+ p.textContent = "UserAgent: ";
+ var useragent = document.createElement('span');
+ useragent.id = "useragent";
+ p.appendChild(useragent);
+ body.appendChild(p);
+
+ // Display input textedit.
+ p = document.createElement('p');
+ p.textContent = "Test Input: ";
+ var input1 = document.createElement('input');
+ input1.id = "input";
+ input1.type = "text";
+ input1.size = 80;
+ p.appendChild(input1);
+ p.appendChild(document.createTextNode(" "));
+ var input2 = document.createElement('input');
+ input2.id = "start";
+ input2.type = "button";
+ input2.onclick = function() { startTest(); return false; }
+ input2.value = "Start Test";
+ p.appendChild(input2);
+ p.appendChild(document.createTextNode(" "));
+ var optionsToggle = document.createElement('a');
+ optionsToggle.id = "optionstoggle";
+ optionsToggle.href = "javascript:toggleOptions()";
+ optionsToggle.textContent = "Show Options";
+ p.appendChild(optionsToggle);
+ p.appendChild(document.createTextNode(" "));
+ var helpToggle = document.createElement('a');
+ helpToggle.id = "helptoggle";
+ helpToggle.href = "javascript:toggleHelp()";
+ helpToggle.textContent = "Show Help";
+ p.appendChild(helpToggle);
+ body.appendChild(p);
+
+ createOptions(body);
+
+ createHelp(body);
+
+ createKeyboard(body, keytable);
+
+ // Test info and summary.
+ var test_info = document.createElement('div');
+ test_info.id = "test-info";
+ test_info.style.display = "none";
+
+ var instructions = document.createElement('div');
+ instructions.id = "instructions";
+ p = document.createElement('p');
+ p.textContent = "Press the highlighted key.";
+ instructions.appendChild(p);
+ test_info.appendChild(instructions);
+
+ var test_done = document.createElement('div');
+ test_done.id = "test-done";
+ p = document.createElement('p');
+ p.textContent = "Test complete!";
+ test_done.appendChild(p);
+ test_info.appendChild(test_done);
+
+ var summary = document.createElement('div');
+ summary.id = "summary";
+ p = document.createElement('p');
+ summary.appendChild(document.createTextNode("Keys Tested: "));
+ span = document.createElement('span');
+ span.id = "keys-total";
+ span.textContent = 0;
+ summary.appendChild(span);
+ summary.appendChild(document.createTextNode("; Passed "));
+ span = document.createElement('span');
+ span.id = "keys-good";
+ span.textContent = 0;
+ summary.appendChild(span);
+ summary.appendChild(document.createTextNode("; Failed "));
+ span = document.createElement('span');
+ span.id = "keys-bad";
+ span.textContent = 0;
+ summary.appendChild(span);
+ summary.appendChild(document.createTextNode("; Skipped "));
+ span = document.createElement('span');
+ span.id = "keys-skipped";
+ span.textContent = 0;
+ summary.appendChild(span);
+ test_info.appendChild(summary);
+
+ var errors = document.createElement('div');
+ errors.id = "errors";
+ test_info.appendChild(errors);
+
+ body.appendChild(test_info);
+}
+
+function addOptionTitle(cell, title) {
+ var span = document.createElement('span');
+ span.classList.add("opttitle");
+ span.textContent = title;
+ cell.appendChild(span);
+ cell.appendChild(document.createElement("br"));
+}
+
+function addOptionCheckbox(cell, id, text) {
+ var label = document.createElement("label");
+
+ var input = document.createElement("input");
+ input.type = "checkbox";
+ input.id = id;
+ input.checked = true;
+ label.appendChild(input);
+
+ label.appendChild(document.createTextNode(" " + text));
+ cell.appendChild(label);
+
+ cell.appendChild(document.createElement("br"));
+}
+
+function addOptionRadio(cell, group, text, handler, checked) {
+ var label = document.createElement("label");
+
+ var input = document.createElement("input");
+ input.type = "radio";
+ input.name = group;
+ input.value = text;
+ input.onclick = handler;
+ input.checked = checked;
+ label.appendChild(input);
+
+ label.appendChild(document.createTextNode(" " + text));
+ cell.appendChild(label);
+
+ cell.appendChild(document.createElement("br"));
+}
+
+function handleModifierGroup() {
+ var radio = document.querySelector("input[name=opt_modifier]:checked");
+ var oldMode = _modifierMode;
+ _modifierMode = radio.value;
+
+ if (oldMode == "Shift") {
+ document.getElementById("ShiftLeft").classList.remove("activeModifierKey");
+ document.getElementById("ShiftRight").classList.remove("activeModifierKey");
+ }
+
+ if (_modifierMode == "Shift") {
+ document.getElementById("ShiftLeft").classList.add("activeModifierKey");
+ document.getElementById("ShiftRight").classList.add("activeModifierKey");
+ }
+}
+
+function createOptions(body) {
+ var options = document.createElement('div');
+ options.id = "options";
+ options.style.display = "none";
+
+ var table = document.createElement('table');
+ table.classList.add("opttable");
+ var row = document.createElement('tr');
+ var cell;
+
+ cell = document.createElement('td');
+ cell.classList.add("optcell");
+ addOptionTitle(cell, "Keyboard Rows");
+ addOptionCheckbox(cell, "opt_row_0", "Row E (top)");
+ addOptionCheckbox(cell, "opt_row_1", "Row D");
+ addOptionCheckbox(cell, "opt_row_2", "Row C");
+ addOptionCheckbox(cell, "opt_row_3", "Row B");
+ addOptionCheckbox(cell, "opt_row_4", "Row A (bottom)");
+ row.appendChild(cell);
+
+ cell = document.createElement('td');
+ cell.classList.add("optcell");
+ addOptionTitle(cell, "Events");
+ addOptionCheckbox(cell, "opt_event_keydown", "keydown");
+ addOptionCheckbox(cell, "opt_event_keyup", "keyup");
+ row.appendChild(cell);
+
+ cell = document.createElement('td');
+ cell.classList.add("optcell");
+ addOptionTitle(cell, "Attributes");
+ addOptionCheckbox(cell, "opt_attr_code", "code");
+ addOptionCheckbox(cell, "opt_attr_key", "key");
+ addOptionCheckbox(cell, "opt_attr_modifiers", "modifiers");
+ row.appendChild(cell);
+
+ cell = document.createElement('td');
+ cell.classList.add("optcell");
+ addOptionTitle(cell, "Modifiers");
+ addOptionRadio(cell, "opt_modifier", "None", handleModifierGroup, true);
+ addOptionRadio(cell, "opt_modifier", "Shift", handleModifierGroup, false);
+ row.appendChild(cell);
+
+ table.appendChild(row);
+ options.appendChild(table);
+
+ body.appendChild(options);
+}
+
+function addHelpText(div, text) {
+ var p = document.createElement('p');
+ p.classList.add("help");
+ p.textContent = text;
+ div.appendChild(p);
+}
+
+function createHelp(body) {
+ var help = document.createElement('div');
+ help.id = "help";
+ help.style.display = "none";
+
+ addHelpText(help, "Click on the \"Start Test\" button to begin testing.");
+ addHelpText(help, "Press the hilighted key to test it.");
+ addHelpText(help, "Clicking anywhere outside the \"Test Input\" editbox will pause testing. To resume, click back inside the editbox.");
+ addHelpText(help, "To skip a key while testing, press Escape.");
+ addHelpText(help, "When testing with modifier keys, the modifier must be pressed before the keydown and released after the keyup of the key being tested.");
+
+ body.appendChild(help);
+}
+
+function createKeyboard(body, keytable) {
+ var keyboard = document.createElement('div');
+ keyboard.classList.add("keyboard");
+
+ var currRow = 0;
+ var row = document.createElement('div');
+ row.classList.add("key-row");
+
+ for (var i = 0; i < keytable.length; i++) {
+ var code = keytable[i][KEYINFO_CODE];
+ var rowId = keytable[i][KEYINFO_ROW];
+ var type = keytable[i][KEYINFO_TYPE];
+ var width = keytable[i][KEYINFO_WIDTH];
+ var keyCap = keytable[i][KEYINFO_KEYCAP];
+
+ if (type == KEYTYPE_END) {
+ continue;
+ }
+
+ if (rowId != currRow) {
+ keyboard.appendChild(row);
+ row = document.createElement('div');
+ row.classList.add("key-row");
+ currRow = rowId;
+ }
+
+ var key = document.createElement('div');
+ key.id = code;
+ key.classList.add("key");
+ if (width != 0) {
+ key.classList.add("wide" + width);
+ }
+ key.textContent = keyCap;
+
+ row.appendChild(key);
+ }
+
+ keyboard.appendChild(row);
+ body.appendChild(keyboard);
+}
diff --git a/testing/web-platform/tests/uievents/keyboard/modifier-keys-combinations.html b/testing/web-platform/tests/uievents/keyboard/modifier-keys-combinations.html
new file mode 100644
index 0000000000..1b364ff72c
--- /dev/null
+++ b/testing/web-platform/tests/uievents/keyboard/modifier-keys-combinations.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>UI Events Test: Modifier keys combinations</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://w3c.github.io/uievents/#idl-keyboardevent" />
+<meta name="assert" content="This test checks that modifier keys combinations are properly detected in 'keydown' event.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<div id="target" tabindex="0">Target</div>
+<script>
+ const keys = {
+ "Shift": '\uE008' + 'y',
+ "Control": '\uE009' + 'y',
+ "Alt": '\uE00A' + 'y',
+ "Meta": '\uE03D' + 'y',
+ };
+
+ target.focus();
+ for (const [key, code] of Object.entries(keys)) {
+ promise_test(() => {
+ return new Promise(resolve => {
+ target.addEventListener("keydown", (event) => {
+ if (event.key != key)
+ resolve(event);
+ });
+ test_driver.send_keys(target, code);
+ }).then((event) => {
+ if (event.shiftKey) {
+ // Shift + y will send a "Y" keydown event on Chromium and Firefox, but a "y" one on WebKit.
+ assert_true(event.key == "y" || event.key == "Y");
+ } else {
+ assert_equals(event.key, "y");
+ }
+ assert_equals(event.shiftKey, key === "Shift");
+ assert_equals(event.ctrlKey, key === "Control");
+ assert_equals(event.altKey, key === "Alt");
+ assert_equals(event.metaKey, key === "Meta");
+ });
+ }, `Check sending "${key} + y" key combination`);
+ }
+</script>
diff --git a/testing/web-platform/tests/uievents/keyboard/modifier-keys.html b/testing/web-platform/tests/uievents/keyboard/modifier-keys.html
new file mode 100644
index 0000000000..635e5d3b77
--- /dev/null
+++ b/testing/web-platform/tests/uievents/keyboard/modifier-keys.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>UI Events Test: Modifier keys</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://w3c.github.io/uievents/#idl-keyboardevent" />
+<meta name="assert" content="This test checks that modifier keys are properly detected in 'keydown' event.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<div id="target" tabindex="0">Target</div>
+<script>
+ const keys = {
+ "Shift": '\uE008',
+ "Control": '\uE009',
+ "Alt": '\uE00A',
+ "Meta": '\uE03D',
+ };
+
+ target.focus();
+ for (const [key, code] of Object.entries(keys)) {
+ promise_test(() => {
+ return new Promise(resolve => {
+ target.addEventListener("keydown", resolve);
+ test_driver.send_keys(target, code);
+ }).then((event) => {
+ assert_equals(event.key, key);
+ assert_equals(event.shiftKey, key === "Shift");
+ assert_equals(event.ctrlKey, key === "Control");
+ assert_equals(event.altKey, key === "Alt");
+ assert_equals(event.metaKey, key === "Meta");
+ });
+ }, `Check sending ${key} key`);
+ }
+</script>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/Status.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/Status.html
new file mode 100644
index 0000000000..392f68edc1
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/Status.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html>
+<head>
+ <title>DOM Level 3 Events Test Status</title>
+</head>
+<body>
+
+<h2>DOM Level 3 Events Test Suite Status</h2>
+
+<p>This test suite is part of the
+<a href="http://www.w3.org/2008/webapps/wiki/">Web Application WG's</a>
+Test Repository as described in WebApps'
+<a href="http://www.w3.org/2008/webapps/wiki/Testing">Testing Wiki</a>.
+</p>
+
+<p>The test suite is for the
+<a href="http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html">DOM Level 3 Events</a> specification.
+</p>
+
+<ul>
+ <li>Test suite status: all of the tests in the <code>approved</code> directory are Approved by WebApps' testing group</li>
+ <li>Test Facilitator: Alex Kuang</li>
+</ul>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/ProcessingInstruction.DOMCharacterDataModified.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/ProcessingInstruction.DOMCharacterDataModified.html
new file mode 100644
index 0000000000..2da0a389e2
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/ProcessingInstruction.DOMCharacterDataModified.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> ProcessingInstruction.data and DOMCharacterDataModified event </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<iframe id="helper" style="display: none"></iframe>
+
+<script>
+ var description = "Test Description: " +
+ "DOMCharacterDataModified event fires after ProcessingInstruction.data have been modified, " +
+ "but the node itself has not been inserted or deleted. The proximal event target of this " +
+ "event shall be the ProcessingInstruction node.";
+
+ var t = async_test(description);
+
+ var HELPER = document.getElementById("helper");
+
+ HELPER.onload = t.step_func(function()
+ {
+ assert_true(HELPER.contentWindow.TestResult);
+ t.done();
+ });
+
+ HELPER.src = "./support/ProcessingInstruction.DOMCharacterDataModified.xml";
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/dispatchEvent.click.checkbox.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/dispatchEvent.click.checkbox.html
new file mode 100644
index 0000000000..8cb548f84c
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/dispatchEvent.click.checkbox.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> MouseEvent: Default action and synthetic click event </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display: none">
+ <input type="checkbox" id="target">
+ <button id="button"> Click Here </button>
+</div>
+
+<script>
+ setup({explicit_done:true});
+ var EVENT = "click";
+ var TARGET = document.getElementById("target");
+ var BUTTON = document.getElementById("button");
+ var state;
+
+ var description = "Test Description: " +
+ "MouseEvent: Default action is performed when a synthetic click event is dispatched on a checkbox element";
+
+ BUTTON.addEventListener(EVENT, TestEvent, true);
+ TARGET.addEventListener(EVENT, TestEvent, true);
+
+ window.onload = function()
+ {
+ state = TARGET.checked;
+ BUTTON.click();
+ }
+
+ function TestEvent(evt)
+ {
+ if (BUTTON == evt.target)
+ {
+ var e;
+ test(function()
+ {
+ BUTTON.removeEventListener(EVENT, TestEvent, true);
+
+ e = document.createEvent("MouseEvent");
+ e.initMouseEvent(EVENT, /* type */
+ false, /* bubbles */
+ true, /* cancelable */
+ window, /* view */
+ 1, /* detail */
+ 0, /* screenX */
+ 0, /* screenY */
+ 0, /* clientX */
+ 0, /* clientY */
+ false, /* ctrlKey */
+ false, /* altKey */
+ false, /* shiftKey */
+ false, /* metaKey */
+ 0, /* button */
+ null /* relatedTarget */);
+
+ assert_array_equals([TARGET.checked, e.type, e.bubbles], [state, EVENT, false]);
+
+ }, "Checkbox state is unchanged before the synthetic click event is dispatched");
+
+ TARGET.dispatchEvent(e);
+ }
+ else if (TARGET == evt.target)
+ {
+ test(function()
+ {
+ assert_array_equals([TARGET.checked, evt.type, evt.bubbles], [!state, EVENT, false]);
+
+ }, description);
+
+ done();
+ }
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/domnodeinserted.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/domnodeinserted.html
new file mode 100644
index 0000000000..e5064d8d46
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/domnodeinserted.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>MutationEvent: DOMNodeInserted Event Type</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+
+<div id="target" style="display: none"></div>
+
+<script>
+var EVENT = "DOMNodeInserted";
+var TARGET;
+var NODE;
+
+var t = async_test("Test Description: DOMNodeInserted event fires when a node has been added as a child of another node.");
+
+TARGET = document.getElementById("target");
+
+TARGET.addEventListener(EVENT, t.step_func(function(evt)
+{
+ assert_equals(evt.type, EVENT);
+ t.done();
+}), true);
+
+NODE = document.createElement("INPUT");
+TARGET.appendChild(NODE);
+</script>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/stopImmediatePropagation.effect.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/stopImmediatePropagation.effect.html
new file mode 100644
index 0000000000..a414d60298
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/stopImmediatePropagation.effect.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> Event.stopImmediatePropagation() immediate effect </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<table id="table" border="1" style="display: none">
+ <tbody id="table-body">
+ <tr id="table-row">
+ <td id="table-cell">Shady Grove</td>
+ <td>Aeolian</td>
+ </tr>
+ <tr id="parent">
+ <td id="target">Over the river, Charlie</td>
+ <td>Dorian</td>
+ </tr>
+ </tbody>
+</table>
+
+<script>
+ var EVENT = "foo";
+ var TARGET = document.getElementById("target");
+ var PARENT = document.getElementById("parent");
+ var TBODY = document.getElementById("table-body");
+ var TABLE = document.getElementById("table");
+ var BODY = document.body;
+ var HTML = document.documentElement;
+ var CurrentTargets = [window, document, HTML, BODY, TABLE, TBODY, PARENT, TARGET];
+ var ExpectResult = [window, window, document, document, HTML, HTML, BODY, BODY, TABLE];
+ var ActualResult = [];
+ var ExpectListeners = [0,1,0,1,0,1,0,1,0];
+ var ActualListeners = [];
+
+ var description = "Test Description: " +
+ "stopImmediatePropagation() prevents other event listeners from being triggered and, unlike " +
+ "Event.stopPropagation(), its effect must be immediate. Once it has been called, further calls " +
+ "to this method have no additional effect.";
+
+ test(function()
+ {
+ for (var i=0; i < CurrentTargets.length; i++)
+ {
+ CurrentTargets[i].addEventListener(EVENT, function(e){TestEvent(e, 0)}, true);
+ CurrentTargets[i].addEventListener(EVENT, function(e){TestEvent(e, 1)}, true);
+ }
+
+ var evt = document.createEvent("Event");
+ evt.initEvent(EVENT, true, true);
+ TARGET.dispatchEvent(evt);
+
+ assert_array_equals(ActualResult, ExpectResult, "ActualResult");
+ assert_array_equals(ActualListeners, ExpectListeners, "ActualListeners");
+
+ }, description);
+
+ function TestEvent(evt, i)
+ {
+ ActualResult.push(evt.currentTarget);
+ ActualListeners.push(i);
+ if ((1 == evt.eventPhase) && (TABLE == evt.currentTarget) && (0 == i))
+ {
+ evt.stopImmediatePropagation();
+ }
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/stopPropagation.deferred.effect.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/stopPropagation.deferred.effect.html
new file mode 100644
index 0000000000..93489c63b4
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/stopPropagation.deferred.effect.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> Event.stopPropagation() deferred effect </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<table id="table" border="1" style="display: none">
+ <tbody id="table-body">
+ <tr id="table-row">
+ <td id="table-cell">Shady Grove</td>
+ <td>Aeolian</td>
+ </tr>
+ <tr id="parent">
+ <td id="target">Over the river, Charlie</td>
+ <td>Dorian</td>
+ </tr>
+ </tbody>
+</table>
+
+<script>
+ var EVENT = "foo";
+ var TARGET = document.getElementById("target");
+ var PARENT = document.getElementById("parent");
+ var TBODY = document.getElementById("table-body");
+ var TABLE = document.getElementById("table");
+ var BODY = document.body;
+ var HTML = document.documentElement;
+ var CurrentTargets = [window, document, HTML, BODY, TABLE, TBODY, PARENT, TARGET];
+ var ExpectResult = [window, window, document, document, HTML, HTML, BODY, BODY, TABLE, TABLE];
+ var ActualResult = [];
+ var ExpectListeners = [0,1,0,1,0,1,0,1,0,1];
+ var ActualListeners = [];
+
+ var description = "Test Description: " +
+ "stopPropagation() prevents other event listeners from being triggered but its effect must be " +
+ "deferred until all event listeners attached on the Event.currentTarget have been triggered.";
+
+ test(function()
+ {
+ for (var i=0; i < CurrentTargets.length; i++)
+ {
+ CurrentTargets[i].addEventListener(EVENT, function(e){TestEvent(e, 0)}, true);
+ CurrentTargets[i].addEventListener(EVENT, function(e){TestEvent(e, 1)}, true);
+ }
+
+ var evt = document.createEvent("Event");
+ evt.initEvent(EVENT, true, true);
+ TARGET.dispatchEvent(evt);
+
+ assert_array_equals(ActualResult, ExpectResult, "ActualResult");
+ assert_array_equals(ActualListeners, ExpectListeners, "ActualListeners");
+
+ }, description);
+
+ function TestEvent(evt, i)
+ {
+ ActualResult.push(evt.currentTarget);
+ ActualListeners.push(i);
+ if ((1 == evt.eventPhase) && (TABLE == evt.currentTarget) && (0 == i))
+ {
+ evt.stopPropagation();
+ }
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/support/ProcessingInstruction.DOMCharacterDataModified.xml b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/support/ProcessingInstruction.DOMCharacterDataModified.xml
new file mode 100644
index 0000000000..4c95ae29df
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/approved/support/ProcessingInstruction.DOMCharacterDataModified.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<root>
+ <head xmlns="http://www.w3.org/1999/xhtml">
+ <title> ProcessingInstruction.data and DOMCharacterDataModified event </title>
+ </head>
+ <div id="log" xmlns="http://www.w3.org/1999/xhtml"></div>
+
+ <pi><?foo bar?></pi>
+
+ <script type="text/javascript" xmlns="http://www.w3.org/1999/xhtml">
+ <![CDATA[
+ var EVENT = "DOMCharacterDataModified";
+ var TARGET = document.getElementsByTagName('pi')[0].firstChild;
+ var TestResult = false;
+
+ TARGET.addEventListener(EVENT, TestEvent, false);
+ TARGET.data = "new" + TARGET.data;
+
+ function TestEvent(evt)
+ {
+ if ((EVENT == evt.type) && (TARGET == evt.target) && ("newbar" == evt.newValue))
+ {
+ TestResult = true;
+ }
+ else
+ {
+ TestResult = false;
+ }
+ }
+ ]]>
+ </script>
+</root> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/CompositionEvent.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/CompositionEvent.html
new file mode 100644
index 0000000000..0f8242b07d
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/CompositionEvent.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> Composition Event Types: compositionstart, compositionupdate, compositionend </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var TARGET;
+ var ExpectResult = ["compositionstart", "compositionupdate", "compositionend"];
+ var ActualResult = [];
+ var count = 0
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener("compositionstart", TestEvent, true);
+ TARGET.addEventListener("compositionupdate", TestEvent, true);
+ TARGET.addEventListener("compositionend", TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ ActualResult.push(evt.type);
+ TARGET.removeEventListener(evt.type, TestEvent, true);
+
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: The composition events occur in a set order relative to one another:
+ 1. compositionstart, 2. compositionupdate (multiple events), 3. compositionend.
+ </h4>
+
+ <pre>
+ <input id="target" value=""/>
+
+ Steps:
+ 1) Open Japanese Microsoft IME and select Hiragana input method
+ 2) Click at the above textbox and then type 'a' using keyboard
+ 3) Press the '{Enter}' key to complete the IME composition
+ 4) <a href="CompositionEvent.html">Click here</a> to test again if not following the steps exactly
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below and nothing is typed to the textbox after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.attrChange.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.attrChange.html
new file mode 100644
index 0000000000..12c45fc848
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.attrChange.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> MutationEvent.attrChange for DOMAttrModified Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "DOMAttrModified";
+ var ATTR = "name";
+ var TARGET;
+ var ExpectResult = [2, 1, 3];
+ var ActualResult = [];
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+
+ TARGET.setAttribute(ATTR, "foo");
+ TARGET.setAttribute(ATTR, "bar");
+ TARGET.removeAttribute(ATTR);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (evt.type == EVENT)
+ {
+ ActualResult.push(evt.attrChange);
+ }
+
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MutationEvent.attrChange indicates the type of change which triggered the DOMAttrModified event.
+ </h4>
+
+ <div id="target"></div>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.attrName.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.attrName.html
new file mode 100644
index 0000000000..ca1ad97d24
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.attrName.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> MutationEvent.attrName for DOMAttrModified Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "DOMAttrModified";
+ var ATTR = "name";
+ var TARGET;
+ var ExpectResult = ["name", "foo", "style"];
+ var ActualResult = [];
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+
+ TARGET.setAttribute(ATTR, "wow");
+ TARGET.setAttribute("foo", "bar");
+ TARGET.removeAttribute("style");
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (evt.type == EVENT)
+ {
+ ActualResult.push(evt.attrName);
+ }
+
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MutationEvent.attrName indicates the name of the changed Attr node
+ in a DOMAttrModified event.
+ </h4>
+
+ <div id="target" name="blah" style="border:solid 1px green; width:350px; height:100px;"></div>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.html
new file mode 100644
index 0000000000..c229abe96e
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> Mutation Event Type: DOMAttrModified </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "DOMAttrModified";
+ var ATTR = "name";
+ var TARGET;
+ var ExpectResult = ["foo", "bar", null];
+ var ActualResult = [];
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+
+ TARGET.setAttribute(ATTR, "foo");
+ TARGET.setAttribute(ATTR, "bar");
+ TARGET.removeAttribute(ATTR);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (evt.type == EVENT)
+ {
+ ActualResult.push(TARGET.getAttribute(ATTR));
+ }
+
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: DOMAttrModified event fires after an Attr.value has been
+ modified and after an Attr node has been added to or removed from an Element.
+ </h4>
+
+ <div id="target"></div>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.newValue.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.newValue.html
new file mode 100644
index 0000000000..77b8a41e1a
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.newValue.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> MutationEvent.newValue for DOMAttrModified Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "DOMAttrModified";
+ var ATTR = "name";
+ var TARGET;
+ var ExpectResult = ["foo", "bar", null];
+ var ActualResult = [];
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+
+ TARGET.setAttribute(ATTR, "foo");
+ TARGET.setAttribute(ATTR, "bar");
+ TARGET.removeAttribute(ATTR);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (evt.type == EVENT)
+ {
+ ActualResult.push(evt.newValue);
+ }
+
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MutationEvent.newValue indicates the new value of the Attr node in DOMAttrModified events.
+ </h4>
+
+ <div id="target"></div>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.prevValue.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.prevValue.html
new file mode 100644
index 0000000000..31fbec7764
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.prevValue.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> MutationEvent.prevValue for DOMAttrModified Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "DOMAttrModified";
+ var ATTR = "name";
+ var TARGET;
+ var ExpectResult = [null, "foo", "bar"];
+ var ActualResult = [];
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+
+ TARGET.setAttribute(ATTR, "foo");
+ TARGET.setAttribute(ATTR, "bar");
+ TARGET.removeAttribute(ATTR);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (evt.type == EVENT)
+ {
+ ActualResult.push(evt.prevValue);
+ }
+
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MutationEvent.prevValue indicates the previous value of the Attr node in DOMAttrModified events.
+ </h4>
+
+ <div id="target"></div>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.relatedNode.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.relatedNode.html
new file mode 100644
index 0000000000..5c30dabe22
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMAttrModified.relatedNode.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> MutationEvent.relatedNode for DOMAttrModified Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "DOMAttrModified";
+ var ATTR = "name";
+ var TARGET;
+ var ExpectResult = ["name", "foo", "style"];
+ var ActualResult = [];
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+
+ TARGET.setAttribute(ATTR, "wow");
+ TARGET.setAttribute("foo", "bar");
+ TARGET.removeAttribute("style");
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (evt.type == EVENT)
+ {
+ ActualResult.push(evt.relatedNode.nodeName);
+ }
+
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: In the case of the DOMAttrModified event, MutationEvent.relatedNode
+ indicates the Attr node which was modified, added, or removed.
+ </h4>
+
+ <div id="target" name="blah" style="border:solid 1px green; width:350px; height:100px;"></div>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMCharacterDataModified.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMCharacterDataModified.html
new file mode 100644
index 0000000000..31d4fbf08f
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMCharacterDataModified.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> MutationEvent: DOMCharacterDataModified Event Type </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "DOMCharacterDataModified";
+ var TARGET;
+ var TEXTNODE;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ TEXTNODE = TARGET.firstChild;
+ TEXTNODE.data += "world";
+
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (EVENT == evt.type)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: DOMCharacterDataModified event fires after CharacterData.data has been modified.
+ </h4>
+
+ <span id="parent">
+ <div id="target" contenteditable style="border:solid 1px green; width:100px; height:100px">Hello </div>
+ </span>
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMNodeInserted.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMNodeInserted.html
new file mode 100644
index 0000000000..0e0d26d1aa
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMNodeInserted.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> MutationEvent: DOMNodeInserted Event Type </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "DOMNodeInserted";
+ var TARGET;
+ var NODE;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+
+ NODE = document.createElement("INPUT");
+ TARGET.appendChild(NODE);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (EVENT == evt.type)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: DOMNodeInserted event fires when a node has been added as a child of another node.
+ </h4>
+
+ <span id="parent">
+ <div id="target" style="border:solid 1px green; width:200px; height:50px">
+ </div>
+ </span>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMNodeRemoved.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMNodeRemoved.html
new file mode 100644
index 0000000000..34d7112027
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMNodeRemoved.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> MutationEvent: DOMNodeRemoved Event Type </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "DOMNodeRemoved";
+ var TARGET;
+ var PARENT;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ PARENT = document.getElementById("parent");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ PARENT.removeChild(TARGET);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (EVENT == evt.type)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: DOMNodeRemoved event fires when a node is being removed from its parent node.
+ </h4>
+
+ <span id="parent">
+ <div id="target" style="border:solid 1px green; width:100px; height:100px">
+ </div>
+ </span>
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMSubtreeModified.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMSubtreeModified.html
new file mode 100644
index 0000000000..1819f563da
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/DOMSubtreeModified.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> MutationEvent: DOMSubtreeModified Event Type </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT1 = "DOMSubtreeModified";
+ var EVENT2 = "DOMNodeRemoved";
+ var TARGET;
+ var HELPER;
+ var ActualResult = [];
+ var ExpectResult = [EVENT2, EVENT1];
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT1, TestEvent, true);
+ TARGET.addEventListener(EVENT2, TestEvent, true);
+
+ HELPER = document.getElementById("helper");
+ TARGET.removeChild(HELPER);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ ActualResult.push(evt.type);
+
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+
+ if (2 < ActualResult.length)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: DOMSubtreeModified event fires after any other events
+ caused by the mutation(s) have occurred.
+ </h4>
+
+ <span id="parent">
+ <div id="target" style="border:solid 1px green; width:200px; height:50px">
+ <input id="helper">
+ </div>
+ </span>
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.defaultPrevented.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.defaultPrevented.html
new file mode 100644
index 0000000000..8acd3cb979
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.defaultPrevented.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title> W3C DOM Level 3 Event Object Property: defaultPrevented </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "click";
+ var TARGET;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestCapture, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestCapture(evt)
+ {
+ try
+ {
+ evt.preventDefault();
+
+ if ((evt.type == EVENT) && (evt.defaultPrevented == true))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h4>
+ Test Description:
+ Event listeners can cancel default actions of cancelable event objects by invoking the Event.preventDefault()
+ method, and determine whether an event has been canceled through the Event.defaultPrevented attribute.
+ </h4>
+
+ Click the hyperlink:
+ <a href="http://samples.msdn.microsoft.com/ietestcenter/" id="target">http://samples.msdn.microsoft.com/ietestcenter</a>
+
+ <p>Test passes if the word "PASS" appears below after clicking the hyperlink and the page does not navigate away.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.eventPhase.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.eventPhase.html
new file mode 100644
index 0000000000..4bd3b51b46
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.eventPhase.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title> W3C DOM Level 2 Event Object Property: eventPhase </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "dblclick";
+ var TARGET, PARENT;
+ var ActualResult = [];
+ var ExpectResult = [];
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ PARENT = document.getElementById("parent");
+
+ ExpectResult = ["[1]" + PARENT, "[2]" + TARGET, "[3]" + document.body];
+
+ PARENT.addEventListener(EVENT, TestEvent, true);
+ PARENT.addEventListener(EVENT, TestEvent, false);
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ TARGET.addEventListener(EVENT, TestEvent, false);
+ document.body.addEventListener(EVENT, TestEvent, false);
+
+ PARENT.removeEventListener(EVENT, TestEvent, false);
+ TARGET.removeEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ ActualResult.push("[" + evt.eventPhase + "]" + evt.currentTarget);
+
+ if ((evt.eventPhase == 3) && (evt.currentTarget == document.body))
+ {
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h4>
+ Test Description:
+ eventPhase is used to indicate which phase of event flow is currently being accomplished.
+ </h4>
+
+ <div id="parent">
+ Double click here: <input id="target" />
+ </div>
+
+ <p>Test passes if the word "PASS" appears below after double clicking the above textbox.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.stopPropagation.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.stopPropagation.html
new file mode 100644
index 0000000000..019143e366
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/Event.stopPropagation.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title> W3C DOM Level 3 Event Object method: stopPropagation </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "mousedown";
+ var TARGET, PARENT;
+ var ActualResult = [];
+ var ExpectResult = [];
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ PARENT = document.getElementById("parent");
+
+ ExpectResult = [document.body, PARENT];
+
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ TARGET.addEventListener(EVENT, TestEvent, false);
+ PARENT.addEventListener(EVENT, TestEvent, true);
+ PARENT.addEventListener(EVENT, TestEvent, false);
+ document.body.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ ActualResult.push(evt.currentTarget);
+
+ if (evt.currentTarget == PARENT)
+ {
+ try
+ {
+ evt.stopPropagation();
+ }
+ catch(ex)
+ {
+ }
+ }
+ }
+
+ function VerifyTest()
+ {
+ if (ActualResult.toString() == ExpectResult.toString())
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h4>
+ Test Description:
+ stopPropagation prevents other event listeners from being triggered.
+ </h4>
+
+ <div id="parent">
+ Click the button: <input id="target" type="button" value="Target" onmouseup="VerifyTest()" />
+ </div>
+
+ <p>Test passes if the word "PASS" appears below after clicking the above button using mouse.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.key.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.key.html
new file mode 100644
index 0000000000..ea1adb0751
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.key.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> KeyboardEvent Object Property: key </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "keydown";
+ var TARGET;
+ var ActualResult = "";
+ var result = true;
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if ((evt.type == EVENT) && (evt.key == "a"))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h4>Test Description: KeyboardEvent Object Property key holds the key value of the key pressed</h4>
+
+ Type 'a' here: <input id="target" value=""/>
+
+ <p>Test passes if the word "PASS" appears below after typing 'a' in the above textbox using keyboard.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.location.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.location.html
new file mode 100644
index 0000000000..63fe460f3d
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.location.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> KeyboardEvent.location </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "keydown";
+ var TARGET;
+ var ExpectResult = ["a", 0, "Control", 1, "Shift", 2];
+ var ActualResult = [];
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ ActualResult.push(evt.key, evt.location);
+
+ if ((evt.type == EVENT) && (evt.key == "Shift"))
+ {
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ TARGET.removeEventListener(EVENT, TestEvent, true);
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: KeyboardEvent.location attribute contains an indication of the
+ location of the key on the device.
+ </h4>
+
+ <pre>
+ <input id="target" value=""/>
+
+ Steps:
+ 1) Type 'a' in the above textbox using keyboard
+ 2) Press '{CTRL}' key on the left side of the keyboard
+ 3) Press '{SHIFT}' key on the right side of the keyboard
+ 4) <a href="KeyboardEvent.location.html">Click here</a> to test again if not following the steps exactly
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.modifiers.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.modifiers.html
new file mode 100644
index 0000000000..ee490b47ec
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/KeyboardEvent.modifiers.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> KeyboardEvent.getModifierState() and 'AltGraph' modifier key </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "keydown";
+ var TARGET;
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if ((evt.type == EVENT) && evt.getModifierState("AltGraph"))
+ {
+ PassTest();
+ TARGET.removeEventListener(EVENT, TestEvent, true);
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: Some operating systems simulate the 'AltGraph' modifier key
+ with the combination of the 'Alt' and 'Control' modifier keys. Implementations
+ are encouraged to use the 'AltGraph' modifier key.
+ </h4>
+
+ <pre>
+ <input id="target" value=""/>
+
+ Steps:
+ 1) Click in the above textbox using mouse
+ 2) Press and hold down '{CTRL}' key and then press '{ALT}' key on the keyboard
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.button.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.button.html
new file mode 100644
index 0000000000..605565a781
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.button.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> MouseEvent.button for mouseup Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "mouseup";
+ var TARGET;
+ var ExpectResult = [0, 1, 2];
+ var ActualResult = [];
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+
+ ActualResult.push(evt.button);
+ TARGET.value = ActualResult;
+
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h4>
+ Test Description: MouseEvent.button value for mouseup event is based on current button pressed.
+ </h4>
+
+ <pre>
+ <input id="target" value=""/>
+
+ Steps:
+ 1) Move the mouse pointer to the above textbox
+ 2) Click the mouse button in this order: Left Button, Middle Button, Right Button
+ 3) <a href="MouseEvent.button.html">Click here</a> to test again if not following the steps exactly
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.image.map.area.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.image.map.area.html
new file mode 100644
index 0000000000..17b7dd5cce
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.image.map.area.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> MouseEvent event on IMG element with MAP and AREA elements</title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var TARGET;
+ var EVENT = "click";
+
+ function TestEvent(evt)
+ {
+ evt.preventDefault();
+
+ if ((EVENT == evt.type) && (TARGET === evt.target))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ window.onload = function(evt)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ document.addEventListener(EVENT, TestEvent, false);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MouseEvent event fires on the AREA element when click the MAP AREA on an image
+ </h4>
+
+ <img src="./support/iepreview.png" usemap="#ieMap" />
+
+ <map name="ieMap">
+ <area id="target" href="MouseEvent.image.map.area.html" shape="rect" coords="140 180 250 250" title="Arrow" />
+ </map>
+
+ <p id="manualsteps">
+ Steps:
+ <ol>
+ <li> Click at the arrow pointer symbol on the bottom-right corner of the image.
+ </ol>
+ </p>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.preventDefault.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.preventDefault.html
new file mode 100644
index 0000000000..e6cb57806d
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MouseEvent.preventDefault.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> MouseEvent: mousedown - preventDefault() for text selection </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT1 = "mousedown";
+ var EVENT2 = "mouseup";
+ var TARGET;
+ var DisableSelection = false;
+ var DefaultPrevented = false;
+ var BEFORE = 0;
+ var AFTER = 0;
+
+ function DisableTextSelection()
+ {
+ DisableSelection = true;
+ }
+
+ function TestEvent(evt)
+ {
+ if ((true == DisableSelection) && (EVENT1 == evt.type))
+ {
+ evt.preventDefault();
+ DefaultPrevented = true;
+ BEFORE = evt.clientX;
+ }
+ if ((true == DisableSelection) && (EVENT2 == evt.type))
+ {
+ AFTER = evt.clientX;
+ }
+ }
+
+ function VerifyResult()
+ {
+ var distance = Math.abs(AFTER - BEFORE);
+
+ if ((true == DefaultPrevented) && (10 < distance) && ("" == window.getSelection()))
+ {
+ PassTest()
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT1, TestEvent, false);
+ TARGET.addEventListener(EVENT2, TestEvent, false);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MouseEvent - Text selection is disabled after cancelling mousedown event.
+ </h4>
+
+ <span id="target" style="border:1px solid green; color:blue">&nbsp; Use mouse to select the whole line here &nbsp;</span>
+
+ <p id="manualsteps">
+ Steps:
+ <ol>
+ <li> Make sure text in the above green box can be selected using mouse
+ <li> Dismiss the selection, if any, by clicking at the green box with mouse
+ <li> Now, click the button: <button onclick="DisableTextSelection()">Disable Selection</button>
+ <li> Drag mouse to select the whole line of the text inside the above green box
+ <li> Click the button: <button id="verify" onclick="VerifyResult()">VerifyResult</button>
+ </ol>
+ </p>
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.hasFeature.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.hasFeature.html
new file mode 100644
index 0000000000..f550a5366d
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.hasFeature.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> MutationEvent: feature detection with hasFeature() </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ window.onload = function()
+ {
+ try
+ {
+ var features = ["MutationEvent",
+ "Events.MutationEvent",
+ "Events.DOMSubtreeModified",
+ "Events.DOMNodeInserted",
+ "Events.DOMNodeRemoved",
+ "Events.DOMAttrModified",
+ "Events.DOMCharacterDataModified"];
+
+ var versions = ["3.0", "", null];
+ var TestResult = true;
+ var HasFeature = false;
+
+ for (var i=0; i<features.length; i++)
+ {
+ for (var j=0; j<versions.length; j++)
+ {
+ HasFeature = document.implementation.hasFeature(features[i], versions[j]);
+ TestResult = HasFeature && TestResult;
+ }
+ }
+
+ if (HasFeature && TestResult)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MutationEvent - feature support detection using DOMImplementation.hasFeature() method
+ </h4>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.initMutationEvent.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.initMutationEvent.html
new file mode 100644
index 0000000000..3b2bceabf4
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.initMutationEvent.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> MutationEvent.initMutationEvent() and Event.trusted </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "foo";
+ var TARGET;
+ var ExpectResult = [];
+ var ActualResult = [];
+ var TestResult = true;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+
+ var evt = document.createEvent("MutationEvent");
+ evt.initMutationEvent(EVENT, /* type */
+ true, /* bubbles */
+ true, /* cancelable */
+ null, /* relatedNode */
+ "hello", /* prevValue */
+ "world", /* newValue */
+ "bar", /* attrName */
+ 1 /* attrChange*/ );
+
+ TARGET.dispatchEvent(evt);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+
+ }
+
+ function TestEvent(evt)
+ {
+ if ((EVENT == evt.type) && (false == evt.trusted))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: initMutationEvent initializes attributes of a MutationEvent object.
+ </h4>
+
+ <input id="target" type="hidden" />
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.relatedNode.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.relatedNode.html
new file mode 100644
index 0000000000..6b92079ef6
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/MutationEvent.relatedNode.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> MutationEvent.relatedNode for DOMNodeInserted and DOMNodeRemoved </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT1 = "DOMNodeInserted";
+ var EVENT2 = "DOMNodeRemoved";
+ var TARGET;
+ var PARENT;
+ var NODE;
+ var ActualResult = [];
+ var ExpectResult = [];
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ PARENT = document.getElementById("parent");
+ TARGET.addEventListener(EVENT1, TestEvent, true);
+ TARGET.addEventListener(EVENT2, TestEvent, true);
+
+ ExpectResult = [TARGET, PARENT];
+
+ NODE = document.createElement("INPUT");
+ TARGET.appendChild(NODE);
+ PARENT.removeChild(TARGET);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ ActualResult.push(evt.relatedNode);
+
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+
+ if (2 < ActualResult.length)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MutationEvent.relatedNode is the parent node of the node being removed for DOMNodeRemoved event;
+ and, it is the parent node of the node that has been inserted for DOMNodeInserted event
+ </h4>
+
+ <span id="parent">
+ <div id="target" style="border:solid 1px green; width:200px; height:50px">
+ </div>
+ </span>
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.fail.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.fail.html
new file mode 100644
index 0000000000..9b0843c115
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.fail.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> ProcessingInstruction.data and DOMCharacterDataModified event </title>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: DOMCharacterDataModified event fires after ProcessingInstruction.data have been modified,
+ but the node itself has not been inserted or deleted. The proximal event target of this event shall be the
+ ProcessingInstruction node.
+ </h4>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.xml b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.xml
new file mode 100644
index 0000000000..34ad59064f
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/ProcessingInstruction.DOMCharacterDataModified.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<root>
+ <head xmlns="http://www.w3.org/1999/xhtml">
+ <title> ProcessingInstruction.data and DOMCharacterDataModified event </title>
+ </head>
+
+ <p xmlns="http://www.w3.org/1999/xhtml">
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: DOMCharacterDataModified event fires after ProcessingInstruction.data have been modified,
+ but the node itself has not been inserted or deleted. The proximal event target of this event shall be the
+ ProcessingInstruction node.
+ </h4>
+
+ <pi><?foo bar?></pi>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div><testresult>FAIL</testresult></div>
+
+ <script type="text/javascript" xmlns="http://www.w3.org/1999/xhtml">
+ <![CDATA[
+ var PassTest = function()
+ {
+ document.getElementsByTagName("testresult")[0].firstChild.data = "PASS";
+ TestResult = true;
+ }
+
+ var FailTest = function()
+ {
+ document.getElementsByTagName("testresult")[0].firstChild.data = "FAIL";
+ TestResult = false;
+ }
+
+ var EVENT = "DOMCharacterDataModified";
+ var TARGET = document.getElementsByTagName('pi')[0].firstChild;
+ var TestResult = false;
+
+ try
+ {
+ TARGET.addEventListener(EVENT, TestEvent, false);
+ TARGET.data = "new" + TARGET.data;
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+
+ function TestEvent(evt)
+ {
+ if ((EVENT == evt.type) && (TARGET == evt.target) && ("newbar" == evt.newValue))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ ]]>
+ </script>
+ </p>
+</root> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.hasFeature.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.hasFeature.html
new file mode 100644
index 0000000000..853cc7c435
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.hasFeature.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> TextEvent: feature detection with hasFeature() </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ window.onload = function()
+ {
+ try
+ {
+ var features = ["TextEvent", "Events.TextEvent", "Events.textInput"];
+ var versions = ["3.0", "", null];
+ var TestResult = true;
+ var HasFeature = false;
+
+ for (var i=0; i<features.length; i++)
+ {
+ for (var j=0; j<versions.length; j++)
+ {
+ HasFeature = document.implementation.hasFeature(features[i], versions[j]);
+ TestResult = HasFeature && TestResult;
+ }
+ }
+
+ if (HasFeature && TestResult)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: TextEvent - feature support detection using DOMImplementation.hasFeature() method
+ </h4>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.initTextEvent.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.initTextEvent.html
new file mode 100644
index 0000000000..52eae11aa9
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.initTextEvent.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> TextEvent.initTextEvent() and Event.trusted </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "foo";
+ var TARGET;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+
+ var evt = document.createEvent("TextEvent");
+ evt.initTextEvent(EVENT, /* type */
+ true, /* bubbles */
+ true, /* cancelable */
+ window, /* view */
+ "domstr", /* data*/
+ 0 /* inputMode */ );
+ TARGET.dispatchEvent(evt);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+
+ }
+
+ function TestEvent(evt)
+ {
+ if ((EVENT == evt.type) && (false == evt.trusted))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: initTextEvent initializes attributes of a TextEvent object.
+ </h4>
+
+ <input id="target" type="hidden" />
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.IME.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.IME.html
new file mode 100644
index 0000000000..af5c736242
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.IME.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> TextEvent: inputMode with DOM_INPUT_METHOD_IME </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "textInput";
+ var TARGET;
+
+ function TestEvent(evt)
+ {
+ TARGET.removeEventListener(EVENT, TestEvent, true);
+ if ((0x04 == evt.inputMode) && ("あ" == evt.data))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: TextEvent.inputMode is DOM_INPUT_METHOD_IME (0x04)
+ when the text string was entered through an Input Method Editor.
+ </h4>
+
+ <span id="parent">
+ <input id="target" type="text" />
+ </span>
+
+ <p id="manualsteps">
+ Steps:
+ <ol>
+ <li> Open Japanese Microsoft IME and select Hiragana input method
+ <li> Click at the above textbox and then type 'a' using keyboard
+ <li> Press '{ENTER}' key to complete the IME composition
+ </ol>
+ </p>
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.drop.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.drop.html
new file mode 100644
index 0000000000..14ffc19765
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.drop.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> TextEvent: inputMode with DOM_INPUT_METHOD_DROP </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "textInput";
+ var TARGET;
+
+ function TestEvent(evt)
+ {
+ TARGET.removeEventListener(EVENT, TestEvent, true);
+
+ if ((0x03 == evt.inputMode) && ("Hello World" == evt.data))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: TextEvent.inputMode is DOM_INPUT_METHOD_DROP (0x03)
+ when the text string was inserted as part of a drag-and-drop operation.
+ </h4>
+
+ <span id="parent">
+ <div contenteditable="true" style="border:solid 1px green; width:150px; height:20px">Hello World</div>
+ <br/>
+ <input id="target" type="text" />
+ </span>
+
+ <p id="manualsteps">
+ Steps:
+ <ol>
+ <li> Select "Hello World" inside the green editbox
+ <li> Drag-and-drop it ("Hello World") to the textbox below the green editbox
+ </ol>
+ </p>
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.keyboard.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.keyboard.html
new file mode 100644
index 0000000000..472dd96ddb
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.keyboard.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> TextEvent: inputMode with DOM_INPUT_METHOD_KEYBOARD </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "textInput";
+ var TARGET;
+
+ function TestEvent(evt)
+ {
+ TARGET.removeEventListener(EVENT, TestEvent, true);
+
+ if ((0x01 == evt.inputMode) && ("a" == evt.data))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: TextEvent.inputMode is DOM_INPUT_METHOD_KEYBOARD (0x01)
+ when the text string was input through a keyboard.
+ </h4>
+
+ <span id="parent">
+ <input id="target" type="text" />
+ </span>
+ <p id="manualsteps">
+ Steps:
+ <ol>
+ <li> Type 'a' in the above texbox using keyboard
+ </ol>
+ </p>
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.paste.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.paste.html
new file mode 100644
index 0000000000..a93259cd60
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.paste.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> TextEvent: inputMode with DOM_INPUT_METHOD_PASTE </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "textInput";
+ var TARGET;
+
+ function TestEvent(evt)
+ {
+ TARGET.removeEventListener(EVENT, TestEvent, true);
+
+ if ((0x02 == evt.inputMode) && ("Hello World" == evt.data))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: TextEvent.inputMode is DOM_INPUT_METHOD_PASTE (0x02)
+ when the text string was pasted in from a clipboard.
+ </h4>
+
+ <span id="parent">
+ <div contenteditable="true" style="border:solid 1px green; width:150px; height:20px">Hello World</div>
+ <br/>
+ <input id="target" type="text" />
+ </span>
+
+ <p id="manualsteps">
+ Steps:
+ <ol>
+ <li> Select and copy "Hello World" inside the green editbox
+ <li> Paste it ("Hello World") to the textbox below the green editbox
+ </ol>
+ </p>
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.script.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.script.html
new file mode 100644
index 0000000000..c1327ebae5
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/TextEvent.inputMode.script.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> TextEvent: inputMode with DOM_INPUT_METHOD_SCRIPT </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "textInput";
+ var TARGET;
+
+ function TestEvent(evt)
+ {
+ TARGET.removeEventListener(EVENT, TestEvent, true);
+
+ if ((0x09 == evt.inputMode) && ("Hello World" == evt.data))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ TARGET.firstChild.data = "Hello World";
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: TextEvent.inputMode is DOM_INPUT_METHOD_SCRIPT (0x09)
+ when the text string was inserted via a script operation on the DOM.
+ </h4>
+
+ <span id="parent">
+ <div id="target" contenteditable="true" style="border:solid 1px green; width:200px; height:50px">
+ </div>
+ </span>
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/UIEvent.load.stylesheet.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/UIEvent.load.stylesheet.html
new file mode 100644
index 0000000000..a948a2f71a
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/UIEvent.load.stylesheet.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> UIEvent: load event for style sheets </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ function TestEvent(evt)
+ {
+ if ((evt.type == EVENT) && (evt.currentTarget == TARGET))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ var EVENT = "load";
+ var TARGET;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, false);
+ TARGET.href = "./support/style01.css";
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: UIEvent - load event fires when the DOM Implementation finishes loading
+ dependent resources, such as style sheets.
+ </h4>
+
+ <LINK id="target" rel="stylesheet" />
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.Capture.Bubble.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.Capture.Bubble.html
new file mode 100644
index 0000000000..4dfe246136
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.Capture.Bubble.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> WheelEvent: wheel Event capturing/bubbling </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ function TestBubble(evt)
+ {
+ if (EVENT == evt.type)
+ {
+ ActualResult.push(evt.currentTarget);
+ }
+
+ if ((3 == evt.eventPhase) && (window === evt.currentTarget))
+ {
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+
+ for (var i=0; i < CURRENTTARGETS.length; i++)
+ {
+ CURRENTTARGETS[i].removeEventListener(EVENT, TestBubble, true);
+ CURRENTTARGETS[i].removeEventListener(EVENT, TestBubble, false);
+ }
+ }
+ }
+
+ var EVENT = "wheel";
+ var TARGET, PARENT, CURRENTTARGETS;
+ var ExpectResult = [];
+ var ActualResult = [];
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ PARENT = document.getElementById("parent");
+ CURRENTTARGETS = [window, document, document.body, PARENT, TARGET];
+ ExpectResult = CURRENTTARGETS + "," + CURRENTTARGETS.reverse();
+
+ for (var i=0; i < CURRENTTARGETS.length; i++)
+ {
+ CURRENTTARGETS[i].addEventListener(EVENT, TestBubble, true);
+ CURRENTTARGETS[i].addEventListener(EVENT, TestBubble, false);
+ }
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: WheelEvent - wheel event bubbles.
+ </h4>
+
+ <span id="parent">
+ <textarea id="target" rows="5" cols="30">TOP TOP TOP TOP TOP TOP TOP Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here END END END END END END END </textarea>
+ </span>
+ <p id="manualsteps">
+ Steps:
+ <ol>
+ <li> Note: an input device with scroll wheel support (e.g., mouse wheel) is required
+ <li> Move the mouse pointer over the above textarea
+ <li> Scroll down the mouse wheel 1 or more units
+ </ol>
+ </p>
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.ctrlKey.zoom.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.ctrlKey.zoom.html
new file mode 100644
index 0000000000..52b17ced96
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.ctrlKey.zoom.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> WheelEvent: wheel - MouseEvent.ctrlKey and Zooming </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ function DisableZooming()
+ {
+ BEFORE = HELPER.getBoundingClientRect().width;
+ DisableZoom = true;
+ }
+
+ function VerifyResult()
+ {
+ AFTER = HELPER.getBoundingClientRect().width;
+
+ if ((true == DisableZoom) && (true == TestResult) && (BEFORE == AFTER))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if ((true == DisableZoom) && (true == evt.ctrlKey) && (EVENT == evt.type))
+ {
+ evt.preventDefault();
+ TestResult = evt.defaultPrevented;
+ }
+ }
+
+ var EVENT = "wheel";
+ var TARGET;
+ var HELPER;
+ var BEFORE;
+ var AFTER;
+ var DisableZoom = false;
+ var TestResult = false;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document;
+ HELPER = document.getElementById("helper");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: The typical default action of the wheel event type, in some cases, is to
+ zoom the document. If this event is canceled, the implementation must not zoom the document.
+ </h4>
+
+ <div id="helper" style="width:100%"></div>
+
+ <p id="manualsteps">
+ Steps:
+ <ol>
+ <li> Note: an input device with scroll wheel support (e.g., mouse wheel) is required
+ <li> Make sure the page can be zoomed in/out by holding down '{CTRL}' key + scrolling the mouse wheel on the page
+ <li> Now, click the button: <button id="verify" onclick="DisableZooming()">Disable Zooming</button>
+ <li> Press and hold down '{CTRL}' key on the keyboard
+ <li> Move the mouse pointer to the center of the page
+ <li> Scroll down/up the mouse wheel some units
+ <li> Click the button: <button id="verify" onclick="VerifyResult()">VerifyResult</button>
+ </ol>
+ </p>
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.deltaMode.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.deltaMode.html
new file mode 100644
index 0000000000..11761f4083
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.deltaMode.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> WheelEvent: wheel - WheelEvent.deltaMode </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "wheel";
+ var TARGET;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if ((0x00 == evt.deltaMode) || (0x01 == evt.deltaMode) || (0x02 == evt.deltaMode))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: WheelEvent.deltaMode attribute contains an indication of the units of
+ measurement for the delta values. Its value may be different based on system configuration.
+ </h4>
+
+ <span id="parent">
+ <div id="target" style="border:solid 1px green; width:220px; height:70px; overflow:scroll">
+ TOP TOP TOP TOP TOP TOP TOP
+ Scroll mouse wheel over here
+ Scroll mouse wheel over here
+ Scroll mouse wheel over here
+ Scroll mouse wheel over here
+ Scroll mouse wheel over here
+ Scroll mouse wheel over here
+ END END END END END END END
+ </div>
+ </span>
+ <p id="manualsteps">
+ Steps:
+ <ol>
+ <li> Note: an input device with scroll wheel support (e.g., mouse wheel) is required
+ <li> Move the mouse pointer over the above green box
+ <li> Scroll down the mouse wheel 1 or more units
+ </ol>
+ </p>
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.hasFeature.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.hasFeature.html
new file mode 100644
index 0000000000..8bd224fa98
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.hasFeature.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> WheelEvent: feature detection with hasFeature() </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ window.onload = function()
+ {
+ try
+ {
+ var features = ["WheelEvent", "Events.WheelEvent", "Events.wheel"];
+ var versions = ["3.0", "", null];
+ var TestResult = true;
+ var HasFeature = false;
+
+ for (var i=0; i<features.length; i++)
+ {
+ for (var j=0; j<versions.length; j++)
+ {
+ HasFeature = document.implementation.hasFeature(features[i], versions[j]);
+ TestResult = HasFeature && TestResult;
+ }
+ }
+
+ if (HasFeature && TestResult)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: WheelEvent - feature support detection using DOMImplementation.hasFeature() method
+ </h4>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.initWheelEvent.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.initWheelEvent.html
new file mode 100644
index 0000000000..cd8c192e41
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.initWheelEvent.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> WheelEvent.initWheelEvent() and Event.trusted </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "foo";
+ var TARGET;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+
+ var evt = document.createEvent("WheelEvent");
+ evt.initWheelEvent(EVENT, /* type */
+ true, /* bubbles */
+ true, /* cancelable */
+ window, /* view */
+ 0, /* detail */
+ 1, /* screenX */
+ 2, /* screenY */
+ 3, /* clientX */
+ 4, /* clientY */
+ 5, /* button */
+ null, /* relatedTarget */
+ "", /* modifiers */
+ 6, /* deltaX*/
+ 7, /* deltaY */
+ 8, /* deltaZ*/
+ 9 /* deltaMode */ );
+ TARGET.dispatchEvent(evt);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+
+ }
+
+ function TestEvent(evt)
+ {
+ if ((EVENT == evt.type) && (false == evt.trusted))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: initWheelEvent initializes attributes of a WheelEvent object.
+ </h4>
+
+ <input id="target" type="hidden" />
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.preventDefault.scroll.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.preventDefault.scroll.html
new file mode 100644
index 0000000000..6cb55a071f
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/WheelEvent.preventDefault.scroll.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> WheelEvent: wheel - preventDefault() for Scrolling </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ function DisableScrolling()
+ {
+ TARGET.scrollTop = 0;
+ BEFORE = TARGET.scrollTop;
+ DisableScroll = true;
+ }
+
+ function VerifyResult()
+ {
+ AFTER = TARGET.scrollTop;
+
+ if ((true == DisableScroll) && (true == TestResult) && (BEFORE == AFTER))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if ((true == DisableScroll) && (EVENT == evt.type))
+ {
+ evt.preventDefault();
+ TestResult = evt.defaultPrevented;
+ }
+ }
+
+ var EVENT = "wheel";
+ var BEFORE;
+ var AFTER;
+ var DisableScroll = false;
+ var TestResult = false;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, false);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: The typical default action of the wheel event type is to scroll the document/element
+ by the indicated amount. If this event is canceled, the implementation must not scroll document/element.
+ </h4>
+
+ <span id="parent">
+ <textarea id="target" rows="5" cols="30">TOP TOP TOP TOP TOP TOP TOP Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here Scroll mouse wheel over here END END END END END END END </textarea>
+ </span>
+ <p id="manualsteps">
+ Steps:
+ <ol>
+ <li> Note: an input device with scroll wheel support (e.g., mouse wheel) is required
+ <li> Make sure the above textarea can be scrolled by scrolling the mouse wheel over it
+ <li> Now, click the button: <button onclick="DisableScrolling()">Disable Scrolling</button>
+ <li> Move the mouse pointer over the above textarea
+ <li> Scroll down the mouse wheel 1 or more units
+ <li> Click the button: <button id="verify" onclick="VerifyResult()">VerifyResult</button>
+ </ol>
+ </p>
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/abort.img.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/abort.img.html
new file mode 100644
index 0000000000..c0fb1eaf97
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/abort.img.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title> W3C DOM Level 3 Event: abort </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ window.localStorage.TestResult = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ window.localStorage.TestResult = "FAIL";
+ }
+
+ function TestCapture(evt)
+ {
+ if ((evt.currentTarget == TARGET) && (evt.type == EVENT))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ function ReloadPage()
+ {
+ var LINK = document.getElementById("link");
+ LINK.href = "abort.img.html";
+ LINK.firstChild.data = "Click here to reload the page and test again.";
+ PARENT.firstChild.data = "Image loaded below. The above link should be clicked before image loads."
+ }
+ </script>
+ </head>
+ <body>
+ <h4>
+ Test Description:
+ The abort event fires when the loading of a resource has been aborted.
+ </h4>
+
+ <h3><a id="link" href="abort.testresult.html">Before image is loaded below, click here.</a></h3>
+
+ <div id="parent">Loading...<br></div>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+
+ <script type="text/javascript">
+ try
+ {
+ window.localStorage.clear();
+
+ var EVENT = "abort";
+ var PARENT = document.getElementById("parent");
+ var TARGET = document.createElement("img");
+ TARGET.width = "400";
+ TARGET.height = "400";
+ TARGET.src = "./support/iepreview10mb.png?" + (new Date()).valueOf();
+ PARENT.appendChild(TARGET);
+ TARGET.onload = ReloadPage;
+ TARGET.addEventListener(EVENT, TestCapture, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/abort.testresult.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/abort.testresult.html
new file mode 100644
index 0000000000..e0f6243b8a
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/abort.testresult.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <h4>
+ Test Description:
+ The abort event fires when the loading of a resource has been aborted.
+ </h4>
+
+ <h3><a id="link" href="abort.img.html">Click here to go back to the test page</a></h3>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>
+ <script>
+ try
+ {
+ var result = window.localStorage.getItem("TestResult");
+ }
+ catch(ex)
+ {
+ }
+ if ("PASS" != result)
+ {
+ result = "FAIL";
+ }
+ document.write(result);
+ </script>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/blur.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/blur.html
new file mode 100644
index 0000000000..cef282bfe5
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/blur.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title> W3C DOM Level 3 Event: blur </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "blur";
+ var TARGET;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestCapture, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestCapture(evt)
+ {
+ if ((evt.type == EVENT) && (evt.currentTarget == TARGET))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h4>Test Description: blur event fires when an event target loses focus.</h4>
+
+ <div id="parent">
+ Click the textbox and then the button: <br />
+ <input id="target" /> <button id="helper">Button</button>
+ </div>
+
+ <p>Test passes if the word "PASS" appears below after clicking the above textbox and then the button.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.data.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.data.html
new file mode 100644
index 0000000000..177c37e8d7
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.data.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> CompositionEvent.data for compositionstart Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "compositionstart";
+ var TARGET;
+ var ExpectResult = [];
+ var ActualResult = [];
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if ((evt.type == EVENT) && (evt.data == ""))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: The value of the data attribute of the compositionstart event
+ shall be null for new IME input.
+ </h4>
+
+ <pre>
+ <input id="target" value=""/>
+
+ Steps:
+ 1) Open Japanese Microsoft IME and select Hiragana input method
+ 2) Click at the above textbox and then type 'a' using keyboard
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.keydown.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.keydown.html
new file mode 100644
index 0000000000..7316d1a8a3
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.keydown.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> compositionstart Event and keydown Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var TARGET;
+ var ExpectResult = ["keydown", "compositionstart", "keyup"];
+ var ActualResult = [];
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener("compositionstart", TestEvent, true);
+ TARGET.addEventListener("keydown", TestEvent, true);
+ TARGET.addEventListener("keyup", TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ ActualResult.push(evt.type);
+
+ if (evt.type == "keyup")
+ {
+ if (ExpectResult.toString() == ActualResult.toString())
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ TARGET.removeEventListener("compositionstart", TestEvent, true);
+ TARGET.removeEventListener("keydown", TestEvent, true);
+ TARGET.removeEventListener("keyup", TestEvent, true);
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: When a keyboard is used to feed an input method editor,
+ compositionstart event type is generated after a keydown event.
+ </h4>
+
+ <pre>
+ <input id="target" value=""/>
+
+ Steps:
+ 1) Open Japanese Microsoft IME and select Hiragana input method
+ 2) Type 'a' in the above textbox using keyboard
+ 3) <a href="compositionstart.keydown.html">Click here</a> to test again if not following the steps exactly
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.preventDefault.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.preventDefault.html
new file mode 100644
index 0000000000..74fc52b579
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/compositionstart.preventDefault.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> Cancelling compositionstart Event via Event.preventDefault() </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "compositionstart";
+ var TARGET;
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ TARGET.addEventListener("keyup", TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (evt.type == EVENT)
+ {
+ evt.preventDefault();
+ }
+
+ if (evt.type == "keyup")
+ {
+ if (TARGET.value == "")
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: The default action of compositionstart event is to launch the appropriate text
+ composition system. If this event is canceled, the text composition system must not be launched.
+ </h4>
+
+ <pre>
+ <input id="target" value=""/>
+
+ Steps:
+ 1) Open Japanese Microsoft IME and select Hiragana input method
+ 2) Click at the above textbox and then type 'a' using keyboard
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below and nothing is typed to the textbox after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/converted/EventListener.dispatch.new.event.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/converted/EventListener.dispatch.new.event.html
new file mode 100644
index 0000000000..e0ab7e0d3e
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/converted/EventListener.dispatch.new.event.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> Dispatch additional events inside an event listener </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<table id="table" border="1" style="display: none">
+ <tbody id="table-body">
+ <tr id="table-row">
+ <td id="table-cell">Shady Grove</td>
+ <td>Aeolian</td>
+ </tr>
+ <tr id="parent">
+ <td id="target">Over the river, Charlie</td>
+ <td>Dorian</td>
+ </tr>
+ </tbody>
+</table>
+
+<script>
+
+ var EVENT = "foo";
+ var TARGET = document.getElementById("target");
+ var PARENT = document.getElementById("parent");
+ var TBODY = document.getElementById("table-body");
+ var TABLE = document.getElementById("table");
+ var BODY = document.body;
+ var HTML = document.documentElement;
+ var CurrentTargets = [window, document, HTML, BODY, TABLE, TBODY, PARENT, TARGET];
+ var ExpectResult = [window, document, HTML, BODY, TABLE, TARGET, PARENT, TBODY,
+ TABLE, BODY, HTML, document, window, TBODY, PARENT, TARGET];
+ var ActualResult = [];
+ var ExpectTypes = "foo,foo,foo,foo,foo,bar,bar,bar,bar,bar,bar,bar,bar,foo,foo,foo,";
+ var ActualTypes = "";
+
+ var description = "Test Description: " +
+ "Implementations of the DOM event model must be reentrant. Event listeners may perform actions that " +
+ "cause additional events to be dispatched. Such events are handled in a synchronous manner, the event " +
+ "propagation that causes the event listener to be triggered must resume only after the event dispatch " +
+ "of the new event is completed.";
+
+ test(function()
+ {
+ for (var i=0; i < CurrentTargets.length; i++)
+ {
+ CurrentTargets[i].addEventListener(EVENT, TestEvent, true);
+ CurrentTargets[i].addEventListener("bar", TestEvent, false);
+ }
+
+ var evt = document.createEvent("Event");
+ evt.initEvent(EVENT, false, true);
+ TARGET.dispatchEvent(evt);
+
+ assert_array_equals(ActualResult, ExpectResult, "ActualResult");
+ assert_equals(ActualTypes, ExpectTypes, "ActualTypes");
+
+ }, description);
+
+ function TestEvent(evt)
+ {
+ ActualResult.push(evt.currentTarget);
+ ActualTypes += evt.type + ",";
+
+ if (TABLE == evt.currentTarget && EVENT == evt.type)
+ {
+ var e = document.createEvent("Event");
+ e.initEvent("bar", true, true);
+ TARGET.dispatchEvent(e);
+ }
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/converted/support/ProcessingInstruction.DOMCharacterDataModified.xml b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/converted/support/ProcessingInstruction.DOMCharacterDataModified.xml
new file mode 100644
index 0000000000..4c95ae29df
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/converted/support/ProcessingInstruction.DOMCharacterDataModified.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<root>
+ <head xmlns="http://www.w3.org/1999/xhtml">
+ <title> ProcessingInstruction.data and DOMCharacterDataModified event </title>
+ </head>
+ <div id="log" xmlns="http://www.w3.org/1999/xhtml"></div>
+
+ <pi><?foo bar?></pi>
+
+ <script type="text/javascript" xmlns="http://www.w3.org/1999/xhtml">
+ <![CDATA[
+ var EVENT = "DOMCharacterDataModified";
+ var TARGET = document.getElementsByTagName('pi')[0].firstChild;
+ var TestResult = false;
+
+ TARGET.addEventListener(EVENT, TestEvent, false);
+ TARGET.data = "new" + TARGET.data;
+
+ function TestEvent(evt)
+ {
+ if ((EVENT == evt.type) && (TARGET == evt.target) && ("newbar" == evt.newValue))
+ {
+ TestResult = true;
+ }
+ else
+ {
+ TestResult = false;
+ }
+ }
+ ]]>
+ </script>
+</root> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/dispatchEvent.click.checkbox.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/dispatchEvent.click.checkbox.html
new file mode 100644
index 0000000000..757bb12646
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/dispatchEvent.click.checkbox.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title id='desc'> MouseEvent: Default action and synthetic click event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "click";
+ var TARGET;
+ var HELPER;
+
+ function TestEvent(evt)
+ {
+ if (HELPER == evt.target)
+ {
+ HELPER.removeEventListener(EVENT, TestEvent, true);
+ var e = document.createEvent("MouseEvent");
+ e.initMouseEvent(EVENT, /* type */
+ false, /* bubbles */
+ true, /* cancelable */
+ window, /* view */
+ 1, /* detail */
+ 0, /* screenX */
+ 0, /* screenY */
+ 0, /* clientX */
+ 0, /* clientY */
+ false, /* ctrlKey */
+ false, /* altKey */
+ false, /* shiftKey */
+ false, /* metaKey */
+ 0, /* button */
+ null /* relatedTarget */ );
+
+ TARGET.dispatchEvent(e);
+ }
+ else if (TARGET == evt.target)
+ {
+ if ((true == TARGET.checked) && (false == evt.bubbles))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ }
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ HELPER = document.getElementById("helper");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ HELPER.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MouseEvent: Default action is performed when a synthetic click event is dispatched on a checkbox element
+ </h4>
+
+ <input type="checkbox" id="target">
+ <button id="helper">Click Here</button>
+
+ <p id="manualsteps">
+ Steps:
+ <ol>
+ <li> Click the button "Click Here"
+ </ol>
+ </p>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/error.image.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/error.image.html
new file mode 100644
index 0000000000..a629652d4f
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/error.image.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title> W3C DOM Level 3 Event: error </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ function TestCapture(evt)
+ {
+ TARGET = document.getElementById("target");
+
+ if ((evt.type == EVENT) && (evt.currentTarget == window) && (evt.target == TARGET))
+ {
+ TestResult = true;
+ }
+ else
+ {
+ TestResult = false;
+ }
+ }
+
+ var EVENT = "error";
+ var TARGET;
+ var TestResult = false;
+
+ try
+ {
+ window.addEventListener(EVENT, TestCapture, true);
+ }
+ catch(ex)
+ {
+ TestResult = false;
+ }
+
+ window.onload = function()
+ {
+ if (true == TestResult)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h4>Test Description: error event fires when an IMG resource failed to load.</h4>
+
+ <img id="target" src="./support/InvalidBitMap.png" alt="ERROR">
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusin.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusin.html
new file mode 100644
index 0000000000..a6eb1b6638
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusin.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title> W3C DOM Level 3 Event: focusin </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "focusin";
+ var TARGET, PARENT;
+
+ window.onload = function()
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ PARENT = document.getElementById("parent");
+
+ PARENT.addEventListener(EVENT, TestBubble, false);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestBubble(evt)
+ {
+ if ((evt.type == EVENT) && (evt.currentTarget == PARENT) && (evt.target == TARGET))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h4>
+ Test Description:
+ focusin event fires when an event target is about to receive focus.
+ </h4>
+
+ <div id="parent">
+ Click here: <input id="target" />
+ </div>
+
+ <p>Test passes if the word "PASS" appears below after clicking the above textbox using mouse.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusin.relatedTarget.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusin.relatedTarget.html
new file mode 100644
index 0000000000..a36d254666
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusin.relatedTarget.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> FocusEvent.relatedTarget for focusin Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "focusin";
+ var TARGET, HELPER;
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ HELPER = document.getElementById("helper");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if ((evt.target == TARGET) && (evt.relatedTarget == HELPER))
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: FocusEvent.relatedTarget for focusin event is the event target losing focus.
+ </h4>
+
+ <pre>
+ <input id="helper" value="" /> <button id="target">BUTTON</button>
+
+ Steps:
+ 1) Click in the above textbox using mouse
+ 2) Then click the above button using mouse
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusout.relatedTarget.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusout.relatedTarget.html
new file mode 100644
index 0000000000..bc02267ed7
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/focusout.relatedTarget.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> FocusEvent.relatedTarget for focusout Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "focusout";
+ var TARGET, HELPER;
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ HELPER = document.getElementById("helper");
+ TARGET.addEventListener("focusout", TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (evt.type == EVENT && evt.relatedTarget == HELPER)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: FocusEvent.relatedTarget for focusout event is the event target receiving focus.
+ </h4>
+
+ <pre>
+ <input id="target" value="" /> <button id="helper">BUTTON</button>
+
+ Steps:
+ 1) Click in the above textbox using mouse
+ 2) Then click the above button using mouse
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/hasFeature.Events.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/hasFeature.Events.html
new file mode 100644
index 0000000000..e0c9ba18d8
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/hasFeature.Events.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> DOMImplementation.hasFeature() with Events, 3.0 and 2.0</title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ window.onload = function()
+ {
+ try
+ {
+ var SupportEvents3 = document.implementation.hasFeature("Events", "3.0");
+ SupportEvents3 = SupportEvents3 && document.implementation.hasFeature("Events", "");
+ var SupportEvents2 = document.implementation.hasFeature("Events", "2.0");
+
+ if (SupportEvents3 && SupportEvents2)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: Since DOM Level 3 Events is built on top of DOM Level 2 Events, an
+ implementation that returns true for "Events" and "3.0" shall also return true for the
+ parameters "Events" and "2.0".
+ </h4>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/hasFeature.feature.string.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/hasFeature.feature.string.html
new file mode 100644
index 0000000000..e96c39c855
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/hasFeature.feature.string.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> DOMImplementation.hasFeature() and Extended Feature String </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var szFeatures = ["Event", "UIEvent","FocusEvent","MouseEvent","WheelEvent","TextEvent",
+ "KeyboardEvent","CompositionEvent","MutationEvent","CustomEvent"];
+
+ var ExpectResult = [];
+ var ActualResult = [];
+ var supported = false;
+
+ window.onload = function()
+ {
+ try
+ {
+ supported = document.implementation.hasFeature("Events", "3.0");
+
+ for (var i=0; i<szFeatures.length; i++)
+ {
+ var szFeature = szFeatures[i];
+
+ supported = document.implementation.hasFeature(szFeature, "3.0") && supported;
+ supported = document.implementation.hasFeature(szFeature, "") && supported;
+ if (!supported)
+ {
+ break;
+ }
+ }
+
+ for (var i=0; i<szFeatures.length; i++)
+ {
+ var szFeature = "Events." + szFeatures[i];
+
+ supported = document.implementation.hasFeature(szFeature, "3.0") && supported;
+ supported = document.implementation.hasFeature(szFeature, "") && supported;
+ if (!supported)
+ {
+ break;
+ }
+ }
+
+ if (supported)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: each interface defined in DOM Level 3 Events has a feature string,
+ which may act as a base feature string or as an extended feature string.
+ </h4>
+
+ <p>Test passes if the word "PASS" appears below.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/load.image.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/load.image.html
new file mode 100644
index 0000000000..19414eaf02
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/load.image.html
@@ -0,0 +1,82 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title> W3C DOM Level 3 Event: load </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ function TestCapture(evt)
+ {
+ if (evt.target.tagName == "IMG")
+ {
+ TARGET = document.getElementById("target");
+
+ if ((evt.type == EVENT) && (evt.currentTarget == document) && (evt.target == TARGET))
+ {
+ TestResult = true;
+ }
+ else
+ {
+ TestResult = false;
+ }
+ }
+ }
+
+ var EVENT = "load";
+ var TARGET;
+ var TestResult = false;
+
+ try
+ {
+ document.addEventListener(EVENT, TestCapture, true);
+ }
+ catch(ex)
+ {
+ TestResult = false;
+ }
+
+ window.onload = function()
+ {
+ if (true == TestResult)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+
+ function ReloadPage()
+ {
+ var LINK = document.getElementById("link");
+ LINK.href = "load.image.html";
+ LINK.appendChild(document.createTextNode("Image loading error. Click here to test again."));
+ }
+ </script>
+ </head>
+ <body>
+ <h4>
+ Test Description:
+ load event fires when the DOM implementation finishes loading the resource (such as the document)
+ and any dependent resources (such as images, style sheets, or scripts).
+ </h4>
+
+ <p><a id="link" href=""></a></p>
+
+ <img id="target" src="./support/iepreview.png" width="300" height="300" onerror="ReloadPage()">
+
+ <p>Test passes if the word "PASS" appears below after the above image is loaded.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseenter.ctrlKey.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseenter.ctrlKey.html
new file mode 100644
index 0000000000..dac16046cf
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseenter.ctrlKey.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> MouseEvent.ctrlKey for mouseenter Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "mouseenter";
+ var TARGET;
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if ((evt.type == EVENT) && (evt.ctrlKey == true))
+ {
+ TARGET.style.border = "solid 1px green";
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MouseEvent.ctrlKey returns true if 'Control' key is depressed, otherwise false.
+ </h4>
+
+ <pre>
+ <img id="target" src="./support/iepreview.png" width="256" height="256" style="border:solid 1px red" />
+
+ Steps:
+ 1) Press and hold down the '{CTRL}' key
+ 2) Move the mouse pointer into the image
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseenter.relatedTarget.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseenter.relatedTarget.html
new file mode 100644
index 0000000000..f2d449dae8
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseenter.relatedTarget.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> MouseEvent.relatedTarget for mouseenter Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "mouseenter";
+ var TARGET, PARENT;
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ PARENT = document.getElementById("parent");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (evt.type == EVENT && evt.relatedTarget == PARENT)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MouseEvent.relatedTarget for mouseenter event indicates
+ the event target a pointing device is exiting, if any.
+ </h4>
+
+ <pre>
+ <div id="parent" style="border:solid 1px green; width:350px; height:100px;">
+
+ <button id="target">BUTTON</button>
+
+ </div>
+
+ Steps:
+ 1) Move the mouse pointer into the above green rectangle
+ 2) Then move the mouse pointer onto the button
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseleave.relatedTarget.html b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseleave.relatedTarget.html
new file mode 100644
index 0000000000..37ca719750
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/mouseleave.relatedTarget.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title id='desc'> MouseEvent.relatedTarget for mouseleave Event </title>
+ <script type="text/javascript">
+ var PassTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "PASS";
+ }
+
+ var FailTest = function()
+ {
+ document.getElementById("testresult").firstChild.data = "FAIL";
+ }
+
+ var EVENT = "mouseleave";
+ var TARGET, PARENT;
+
+ window.onload = function(e)
+ {
+ try
+ {
+ TARGET = document.getElementById("target");
+ PARENT = document.getElementById("parent");
+ TARGET.addEventListener(EVENT, TestEvent, true);
+ }
+ catch(ex)
+ {
+ FailTest();
+ }
+ }
+
+ function TestEvent(evt)
+ {
+ if (evt.type == EVENT && evt.relatedTarget == PARENT)
+ {
+ PassTest();
+ }
+ else
+ {
+ FailTest();
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <h3>DOM Events</h3>
+ <h4>
+ Test Description: MouseEvent.relatedTarget for mouseleave event indicates
+ the event target a pointing device is entering, if any.
+ </h4>
+
+ <pre>
+ <div id="parent" style="border:solid 1px green; width:350px; height:100px;">
+
+ <button id="target">BUTTON</button>
+
+ </div>
+
+ Steps:
+ 1) Move the mouse pointer onto the above button
+ 2) Then move the mouse pointer out of it
+ </pre>
+
+ <p>Test passes if the word "PASS" appears below after following the above steps.</p>
+ <div>Test result: </div>
+ <div id='testresult'>FAIL</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/16kb.js b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/16kb.js
new file mode 100644
index 0000000000..fb3c0d64b1
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/16kb.js
@@ -0,0 +1,140 @@
+var text =
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " +
+"This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! This is a test! " ;
+ActualResult.push("SCRIPT:loaded");
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/InvalidBitMap.png b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/InvalidBitMap.png
new file mode 100644
index 0000000000..0a15a8e10d
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/InvalidBitMap.png
@@ -0,0 +1 @@
+Invalid BitMap \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/iepreview.png b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/iepreview.png
new file mode 100644
index 0000000000..63959a0562
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/iepreview.png
Binary files differ
diff --git a/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/style01.css b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/style01.css
new file mode 100644
index 0000000000..961757bf3d
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy-domevents-tests/submissions/Microsoft/support/style01.css
@@ -0,0 +1,3 @@
+BODY {
+ PADDING-BOTTOM: 0px; BACKGROUND-COLOR: #eef0eb; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px
+}
diff --git a/testing/web-platform/tests/uievents/legacy/Event-subclasses-init.html b/testing/web-platform/tests/uievents/legacy/Event-subclasses-init.html
new file mode 100644
index 0000000000..a79a9f18ad
--- /dev/null
+++ b/testing/web-platform/tests/uievents/legacy/Event-subclasses-init.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+for (let eventTypeName of ['UIEvent', 'MouseEvent', 'KeyboardEvent', 'CompositionEvent']) {
+ test(function() {
+ let eventType = self[eventTypeName];
+ assert_equals(eventType.length, 1);
+
+ let event = new eventType('test');
+ let initFunction = "init" + eventTypeName;
+ assert_throws_js(TypeError, function() { eventType.prototype[initFunction].call(event) });
+ }, `Call init${eventTypeName} without parameters`);
+}
+</script>
diff --git a/testing/web-platform/tests/uievents/mouse/attributes.html b/testing/web-platform/tests/uievents/mouse/attributes.html
new file mode 100644
index 0000000000..bbc388445c
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/attributes.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<title>MouseEvent attributes</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/utils.js"></script>
+
+<span id="left">Left</span> <span id="right">Right</span>
+
+<script>
+ 'use strict';
+
+ const event_list = ["mouseover", "mouseenter", "mousemove",
+ "mousedown", "mouseup", "mouseout", "mouseleave"];
+
+ promise_test(async () => {
+ let left = document.getElementById("left");
+ let right = document.getElementById("right");
+
+ let event_promises = [];
+ event_list.forEach(ename => event_promises.push(getEvent(ename, right)));
+
+ let actions = new test_driver.Actions().addPointer("TestPointer", "mouse")
+ .pointerMove(0, 0, {origin: left})
+ .pointerDown()
+ .pointerUp()
+ .pointerMove(0, 0, {origin: right})
+ .pointerDown()
+ .pointerUp()
+ .pointerMove(0, 0, {origin: left})
+ .pointerDown()
+ .pointerUp()
+ await actions.send();
+
+ for (let i = 0; i < event_promises.length; i++) {
+ let e = await event_promises[i];
+
+ assert_equals(e.constructor, window.MouseEvent,
+ e.type + " should use a MouseEvent constructor");
+ assert_true(e instanceof MouseEvent,
+ e.type + " should be a MouseEvent");
+
+ assert_true(e.isTrusted,
+ e.type + ".isTrusted attribute");
+
+ assert_equals(e.composed,
+ e.type != 'mouseenter' && e.type != 'mouseleave',
+ e.type + ".composed attribute");
+
+ assert_equals(e.bubbles,
+ e.type != 'mouseenter' && e.type != 'mouseleave',
+ e.type + ".bubbles attribute");
+
+ assert_equals(e.cancelable,
+ e.type != 'mouseenter' && e.type != 'mouseleave',
+ e.type + ".cancelable attribute");
+ }
+ }, "MouseEvent attributes");
+</script>
diff --git a/testing/web-platform/tests/uievents/mouse/cancel-mousedown-in-subframe.html b/testing/web-platform/tests/uievents/mouse/cancel-mousedown-in-subframe.html
new file mode 100644
index 0000000000..0735037735
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/cancel-mousedown-in-subframe.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="resources/utils.js"></script>
+<body>
+ <div>
+ Dragging the mouse from child frame to parent frame causes both <code>mousedown</code> and
+ <code>mouseup</code> events being dispatched to child frame, regardless of whether the
+ <code>mousedown</code> event is canceled or not.
+ </div>
+ <iframe id="child_frame" width="300px" height="40px"
+ src="resources/mouse-event-reporter-subframe.html">
+ </iframe>
+</body>
+<script>
+ "use strict"
+ let topframe_loaded = getEvent("load", window);
+ let subframe_loaded = getMessageData("load", frames[0]);
+
+ let top_frame_mousedown;
+ let top_frame_mouseup;
+
+ promise_setup(async () => {
+ await topframe_loaded;
+ await subframe_loaded;
+
+ window.addEventListener("mousedown", e => top_frame_mousedown = true);
+ window.addEventListener("mouseup", e => top_frame_mouseup = true);
+ });
+
+ [false, true].forEach(cancel_mousedown => {
+ let mousedown_msg = cancel_mousedown ? "canceled" : "not-canceled";
+
+ promise_test(async () => {
+ top_frame_mousedown = false;
+ top_frame_mouseup = false;
+
+ sendMessage(frames[0], "cancel-mousedown", cancel_mousedown);
+
+ const mousedown_promise = getMessageData("mousedown", frames[0]);
+ const mouseup_promise = getMessageData("mouseup", frames[0]);
+
+ const child_frame = document.getElementById("child_frame");
+ const actions_promise = new test_driver.Actions()
+ .pointerMove(5, 5, {origin: child_frame})
+ .pointerDown()
+ .pointerMove(5, 5, {origin: document.body})
+ .pointerUp()
+ .send();
+
+ await actions_promise;
+
+ let mousedown_message = await mousedown_promise;
+ let mouseup_message = await mouseup_promise;
+
+ assert_equals(mousedown_message.param, mousedown_msg, "Child frame canceled mousedown?");
+ assert_false(top_frame_mousedown, "Top frame received mousedown?");
+ assert_false(top_frame_mouseup, "Top frame received mouseup?");
+ }, "Child frame receives mousedown/mouseup when mousedown is " + mousedown_msg);
+ });
+</script>
diff --git a/testing/web-platform/tests/uievents/mouse/layout_change_should_fire_mouseover.html b/testing/web-platform/tests/uievents/mouse/layout_change_should_fire_mouseover.html
new file mode 100644
index 0000000000..49257ae60d
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/layout_change_should_fire_mouseover.html
@@ -0,0 +1,97 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Mouseover/enter is sent on layout change</title>
+ <meta name="viewport" content="width=device-width">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <style>
+ #spacer {
+ height: 100px;
+ width: 100px;
+ }
+ #red {
+ background-color: rgb(255, 0, 0);
+ position: absolute;
+ z-index: 0;
+ left: 0px;
+ top: 0px;
+ height: 100px;
+ width: 100px;
+ }
+ #blue {
+ background-color: rgb(0, 0, 255);
+ position: absolute;
+ z-index: 1;
+ left: 0px;
+ top: 0px;
+ height: 100px;
+ width: 100px;
+ }
+ #blue:hover {
+ background-color: rgb(255, 255, 0);
+ }
+ </style>
+ </head>
+ <body onload="run();">
+ <div id="spacer"></div>
+ <div id="red"></div>
+ <h4>Test Description: Tests that the mouseover event is fired and the element has a hover effect when the element underneath the mouse cursor is changed.
+ <ol>
+ <li>Put your mouse over the red rectangle</li>
+ <li>Click the primary mouse button</li>
+ </ol>
+ </h4>
+ <script type="text/javascript">
+ var testMouseOver = async_test('Tests that the mouseover event is fired and the element has a hover effect when the element underneath the mouse cursor is changed.');
+ var actions_promise;
+
+ var eventList = [];
+ function addBlue() {
+ document.body.innerHTML += '<div id="blue"></div>';
+ var blue = document.getElementById("blue");
+ var events = ['mouseover', 'mousemove', 'mouseout', 'mouseenter', 'mouseleave'];
+ events.forEach(function (event) {
+ blue.addEventListener(event, checkHoverEffect);
+ });
+ testMouseOver.step_timeout(function () {
+ checkEventSequence();
+ }, 2500);
+ }
+
+ function checkEventSequence() {
+ var result = eventList.join();
+ assert_equals(result, 'mouseover,mouseenter');
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ testMouseOver.done();
+ });
+ }
+
+ function run() {
+ document.addEventListener('click', addBlue);
+ }
+
+ function checkHoverEffect(event) {
+ eventList.push(event.type);
+ testMouseOver.step(function () {
+ assert_equals(event.target.id, "blue");
+ assert_equals(getComputedStyle(event.target).backgroundColor, "rgb(255, 255, 0)");
+ if (event.type == "mouseenter") {
+ checkEventSequence();
+ }
+ });
+ }
+
+ // Inject mouse inputs.
+ actions_promise = new test_driver.Actions()
+ .pointerMove(0, 0, {origin: red})
+ .pointerDown()
+ .pointerUp()
+ .send();
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/mouse/mouse_boundary_events_after_removing_last_over_element.html b/testing/web-platform/tests/uievents/mouse/mouse_boundary_events_after_removing_last_over_element.html
new file mode 100644
index 0000000000..817c5d9ecc
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/mouse_boundary_events_after_removing_last_over_element.html
@@ -0,0 +1,153 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Redundant "mouseenter" shouldn't be fired without "mouseleave"s</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-actions.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<script>
+"use strict";
+
+function stringifyEvents(eventArray) {
+ if (!eventArray.length) {
+ return "[]";
+ }
+ let result = "";
+ eventArray.forEach(event => {
+ if (result != "") {
+ result += ", ";
+ }
+ result += `${event.type}@${
+ event.target?.nodeType == Node.ELEMENT_NODE
+ ? `${event.target.localName}${
+ event.target.id ? `#${event.target.id}` : ""
+ }`
+ : event.target?.localName
+ }`;
+ });
+ return result;
+}
+
+function eventsAfterClick(eventArray) {
+ const indexAtClick = eventArray.findIndex(e => e.type == "click");
+ if (indexAtClick >= 0) {
+ return eventArray.slice(indexAtClick + 1);
+ }
+ return [];
+}
+
+addEventListener("load", () => {
+ promise_test(async () => {
+ const div1 = document.createElement("div");
+ div1.setAttribute("id", "grandparent");
+ div1.setAttribute("style", "width: 32px; height: 32px");
+ const div2 = document.createElement("div");
+ div2.setAttribute("id", "parent");
+ div2.setAttribute("style", "width: 32px; height: 32px");
+ const div3 = document.createElement("div");
+ div3.setAttribute("id", "child");
+ div3.setAttribute("style", "width: 32px; height: 32px");
+ div1.appendChild(div2);
+ div2.appendChild(div3);
+ document.body.appendChild(div1);
+ const bodyRect = document.body.getBoundingClientRect();
+ const div3Rect = div3.getBoundingClientRect();
+ let events = [];
+ for (const type of ["mouseenter", "mouseleave", "mouseover", "mouseout", "mousemove"]) {
+ for (const node of [document.body, div1, div2, div3]) {
+ node.addEventListener(type, event => {
+ if (event.target == node) {
+ events.push({type: event.type, target: event.target});
+ }
+ }, {capture: true});
+ }
+ }
+ div3.addEventListener("click", event => {
+ div3.remove();
+ events.push({type: event.type, target: event.target});
+ }, {once: true});
+ await new test_driver.Actions()
+ .pointerMove(div3Rect.x + 10, div3Rect.y + 10, {})
+ .pointerDown()
+ .pointerUp() // The clicked in the child, then it's removed from the DOM tree
+ .pointerMove(bodyRect.x + 10, bodyRect.y + 10, {}) // Then, move onto the <body>
+ .send();
+ // FYI: Comparing `mouseenter`s before `click` requires additional
+ // initialization, but it's out of scope of this bug. Therefore, we
+ // compare only events after `click`.
+ const expectedEvents = [ // no events should be fired on the child due to disconnected
+ { type: "mouseover", target: div2 }, // mouseover should be fired because of the mutation
+ { type: "mouseout", target: div2}, // mouseout should be fired because of the mutation
+ { type: "mouseleave", target: div2},
+ { type: "mouseleave", target: div1},
+ { type: "mouseover", target: document.body},
+ { type: "mousemove", target: document.body},
+ ];
+ assert_equals(
+ stringifyEvents(eventsAfterClick(events)),
+ stringifyEvents(expectedEvents),
+ );
+ div1.remove();
+ }, "After removing the last over element, redundant mouseenter events should not be fired on the ancestors");
+
+ promise_test(async () => {
+ const hostContainer = document.createElement("div");
+ hostContainer.setAttribute("id", "containerOfShadowHost");
+ hostContainer.setAttribute("style", "margin-top: 32px; height: 32px");
+ const host = document.createElement("div");
+ host.setAttribute("id", "shadowHost");
+ host.setAttribute("style", "width: 32px; height: 32px");
+ const root = host.attachShadow({mode: "open"});
+ const rootElementInShadow = document.createElement("div");
+ root.appendChild(rootElementInShadow);
+ rootElementInShadow.setAttribute("id", "divInShadow");
+ rootElementInShadow.setAttribute("style", "width: 32px; height: 32px");
+ hostContainer.appendChild(host);
+ document.body.appendChild(hostContainer);
+ const bodyRect = document.body.getBoundingClientRect();
+ const rootElementInShadowRect = rootElementInShadow.getBoundingClientRect();
+ let events = [];
+ for (const type of ["mouseenter", "mouseleave", "mouseover", "mouseout", "mousemove"]) {
+ for (const node of [document.body, hostContainer, host, root, rootElementInShadow]) {
+ node.addEventListener(type, event => {
+ if (event.target == node) {
+ events.push({type: event.type, target: event.target});
+ }
+ }, {capture: true});
+ }
+ }
+ rootElementInShadow.addEventListener("click", event => {
+ rootElementInShadow.remove();
+ events.push({type: event.type, target: event.target});
+ }, {once: true});
+ await new test_driver.Actions()
+ .pointerMove(rootElementInShadowRect.x + 10, rootElementInShadowRect.y + 10, {})
+ .pointerDown()
+ .pointerUp() // The clicked root element in the shadow is removed here.
+ .pointerMove(bodyRect.x + 10, bodyRect.y + 10, {}) // Then, move onto the <body>
+ .send();
+ // FYI: Comparing `mouseenter`s before `click` requires additional
+ // initialization, but it's out of scope of this bug. Therefore, we
+ // compare only events after `click`.
+ const expectedEvents = [ // no events should be fired on rootElementInShadow due to disconnected
+ { type: "mouseover", target: host}, // mouseover should be fired because of the mutation
+ { type: "mouseout", target: host}, // mouseout should be fired because of the mutation
+ { type: "mouseleave", target: host},
+ { type: "mouseleave", target: hostContainer},
+ { type: "mouseover", target: document.body},
+ { type: "mousemove", target: document.body},
+ ];
+ assert_equals(
+ stringifyEvents(eventsAfterClick(events)),
+ stringifyEvents(expectedEvents),
+ );
+ hostContainer.remove();
+ }, "After removing the root element in the shadow under the cursor, mouseleave events should be targeted outside the shadow, but redundant mouseenter events should not be fired");
+}, {once: true});
+</script>
+</head>
+<body style="padding-top: 32px"></body>
+</html>
diff --git a/testing/web-platform/tests/uievents/mouse/mouse_buttons_back_forward.html b/testing/web-platform/tests/uievents/mouse/mouse_buttons_back_forward.html
new file mode 100644
index 0000000000..2323bc1026
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/mouse_buttons_back_forward.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Mouse Button Back/Forward</title>
+ <link rel="author" title="Google" href="http://www.google.com/" />
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script>
+ var testMouseUp = async_test('Tests that the mouseup is preventable.');
+ var received_back = false;
+ var received_forward = false;
+ const backButton = 3;
+ const forwardButton = 4;
+ var actions_promise;
+ window.addEventListener('mouseup', function(e) {
+ if (e.button == backButton) {
+ received_back = true;
+ e.preventDefault();
+ } else if (e.button == forwardButton) {
+ received_forward = true;
+ e.preventDefault();
+ }
+ if (received_back && received_forward) {
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ testMouseUp.done();
+ });
+ }
+ });
+
+ function inject_input() {
+ // First click on back button and then forward button.
+ var actions = new test_driver.Actions();
+ actions_promise = actions.pointerMove(0, 0, {origin: target})
+ .pointerDown({button: actions.ButtonType.BACK})
+ .pointerUp({button: actions.ButtonType.BACK})
+ .pointerDown({button: actions.ButtonType.FORWARD})
+ .pointerUp({button: actions.ButtonType.FORWARD})
+ .send();
+ }
+ </script>
+
+ </head>
+ <body id="target" onload="inject_input()">
+ <h4>Test Description: Tests that the mouseup event is prevented.
+ <ol>
+ <li>Click the back mouse button</li>
+ <li>Click the back mouse forward</li>
+ </ol>
+ </h4>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/mouse/mouseenter-mouseleave-on-drag.html b/testing/web-platform/tests/uievents/mouse/mouseenter-mouseleave-on-drag.html
new file mode 100644
index 0000000000..c36a1501c0
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/mouseenter-mouseleave-on-drag.html
@@ -0,0 +1,187 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for redundant mouseenter or mouseleave events</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+</head>
+<style>
+#outer {
+ background: grey;
+ position: absolute;
+ left: 100px;
+ top: 100px;
+ width: 100px;
+ height: 100px;
+}
+#inner {
+ background: red;
+ position: absolute;
+ left: 30px;
+ top: 30px;
+ width: 40px;
+ height: 40px;
+}
+</style>
+
+<body>
+ <!-- Verifies that dragging mouse in/out of an element doesn't fire redundant
+ mouseenter or mouseleave events (crbug.com/356090 & crbug.com/470258) -->
+ <div id="outer">
+ <div id="inner"></div>
+ </div>
+</body>
+<script>
+let eventLog = [];
+let nextUncheckedEventIndex = 0;
+
+// Ensure match to the next sequence of events in the event log.
+function assert_next_events(target, expectedEventNames, message) {
+ for (let i = 0; i < expectedEventNames.length; i++) {
+ assert_true(nextUncheckedEventIndex < eventLog.length,
+ `${message}: empty event queue`);
+ const observed = eventLog[nextUncheckedEventIndex++];
+ const expected = `${expectedEventNames[i]}@${target.id}`;
+ assert_equals(observed, expected,`${message}: Event mismatch`);
+ }
+}
+
+// After validating the expected events, all entries in the event map
+// must be false or we have recorded an unexpected event.
+function assert_empty_event_queue(message) {
+ const uncheckedEvents = eventLog.length - nextUncheckedEventIndex;
+ assert_equals(uncheckedEvents, 0,
+ `${message}: Unexpected events ` +
+ `${eventLog.slice(-uncheckedEvents).join(", ")}`);
+}
+
+function addEventListeners(test) {
+ const eventTypes = [
+ 'mousedown',
+ 'mouseenter',
+ 'mouseleave',
+ 'mousemove',
+ 'mouseout',
+ 'mouseover',
+ 'mouseup'
+ ];
+ ['inner', 'outer'].forEach(id => {
+ const element = document.getElementById(id);
+ eventTypes.forEach(eventType => {
+ const listener = (e) => {
+ if (e.eventPhase == Event.AT_TARGET) {
+ eventLog.push(`${eventType}@${id}`);
+ }
+ };
+ element.addEventListener(eventType, listener);
+ test.add_cleanup(() => {
+ element.removeEventListener(eventType, listener);
+ });
+ })
+ });
+}
+
+// At the end of each action sequence we move the mouse over the root element.
+// Once this event is detected, all other upstream events must be logged and
+// we can proceed with the checks.
+async function mousemoveOverRootElement() {
+ return new Promise(resolve => {
+ const listener = (e) => {
+ if (e.eventPhase == Event.AT_TARGET) {
+ document.documentElement.removeEventListener('mousemove', listener);
+ resolve();
+ }
+ };
+ document.documentElement.addEventListener('mousemove', listener);
+ });
+}
+
+window.onload = async () => {
+ const outer = document.getElementById('outer');
+ const inner = document.getElementById('inner');
+ const leftOuter = 100;
+ const rightOuter = 200;
+ const leftInner = 130;
+ const rightInner = 170;
+ const centerY = 150;
+
+ promise_test(async t => {
+ addEventListeners(t);
+ const completionPromise = mousemoveOverRootElement();
+ const actions =new test_driver.Actions();
+ actions.pointerMove(leftOuter + 10, centerY)
+ .pointerDown({button: actions.ButtonType.LEFT})
+ .pointerMove(rightOuter - 10, centerY)
+ .pointerUp({button: actions.ButtonType.LEFT})
+ .pointerMove(0, 0)
+ .send();
+ await actions;
+ await completionPromise;
+
+ assert_next_events(outer, ['mouseover', 'mouseenter', 'mousemove'],
+ 'Move over outer element');
+ assert_next_events(outer, ['mousedown', 'mousemove', 'mouseup'],
+ 'Drag across outer element');
+ assert_next_events(outer, ['mouseout', 'mouseleave'],
+ 'Move to origin');
+ assert_empty_event_queue('Drag across outer element');
+ }, 'Test dragging across inner div');
+
+ promise_test(async t => {
+ addEventListeners(t);
+ const completionPromise = mousemoveOverRootElement();
+ const actions =new test_driver.Actions();
+ actions.pointerMove(leftOuter + 10, centerY)
+ .pointerDown({button: actions.ButtonType.LEFT})
+ .pointerMove(leftInner + 10, centerY)
+ .pointerUp({button: actions.ButtonType.LEFT})
+ .pointerMove(0, 0)
+ .send();
+ await actions;
+ await completionPromise;
+
+ assert_next_events(outer, ['mouseover', 'mouseenter', 'mousemove'],
+ 'Move over outer element');
+ assert_next_events(outer, ['mousedown', 'mouseout'],
+ 'Initiate drag');
+ assert_next_events(inner,
+ ['mouseover', 'mouseenter', 'mousemove', 'mouseup'],
+ 'Drag into inner element');
+ assert_next_events(inner, ['mouseout', 'mouseleave'],
+ 'Move to origin');
+ assert_next_events(outer, [ 'mouseleave'],
+ 'Move to origin');
+ assert_empty_event_queue('Drag into inner element');
+ }, 'Test dragging into inner div');
+
+ promise_test(async t => {
+ addEventListeners(t);
+ const completionPromise = mousemoveOverRootElement();
+ const actions =new test_driver.Actions();
+ actions.pointerMove(leftInner + 10, centerY)
+ .pointerDown({button: actions.ButtonType.LEFT})
+ .pointerMove(rightInner + 10, centerY)
+ .pointerUp({button: actions.ButtonType.LEFT})
+ .pointerMove(0, 0)
+ .send();
+ await actions;
+ await completionPromise;
+
+ assert_next_events(inner, ['mouseover'], 'Move over inner element');
+ assert_next_events(outer, ['mouseenter'], 'Enter outer');
+ assert_next_events(inner, ['mouseenter', 'mousemove'],
+ 'Move across inner element');
+ assert_next_events(inner, ['mousedown', 'mouseout', 'mouseleave'],
+ 'Drag out of inner');
+ assert_next_events(outer, ['mouseover', 'mousemove', 'mouseup'],
+ 'Drag into outer');
+ assert_next_events(outer, ['mouseout', 'mouseleave'],
+ 'Move to origin');
+ assert_empty_event_queue('Drag into inner element');
+ }, 'Test dragging out of inner div');
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/uievents/mouse/mouseevent_move_button.html b/testing/web-platform/tests/uievents/mouse/mouseevent_move_button.html
new file mode 100644
index 0000000000..edde11d022
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/mouseevent_move_button.html
@@ -0,0 +1,102 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Mouse Events with button depressed</title>
+ <meta name="timeout" content="long">
+ <meta name="viewport" content="width=device-width">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <style>
+ div.box {
+ border: 2px solid lightgray;
+ margin: 25px;
+ padding: 25px;
+ float: left;
+ }
+ #lightyellow {
+ background-color: lightyellow;
+ }
+ #lightblue {
+ background-color: lightblue;
+ }
+ #lightgreen {
+ background-color: lightgreen;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h2>Mouse Events</h2>
+ <h4>Test Description: This test checks if mouse events set button property correctly
+ <ol>
+ <li>Put your mouse over the green rectangle</li>
+ <li>Press a non-primary button and hold it</li>
+ <li>Drag mouse to blue rectangle</li>
+ <li>Release mouse button</li>
+ </ol>
+ </h4>
+ <div class="box" id="lightyellow">
+ <div class="box" id="lightgreen"></div>
+ <div class="box" id="lightblue"></div>
+ </div>
+ <script>
+ var test = async_test("mouse events fired without button state");
+ var button = -1;
+ var actions_promise;
+
+ function run() {
+ var lightgreen = document.getElementById("lightgreen");
+ var lightyellow = document.getElementById("lightyellow");
+ var lightblue = document.getElementById("lightblue");
+
+ on_event(lightgreen, "contextmenu", function (event) {
+ event.preventDefault();
+ });
+
+ on_event(lightgreen, "mousedown", function (event) {
+ test.step(function() {assert_equals(button, -1, "There must only be one mouse down event.");});
+ test.step(function() {assert_not_equals(event.button, 0, "Must not be primary button.");});
+ button = event.button;
+ });
+ on_event(lightyellow, "click", function (event) {
+ test.step(function() {assert_equals(event.button, button, "Button must be the same as mousedown.");});
+ });
+ on_event(lightyellow, "mousemove", function (event) {
+ if (button != -1) {
+ test.step(function() {assert_equals(event.button, 0, "Button must be un-initialized for mousemove.");});
+ }
+ });
+ on_event(lightgreen, "mouseleave", function (event) {
+ if (button != -1) {
+ test.step(function() {assert_equals(event.button, 0, "Button must be un-initialized for mouseleave.");});
+ }
+ });
+ on_event(lightblue, "mouseenter", function (event) {
+ if (button != -1) {
+ test.step(function() {assert_equals(event.button, 0, "Button must be un-initialized for mouseenter.");});
+ }
+ });
+ on_event(lightblue, "mouseup", function (event) {
+ if (button != -1) {
+ test.step(function() {assert_equals(event.button, button, "Button must be the same as mousedown.");});
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ test.done();
+ });
+ }
+ });
+
+ // Inject mouse inputs.
+ var actions = new test_driver.Actions();
+ actions_promise = actions.pointerMove(0, 0, {origin: lightgreen})
+ .pointerDown({button: actions.ButtonType.MIDDLE})
+ .pointerMove(0, 0, {origin: lightyellow})
+ .pointerMove(0, 0, {origin: lightblue})
+ .pointerUp({button: actions.ButtonType.MIDDLE})
+ .send();
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/mouse/mousemove_prevent_default_action.tentative.html b/testing/web-platform/tests/uievents/mouse/mousemove_prevent_default_action.tentative.html
new file mode 100644
index 0000000000..4caf98087f
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/mousemove_prevent_default_action.tentative.html
@@ -0,0 +1,98 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>mousemove event: preventDefault()</title>
+<link rel="author" title="Mirko Brodesser" href="mailto:mbrodesser@mozilla.com">
+<link rel="help" href="https://github.com/w3c/uievents/issues/278">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-actions.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<script src=resources/utils.js></script>
+
+<body>
+ <div id="a">div a</div>
+ <div id="b">div b</div>
+ <div id="c" draggable="true">div c</div>
+</body>
+
+<script>
+ 'use strict';
+
+ let event_log = [];
+
+ function logEvents(e) {
+ event_log.push(e.type);
+ }
+
+ function initialize(test) {
+ // Deliberately avoiding mouseup here because the last selectionchange
+ // may be fired before or after the mouseup.
+ addTestScopedListener(document, "mousedown", logEvents, test);
+ addTestScopedListener(document, "mousemove", e => e.preventDefault(), test);
+ event_log = [];
+ }
+
+ promise_test(async test => {
+ initialize(test);
+ addTestScopedListener(document, "selectionchange", logEvents, test);
+
+ const a = document.getElementById("a");
+ const b = document.getElementById("b");
+
+ let mouseup_promise = getEvent("mouseup", document);
+
+ await new test_driver.Actions()
+ .pointerMove(0, 0, {origin: a})
+ .pointerDown()
+ .addTick()
+ .addTick()
+ .pointerMove(0, 0, {origin: b})
+ .addTick()
+ .addTick()
+ .pointerUp()
+ .send();
+
+ await mouseup_promise;
+
+ const expected_events = ["mousedown", "selectionchange", "selectionchange"];
+
+ assert_equals(event_log.toString(), expected_events.toString(),
+ "received events");
+ }, "selectionchange event firing when mousemove event is prevented");
+
+ promise_test(async test => {
+ initialize(test);
+ addTestScopedListener(document, 'dragstart', (event) => {
+ // For this test, it is enough to see the dragstart event. The event is
+ // cancelled here to suppress the actual drag operation because Blink's
+ // implementation of test_driver doesn't seem to be able to dispatch any
+ // event once the dragging is active.
+ event.preventDefault();
+ logEvents(event);
+ }, test);
+
+ const b = document.getElementById("b");
+ const c = document.getElementById("c");
+
+ const mouseup_promise = getEvent('mouseup', document);
+
+ await new test_driver.Actions()
+ .pointerMove(0, 0, {origin: c})
+ .pointerDown()
+ .addTick()
+ .addTick()
+ .pointerMove(0, 0, {origin: b})
+ .addTick()
+ .addTick()
+ .pointerUp()
+ .send();
+
+ await mouseup_promise;
+
+ const expected_events = ["mousedown", "dragstart"];
+
+ assert_equals(event_log.toString(), expected_events.toString(),
+ "received events");
+ }, "dragstart event firing when mousemove event is prevented");
+</script>
diff --git a/testing/web-platform/tests/uievents/mouse/mouseover-at-removing-mousedown-target.html b/testing/web-platform/tests/uievents/mouse/mouseover-at-removing-mousedown-target.html
new file mode 100644
index 0000000000..959dcef681
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/mouseover-at-removing-mousedown-target.html
@@ -0,0 +1,81 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<meta name="variant" content="?duration=16"> <!-- 60fps -->
+<meta name="variant" content="?duration=42"> <!-- 24fps -->
+<title>Check whether `mouseup` events are fired after pending boundary events</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-actions.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<style>
+div#parent {
+ width: 100%;
+ height: 50px;
+ background-color: gray;
+}
+div#child {
+ width: 100%;
+ height: 40px;
+ background-color: lime;
+}
+</style>
+</head>
+<body>
+<div id="parent"><div id="child"></div></div>
+<script>
+"use strict";
+
+const searchParams = new URLSearchParams(document.location.search);
+const duration = parseInt(searchParams.get("duration"));
+
+async function runTest(t) {
+ const parent = document.getElementById("parent");
+ const child = document.getElementById("child");
+ const mouseEvents = [];
+ function onMouseOverOrUp(event) {
+ // Ignore events before `mousedown` to make this test simpler.
+ if (mouseEvents[0]?.startsWith("mousedown")) {
+ mouseEvents.push(`${event.type}@${event.target.localName}${event.target.id ? `#${event.target.id}` : ""}`);
+ }
+ }
+ try {
+ child.getBoundingClientRect(); // flush layout
+ child.addEventListener("mousedown", event => {
+ event.target.remove();
+ mouseEvents.push("mousedown@div#child");
+ }, {once: true});
+ document.addEventListener("mouseover", onMouseOverOrUp, {capture: true});
+ document.addEventListener("mouseup", onMouseOverOrUp, {once: true, capture: true});
+ const actions = new test_driver.Actions(duration);
+ await actions.pointerMove(10, 10, {origin: child})
+ .pointerDown({button: actions.ButtonType.LEFT})
+ .pointerUp({button: actions.ButtonType.LEFT})
+ .send();
+ await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
+ assert_equals(
+ mouseEvents.toString(),
+ "mousedown@div#child,mouseover@div#parent,mouseup@div#parent",
+ t.name
+ );
+ } finally {
+ document.removeEventListener("mouseover", onMouseOverOrUp, {capture: true});
+ parent.appendChild(child);
+ }
+}
+
+// This test tries to detect intermittent case that mouseout might be fired
+// after a while from a DOM tree change. Therefore, trying same test 30 times.
+for (let i = 0; i < 30; i++) {
+ promise_test(async t => {
+ await runTest(t);
+ // Make things stabler to start next test.
+ await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
+ }, `mouseover should be fired before mouseup if mousedown target is removed (${i})`);
+}
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/mouse/resources/mouse-event-reporter-subframe.html b/testing/web-platform/tests/uievents/mouse/resources/mouse-event-reporter-subframe.html
new file mode 100644
index 0000000000..f12f429491
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/resources/mouse-event-reporter-subframe.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<script src="utils.js"></script>
+<style>
+ body, html {
+ margin: 0;
+ padding; 0;
+ background-color: #bfb;
+ }
+</style>
+<body>
+ <div>Child frame</div>
+</body>
+<script>
+ "use strict";
+ let cancel_mousedown = false;
+
+ window.addEventListener("load", () => {
+ window.addEventListener("message", event => {
+ let data = event.data;
+ if (data.type == "cancel-mousedown")
+ cancel_mousedown = data.param;
+ });
+
+ window.addEventListener("mousedown", e => {
+ let msg = "not-canceled";
+ if (cancel_mousedown) {
+ e.preventDefault();
+ msg = "canceled";
+ }
+ sendMessage(window.top, "mousedown", msg);
+ });
+
+ window.addEventListener("mouseup", e => sendMessage(window.top, "mouseup"));
+
+ sendMessage(parent, "load");
+ });
+</script>
diff --git a/testing/web-platform/tests/uievents/mouse/resources/utils.js b/testing/web-platform/tests/uievents/mouse/resources/utils.js
new file mode 100644
index 0000000000..6f5f6f4b6c
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/resources/utils.js
@@ -0,0 +1,35 @@
+// Sends to Window |w| the object |{type, param}|.
+function sendMessage(w, type, param) {
+ w.postMessage({"type": type, "param": param}, "*");
+}
+
+// Returns a |Promise| that gets resolved with the event object when |target|
+// receives an event of type |event_type|.
+function getEvent(event_type, target) {
+ return new Promise(resolve => {
+ target.addEventListener(event_type, e => resolve(e), {once: true});
+ });
+}
+
+// Adds a listener that is automatically removed at the end of the test.
+function addTestScopedListener(target, type, listener, test) {
+ target.addEventListener(type, listener);
+ test.add_cleanup(() => {
+ target.removeEventListener(type, listener);
+ });
+}
+
+// Returns a |Promise| that gets resolved with |event.data| when |window|
+// receives from |source| a "message" event whose |event.data.type| matches the string
+// |message_data_type|.
+function getMessageData(message_data_type, source) {
+ return new Promise(resolve => {
+ function waitAndRemove(e) {
+ if (e.source != source || !e.data || e.data.type != message_data_type)
+ return;
+ window.removeEventListener("message", waitAndRemove);
+ resolve(e.data);
+ }
+ window.addEventListener("message", waitAndRemove);
+ });
+}
diff --git a/testing/web-platform/tests/uievents/mouse/synthetic-mouse-enter-leave-over-out-button-state-after-target-removed.tentative.html b/testing/web-platform/tests/uievents/mouse/synthetic-mouse-enter-leave-over-out-button-state-after-target-removed.tentative.html
new file mode 100644
index 0000000000..fad82f850d
--- /dev/null
+++ b/testing/web-platform/tests/uievents/mouse/synthetic-mouse-enter-leave-over-out-button-state-after-target-removed.tentative.html
@@ -0,0 +1,240 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<meta name="variant" content="?buttonType=LEFT&button=0&buttons=1">
+<meta name="variant" content="?buttonType=MIDDLE&button=1&buttons=4">
+<title>Testing button state of synthesized mouse(out|over|leave|enter) events</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<style>
+#parent {
+ background-color: lightseagreen;
+ padding: 0;
+ height: 40px;
+ width: 40px;
+}
+#child {
+ background-color: red;
+ margin: 0;
+ height: 30px;
+ width: 30px;
+}
+</style>
+</head>
+<body>
+<div id="parent"><div id="child">abc</div></div>
+<script>
+const searchParams = new URLSearchParams(document.location.search);
+const buttonType = searchParams.get("buttonType");
+const button = parseInt(searchParams.get("button"));
+const buttons = parseInt(searchParams.get("buttons"));
+
+let events = [];
+function eventToString(data) {
+ if (!data) {
+ return "{}";
+ }
+ return `{ '${data.type}' on '${data.target}': button=${data.button}, buttons=${data.buttons} }`;
+}
+
+function eventsToString(events) {
+ if (!events.length) {
+ return "[]";
+ }
+ let ret = "[";
+ for (const data of events) {
+ if (ret != "[") {
+ ret += ", ";
+ }
+ ret += eventToString(data);
+ }
+ return ret + "]";
+}
+
+function removeEventsBefore(eventType) {
+ while (events[0]?.type != eventType) {
+ events.shift();
+ }
+}
+
+const parentElement = document.getElementById("parent");
+const childElement = document.getElementById("child");
+
+function promiseLayout() {
+ return new Promise(resolve => {
+ (childElement.isConnected ? childElement : parentElement).getBoundingClientRect();
+ requestAnimationFrame(() => requestAnimationFrame(resolve));
+ });
+}
+
+promise_test(async () => {
+ await new Promise(resolve => {
+ addEventListener("load", resolve, { once: true });
+ });
+
+ ["mouseout", "mouseover", "mouseleave", "mouseenter", "mousemove", "mousedown"].forEach(eventType => {
+ parentElement.addEventListener(eventType, event => {
+ if (event.target != parentElement) {
+ return;
+ }
+ events.push({
+ type: event.type,
+ target: "parent",
+ button: event.button,
+ buttons: event.buttons,
+ });
+ });
+ childElement.addEventListener(eventType, event => {
+ if (event.target != childElement) {
+ return;
+ }
+ events.push({
+ type: event.type,
+ target: "child",
+ button: event.button,
+ buttons: event.buttons,
+ });
+ });
+ });
+}, "Setup event listeners and wait for load");
+
+promise_test(async t => {
+ events = [];
+ await promiseLayout();
+ childElement.addEventListener("mousedown", () => childElement.remove(), {once: true});
+ const {x, y} = (function () {
+ const rect = childElement.getBoundingClientRect();
+ return { x: rect.left, y: rect.top };
+ })();
+ const actions = new test_driver.Actions();
+ await actions.pointerMove(10, 10, {origin: childElement})
+ .pointerDown({button: actions.ButtonType[buttonType]})
+ .pause(100) // Allow browsers to synthesize mouseout, etc
+ .pointerUp({button: actions.ButtonType[buttonType]})
+ .send();
+ await promiseLayout();
+ removeEventsBefore("mousedown");
+ test(() => {
+ const maybeMouseDownEvent =
+ events.length && events[0].type == "mousedown" ? events.shift() : undefined;
+ assert_equals(
+ eventToString(maybeMouseDownEvent),
+ eventToString({ type: "mousedown", target: "child", button, buttons })
+ );
+ }, `${t.name}: mousedown should've been fired`);
+ assert_true(events.length > 0, `${t.name}: Some events should've been fired after mousedown`);
+ test(() => {
+ // Before `mousedown` is fired, both parent and child must have received
+ // `mouseenter`, only the child must have received `mouseover`. Then, the
+ // child is now moved away by the `mousedown` listener. Therefore,
+ // `mouseout` and `mouseleave` should be fired on the child as the spec of
+ // UI Events defines. Then, they are not a button press events. Therefore,
+ // the `button` should be 0, but buttons should be set to 4 because of
+ // pressing the middle button.
+ let mouseOutOrLeave = [];
+ while (events[0]?.type == "mouseout" || events[0]?.type == "mouseleave") {
+ mouseOutOrLeave.push(events.shift());
+ }
+ assert_equals(
+ eventsToString(mouseOutOrLeave),
+ eventsToString([
+ { type: "mouseout", target: "child", button: 0, buttons },
+ { type: "mouseleave", target: "child", button: 0, buttons },
+ ])
+ );
+ }, `${t.name}: mouseout and mouseleave should've been fired on the removed child`);
+ test(() => {
+ // And `mouseover` should be fired on the parent as the spec of UI Events
+ // defines.
+ let mouseOver = [];
+ while (events[0]?.type == "mouseover") {
+ mouseOver.push(events.shift());
+ }
+ assert_equals(
+ eventsToString(mouseOver),
+ eventsToString([{ type: "mouseover", target: "parent", button: 0, buttons }])
+ );
+ }, `${t.name}: mouseover should've been fired on the parent`);
+ test(() => {
+ // On the other hand, it's unclear about `mouseenter`. The mouse cursor has
+ // never been moved out from the parent. Therefore, it shouldn't be fired
+ // on the parent ideally, but all browsers do not pass this test and there
+ // is no clear definition about this case.
+ let mouseEnter = [];
+ while (events.length && events[0].type == "mouseenter") {
+ mouseEnter.push(events.shift());
+ }
+ assert_equals(eventsToString(mouseEnter), eventsToString([]));
+ }, `${t.name}: mouseenter should not have been fired on the parent`);
+ assert_equals(eventsToString(events), eventsToString([]), "All events should've been checked");
+ parentElement.appendChild(childElement);
+}, "Removing an element at mousedown");
+
+promise_test(async t => {
+ events = [];
+ await promiseLayout();
+ childElement.addEventListener("mouseup", () => childElement.remove(), {once: true});
+ const {x, y} = (function () {
+ const rect = childElement.getBoundingClientRect();
+ return { x: rect.left, y: rect.top };
+ })();
+ const actions = new test_driver.Actions();
+ await actions.pointerMove(10, 10, {origin: childElement})
+ .pointerDown({button: actions.ButtonType[buttonType]})
+ .pointerUp({button: actions.ButtonType[buttonType]})
+ .send();
+ await promiseLayout();
+ removeEventsBefore("mousedown");
+ test(() => {
+ const maybeMouseDownEvent =
+ events.length && events[0].type == "mousedown" ? events.shift() : undefined;
+ assert_equals(
+ eventToString(maybeMouseDownEvent),
+ eventToString({ type: "mousedown", target: "child", button, buttons })
+ );
+ }, `${t.name}: mousedown should've been fired`);
+ assert_true(events.length > 0, `${t.name}: Some events should've been fired after mousedown`);
+ // Same as the `mousedown` case except `buttons` value because `mouseout`,
+ // `mouseleave`, `mouseover` and `mouseenter` should (or may) be fired
+ // after the `mouseup`. Therefore, `.buttons` should not have the button
+ // flag.
+ test(() => {
+ let mouseOutOrLeave = [];
+ while (events[0]?.type == "mouseout" || events[0]?.type == "mouseleave") {
+ mouseOutOrLeave.push(events.shift());
+ }
+ assert_equals(
+ eventsToString(mouseOutOrLeave),
+ eventsToString([
+ { type: "mouseout", target: "child", button: 0, buttons: 0 },
+ { type: "mouseleave", target: "child", button: 0, buttons: 0 },
+ ])
+ );
+ }, `${t.name}: mouseout and mouseleave should've been fired on the removed child`);
+ test(() => {
+ let mouseOver = [];
+ while (events[0]?.type == "mouseover") {
+ mouseOver.push(events.shift());
+ }
+ assert_equals(
+ eventsToString(mouseOver),
+ eventsToString([{ type: "mouseover", target: "parent", button: 0, buttons: 0 }])
+ );
+ }, `${t.name}: mouseover should've been fired on the parent`);
+ test(() => {
+ let mouseEnter = [];
+ while (events[0]?.type == "mouseenter") {
+ mouseEnter.push(events.shift());
+ }
+ assert_equals(eventsToString(mouseEnter), eventsToString([]));
+ }, `${t.name}: mouseenter should not have been fired on the parent`);
+ assert_equals(eventsToString(events), eventsToString([]), "All events should've been checked");
+ parentElement.appendChild(childElement);
+}, "Removing an element at mouseup");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/order-of-events/README.md b/testing/web-platform/tests/uievents/order-of-events/README.md
new file mode 100644
index 0000000000..a6ef35eb0b
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/README.md
@@ -0,0 +1,15 @@
+Order of events
+============================
+
+Testing of how events fire in relation to one another
+
+(this is the big work item)
+
+Expecting to need:
+ * braindead test (does it work at all?)
+ * specific functional tests
+ * specific edge cases
+
+Notes:
+ * small tests so that they can be given specific names for what's broken if it fails
+ * include a link to the corresponding test in the spec.
diff --git a/testing/web-platform/tests/uievents/order-of-events/focus-events/focus-automated-blink-webkit.html b/testing/web-platform/tests/uievents/order-of-events/focus-events/focus-automated-blink-webkit.html
new file mode 100644
index 0000000000..41de454136
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/focus-events/focus-automated-blink-webkit.html
@@ -0,0 +1,159 @@
+<!DOCTYPE html>
+<!-- Modified from Chris Rebert's manual version -->
+<!-- This documents the behavior according to blink's implementation -->
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Focus-related events should fire in the correct order</title>
+ <link rel="help" href="https://w3c.github.io/uievents/#events-focusevent-event-order">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body id="body">
+ <input type="text" id="a" value="First">
+ <input type="text" id="b" value="Second">
+ <br>
+ <input type="text" id="c" value="Third">
+ <iframe id="iframe">
+ </iframe>
+ <br>
+ <script>
+
+ var test_id = 0;
+ var tests = ['normal', 'iframe']
+
+ function record(evt) {
+ if (done && (evt.type == 'focusin' || evt.type == 'focus') && (evt.target == c)) {
+ startNext();
+ }
+ if (!done) {
+ var activeElement = document.activeElement ?
+ (document.activeElement.tagName === 'IFRAME' ?
+ document.activeElement.contentDocument.activeElement.id :
+ document.activeElement.id) : null;
+ events[tests[test_id]].push(evt.type);
+ targets[tests[test_id]].push(evt.target.id);
+ focusedElements[tests[test_id]].push(activeElement);
+ relatedTargets[tests[test_id]].push(evt.relatedTarget ? evt.relatedTarget.id : null);
+ }
+ }
+ function startNext() {
+ done = false;
+ test_id++;
+ }
+ function finish() {
+ done = true;
+ }
+ var relevantEvents = [
+ 'focus',
+ 'blur',
+ 'focusin',
+ 'focusout'
+ ];
+
+ var iframe = document.getElementById('iframe');
+ var a = document.getElementById('a');
+ var b = document.getElementById('b');
+ var c = document.getElementById('c');
+ var d = document.createElement('input');
+
+ d.setAttribute('id', 'd');
+ d.setAttribute('type', 'text');
+ d.setAttribute('value', 'Fourth');
+
+ var events = {'normal': [], 'iframe': []};
+ var targets = {'normal': [], 'iframe': []};
+ var focusedElements = {'normal': [], 'iframe': []};
+ var relatedTargets = {'normal': [], 'iframe': []};
+ var done = false;
+
+ var async_test_normal = async_test('Focus-related events should fire in the correct order (same DocumentOwner)');
+ var async_test_iframe_static = async_test('Focus-related events should fire in the correct order (different DocumentOwner)');
+
+ window.onload = function(evt) {
+
+ iframe.contentDocument.body.appendChild(d);
+
+ var inputs = [a, b, c, d];
+
+ for (var i = 0; i < inputs.length; i++) {
+ for (var k = 0; k < relevantEvents.length; k++) {
+ inputs[i].addEventListener(relevantEvents[k], record, false);
+ }
+ }
+
+ a.addEventListener('focusin', function() { b.focus(); }, false);
+ b.addEventListener('focusin', function() {
+ async_test_normal.step( function() {
+ assert_array_equals(
+ events['normal'],
+ ['focus', 'focusin', 'blur', 'focusout', 'focus', 'focusin'],
+ 'Focus-related events should fire in this order: focusin, focus, focusout, focusin, blur, focus'
+ );
+
+ assert_array_equals(
+ targets['normal'],
+ [ 'a', 'a', 'a', 'a', 'b', 'b'],
+ 'Focus-related events should fire at the correct targets'
+ );
+
+ assert_array_equals(
+ relatedTargets['normal'],
+ [ null, null, 'b', 'b', 'a', 'a'],
+ 'Focus-related events should reference correct relatedTargets'
+ );
+
+ assert_array_equals(
+ focusedElements['normal'],
+ [ 'a', 'a', 'body', 'body', 'b', 'b'],
+ 'Focus-related events should fire at the correct time relative to actual focus changes'
+ );
+
+ async_test_normal.done();
+ });
+
+ b.addEventListener('focusout', function() { finish(); c.focus(); });
+ b.blur();
+
+ }, false);
+
+ c.addEventListener('focusin', function() {d.focus();});
+ d.addEventListener('focusin', function() {
+ async_test_iframe_static.step(function() {
+ assert_array_equals(
+ events['iframe'],
+ ['focus', 'focusin', 'blur', 'focusout', 'focus', 'focusin'],
+ 'Focus-related events should fire in this order: focusin, focus, focusout, focusin, blur, focus'
+ );
+
+ assert_array_equals(
+ targets['iframe'],
+ [ 'c', 'c', 'c', 'c', 'd', 'd'],
+ 'Focus-related events should fire at the correct targets'
+ );
+
+ assert_array_equals(
+ relatedTargets['iframe'],
+ [ null, null, null, null, null, null],
+ 'Focus-related events should reference correct relatedTargets'
+ );
+
+ assert_array_equals(
+ focusedElements['iframe'],
+ [ 'c', 'c', 'body', 'body', 'd', 'd'],
+ 'Focus-related events should fire at the correct time relative to actual focus changes'
+ );
+
+ async_test_iframe_static.done();
+ });
+
+ d.addEventListener('focusout', function() { finish();});
+
+ }, false);
+
+ a.focus();
+ }
+
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/order-of-events/focus-events/focus-contained.html b/testing/web-platform/tests/uievents/order-of-events/focus-events/focus-contained.html
new file mode 100644
index 0000000000..8df612c108
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/focus-events/focus-contained.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Focus-related events should fire in the correct order</title>
+ <link rel="help" href="https://w3c.github.io/uievents/#events-focusevent-event-order">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="/uievents/resources/eventrecorder.js"></script>
+</head>
+
+<body>
+ <ol>
+ <li>Click into the text input.</li>
+ <li>Click just below the text input.</li>
+ <li>Click into the text input again.</li>
+ <li>Click the "Done" button.</li>
+ </ol>
+ <div id="a" tabindex="1" style="width:400px; height:300px">
+ <br /><br /><br />
+ <input type="text", id="b"></div>
+ </div>
+ <button type="button" id="done">Done</button>
+</body>
+
+<script>
+setup({explicit_timeout: true});
+function stopPropagation(e) {
+ e.stopPropagation();
+}
+var relevantEvents = [
+ "focus",
+ "blur",
+ "focusin",
+ "focusout"
+];
+window.onload = async function () {
+ var a = document.getElementById("a");
+ var b = document.getElementById("b");
+ var button = document.getElementById("done");
+ var inputs = [a, b];
+ EventRecorder.configure({
+ objectMap: {
+ "a": a,
+ "b": b,
+ }
+ });
+
+ EventRecorder.addEventListenersForNodes(relevantEvents, inputs, stopPropagation);
+ var expected = [
+ {type: "focus", target: "b"},
+ {type: "focusin", target: "b"},
+ {type: "blur", target: "b"},
+ {type: "focusout", target: "b"},
+ {type: "focus", target: "a"},
+ {type: "focusin", target: "a"},
+ {type: "blur", target: "a"},
+ {type: "focusout", target: "a"},
+ {type: "focus", target: "b"},
+ {type: "focusin", target: "b"},
+ {type: "blur", target: "b"},
+ {type: "focusout", target: "b"}
+ ];
+
+ async_test(function(t) {
+ button.addEventListener("click", function () {
+ t.step(function () {
+ assert_true(EventRecorder.checkRecords(expected));
+ t.done();
+ });
+ }, false);
+ }, "Focus-related events should fire in the correct order");
+ EventRecorder.start();
+
+ await new test_driver.Actions()
+ .pointerMove(0, 0, {origin: b})
+ .pointerDown()
+ .pointerUp()
+ .pointerMove(0, 0, {origin: a})
+ .pointerDown()
+ .pointerUp()
+ .pointerMove(0, 0, {origin: b})
+ .pointerDown()
+ .pointerUp()
+ .pointerMove(0, 0, {origin: button})
+ .pointerDown()
+ .pointerUp()
+ .send();
+};
+</script>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/order-of-events/focus-events/focus-management-expectations.html b/testing/web-platform/tests/uievents/order-of-events/focus-events/focus-management-expectations.html
new file mode 100644
index 0000000000..1845c15d71
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/focus-events/focus-management-expectations.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <meta charset="utf-8">
+ <title>Focus management event expectations</title>
+ <link rel="author" title="Mu-An Chiou" href="https://muan.co">
+ <link rel="help" href="https://w3c.github.io/uievents/#event-flow-activation">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+</head>
+
+<body>
+ <button type="button" id="fromEl">Focus management from button</button>
+ <button type="button" id="toEl">To button</button>
+ <button type="button" id="EndTestEl">End test button</button>
+</body>
+
+<script>
+ const from = document.getElementById("fromEl")
+ const to = document.getElementById("toEl")
+ const endTest = document.getElementById("EndTestEl")
+
+ from.addEventListener("keydown", function (event) {
+ if (event.key === " ") to.focus()
+ })
+
+ async_test(function (t) {
+ let buttonFocused = false
+ to.addEventListener("click", t.unreached_func("Button should not be clicked"))
+ to.addEventListener("focus", () => buttonFocused = true)
+ endTest.addEventListener('click', () => {
+ assert_true(buttonFocused, "Button should be focused")
+ t.step_timeout(() => t.done(), 200)
+ })
+
+ // execute test
+ from.focus()
+ new test_driver.Actions().keyDown("\ue00d").keyUp("\ue00d").send().then(() =>
+ new test_driver.click(endTest)
+ )
+ }, "Keydown to focus should not trigger activation")
+</script>
+
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/order-of-events/focus-events/focus.html b/testing/web-platform/tests/uievents/order-of-events/focus-events/focus.html
new file mode 100644
index 0000000000..7942674a70
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/focus-events/focus.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Focus-related events should fire in the correct order</title>
+ <link rel="author" title="Chris Rebert" href="http://chrisrebert.com">
+ <link rel="help" href="https://w3c.github.io/uievents/#events-focusevent-event-order">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/uievents/resources/eventrecorder.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+</head>
+
+<body>
+ <ol>
+ <li>Click into the first text input.</li>
+ <li>Click into the second text input.</li>
+ <li>Click the "Done" button.</li>
+ </ol>
+ <input type="text" id="a" value="First">
+ <br>
+ <input type="text" id="b" value="Second">
+ <br>
+ <button type="button" id="done">Done</button>
+</body>
+
+<script>
+setup({explicit_timeout: true});
+function stopPropagation(e) {
+ if (event.type == "focusin" || event.type == "focusout")
+ assert_true(event.bubbles);
+ e.stopPropagation();
+}
+var relevantEvents = [
+ "focus",
+ "blur",
+ "focusin",
+ "focusout"
+];
+window.onload = function () {
+ var a = document.getElementById("a");
+ var b = document.getElementById("b");
+ var button = document.getElementById("done");
+ var inputs = [a, b];
+ var actions_promise;
+ EventRecorder.configure({
+ objectMap: {
+ "a": a,
+ "b": b,
+ }
+ });
+
+ EventRecorder.addEventListenersForNodes(relevantEvents, inputs, stopPropagation);
+ var expected = [
+ {type: "focus", target: "a"},
+ {type: "focusin", target: "a"},
+ {type: "blur", target: "a"},
+ {type: "focusout", target: "a"},
+ {type: "focus", target: "b"},
+ {type: "focusin", target: "b"},
+ {type: "blur", target: "b"},
+ {type: "focusout", target: "b"}
+ ];
+
+ async_test(function(t) {
+ button.addEventListener("click", function () {
+ t.step(function () {
+ assert_true(EventRecorder.checkRecords(expected));
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ t.done();
+ });
+ });
+ }, false);
+ }, "Focus-related events should fire in the correct order");
+ EventRecorder.start();
+
+ // Inject mouse inputs.
+ actions_promise = new test_driver.Actions()
+ .pointerMove(0, 0, {origin: a})
+ .pointerDown()
+ .pointerUp()
+ .pointerMove(0, 0, {origin: b})
+ .pointerDown()
+ .pointerUp()
+ .pointerMove(0, 0, {origin: button})
+ .pointerDown()
+ .pointerUp()
+ .send();
+};
+</script>
+</html>
diff --git a/testing/web-platform/tests/uievents/order-of-events/focus-events/legacy-manual.html b/testing/web-platform/tests/uievents/order-of-events/focus-events/legacy-manual.html
new file mode 100644
index 0000000000..e71273973e
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/focus-events/legacy-manual.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Focus-related events (including legacy events) should fire in the correct order</title>
+ <link rel="author" title="Chris Rebert" href="http://chrisrebert.com">
+ <link rel="help" href="https://w3c.github.io/uievents/#legacy-focusevent-event-order">
+ <meta name="flags" content="interact">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <ol>
+ <li>Click into the first text input.</li>
+ <li>Click into the second text input.</li>
+ <li>Click the "Done" button.</li>
+ </ol>
+
+ <input type="text" id="a" value="First">
+ <br>
+ <input type="text" id="b" value="Second">
+ <br>
+ <button type="button" id="done">Done</button>
+
+ <script>
+setup({explicit_timeout: true});
+var done = false;
+var events = [];
+var targets = [];
+function record(e) {
+ if (done) {
+ return;
+ }
+ events.push(e.type);
+ targets.push(e.target.id);
+}
+function finish() {
+ done = true;
+}
+var relevantEvents = [
+ 'focus',
+ 'blur',
+ 'focusin',
+ 'focusout',
+ 'DOMFocusIn',
+ 'DOMFocusOut'
+];
+window.onload = function () {
+ var a = document.getElementById('a');
+ var b = document.getElementById('b');
+ var inputs = [a, b];
+
+ b.addEventListener('blur', finish, false);
+ b.addEventListener('focusout', finish, false);
+ b.addEventListener('DOMFocusOut', finish, false);
+
+ for (var i = 0; i < inputs.length; i++) {
+ for (var k = 0; k < relevantEvents.length; k++) {
+ inputs[i].addEventListener(relevantEvents[k], record, false);
+ }
+ }
+
+ async_test(function(t) {
+ document.getElementById('done').addEventListener('click', function () {
+ finish();
+ t.step(function () {
+ assert_array_equals(
+ events,
+ ['focusin', 'focus', 'DOMFocusIn', 'focusout', 'focusin', 'blur', 'DOMFocusOut', 'focus', 'DOMFocusIn'],
+ 'Focus-related events should fire in this order: focusin, focus, DOMFocusIn, focusout, focusin, blur, DOMFocusOut, focus, DOMFocusIn'
+ );
+ assert_array_equals(
+ targets,
+ [ 'a', 'a', 'a', 'a', 'b', 'a', 'a', 'b', 'b'],
+ 'Focus-related events should fire at the correct targets'
+ );
+ t.done();
+ });
+ }, false);
+ }, 'Focus-related events should fire in the correct order');
+};
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-cancel.html b/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-cancel.html
new file mode 100644
index 0000000000..082c2a0cc3
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-cancel.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Default action is canceled if the click event is canceled.</title>
+ <link rel="help" href="https://w3c.github.io/uievents/#events-clickevent-event-order">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ </head>
+ <body>
+ <input type="checkbox" id="checkbox">Check me!<br>
+ <button type="button" id="button">Button</button>
+ <script>
+async_test(function(t) {
+ var box_clicked = false;
+
+ var box = document.getElementById("checkbox");
+ box.addEventListener("click", function(event) {
+ box_clicked = true;
+ event.preventDefault();
+ });
+
+ var button = document.getElementById("button");
+ button.addEventListener("click", t.step_func_done(function() {
+ assert_true(box_clicked);
+ assert_false(box.checked);
+ }));
+
+ test_driver.click(box).then(function() {
+ return test_driver.click(button);
+ }).catch(t.unreached_func("click failed"));
+});
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-body.html b/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-body.html
new file mode 100644
index 0000000000..45453c75ca
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-body.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Clicking on the body element itself fires a click event</title>
+ <link rel="author" title="Chris Rebert" href="http://chrisrebert.com">
+ <link rel="help" href="https://w3c.github.io/uievents/#event-type-click">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <style>
+html {
+ background-color: white;
+ margin: 0;
+}
+body {
+ background-color: blue;
+ margin: 0;
+}
+#guineapig {
+ background-color: white;
+ margin-bottom: 100px;/* Expose an area of the body element itself */
+}
+#other {
+ background-color: white;
+}
+ </style>
+ </head>
+ <body>
+ <p id="guineapig">Click on the blue area below.</p>
+ <p id="other">&nbsp;</p><!-- Needed to prevent the margin from collapsing -->
+ <script>
+setup({explicit_timeout: true});
+promise_test(async function(t) {
+ document.body.addEventListener('click', function (event) {
+ t.step(function () {
+ assert_equals(event.target, document.body, 'target of click event must be the body element');
+ assert_equals(event.eventPhase, Event.AT_TARGET, 'click event must propagate to the body element at the Target Phase');
+ var passed = event.target === document.body && event.eventPhase === Event.AT_TARGET;
+ document.body.style.backgroundColor = 'white';
+ var guineapig = document.getElementById('guineapig');
+ guineapig.style.marginBottom = '16px';
+ if (passed) {
+ guineapig.textContent = 'PASS';
+ guineapig.style.backgroundColor = 'green';
+ }
+ t.done();
+ });
+ }, false);
+
+ await test_driver.click(document.body);
+}, "Clicking on the body element itself should fire a click event targeted at the body element");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-div.html b/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-div.html
new file mode 100644
index 0000000000..bf06d8251c
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-div.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Clicking on a div element that has no click event handler fires a click event</title>
+ <link rel="author" title="Chris Rebert" href="http://chrisrebert.com">
+ <link rel="help" href="https://w3c.github.io/uievents/#event-type-click">
+ <link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <style>
+#square {
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+ color: white;
+ /* Center the "Click me" text */
+ line-height: 100px;
+ text-align: center;
+}
+ </style>
+ </head>
+ <body>
+ <p>Click on the blue square below.</p>
+ <div id="square">Click me</div>
+ <script>
+setup({explicit_timeout: true});
+promise_test(async function(t) {
+ document.addEventListener('click', function (event) {
+ var square = document.getElementById('square');
+ t.step(function () {
+ assert_equals(event.target, square, 'target of click event must be the test square');
+ assert_equals(event.eventPhase, Event.BUBBLING_PHASE, 'click event must propagate to the document object during the Bubbling Phase');
+ square.textContent = 'PASS';
+ square.style.backgroundColor = 'green';
+ t.done();
+ });
+ }, false);
+
+ await test_driver.click(square);
+}, "Clicking on a div element and having a click event listener on only document");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-html.html b/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-html.html
new file mode 100644
index 0000000000..e93acc6749
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-on-html.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Clicking on the html element itself fires a click event</title>
+ <link rel="author" title="Chris Rebert" href="http://chrisrebert.com">
+ <link rel="help" href="https://w3c.github.io/uievents/#event-type-click">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <style>
+html {
+ background-color: blue;
+ margin: 0;
+}
+body {
+ background-color: red;
+ height: 0;
+ margin: 0;
+}
+#guineapig {
+ background-color: white;
+ padding-top: 50px;/* Text is easier to see when it's not at the exact top of the viewport */
+ margin-top: 0;/* Ensure there's no exposed html element above this */
+ margin-bottom: 100px;/* Expose an area of the html element itself */
+}
+#other {
+ background-color: white;
+ height: 100vh;/* Push the rest of the html element outside of the viewport */
+}
+ </style>
+ </head>
+ <body>
+ <p id="guineapig">Click on the blue area below.</p>
+ <p id="other">&nbsp;</p><!-- Needed to prevent the margin from collapsing -->
+ <script>
+setup({explicit_timeout: true});
+promise_test(async function(t) {
+ document.documentElement.addEventListener('click', function (event) {
+ t.step(function () {
+ assert_equals(event.target, document.documentElement, 'target of click event must be the html element');
+ assert_equals(event.eventPhase, Event.AT_TARGET, 'click event must propagate to the html element at the Target Phase');
+ var passed = event.target === document.documentElement && event.eventPhase === Event.AT_TARGET;
+ document.documentElement.style.backgroundColor = 'white';
+ document.getElementById('other').style.height = 'auto';
+ var guineapig = document.getElementById('guineapig');
+ guineapig.style.marginBottom = '16px';
+ if (passed) {
+ guineapig.textContent = 'PASS';
+ guineapig.style.backgroundColor = 'green';
+ }
+ t.done();
+ });
+ }, false);
+
+ const xPositionInHtml = yPositionInHtml = 150;
+ await new test_driver.Actions()
+ .pointerMove(xPositionInHtml, yPositionInHtml)
+ .pointerDown()
+ .pointerUp()
+ .send();
+}, "Clicking on the html element itself should fire a click event targeted at the html element");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-order.html b/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-order.html
new file mode 100644
index 0000000000..1285a31efc
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/mouse-events/click-order.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Click-related events should fire in the correct order</title>
+ <link rel="help" href="https://w3c.github.io/uievents/#events-clickevent-event-order">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="/uievents/resources/eventrecorder.js"></script>
+ </head>
+ <body>
+ <ol>
+ <li>Double-click into the blue area.</li>
+ <li>Click the "Done" button.</li>
+ </ol>
+ <div id="blue" style="width:400px; height:300px; background-color: blue;"></div>
+ <button type="button" id="done">Done</button>
+</body>
+<script>
+setup({explicit_timeout: true});
+
+function bubbles(e) {
+ assert_true(e.bubbles);
+}
+
+var relevantEvents = [
+ "mousedown",
+ "mouseup",
+ "mousemove",
+ "click",
+ "dblclick"
+];
+
+window.onload = async function () {
+ var blue = document.getElementById("blue");
+ var button = document.getElementById("done");
+ var inputs = [blue];
+ EventRecorder.configure({
+ mergeEventTypes: ["mousemove"],
+ objectMap: {
+ "blue": blue
+ }
+ });
+
+ EventRecorder.addEventListenersForNodes(relevantEvents, inputs, bubbles);
+ var expected = [
+ {type: "mousemove", target: "blue", optional: true},
+ {type: "mousedown", target: "blue"},
+ {type: "mousemove", target: "blue", optional: true},
+ {type: "mouseup", target: "blue"},
+ {type: "click", target: "blue"},
+ {type: "mousemove", target: "blue", optional: true},
+ {type: "mousedown", target: "blue"},
+ {type: "mousemove", target: "blue", optional: true},
+ {type: "mouseup", target: "blue"},
+ {type: "click", target: "blue"},
+ {type: "dblclick", target: "blue"},
+ {type: "mousemove", target: "blue", optional: true}
+ ];
+
+ async_test(function(t) {
+ button.addEventListener("click", function () {
+ t.step(function () {
+ assert_true(EventRecorder.checkRecords(expected));
+ t.done();
+ });
+ }, false);
+ }, "Click-related events should fire in the correct order");
+ EventRecorder.start();
+
+ await new test_driver.Actions()
+ .pointerMove(0, 0, {origin: blue})
+ .pointerDown()
+ .pointerUp()
+ .pointerDown()
+ .pointerUp()
+ .pointerMove(0, 0, {origin: button})
+ .pointerDown()
+ .pointerUp()
+ .send();
+};
+ </script>
+</html>
diff --git a/testing/web-platform/tests/uievents/order-of-events/mouse-events/mouseevents-mousemove.htm b/testing/web-platform/tests/uievents/order-of-events/mouse-events/mouseevents-mousemove.htm
new file mode 100644
index 0000000000..98a35bbcf6
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/mouse-events/mouseevents-mousemove.htm
@@ -0,0 +1,92 @@
+<!doctype html>
+ <head>
+ <meta charset=utf-8>
+ <title>MouseEvent - mousemove event order</title>
+ <style>
+ .testarea { margin: auto; width: 80%; height: 250px; border: 1px solid grey; position: relative; }
+
+ #start,#end { background-color: red; border: 1px solid black; margin: 0; padding: 0; }
+ /* start/end layout */
+ #start.green,#end.green { background-color: green; }
+ #start { position: absolute; left: 15%; top: 15%; width: 50%; height: 50%; }
+ #end { position: absolute; right: 15%; bottom: 15%; width: 50%; height: 50%; }
+ </style>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script>
+ setup({explicit_timeout: true});
+ </script>
+ <script src="/uievents/resources/eventrecorder.js"></script>
+ </head>
+ <body>
+ <p><strong>Description</strong>: Verifies that mousemove events track the pointer position and transition from top-most
+ visible element to top-most visible element, changing targets
+ in the DOM along the way.</p>
+
+ <p><strong>Instructions</strong>: </p>
+ <ol>
+ <li>Move the pointer to the upper-left red box and then move it directly toward and into the lower-right red box.
+ </ol>
+ <p><strong>Test Passes</strong> if both boxes turn green and the word 'PASS' appears below</p>
+
+ <section class="testarea">
+ <div id="end"></div>
+ <div id="start"></div>
+ </section>
+
+ <script>
+ var mouse_test = async_test("Mousemove events");
+ var start = document.getElementById("start");
+ var end = document.getElementById("end");
+ var actions_promise;
+
+ EventRecorder.configure({
+ mergeEventTypes: ["mousemove"],
+ objectMap: {
+ "div#start": start,
+ "div#end": end
+ }
+ });
+
+
+ start.addRecordedEventListener('mousemove', function (e) {
+ e.stopPropagation();
+ this.className = "green";
+ });
+
+ end.addRecordedEventListener('mousemove', function (e) {
+ e.stopPropagation();
+ this.className = "green";
+ endTest();
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => mouse_test.done() );
+ });
+
+ function endTest() {
+ EventRecorder.stop();
+ var results = EventRecorder.getRecords();
+ // Check results:
+ mouse_test.step(function () {
+ assert_equals(results.length, 2, "Two mousemove events");
+ assert_equals(results[0].event.type, "mousemove", "First event is a mousemove event");
+ assert_equals(results[1].event.type, "mousemove", "Second event is a mousemove event");
+ assert_equals(results[0].event.target, "div#start", "First event targetted #start");
+ assert_equals(results[1].event.target, "div#end", "Second event targetted #end");
+ });
+ }
+
+ EventRecorder.start();
+
+ var rect = start.getClientRects()[0];
+ // Inject mouse inputs.
+ actions_promise = new test_driver.Actions()
+ .pointerMove(0, 0, {origin: start})
+ .pointerMove(Math.round(rect.width/2) + 10,
+ Math.round(rect.height/2) + 10, {origin: start})
+ .send();
+ </script>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/order-of-events/mouse-events/mousemove-across.html b/testing/web-platform/tests/uievents/order-of-events/mouse-events/mousemove-across.html
new file mode 100644
index 0000000000..52d5a93cf9
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/mouse-events/mousemove-across.html
@@ -0,0 +1,162 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Mousemove handling across elements</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/uievents/resources/eventrecorder.js"></script>
+<style>
+#a {
+ background: red;
+ height: 120px;
+ width: 200px;
+}
+#b {
+ margin: 100px;
+ height: 120px;
+ width: 200px;
+ background: green;
+}
+#c {
+ height: 120px;
+ width: 200px;
+ background: yellow;
+}
+
+#a1 {
+ background: blue;
+ height: 120px;
+ width: 200px;
+}
+#b1 {
+ padding: 1px;
+ margin: 100px;
+ height: 120px;
+ width: 200px;
+ background: green;
+}
+#c1 {
+ height: 120px;
+ width: 200px;
+ background: black;
+}
+</style>
+<p>
+ Steps:
+ <ol>
+ <li>Move your mouse across the yellow/red <code>&lt;div&gt;</code> element quickly from right to left.
+ <li>Move your mouse across the black/blue <code>&lt;div&gt;</code> element quickly from right to left.
+ <li>If the test fails, redo it again and move faster on the black/blue <code>&lt;div&gt;</code> element next time.
+ </ol>
+</p>
+
+<div id="c">
+ <div id="b">
+ <div id="a" align="center"></div>
+ </div>
+</div>
+<br />
+<div id="c1">
+ <div id="b1">
+ <div id="a1" align="center"></div>
+ </div>
+</div>
+
+<script>
+setup({explicit_timeout: true});
+var relevantEvents = [
+ "mousemove",
+ "mouseover",
+ "mouseenter",
+ "mouseout",
+ "mouseleave"
+];
+
+function stopPropagation(e) {
+ event.stopPropagation();
+}
+
+window.onload = async function() {
+ var a = document.getElementById("a");
+ var b = document.getElementById("b");
+ var c = document.getElementById("c");
+ var a1 = document.getElementById("a1");
+ var b1 = document.getElementById("b1");
+ var c1 = document.getElementById("c1");
+ var inputs = [a, b, c, a1, b1, c1];
+ EventRecorder.configure({
+ mergeEventTypes: ["mousemove"],
+ objectMap: {
+ "a": a,
+ "b": b,
+ "c": c,
+ "a1": a1,
+ "b1": b1,
+ "c1": c1
+ }
+ });
+ EventRecorder.addEventListenersForNodes(relevantEvents, inputs, stopPropagation);
+ var expected = [
+ {type: "mouseover", target: "a"},
+ {type: "mouseenter", target: "c"},
+ {type: "mouseenter", target: "b"},
+ {type: "mouseenter", target: "a"},
+ {type: "mousemove", target: "a", optional: true},
+ {type: "mouseout", target: "a"},
+ {type: "mouseleave", target: "a"},
+ {type: "mouseleave", target: "b"},
+ {type: "mouseover", target: "c"},
+ {type: "mousemove", target: "c", optional: true},
+ {type: "mouseout", target: "c"},
+ {type: "mouseleave", target: "c"},
+ {type: "mouseover", target: "a1"},
+ {type: "mouseenter", target: "c1"},
+ {type: "mouseenter", target: "b1"},
+ {type: "mouseenter", target: "a1"},
+ {type: "mousemove", target: "a1", optional: true},
+ {type: "mouseout", target: "a1"},
+ {type: "mouseleave", target: "a1"},
+ {type: "mouseleave", target: "b1"},
+ {type: "mouseover", target: "c1"},
+ {type: "mousemove", target: "c1", optional: true},
+ {type: "mouseout", target: "c1"},
+ {type: "mouseleave", target: "c1"},
+ ];
+ async_test(function(t) {
+ c1.addEventListener("mouseleave", function() {
+ t.step(function() {
+ assert_true(EventRecorder.checkRecords(expected));
+ t.done();
+ });
+ }, false);
+ }, "Mousemove events across elements should fire in the correct order.");
+ EventRecorder.start();
+
+ var a_rect = a.getClientRects()[0];
+ var c_rect = c.getClientRects()[0];
+ var center_a_x = Math.round((a_rect.left + a_rect.right) / 2);
+ var center_a_y = Math.round((a_rect.top + a_rect.bottom) / 2);
+
+ var a1_rect = a1.getClientRects()[0];
+ var c1_rect = c1.getClientRects()[0];
+ var center_a1_x = Math.round((a1_rect.left + a1_rect.right) / 2);
+ var center_a1_y = Math.round((a1_rect.top + a1_rect.bottom) / 2);
+ // Inject mouse inputs.
+ await new test_driver.Actions()
+ .pointerMove(a_rect.right + 20, center_a_y)
+ .pointerMove(center_a_x, center_a_y)
+ .pointerMove(a_rect.left + 20, center_a_y)
+ .pointerMove(a_rect.left - 20, center_a_y)
+ .pointerMove(c_rect.left + 20, center_a_y)
+ .pointerMove(0, center_a_y)
+ .pointerMove(a1_rect.right + 20, center_a1_y)
+ .pointerMove(center_a1_x, center_a1_y)
+ .pointerMove(a1_rect.left + 20, center_a1_y)
+ .pointerMove(a1_rect.left - 20, center_a1_y)
+ .pointerMove(c1_rect.left + 20, center_a1_y)
+ .pointerMove(0, center_a1_y)
+ .send();
+};
+</script>
diff --git a/testing/web-platform/tests/uievents/order-of-events/mouse-events/mousemove-between.html b/testing/web-platform/tests/uievents/order-of-events/mouse-events/mousemove-between.html
new file mode 100644
index 0000000000..f9c422cc93
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/mouse-events/mousemove-between.html
@@ -0,0 +1,132 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Mousemove handling between elements</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/uievents/resources/eventrecorder.js"></script>
+<style>
+#a {
+ height: 120px;
+ width: 200px;
+ background: blue;
+ display: flex;
+ justify-content: center;
+}
+#b {
+ height: 60px;
+ width: 100px;
+ margin: auto;
+ background: green;
+}
+#c {
+ height: 120px;
+ width: 200px;
+ background: yellow;
+}
+</style>
+<p>
+ Steps:
+
+ <ol>
+ <li>Move your mouse over the blue <code>&lt;div&gt;</code> element, later
+ over the green one, later back to the blue one.
+ <li>Move the mouse from the blue element to the yellow one, later to the
+ white background.
+ </ol>
+</p>
+
+
+<div id="a">
+ <div id="b" align="center"></div>
+</div>
+<div id="c"></div>
+
+<script>
+setup({explicit_timeout: true});
+
+var relevantEvents = [
+ "mousemove",
+ "mouseover",
+ "mouseenter",
+ "mouseout",
+ "mouseleave"
+];
+
+function stopPropagation(e) {
+ if (e.type != "mouseenter" && e.type != "mouseleave")
+ assert_true(e.bubbles);
+ event.stopPropagation();
+}
+
+window.onload = async function() {
+ var a = document.getElementById("a");
+ var b = document.getElementById("b");
+ var c = document.getElementById("c");
+ var inputs = [a, b, c];
+ EventRecorder.configure({
+ mergeEventTypes: ["mousemove"],
+ objectMap: {
+ "a": a,
+ "b": b,
+ "c": c
+ }
+ });
+ EventRecorder.addEventListenersForNodes(relevantEvents, inputs, stopPropagation);
+ var expected = [
+ {type: "mouseover", target: "a"},
+ {type: "mouseenter", target: "a"},
+ {type: "mousemove", target: "a", optional: true},
+ {type: "mouseout", target: "a"},
+ {type: "mouseover", target: "b"},
+ {type: "mouseenter", target: "b"},
+ {type: "mousemove", target: "b", optional: true},
+ {type: "mouseout", target: "b"},
+ {type: "mouseleave", target: "b"},
+ {type: "mouseover", target: "a"},
+ {type: "mousemove", target: "a", optional: true},
+ {type: "mouseout", target: "a"},
+ {type: "mouseleave", target: "a"},
+ {type: "mouseover", target: "c"},
+ {type: "mouseenter", target: "c"},
+ {type: "mousemove", target: "c", optional: true},
+ {type: "mouseout", target: "c"},
+ {type: "mouseleave", target: "c"}
+ ];
+ async_test(function(t) {
+ c.addEventListener("mouseleave", function() {
+ EventRecorder.stop();
+ t.step(function() {
+ assert_true(EventRecorder.checkRecords(expected));
+ t.done();
+ });
+ }, false);
+ }, "Mousemove events between elements should fire in the correct order.");
+ EventRecorder.start();
+
+ var a_rect = a.getClientRects()[0];
+ var b_rect = b.getClientRects()[0];
+ var c_rect = c.getClientRects()[0];
+ var center_b_y = Math.round((b_rect.top + b_rect.bottom) / 2);
+ var center_c_y = Math.round((c_rect.top + c_rect.bottom) / 2);
+
+ // Inject mouse inputs.
+ await new test_driver.Actions()
+ .pointerMove(b_rect.right + 10, center_b_y)
+ .pause(50)
+ .pointerMove(0, 0, {origin: b})
+ .pause(50)
+ .pointerMove(b_rect.right + 10, center_b_y)
+ .pause(50)
+ .pointerMove(a_rect.right + 10, center_b_y)
+ .pause(50)
+ .pointerMove(c_rect.right + 10, center_c_y)
+ .pause(50)
+ .pointerMove(0, 0, {origin: c})
+ .pause(50)
+ .pointerMove(c_rect.right + 20, c_rect.bottom + 20)
+ .send();
+};
+</script>
diff --git a/testing/web-platform/tests/uievents/order-of-events/mouse-events/mouseover-out.html b/testing/web-platform/tests/uievents/order-of-events/mouse-events/mouseover-out.html
new file mode 100644
index 0000000000..f10518c7f1
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/mouse-events/mouseover-out.html
@@ -0,0 +1,141 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Mouseover/mouseout handling</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<style>
+#outer,
+#inner,
+#released {
+ padding: 10px;
+ margin: 10px;
+ height: 15px;
+}
+
+#outer:hover,
+#inner:hover,
+#released:hover {
+ background: red;
+}
+
+#outer {
+ background: blue;
+}
+
+#inner {
+ background: green;
+}
+
+#released {
+ background: yellow;
+}
+</style>
+<p>
+ Steps:
+
+ <ol>
+ <li>Move your mouse over the blue <code>&lt;div&gt;</code> element, later
+ over the green one, later over the yellow one.
+ <li>Move the mouse from the yellow element to the green one, later to the
+ blue one, and later over this paragraph.
+ </ol>
+</p>
+
+
+<div id="outer">
+ <div id="inner"></div>
+</div>
+<div id="released"></div>
+
+<div id="log"></div>
+
+<script>
+var t = async_test("Mouseover/out events");
+var outer = document.getElementById("outer");
+var inner = document.getElementById("inner");
+var actions_promise;
+
+var inner_over = 0;
+var inner_out = 0;
+
+var outer_own_over = 0;
+var outer_own_out = 0;
+var outer_over = 0;
+var outer_out = 0;
+
+inner.addEventListener("mouseover", t.step_func(function(e) {
+ assert_equals(inner_over, inner_out, "mouseover is received before mouseout");
+
+ switch (inner_over) {
+ case 0:
+ assert_equals(outer_own_over, 1, "should have triggered a mouseover in the outer before");
+ break;
+ case 1:
+ assert_equals(outer_own_over, 1, "should have not triggered a mouseover in the outer before");
+ break;
+ default:
+ assert_true(false, "should not get more than two mouseovers");
+ }
+
+ inner_over++;
+}), false);
+
+inner.addEventListener("mouseout", t.step_func(function(e) {
+ assert_equals(inner_over, inner_out + 1, "mouseout is received after mouseover");
+
+ switch (inner_out) {
+ case 0:
+ assert_equals(outer_own_out, 1, "mouseout should have been received in the parent when hovering over this element");
+ break;
+ case 1:
+ break;
+ default:
+ assert_true(false, "should not get more than two mouseouts");
+ }
+
+ inner_out++;
+}), false);
+
+outer.addEventListener("mouseover", t.step_func(function(e) {
+ if (e.target == outer) {
+ assert_equals(outer_own_over, outer_own_out, "outer: mouseover is received before mouseout");
+ outer_own_over++;
+ } else {
+ assert_equals(outer_over - outer_own_over, inner_over - 1, "mouseover: should only receive this via bubbling");
+ }
+
+ outer_over++;
+}), false);
+
+outer.addEventListener('mouseout', t.step_func(function(e) {
+ if (e.target == outer) {
+ assert_equals(outer_own_over, outer_own_out + 1, "outer: mouseout is received after mouseover");
+ if (outer_own_out == 1) {
+ assert_equals(inner_out, 2, "inner should be done now");
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ t.done();
+ });
+ }
+
+ outer_own_out++;
+ } else {
+ assert_equals(outer_out - outer_own_out, inner_out - 1, "mouseout: should only receive this via bubbling");
+ }
+
+ outer_out++;
+}), false);
+
+// Inject mouse inputs.
+actions_promise = new test_driver.Actions()
+ .pointerMove(0, 0, {origin: outer})
+ .pointerMove(0, 0, {origin: inner})
+ .pointerMove(0, 0, {origin: released})
+ .pointerMove(0, 0, {origin: inner})
+ .pointerMove(0, 0, {origin: outer})
+ .pointerMove(0, 0)
+ .send();
+</script>
diff --git a/testing/web-platform/tests/uievents/order-of-events/mouse-events/wheel-basic.html b/testing/web-platform/tests/uievents/order-of-events/mouse-events/wheel-basic.html
new file mode 100644
index 0000000000..1a43022d29
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/mouse-events/wheel-basic.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<head>
+ <meta charset=utf-8>
+ <title>WheelEvent - basic wheel event</title>
+ <style>
+ .testarea{ margin: auto; width: 800px; height: 250px; border: 1px solid grey; position: relative; }
+
+ #wheelbox, #scrollbox { background-color: red; border: 1px solid black; margin: 0; padding: 0; }
+ #wheelbox.green, #scrollbox.green { background-color: green; }
+ #wheelbox { position: absolute; left: 15%; top: 15%; width: 50%; height: 50% }
+ #scrollbox { position: absolute; right: 15%; bottom: 15%; width: 50%; height: 50% }
+ </style>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script>
+ setup({explicit_timeout: true});
+ </script>
+ <script src="/uievents/resources/eventrecorder.js"></script>
+</head>
+
+<body>
+ <p><strong>Description</strong>: Verifies that wheel events are captured and sent</p>
+ <p><strong>Instructions</strong>: </p>
+ <ol>
+ <li>Place your mouse pointer over the top box</li>
+ <li>Scroll the mouse wheel to change the box color</li>
+ <li>Move the mouse pointer to the second box</li>
+ <li>Scroll the mouse wheel again to change this box's color</li>
+ </ol>
+ <p><strong>Test Passes</strong> if the box turns green and the word 'PASS' appears below</p>
+
+ <section class="testarea">
+ <div id="scrollbox"></div>
+ <div id="wheelbox"></div>
+ </section>
+
+ <script>
+ var wheelbox = document.getElementById("wheelbox");
+ var scrollbox = document.getElementById("scrollbox");
+ var test_wheel = async_test("wheel event test");
+ var actions_promise;
+
+ EventRecorder.configure({
+ mergeEventTypes: ['wheel'],
+ objectMap: {
+ "div#wheelbox": wheelbox,
+ "div#scrollbox": scrollbox
+ }
+ });
+
+ wheelbox.addRecordedEventListener('wheel', function (e) {
+ e.stopPropagation();
+ this.className = "green";
+ });
+
+ scrollbox.addRecordedEventListener('wheel', function (e) {
+ e.stopPropagation();
+ this.className = "green";
+ endTest();
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ test_wheel.done();
+ });
+ });
+
+ function endTest() {
+ EventRecorder.stop();
+ var results = EventRecorder.getRecords();
+ test_wheel.step(function () {
+ // Check results:
+ assert_equals(results.length, 2, "Two mousemove events");
+ assert_equals(results[0].event.type, 'wheel', "First event is a wheel event");
+ assert_equals(results[1].event.type, 'wheel', "Second event is a wheel event");
+ assert_equals(results[0].event.target, 'div#wheelbox', "First event targetted wheelbox");
+ assert_equals(results[1].event.target, 'div#scrollbox', "Second event targetted scrollbox");
+ });
+ }
+
+ EventRecorder.start();
+
+ // Inject wheel inputs.
+ actions_promise = new test_driver.Actions()
+ .scroll(0, 0, 0, 10, {origin: wheelbox})
+ .scroll(160, 50, 0, 20, {origin: scrollbox})
+ .send();
+ </script>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/uievents/order-of-events/mouse-events/wheel-scrolling.html b/testing/web-platform/tests/uievents/order-of-events/mouse-events/wheel-scrolling.html
new file mode 100644
index 0000000000..44e76bff6c
--- /dev/null
+++ b/testing/web-platform/tests/uievents/order-of-events/mouse-events/wheel-scrolling.html
@@ -0,0 +1,109 @@
+<!doctype html>
+<head>
+ <meta charset=utf-8>
+ <title>WheelEvent - scrolling wheel event</title>
+ <style>
+ .testarea{ margin: auto; width: 80%; height: 250px; border: 1px solid grey; position: relative; }
+
+ #wheelbox { background-color: red; border: 1px solid black; margin: 0; padding: 0; }
+ #wheelbox.green { background-color: green; }
+ #wheelbox { position: absolute; left: 15%; top: 15%; width: 50%; height: 50% }
+
+ #lipsum { margin: auto; width: 40%; position: relative; }
+ </style>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script>
+ setup({explicit_timeout: true});
+ </script>
+ <script src="/uievents/resources/eventrecorder.js"></script>
+</head>
+
+<body>
+ <p><strong>Description</strong>: Verifies that we can scroll the page when wheel events are captured</p>
+ <p><strong>Instructions</strong>: </p>
+ <ol>
+ <li>Place your mouse over the box</li>
+ <li>Scroll the mouse wheel to change the box color</li>
+ </ol>
+ <p><strong>Test Passes</strong> if the box turns green and the word 'PASS' appears below</p>
+
+ <section class="testarea">
+ <div id="wheelbox"></div>
+ </section>
+
+ <script>
+ var wheelbox = document.getElementById("wheelbox");
+ var test_wheel_scrolling = async_test("wheel scrolling test");
+ var actions_promise;
+
+ EventRecorder.configure({
+ mergeEventTypes: ['wheel'],
+ objectMap: {
+ "div#wheelbox": wheelbox
+ }
+ });
+
+ wheelbox.addRecordedEventListener('wheel', function (e) {
+ e.stopPropagation();
+ this.className = "green";
+ endTest();
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ test_wheel_scrolling.done();
+ });
+ });
+
+ function endTest() {
+ EventRecorder.stop();
+ var results = EventRecorder.getRecords();
+ test_wheel_scrolling.step(function () {
+ // Check results:
+ assert_equals(results.length, 1, "One mousemove event");
+ assert_equals(results[0].event.type, 'wheel', "First event is a wheel event");
+ assert_equals(results[0].event.target, 'div#wheelbox', "First event targetted wheelbox");
+ });
+ }
+
+ EventRecorder.start();
+
+ // Inject wheel inputs.
+ actions_promise = new test_driver.Actions()
+ .scroll(0, 0, 0, 10, {origin: wheelbox})
+ .send();
+ </script>
+
+<section id="lipsum">
+ <p>
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras non sodales nunc. Nunc interdum laoreet magna, quis faucibus mi malesuada ut. Donec eu dictum nibh. Quisque consectetur velit arcu, ac bibendum lacus interdum eget. Sed gravida consequat lectus feugiat feugiat. Nunc finibus lacus sit amet ultrices pulvinar. Integer ultrices nulla ut ligula porttitor aliquet. Nulla dapibus dignissim cursus. Morbi euismod accumsan dapibus. Nullam rutrum neque eu finibus luctus. Praesent ultricies pellentesque bibendum.
+ </p>
+ <p>
+Cras faucibus facilisis justo, sit amet euismod nulla posuere sit amet. Donec odio justo, egestas ornare tristique vitae, convallis ac diam. Cras rutrum, massa nec feugiat sodales, diam ex faucibus diam, ac imperdiet dolor lacus eu nisi. Fusce feugiat ex vitae ex fermentum convallis. Pellentesque vulputate cursus lorem, vel sollicitudin eros feugiat a. Morbi egestas neque erat, eget semper nisi tempor id. Etiam eleifend fermentum convallis. Proin sem ipsum, porttitor a condimentum vel, malesuada ac est.
+ </p>
+ <p>
+Curabitur at porttitor ipsum, nec aliquam sapien. Quisque aliquet dapibus nulla. Donec consequat ornare dui, quis efficitur metus fringilla vitae. Fusce ut ultricies neque. In rutrum efficitur mi ut rhoncus. In ornare, justo quis volutpat dapibus, nulla ligula tincidunt dui, vitae porttitor lectus est eget metus. Integer convallis leo vitae dui auctor, at consectetur sem sollicitudin. Ut condimentum enim non tellus finibus mattis.
+ </p>
+ <p>
+Aenean pharetra, erat rutrum lacinia iaculis, ligula quam efficitur nibh, sit amet porttitor est ligula semper sapien. Morbi cursus finibus justo blandit commodo. Pellentesque at diam scelerisque, varius dolor a, tempus tortor. Nam placerat mi id elit eleifend scelerisque. Fusce imperdiet ac augue id fringilla. Quisque luctus nec sapien in tempor. Vestibulum faucibus metus nulla, nec faucibus metus rutrum sit amet. Nulla facilisi. Aliquam varius dignissim laoreet. Morbi gravida, velit sed efficitur iaculis, enim lectus hendrerit diam, ac aliquam mauris enim ut nulla. Vivamus quis aliquet libero. Vivamus accumsan elit et dolor posuere, ac volutpat nulla blandit. Proin vitae tortor rutrum, hendrerit odio vitae, ultricies metus. Pellentesque mattis sem ac lorem lacinia vestibulum. Ut orci est, placerat vitae imperdiet ac, dictum a nisi.
+ </p>
+ <p>
+Proin elementum faucibus neque, sed varius est rhoncus nec. Ut nec porttitor velit, a viverra lorem. Nam lectus arcu, malesuada non suscipit at, efficitur eget diam. Morbi at purus vitae nisl mollis suscipit ac at dolor. Nam vel ullamcorper est. Sed efficitur ligula quis elit viverra, at ornare velit posuere. Maecenas porta risus velit, eu pharetra ex vehicula rutrum. Mauris eu tortor vestibulum, tristique arcu et, euismod velit. Donec et mattis ligula. Pellentesque lacinia elit sit amet libero rhoncus convallis. Aenean porta, enim eget consequat blandit, leo ante finibus massa, gravida viverra dolor massa porta neque.
+ </p>
+ <p>
+ Mauris vitae tortor quis nibh tempus tempor et quis eros. Quisque massa libero, pulvinar nec fringilla non, molestie eget justo. Maecenas mollis est et felis auctor, eu sodales erat fermentum. Curabitur porttitor nibh magna, non porta mi dictum et. Aliquam nec auctor nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi nec porttitor ante, a rutrum ante. Vivamus faucibus et augue sit amet auctor. Nulla nec risus lacus. Quisque mattis vitae neque sit amet aliquet. Nam placerat mattis iaculis.
+ </p>
+ <p>
+Quisque ultrices varius nisi eu feugiat. Sed a aliquam risus. Nulla fermentum erat odio, ultricies fermentum arcu tristique a. Phasellus vulputate sapien in augue sollicitudin auctor. Aenean eu lectus placerat, bibendum leo et, efficitur diam. Quisque in lacus in justo volutpat convallis. Sed vitae rhoncus tellus. Curabitur elementum mi id diam volutpat interdum. Proin urna orci, vehicula non mattis dictum, dignissim a sem. Vivamus in ultricies quam, id auctor arcu. In lacinia ex ac dui fermentum pulvinar. Donec luctus auctor ultrices. Suspendisse semper eros a dolor vulputate aliquam.
+ </p>
+ <p>
+Nullam in tempor tellus, ac ullamcorper tortor. Cras vel aliquet magna, in congue nisi. Nam turpis quam, consectetur at vehicula ut, pellentesque eu risus. In vestibulum neque a ex fringilla tempor quis ac dui. Praesent dictum venenatis scelerisque. Proin ut lectus lobortis, eleifend ipsum blandit, tristique mi. Etiam lacus est, scelerisque at lectus at, interdum mattis ex. Nulla neque mauris, suscipit tempus elementum quis, viverra eu ligula. Etiam at velit vulputate, pulvinar metus eu, hendrerit odio. Sed nec feugiat tortor. Fusce nunc sapien, pretium non viverra et, volutpat eu arcu. Nullam libero justo, varius at suscipit at, scelerisque ut lectus. In leo lorem, tempor sed pellentesque nec, vulputate non lectus. Pellentesque volutpat sit amet lectus in finibus. Aliquam tristique, arcu sit amet venenatis commodo, ligula dolor efficitur ante, at faucibus mi diam ac sapien.
+ </p>
+ <p>
+Ut porttitor metus et mauris euismod iaculis. Ut in lorem neque. Nam a sollicitudin ligula, non lobortis sapien. Curabitur ullamcorper justo quis vulputate cursus. Aliquam rhoncus volutpat quam non condimentum. Donec dictum aliquam metus tempor vehicula. Curabitur lorem urna, venenatis vel tellus et, mollis ornare sapien. Aliquam erat elit, tristique at suscipit efficitur, condimentum eget quam. Quisque vel metus nisl. Integer eget cursus neque, sed auctor purus. Sed ac urna nec lectus elementum laoreet. Donec posuere diam ut nibh vestibulum efficitur. Nam ut rhoncus enim, semper sollicitudin libero.
+ </p>
+</section>
+</body>
+</html>
diff --git a/testing/web-platform/tests/uievents/resources/eventrecorder.js b/testing/web-platform/tests/uievents/resources/eventrecorder.js
new file mode 100644
index 0000000000..1e306c0d0a
--- /dev/null
+++ b/testing/web-platform/tests/uievents/resources/eventrecorder.js
@@ -0,0 +1,315 @@
+// interface EventRecorder {
+// static void start();
+// static void stop();
+// static void clearRecords();
+// static sequence<EventRecord> getRecords();
+// static void configure(EventRecorderOptions options);
+// };
+// * getRecords
+// * returns an array of EventRecord objects; the array represents the sequence of events captured at anytime after the last clear()
+// call, between when the recorder was started and stopped (including multiple start/stop pairs)
+// * configure
+// * sets options that should apply to the recorder. If the recorder has any existing records, than this API throws an exception.
+// * start
+// * starts/un-pauses the recorder
+// * stop
+// * stops/pauses the recorder
+// * clear
+// * purges all recorded records
+
+// ----------------------
+
+// dictionary EventRecorderOptions {
+// sequence<SupportedEventTypes> mergeEventTypes;
+// ObjectNamedMap objectMap;
+// };
+// * mergeEventTypes
+// * a list of event types that should be consolidated into one record when all of the following conditions are true:
+// 1) The events are of the same type and follow each other chronologically
+// 2) The events' currentTarget is the same
+// * The default is an empty list (no event types are merged).
+// * objectMap
+// * Sets up a series
+
+// dictionary ObjectNamedMap {
+// //<keys will be 'targetTestID' names, with values of the objects which they label>
+// };
+// * targetTestID = the string identifier that the associated target object should be known as (for purposes of unique identification. This
+// need not be the same as the Node's id attribute if it has one. If no 'targetTestID' string mapping is provided via this
+// map, but is encountered later when recording specific events, a generic targetTestID of 'UNKNOWN_OBJECT' is used.
+
+// ----------------------
+
+// dictionary EventRecord {
+// unsigned long chronologicalOrder;
+// unsigned long sequentialOccurrences;
+// sequence<EventRecord>? nestedEvents;
+// DOMString interfaceType;
+// EventRecordDetails event;
+// };
+// * chronologicalOrder
+// * Since some events may be dispatched re-entrantly (e.g., while existing events are being dispatched), and others may be merged
+// given the 'mergeEventTypes' option in the EventRecorder, this value is the actual chronological order that the event fired
+// * sequentialOccurrences
+// * If this event was fired multiple times in a row (see the 'mergeEventTypes' option), this value is the count of occurrences.
+// A value of 1 means this was the only occurrence of this event (that no events were merged with it). A value greater than 1
+// indicates that the event occurred that many times in a row.
+// * nestedEvents
+// * The holds all the events that were sequentially dispatched synchronously while the current event was still being dispatched
+// (e.g., between the time that this event listener was triggered and when it returned).
+// * Has the value null if no nested events were recorded during the invocation of this listener.
+// * interfaceType
+// * The string indicating which Event object (or derived Event object type) the recorded event object instance is based on.
+// * event
+// * Access to the recorded event properties for the event instance (not the actual event instance itself). A snapshot of the
+// enumerable properties of the event object instance at the moment the listener was first triggered.
+
+// ----------------------
+
+// dictionary EventRecordDetails {
+// //<recorded property names with their values for all enumerable properties of the event object instance>
+// };
+// * EventRecordDetails
+// * For records with 'sequentialOccurrences' > 1, only the first occurence is recorded (subsequent event details are dropped).
+// * Object reference values (e.g., event.target, event.currentTarget, etc.) are replaced with their mapped 'targetTestID' string.
+// If no 'targetTestID' string mapping is available for a particular object, the value 'UNKNOWN_OBJECT' is returned.
+
+// ----------------------
+
+// partial interface Node {
+// void addRecordedEventListener(SupportedEventTypes type, EventListener? handler, optional boolean capturePhase = false);
+// void removeRecordedEventListener(SupportedEventTypes type, EventListener? handler, optional boolean capturePhase = false);
+// };
+//
+// enum SupportedEventTypes = {
+// "mousemove",
+// etc...
+// };
+// * addRecordedEventListener
+// * handler = pass null if you want only a default recording of the event (and don't need any other special handling). Otherwise,
+// the handler will be invoked normally as part of the event's dispatch.
+// * <other params> are the same as those defined on addEventListener/removeEventListenter APIs (see DOM4)
+// * Use this API *instead of* addEventListener to record your events for testing purposes.
+
+(function EventRecorderScope(global) {
+ "use strict";
+
+ if (global.EventRecorder)
+ return; // Already initialized.
+
+ // WeakMap polyfill
+ if (!global.WeakMap) {
+ throw new Error("EventRecorder depends on WeakMap! Please polyfill for completeness to run in this user agent!");
+ }
+
+ // Globally applicable variables
+ var allRecords = [];
+ var recording = false;
+ var rawOrder = 1;
+ var mergeTypesTruthMap = {}; // format of { eventType: true, ... }
+ var eventsInScope = []; // Tracks synchronous event dispatches
+ var handlerMap = new WeakMap(); // Keeps original handlers (so that they can be used to un-register for events.
+
+ // Find all Event Object Constructors on the global and add them to the map along with their name (sans 'Event')
+ var eventConstructorsNameMap = new WeakMap(); // format of key: hostObject, value: alias to use.
+ var regex = /[A-Z][A-Za-z0-9]+Event$/;
+ Object.getOwnPropertyNames(global).forEach(function (propName) {
+ if (regex.test(propName))
+ eventConstructorsNameMap.set(global[propName], propName);
+ });
+ var knownObjectsMap = eventConstructorsNameMap;
+
+ Object.defineProperty(global, "EventRecorder", {
+ writable: true,
+ configurable: true,
+ value: Object.create(null, {
+ start: {
+ enumerable: true, configurable: true, writable: true, value: function start() { recording = true; }
+ },
+ stop: {
+ enumerable: true, configurable: true, writable: true, value: function stop() { recording = false; }
+ },
+ clearRecords: {
+ enumerable: true, configurable: true, writable: true, value: function clearRecords() {
+ rawOrder = 1;
+ allRecords = [];
+ }
+ },
+ getRecords: {
+ enumerable: true, configurable: true, writable: true, value: function getRecords() { return allRecords; }
+ },
+ checkRecords: {
+ enumerable: true, configurable: true, writable: true, value: function checkRecords(expected) {
+ if (expected.length < allRecords.length) {
+ return false;
+ }
+ var j = 0;
+ for (var i = 0; i < expected.length; ++i) {
+ if (j >= allRecords.length) {
+ if (expected[i].optional) {
+ continue;
+ }
+ return false;
+ }
+ if (expected[i].type == allRecords[j].event.type && expected[i].target == allRecords[j].event.currentTarget) {
+ ++j;
+ continue;
+ }
+ if (expected[i].optional) {
+ continue;
+ }
+ return false;
+ }
+ return true;
+ }
+ },
+ configure: {
+ enumerable: true, configurable: true, writable: true, value: function configure(options) {
+ if (allRecords.length > 0)
+ throw new Error("Wrong time to call me: EventRecorder.configure must only be called when no recorded events are present. Try 'clearRecords' first.");
+
+ // Un-configure existing options by calling again with no options set...
+ mergeTypesTruthMap = {};
+ knownObjectsMap = eventConstructorsNameMap;
+
+ if (!(options instanceof Object))
+ return;
+ // Sanitize the passed object (tease-out getter functions)
+ var sanitizedOptions = {};
+ for (var x in options) {
+ sanitizedOptions[x] = options[x];
+ }
+ if (sanitizedOptions.mergeEventTypes && Array.isArray(sanitizedOptions.mergeEventTypes)) {
+ sanitizedOptions.mergeEventTypes.forEach(function (eventType) {
+ if (typeof eventType == "string")
+ mergeTypesTruthMap[eventType] = true;
+ });
+ }
+ if (sanitizedOptions.objectMap && (sanitizedOptions.objectMap instanceof Object)) {
+ for (var y in sanitizedOptions.objectMap) {
+ knownObjectsMap.set(sanitizedOptions.objectMap[y], y);
+ }
+ }
+ }
+ },
+ addEventListenersForNodes: {
+ enumerable: true, configurable: true, writable: true, value: function addEventListenersForNodes(events, nodes, handler) {
+ for (var i = 0; i < nodes.length; ++i) {
+ for (var j = 0; j < events.length; ++j) {
+ nodes[i].addRecordedEventListener(events[j], handler);
+ }
+ }
+ }
+ }
+ })
+ });
+
+ function EventRecord(rawEvent) {
+ this.chronologicalOrder = rawOrder++;
+ this.sequentialOccurrences = 1;
+ this.nestedEvents = null; // potentially a []
+ this.interfaceType = knownObjectsMap.get(rawEvent.constructor);
+ if (!this.interfaceType) // In case (somehow) this event's constructor is not named something with an 'Event' suffix...
+ this.interfaceType = rawEvent.constructor.toString();
+ this.event = new CloneObjectLike(rawEvent);
+ }
+
+ // Only enumerable props including prototype-chain (non-recursive), w/no functions.
+ function CloneObjectLike(object) {
+ for (var prop in object) {
+ var val = object[prop];
+ if (Array.isArray(val))
+ this[prop] = CloneArray(val);
+ else if (typeof val == "function")
+ continue;
+ else if ((typeof val == "object") && (val != null)) {
+ this[prop] = knownObjectsMap.get(val);
+ if (this[prop] === undefined)
+ this[prop] = "UNKNOWN_OBJECT (" + val.toString() + ")";
+ }
+ else
+ this[prop] = val;
+ }
+ }
+
+ function CloneArray(array) {
+ var dup = [];
+ for (var i = 0, len = array.length; i < len; i++) {
+ var val = array[i]
+ if (typeof val == "undefined")
+ throw new Error("Ugg. Sparce arrays are not supported. Sorry!");
+ else if (Array.isArray(val))
+ dup[i] = "UNKNOWN_ARRAY";
+ else if (typeof val == "function")
+ dup[i] = "UNKNOWN_FUNCTION";
+ else if ((typeof val == "object") && (val != null)) {
+ dup[i] = knownObjectsMap.get(val);
+ if (dup[i] === undefined)
+ dup[i] = "UNKNOWN_OBJECT (" + val.toString() + ")";
+ }
+ else
+ dup[i] = val;
+ }
+ return dup;
+ }
+
+ function generateRecordedEventHandlerWithCallback(callback) {
+ return function(e) {
+ if (recording) {
+ // Setup the scope for any synchronous events
+ eventsInScope.push(recordEvent(e));
+ callback.call(this, e);
+ eventsInScope.pop();
+ }
+ }
+ }
+
+ function recordedEventHandler(e) {
+ if (recording)
+ recordEvent(e);
+ }
+
+ function recordEvent(e) {
+ var record = new EventRecord(e);
+ var recordList = allRecords;
+ // Adjust which sequential list to use depending on scope
+ if (eventsInScope.length > 0) {
+ recordList = eventsInScope[eventsInScope.length - 1].nestedEvents;
+ if (recordList == null) // This top-of-stack event record hasn't had any nested events yet.
+ recordList = eventsInScope[eventsInScope.length - 1].nestedEvents = [];
+ }
+ if (mergeTypesTruthMap[e.type] && (recordList.length > 0)) {
+ var tail = recordList[recordList.length-1];
+ // Same type and currentTarget?
+ if ((tail.event.type == record.event.type) && (tail.event.currentTarget == record.event.currentTarget)) {
+ tail.sequentialOccurrences++;
+ return;
+ }
+ }
+ recordList.push(record);
+ return record;
+ }
+
+ Object.defineProperties(Node.prototype, {
+ addRecordedEventListener: {
+ enumerable: true, writable: true, configurable: true,
+ value: function addRecordedEventListener(type, handler, capture) {
+ if (handler == null)
+ this.addEventListener(type, recordedEventHandler, capture);
+ else {
+ var subvertedHandler = generateRecordedEventHandlerWithCallback(handler);
+ handlerMap.set(handler, subvertedHandler);
+ this.addEventListener(type, subvertedHandler, capture);
+ }
+ }
+ },
+ removeRecordedEventListener: {
+ enumerable: true, writable: true, configurable: true,
+ value: function addRecordedEventListener(type, handler, capture) {
+ var alternateHandlerUsed = handlerMap.get(handler);
+ this.removeEventListenter(type, alternateHandlerUsed ? alternateHandlerUsed : recordedEventHandler, capture);
+ }
+ }
+ });
+
+})(window); \ No newline at end of file