summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/uievents/order-of-events
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/uievents/order-of-events
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/uievents/order-of-events')
-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
17 files changed, 1515 insertions, 0 deletions
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>