diff options
Diffstat (limited to 'dom/events/test/test_mouse_enterleave_iframe.html')
-rw-r--r-- | dom/events/test/test_mouse_enterleave_iframe.html | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/dom/events/test/test_mouse_enterleave_iframe.html b/dom/events/test/test_mouse_enterleave_iframe.html new file mode 100644 index 0000000000..52d944ecca --- /dev/null +++ b/dom/events/test/test_mouse_enterleave_iframe.html @@ -0,0 +1,362 @@ +<!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> |