summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/uievents/mouse/mouseenter-mouseleave-on-drag.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/uievents/mouse/mouseenter-mouseleave-on-drag.html')
-rw-r--r--testing/web-platform/tests/uievents/mouse/mouseenter-mouseleave-on-drag.html187
1 files changed, 187 insertions, 0 deletions
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>