summaryrefslogtreecommitdiffstats
path: root/dom/events/test/test_mouse_enterleave_iframe.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/events/test/test_mouse_enterleave_iframe.html')
-rw-r--r--dom/events/test/test_mouse_enterleave_iframe.html362
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>