187 lines
6.3 KiB
HTML
187 lines
6.3 KiB
HTML
<!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>
|