Source code
Revision control
Copy as Markdown
Other Tools
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0,minimum-scale=1.0">
<title>Test for no synthetic eMouseMove after swipe to scroll</title>
<script type="application/javascript" src="apz_test_native_event_utils.js"></script>
<script type="application/javascript" src="apz_test_utils.js"></script>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<style>
body {
margin: 0;
}
div {
margin: 0;
height: 2lh;
}
div:hover {
background-color: limegreen;
}
</style>
<script>
"use strict";
addEventListener("DOMContentLoaded", () => {
document.body.innerHTML = "";
for (let i = 0; i < 100; i++) {
const div = document.createElement("div");
div.id = `div${i}`;
document.body.appendChild(div);
}
document.documentElement.getBoundingClientRect();
waitUntilApzStable()
.then(test)
.then(subtestDone, subtestFailed);
}, {once: true});
async function test() {
while (document.documentElement.scrollY == 0) {
// the scrollframe is not yet marked as APZ-scrollable. Mark it so
// before continuing.
document.documentElement.scrollTo(0, 1);
await promiseApzFlushedRepaints();
}
const height = window.innerHeight;
const divToBeSwiped = document.body.querySelector(`div:nth-child(${
Math.floor(height / document.body.firstElementChild.getBoundingClientRect().height)
})`);
const divToBeSwipedRect = divToBeSwiped.getBoundingClientRect();
ok(
height > divToBeSwipedRect.height * 5,
`The viewport should be able to show at least 5 <div> elements, expected taller than ${
divToBeSwipedRect.height * 5
}, but ${height}`
);
// Wait for synthesized mousemove is flushed in the next animation frame
// before doing some since it'll fix the `:hover` state and mouse/pointer
// boundary event state with the latest layout.
function flushPendingSynthesizedMouseMove(aCallback) {
requestAnimationFrame(
() => requestAnimationFrame(aCallback)
);
}
function promiseFlushPendingSynthesizedMouseMove() {
return new Promise(resolve => {
flushPendingSynthesizedMouseMove(resolve);
});
}
// First, make PresShell forgets the last mouse location which may be set accidentally.
synthesizeMouseAtCenter(divToBeSwiped, {type: "mousecancel"}, {once: true});
// Hopefully, synthesize a tap first. That may cause PresShell storing the
// tap point as the last mouse location since that should cause a set of
// compatibility mouse events.
info("Synthesizing a tap...");
const waitForClick = new Promise(resolve => {
addEventListener("click", event => {
is(
event.target,
divToBeSwiped,
"`click` should be fired on the bottom <div>"
);
const clickPosition = { x: event.clientX, y: event.clientY };
flushPendingSynthesizedMouseMove(() => resolve(clickPosition));
}, {once: true});
});
await promiseNativePointerTap(
divToBeSwiped,
"touch",
divToBeSwipedRect.width / 2,
divToBeSwipedRect.height / 2
);
info("Waiting for the click...");
const clickPosition = await waitForClick;
// Then, swipe from the bottom <div> to above to scroll down.
info("Synthesizing a swipe...");
const scrollTopBefore = document.documentElement.scrollTop;
const waitForPointerCancel = new Promise(resolve => {
addEventListener("pointercancel", resolve, {once: true});
});
const transformEndPromise = promiseTransformEnd();
await promiseNativePointerDrag(
divToBeSwiped,
"touch",
divToBeSwipedRect.width / 2,
divToBeSwipedRect.height / 2,
0, // deltaX
divToBeSwipedRect.height * -3 // deltaY
);
info("Waiting for pointercancel which should be caused by the swipe...");
await waitForPointerCancel;
info("Waiting for transformEndPromise...");
await transformEndPromise;
info("Waiting for promiseApzFlushedRepaints()...");
await promiseApzFlushedRepaints();
await promiseFlushPendingSynthesizedMouseMove();
const scrollTopAfter = document.documentElement.scrollTop;
ok(
scrollTopBefore + divToBeSwipedRect.height < scrollTopAfter,
`The swipe should cause scrolling down, expected greater than ${
scrollTopBefore + divToBeSwipedRect.height
} (scrollTopBefore: ${scrollTopBefore}), but got ${scrollTopAfter}`
);
// Finally, the scroll down causes the element underneath the start position
// of the swipe is a following <div> of the original <div> element. However,
// user must not want the <div> to have the :hover state since they have not
// touched the <div>.
const hoveredDiv = document.querySelector("div:hover");
const elementAtClickedPosition = document.elementFromPoint(clickPosition.x, clickPosition.y);
ok(
!hoveredDiv || hoveredDiv != elementAtClickedPosition,
`The div element at the previously clicked position should not have :hover state, got ${
hoveredDiv ? hoveredDiv.outerHTML : "null"
}${
elementAtClickedPosition
? ` which should never be ${elementAtClickedPosition.outerHTML}`
: ""
}`
);
}
</script>
</head>
<body></body>
</html>