362 lines
11 KiB
HTML
362 lines
11 KiB
HTML
<!doctype html>
|
|
<meta charset="utf-8">
|
|
<title>Test mouseenter and mouseleave for iframe.</title>
|
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
|
<script src="/tests/SimpleTest/paint_listener.js"></script>
|
|
<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
|
|
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
|
|
<style>
|
|
#start {
|
|
width: 300px;
|
|
height: 30px;
|
|
}
|
|
|
|
#target, #target2 {
|
|
width: 150px;
|
|
height: 150px;
|
|
background-color: #fcc;
|
|
display: inline-block;
|
|
}
|
|
|
|
#frame, #frame2 {
|
|
height: 100%;
|
|
width: 100%;
|
|
}
|
|
|
|
#reflow, #div {
|
|
width: 300px;
|
|
height: 10px;
|
|
background-color: lightgreen;
|
|
}
|
|
</style>
|
|
<div id="start">Start from here!!</div>
|
|
<div id="div"></div>
|
|
<div id="target">
|
|
<iframe id="frame" frameborder="0" scrolling="no"></iframe>
|
|
</div>
|
|
<div id="target2">
|
|
<iframe id="frame2" frameborder="0" scrolling="no"></iframe>
|
|
</div>
|
|
<div id="reflow"></div>
|
|
<script>
|
|
|
|
function reflow() {
|
|
let div = document.getElementById("reflow");
|
|
div.style.display = "none";
|
|
div.getBoundingClientRect();
|
|
div.style.display = "block";
|
|
div.getBoundingClientRect();
|
|
}
|
|
|
|
function waitForMessage(aRemoteTarget, aEventType, aTargetName, aLastExpectedElement) {
|
|
return new Promise(function (aResolve, aReject) {
|
|
const data = `waiting for "${aEventType}" on <${aTargetName}> in <iframe id="${aRemoteTarget.id}">`;
|
|
let expectedMessageReceived = false;
|
|
window.addEventListener("message", function listener(aEvent) {
|
|
if (aEvent.source != aRemoteTarget.contentWindow) {
|
|
return;
|
|
}
|
|
|
|
if (aEvent.data.eventType == "reflowed") {
|
|
if (expectedMessageReceived) {
|
|
window.removeEventListener("message", listener);
|
|
aResolve();
|
|
ok(true, `Message listener ${data} is correctly removed`);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (aEvent.data.eventType !== aEventType) {
|
|
window.removeEventListener("message", listener);
|
|
is(
|
|
aEvent.data.eventType,
|
|
aEventType,
|
|
`receive unexpected message ${JSON.stringify(aEvent.data)} at ${data}`
|
|
);
|
|
aReject(new Error(`receive unexpected message ${JSON.stringify(aEvent.data)} at ${data}`));
|
|
return;
|
|
}
|
|
|
|
if (aEvent.data.targetName !== aTargetName) {
|
|
return;
|
|
}
|
|
|
|
if (expectedMessageReceived) {
|
|
window.removeEventListener("message", listener);
|
|
ok(false, `receive redundant message at ${data}`);
|
|
aReject(new Error(`receive redundant message at ${data}`));
|
|
return;
|
|
}
|
|
|
|
expectedMessageReceived = true;
|
|
ok(true, `receive message at ${data}`);
|
|
if (aLastExpectedElement) {
|
|
// Trigger a reflow which will generate synthesized mouse move event.
|
|
aRemoteTarget.contentWindow.postMessage("reflow", "*");
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Wait for "mouseenter" events in a child document.
|
|
*
|
|
* @param aRemoteTarget An <iframe> element which has the child document.
|
|
* @param aTargetNames An array of `mouseenter` targets which you want to
|
|
* listen to. The order should be ancestor to descendant.
|
|
*/
|
|
function waitForMouseEnterMessages(aRemoteTarget, aTargetNames) {
|
|
let promises = [];
|
|
let targetName;
|
|
while ((targetName = aTargetNames.shift())) {
|
|
promises.push(
|
|
waitForMessage(aRemoteTarget, "mouseenter", targetName, !aTargetNames.length)
|
|
);
|
|
}
|
|
return Promise.all(promises);
|
|
}
|
|
|
|
/**
|
|
* Wait for "mouseleave" events in a child document.
|
|
*
|
|
* @param aRemoteTarget An <iframe> element which has the child document.
|
|
* @param aTargetNames An array of `mouseleave` targets which you want to
|
|
* listen to. The order should be ancestor to descendant.
|
|
*/
|
|
function waitForMouseLeaveMessages(aRemoteTarget, aTargetNames) {
|
|
let promises = [];
|
|
let targetName;
|
|
while ((targetName = aTargetNames.pop())) {
|
|
promises.push(
|
|
waitForMessage(aRemoteTarget, "mouseleave", targetName, !aTargetNames.length)
|
|
);
|
|
}
|
|
return Promise.all(promises);
|
|
}
|
|
|
|
function waitForLeaveEvent(aTarget) {
|
|
return new Promise(function(aResolve) {
|
|
aTarget.addEventListener("mouseleave", function(aEvent) {
|
|
ok(true, `receive ${aEvent.type}`);
|
|
aResolve();
|
|
}, { once: true });
|
|
});
|
|
}
|
|
|
|
function waitForEnterLeaveEvents(aEnterTarget, aLeaveTarget) {
|
|
let expectedEvents = [{target: aEnterTarget, eventName: "mouseenter"}];
|
|
if (aLeaveTarget) {
|
|
expectedEvents.push({target: aLeaveTarget, eventName: "mouseleave"})
|
|
}
|
|
|
|
return new Promise(function(aResolve, aReject) {
|
|
function cleanup() {
|
|
aEnterTarget.removeEventListener("mouseenter", listener);
|
|
aEnterTarget.removeEventListener("mouseleave", unexpectedEvent);
|
|
if (aLeaveTarget) {
|
|
aLeaveTarget.removeEventListener("mouseenter", unexpectedEvent);
|
|
aLeaveTarget.removeEventListener("mouseleave", listener);
|
|
}
|
|
}
|
|
|
|
function unexpectedEvent(aEvent) {
|
|
cleanup();
|
|
ok(false, `receive unexpected ${aEvent.type}`);
|
|
aReject(new Error(`receive unexpected ${aEvent.type}`));
|
|
}
|
|
|
|
async function listener(aEvent) {
|
|
if (expectedEvents.length <= 0) {
|
|
unexpectedEvent(aEvent);
|
|
return;
|
|
}
|
|
|
|
let expectedEvent = expectedEvents.pop();
|
|
if (expectedEvent.target == aEvent.target &&
|
|
expectedEvent.eventName == aEvent.type) {
|
|
ok(true, `receive ${aEvent.type}`);
|
|
} else {
|
|
unexpectedEvent(aEvent);
|
|
return;
|
|
}
|
|
|
|
if (!expectedEvents.length) {
|
|
// Trigger a reflow which will generate synthesized mouse move event.
|
|
reflow();
|
|
// Now wait a bit to see if there is any unexpected event fired.
|
|
setTimeout(function() {
|
|
cleanup();
|
|
aResolve();
|
|
}, 0);
|
|
}
|
|
}
|
|
|
|
aEnterTarget.addEventListener("mouseenter", listener);
|
|
aEnterTarget.addEventListener("mouseleave", unexpectedEvent);
|
|
if (aLeaveTarget) {
|
|
aLeaveTarget.addEventListener("mouseenter", unexpectedEvent);
|
|
aLeaveTarget.addEventListener("mouseleave", listener);
|
|
}
|
|
});
|
|
}
|
|
|
|
function moveMouseToInitialPosition() {
|
|
info("Mouse moves to initial position");
|
|
return promiseNativeMouseEvent({
|
|
type: "mousemove",
|
|
target: document.getElementById("start"),
|
|
atCenter: true,
|
|
});
|
|
}
|
|
|
|
add_setup(async function() {
|
|
// Wait for focus before starting tests.
|
|
await SimpleTest.promiseFocus();
|
|
|
|
// Wait for apz getting stable.
|
|
await waitUntilApzStable();
|
|
|
|
// Move mouse to initial position.
|
|
await moveMouseToInitialPosition();
|
|
|
|
// After initializing the mouse cursor position, we should load <iframe>s.
|
|
// This avoids the case that the cursor is over one of them.
|
|
info("Load child documents into the iframes");
|
|
let promiseLoadingIFrames = [];
|
|
for (const iframe of document.querySelectorAll("iframe")) {
|
|
promiseLoadingIFrames.push(
|
|
new Promise(resolve => { iframe.addEventListener("load", resolve, {once: true}); })
|
|
);
|
|
iframe.src = "http://example.com/tests/dom/events/test/file_mouse_enterleave.html";
|
|
}
|
|
await Promise.all(promiseLoadingIFrames);
|
|
});
|
|
|
|
add_task(async function testMouseEnterLeave() {
|
|
let div = document.getElementById("div");
|
|
let target = document.getElementById("target");
|
|
let iframe = document.getElementById("frame");
|
|
|
|
info("Mouse moves to the div above iframe");
|
|
let promise = waitForEnterLeaveEvents(div);
|
|
synthesizeNativeMouseEvent({
|
|
type: "mousemove",
|
|
target: div,
|
|
atCenter: true,
|
|
});
|
|
await promise;
|
|
|
|
info("Mouse moves into iframe");
|
|
promise = Promise.all([waitForEnterLeaveEvents(target, div),
|
|
waitForMouseEnterMessages(iframe, ["html", "div"])]);
|
|
synthesizeNativeMouseEvent({
|
|
type: "mousemove",
|
|
target,
|
|
atCenter: true,
|
|
});
|
|
await promise;
|
|
|
|
info("Mouse moves out from iframe to the div above iframe");
|
|
promise = Promise.all([waitForEnterLeaveEvents(div, target),
|
|
waitForMouseLeaveMessages(iframe, ["html", "div"])]);
|
|
synthesizeNativeMouseEvent({
|
|
type: "mousemove",
|
|
target: div,
|
|
atCenter: true,
|
|
});
|
|
await promise;
|
|
|
|
// Move mouse back to initial position. This is to prevent unexpected
|
|
// mouseleave event in initial steps for test-verify which runs same test
|
|
// multiple times.
|
|
await moveMouseToInitialPosition();
|
|
});
|
|
|
|
add_task(async function testMouseEnterLeaveBetweenIframe() {
|
|
let target = document.getElementById("target");
|
|
let iframe = document.getElementById("frame");
|
|
|
|
info("Mouse moves into the first iframe");
|
|
let promise = Promise.all([waitForEnterLeaveEvents(target),
|
|
waitForMouseEnterMessages(iframe, ["html", "div"])]);
|
|
synthesizeNativeMouseEvent({
|
|
type: "mousemove",
|
|
target,
|
|
atCenter: true,
|
|
});
|
|
await promise;
|
|
|
|
let target2 = document.getElementById("target2");
|
|
let iframe2 = document.getElementById("frame2");
|
|
|
|
info("Mouse moves out from the first iframe to the second iframe");
|
|
promise = Promise.all([waitForEnterLeaveEvents(target2, target),
|
|
waitForMouseLeaveMessages(iframe, ["html", "div"]),
|
|
waitForMouseEnterMessages(iframe2, ["html", "div"])]);
|
|
synthesizeNativeMouseEvent({
|
|
type: "mousemove",
|
|
target: target2,
|
|
atCenter: true,
|
|
})
|
|
await promise;
|
|
|
|
info("Mouse moves out from the second iframe to the first iframe");
|
|
promise = Promise.all([waitForEnterLeaveEvents(target, target2),
|
|
waitForMouseLeaveMessages(iframe2, ["html", "div"]),
|
|
waitForMouseEnterMessages(iframe, ["html", "div"])]);
|
|
synthesizeNativeMouseEvent({
|
|
type: "mousemove",
|
|
target,
|
|
atCenter: true,
|
|
});
|
|
await promise;
|
|
|
|
// Move mouse back to initial position.
|
|
await Promise.all([waitForLeaveEvent(target),
|
|
waitForMouseLeaveMessages(iframe, ["html", "div"]),
|
|
moveMouseToInitialPosition()]);
|
|
});
|
|
|
|
add_task(async function testMouseEnterLeaveSwitchWindow() {
|
|
let target = document.getElementById("target");
|
|
let iframe = document.getElementById("frame");
|
|
|
|
info("Mouse moves into iframe");
|
|
let promise = Promise.all([waitForEnterLeaveEvents(target),
|
|
waitForMouseEnterMessages(iframe, ["html", "div"])]);
|
|
synthesizeNativeMouseEvent({
|
|
type: "mousemove",
|
|
target,
|
|
atCenter: true,
|
|
});
|
|
await promise;
|
|
|
|
info("Open and switch to new window");
|
|
promise = Promise.all([waitForLeaveEvent(target),
|
|
waitForMouseLeaveMessages(iframe, ["html", "div"])]);
|
|
let win = window.open("http://example.com/tests/dom/events/test/file_mouse_enterleave.html");
|
|
// Trigger a reflow which will generate synthesized mouse move event.
|
|
win.postMessage("reflow", "*");
|
|
await promise;
|
|
|
|
info("Switch back to test window");
|
|
promise = Promise.all([waitForEnterLeaveEvents(target),
|
|
waitForMouseEnterMessages(iframe, ["html", "div"])]);
|
|
win.close();
|
|
// Trigger a reflow which will generate synthesized mouse move event.
|
|
reflow();
|
|
// Wait for apz getting stable.
|
|
await waitUntilApzStable();
|
|
synthesizeNativeMouseEvent({
|
|
type: "mousemove",
|
|
target,
|
|
atCenter: true,
|
|
});
|
|
await promise;
|
|
|
|
// Move mouse back to initial position.
|
|
await Promise.all([waitForLeaveEvent(target),
|
|
moveMouseToInitialPosition()]);
|
|
});
|
|
</script>
|