tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_mouse_enterleave_iframe.html (11408B)


      1 <!doctype html>
      2 <meta charset="utf-8">
      3 <title>Test mouseenter and mouseleave for iframe.</title>
      4 <script src="/tests/SimpleTest/SimpleTest.js"></script>
      5 <script src="/tests/SimpleTest/EventUtils.js"></script>
      6 <script src="/tests/SimpleTest/paint_listener.js"></script>
      7 <script src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
      8 <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
      9 <style>
     10 #start {
     11  width: 300px;
     12  height: 30px;
     13 }
     14 
     15 #target, #target2 {
     16  width: 150px;
     17  height: 150px;
     18  background-color: #fcc;
     19  display: inline-block;
     20 }
     21 
     22 #frame, #frame2 {
     23  height: 100%;
     24  width: 100%;
     25 }
     26 
     27 #reflow, #div {
     28  width: 300px;
     29  height: 10px;
     30  background-color: lightgreen;
     31 }
     32 </style>
     33 <div id="start">Start from here!!</div>
     34 <div id="div"></div>
     35 <div id="target">
     36  <iframe id="frame" frameborder="0" scrolling="no"></iframe>
     37 </div>
     38 <div id="target2">
     39  <iframe id="frame2" frameborder="0" scrolling="no"></iframe>
     40 </div>
     41 <div id="reflow"></div>
     42 <script>
     43 
     44 function reflow() {
     45  let div = document.getElementById("reflow");
     46  div.style.display = "none";
     47  div.getBoundingClientRect();
     48  div.style.display = "block";
     49  div.getBoundingClientRect();
     50 }
     51 
     52 function waitForMessage(aRemoteTarget, aEventType, aTargetName, aLastExpectedElement) {
     53  return new Promise(function (aResolve, aReject) {
     54    const data = `waiting for "${aEventType}" on <${aTargetName}> in <iframe id="${aRemoteTarget.id}">`;
     55    let expectedMessageReceived = false;
     56    window.addEventListener("message", function listener(aEvent) {
     57      if (aEvent.source != aRemoteTarget.contentWindow) {
     58        return;
     59      }
     60 
     61      if (aEvent.data.eventType == "reflowed") {
     62        if (expectedMessageReceived) {
     63          window.removeEventListener("message", listener);
     64          aResolve();
     65          ok(true, `Message listener ${data} is correctly removed`);
     66        }
     67        return;
     68      }
     69 
     70      if (aEvent.data.eventType !== aEventType) {
     71        window.removeEventListener("message", listener);
     72        is(
     73          aEvent.data.eventType,
     74          aEventType,
     75          `receive unexpected message ${JSON.stringify(aEvent.data)} at ${data}`
     76        );
     77        aReject(new Error(`receive unexpected message ${JSON.stringify(aEvent.data)} at ${data}`));
     78        return;
     79      }
     80 
     81      if (aEvent.data.targetName !== aTargetName) {
     82        return;
     83      }
     84 
     85      if (expectedMessageReceived) {
     86        window.removeEventListener("message", listener);
     87        ok(false, `receive redundant message at ${data}`);
     88        aReject(new Error(`receive redundant message at ${data}`));
     89        return;
     90      }
     91 
     92      expectedMessageReceived = true;
     93      ok(true, `receive message at ${data}`);
     94      if (aLastExpectedElement) {
     95        // Trigger a reflow which will generate synthesized mouse move event.
     96        aRemoteTarget.contentWindow.postMessage("reflow", "*");
     97      }
     98    });
     99  });
    100 }
    101 
    102 /**
    103 * Wait for "mouseenter" events in a child document.
    104 *
    105 * @param aRemoteTarget An <iframe> element which has the child document.
    106 * @param aTargetNames  An array of `mouseenter` targets which you want to
    107 *                      listen to.  The order should be ancestor to descendant.
    108 */
    109 function waitForMouseEnterMessages(aRemoteTarget, aTargetNames) {
    110  let promises = [];
    111  let targetName;
    112  while ((targetName = aTargetNames.shift())) {
    113    promises.push(
    114      waitForMessage(aRemoteTarget, "mouseenter", targetName, !aTargetNames.length)
    115    );
    116  }
    117  return Promise.all(promises);
    118 }
    119 
    120 /**
    121 * Wait for "mouseleave" events in a child document.
    122 *
    123 * @param aRemoteTarget An <iframe> element which has the child document.
    124 * @param aTargetNames  An array of `mouseleave` targets which you want to
    125 *                      listen to.  The order should be ancestor to descendant.
    126 */
    127 function waitForMouseLeaveMessages(aRemoteTarget, aTargetNames) {
    128  let promises = [];
    129  let targetName;
    130  while ((targetName = aTargetNames.pop())) {
    131    promises.push(
    132      waitForMessage(aRemoteTarget, "mouseleave", targetName, !aTargetNames.length)
    133    );
    134  }
    135  return Promise.all(promises);
    136 }
    137 
    138 function waitForLeaveEvent(aTarget) {
    139  return new Promise(function(aResolve) {
    140    aTarget.addEventListener("mouseleave", function(aEvent) {
    141      ok(true, `receive ${aEvent.type}`);
    142      aResolve();
    143    }, { once: true });
    144  });
    145 }
    146 
    147 function waitForEnterLeaveEvents(aEnterTarget, aLeaveTarget) {
    148  let expectedEvents = [{target: aEnterTarget, eventName: "mouseenter"}];
    149  if (aLeaveTarget) {
    150    expectedEvents.push({target: aLeaveTarget, eventName: "mouseleave"})
    151  }
    152 
    153  return new Promise(function(aResolve, aReject) {
    154    function cleanup() {
    155      aEnterTarget.removeEventListener("mouseenter", listener);
    156      aEnterTarget.removeEventListener("mouseleave", unexpectedEvent);
    157      if (aLeaveTarget) {
    158        aLeaveTarget.removeEventListener("mouseenter", unexpectedEvent);
    159        aLeaveTarget.removeEventListener("mouseleave", listener);
    160      }
    161    }
    162 
    163    function unexpectedEvent(aEvent) {
    164      cleanup();
    165      ok(false, `receive unexpected ${aEvent.type}`);
    166      aReject(new Error(`receive unexpected ${aEvent.type}`));
    167    }
    168 
    169    async function listener(aEvent) {
    170      if (expectedEvents.length <= 0) {
    171        unexpectedEvent(aEvent);
    172        return;
    173      }
    174 
    175      let expectedEvent = expectedEvents.pop();
    176      if (expectedEvent.target == aEvent.target &&
    177          expectedEvent.eventName == aEvent.type) {
    178        ok(true, `receive ${aEvent.type}`);
    179      } else {
    180        unexpectedEvent(aEvent);
    181        return;
    182      }
    183 
    184      if (!expectedEvents.length) {
    185        // Trigger a reflow which will generate synthesized mouse move event.
    186        reflow();
    187        // Now wait a bit to see if there is any unexpected event fired.
    188        setTimeout(function() {
    189          cleanup();
    190          aResolve();
    191        }, 0);
    192      }
    193    }
    194 
    195    aEnterTarget.addEventListener("mouseenter", listener);
    196    aEnterTarget.addEventListener("mouseleave", unexpectedEvent);
    197    if (aLeaveTarget) {
    198      aLeaveTarget.addEventListener("mouseenter", unexpectedEvent);
    199      aLeaveTarget.addEventListener("mouseleave", listener);
    200    }
    201  });
    202 }
    203 
    204 function moveMouseToInitialPosition() {
    205  info("Mouse moves to initial position");
    206  return promiseNativeMouseEvent({
    207    type: "mousemove",
    208    target: document.getElementById("start"),
    209    atCenter: true,
    210  });
    211 }
    212 
    213 add_setup(async function() {
    214  // Wait for focus before starting tests.
    215  await SimpleTest.promiseFocus();
    216 
    217  // Wait for apz getting stable.
    218  await waitUntilApzStable();
    219 
    220  // Move mouse to initial position.
    221  await moveMouseToInitialPosition();
    222 
    223  // After initializing the mouse cursor position, we should load <iframe>s.
    224  // This avoids the case that the cursor is over one of them.
    225  info("Load child documents into the iframes");
    226  let promiseLoadingIFrames = [];
    227  for (const iframe of document.querySelectorAll("iframe")) {
    228    promiseLoadingIFrames.push(
    229      new Promise(resolve => { iframe.addEventListener("load", resolve, {once: true}); })
    230    );
    231    iframe.src = "http://example.com/tests/dom/events/test/file_mouse_enterleave.html";
    232  }
    233  await Promise.all(promiseLoadingIFrames);
    234 });
    235 
    236 add_task(async function testMouseEnterLeave() {
    237  let div = document.getElementById("div");
    238  let target = document.getElementById("target");
    239  let iframe = document.getElementById("frame");
    240 
    241  info("Mouse moves to the div above iframe");
    242  let promise = waitForEnterLeaveEvents(div);
    243  synthesizeNativeMouseEvent({
    244    type: "mousemove",
    245    target: div,
    246    atCenter: true,
    247  });
    248  await promise;
    249 
    250  info("Mouse moves into iframe");
    251  promise = Promise.all([waitForEnterLeaveEvents(target, div),
    252                         waitForMouseEnterMessages(iframe, ["html", "div"])]);
    253  synthesizeNativeMouseEvent({
    254    type: "mousemove",
    255    target,
    256    atCenter: true,
    257  });
    258  await promise;
    259 
    260  info("Mouse moves out from iframe to the div above iframe");
    261  promise = Promise.all([waitForEnterLeaveEvents(div, target),
    262                         waitForMouseLeaveMessages(iframe, ["html", "div"])]);
    263  synthesizeNativeMouseEvent({
    264    type: "mousemove",
    265    target: div,
    266    atCenter: true,
    267  });
    268  await promise;
    269 
    270  // Move mouse back to initial position. This is to prevent unexpected
    271  // mouseleave event in initial steps for test-verify which runs same test
    272  // multiple times. 
    273  await moveMouseToInitialPosition();
    274 });
    275 
    276 add_task(async function testMouseEnterLeaveBetweenIframe() {
    277  let target = document.getElementById("target");
    278  let iframe = document.getElementById("frame");
    279 
    280  info("Mouse moves into the first iframe");
    281  let promise = Promise.all([waitForEnterLeaveEvents(target),
    282                             waitForMouseEnterMessages(iframe, ["html", "div"])]);
    283  synthesizeNativeMouseEvent({
    284    type: "mousemove",
    285    target,
    286    atCenter: true,
    287  });
    288  await promise;
    289 
    290  let target2 = document.getElementById("target2");
    291  let iframe2 = document.getElementById("frame2");
    292 
    293  info("Mouse moves out from the first iframe to the second iframe");
    294  promise = Promise.all([waitForEnterLeaveEvents(target2, target),
    295                         waitForMouseLeaveMessages(iframe, ["html", "div"]),
    296                         waitForMouseEnterMessages(iframe2, ["html", "div"])]);
    297  synthesizeNativeMouseEvent({
    298    type: "mousemove",
    299    target: target2,
    300    atCenter: true,
    301  })
    302  await promise;
    303 
    304  info("Mouse moves out from the second iframe to the first iframe");
    305  promise = Promise.all([waitForEnterLeaveEvents(target, target2),
    306                         waitForMouseLeaveMessages(iframe2, ["html", "div"]),
    307                         waitForMouseEnterMessages(iframe, ["html", "div"])]);
    308  synthesizeNativeMouseEvent({
    309    type: "mousemove",
    310    target,
    311    atCenter: true,
    312  });
    313  await promise;
    314 
    315  // Move mouse back to initial position.
    316  await Promise.all([waitForLeaveEvent(target),
    317                     waitForMouseLeaveMessages(iframe, ["html", "div"]),
    318                     moveMouseToInitialPosition()]);
    319 });
    320 
    321 add_task(async function testMouseEnterLeaveSwitchWindow() {
    322  let target = document.getElementById("target");
    323  let iframe = document.getElementById("frame");
    324 
    325  info("Mouse moves into iframe");
    326  let promise = Promise.all([waitForEnterLeaveEvents(target),
    327                             waitForMouseEnterMessages(iframe, ["html", "div"])]);
    328  synthesizeNativeMouseEvent({
    329    type: "mousemove",
    330    target,
    331    atCenter: true,
    332  });
    333  await promise;
    334 
    335  info("Open and switch to new window");
    336  promise = Promise.all([waitForLeaveEvent(target),
    337                         waitForMouseLeaveMessages(iframe, ["html", "div"])]);
    338  let win = window.open("http://example.com/tests/dom/events/test/file_mouse_enterleave.html");
    339  // Trigger a reflow which will generate synthesized mouse move event.
    340  win.postMessage("reflow", "*");
    341  await promise;
    342 
    343  info("Switch back to test window");
    344  promise = Promise.all([waitForEnterLeaveEvents(target),
    345                         waitForMouseEnterMessages(iframe, ["html", "div"])]);
    346  win.close();
    347  // Trigger a reflow which will generate synthesized mouse move event.
    348  reflow();
    349  // Wait for apz getting stable.
    350  await waitUntilApzStable();
    351  synthesizeNativeMouseEvent({
    352    type: "mousemove",
    353    target,
    354    atCenter: true,
    355  });
    356  await promise;
    357 
    358  // Move mouse back to initial position.
    359  await Promise.all([waitForLeaveEvent(target),
    360                     moveMouseToInitialPosition()]);
    361 });
    362 </script>