tor-browser

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

browser_touch_all_events.js (6783B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
      4 
      5 "use strict";
      6 
      7 const TEST_URL = `${URL_ROOT_COM_SSL}touch_iframe_parent.html`;
      8 const TEST_URL2 = `${URL_ROOT_COM_SSL}touch_iframe_parent_desktop.html`;
      9 const REMOTE_IFRAME_URL = `${URL_ROOT_ORG_SSL}touch_iframe_child.html`;
     10 
     11 const EXPECTED_TAP_EVENTS =
     12  "pointerdown touchstart pointerup touchend mousemove mousedown mouseup click";
     13 const EXPECTED_DRAG_EVENTS =
     14  "pointerdown touchstart pointermove touchmove pointerup touchend";
     15 const EXPECTED_DOUBLE_TAP_EVENTS = `${EXPECTED_TAP_EVENTS} ${EXPECTED_TAP_EVENTS} dblclick`;
     16 const EXPECTED_DOUBLE_TAP_ZOOM_EVENTS = `pointerdown touchstart pointerup touchend pointerdown touchstart pointerup touchend`;
     17 const EXPECTED_LONG_TAP_EVENTS = `pointerdown touchstart mousemove contextmenu pointerup touchend`;
     18 
     19 addRDMTask(TEST_URL, async function ({ ui }) {
     20  reloadOnTouchChange(true);
     21  await toggleTouchSimulation(ui);
     22  await runTests(
     23    ui,
     24    ["topFrame", "localIFrame", "remoteIFrame"],
     25    ["tap", "drag", "double_tap", "long_tap"]
     26  );
     27  await toggleTouchSimulation(ui);
     28 });
     29 
     30 // The following tests change the page's zoom state, so we run each of them
     31 // separately to ensure they don't interfere with each other.
     32 for (const frameName of ["topFrame", "localIFrame", "remoteIFrame"]) {
     33  addRDMTask(TEST_URL2, async function ({ ui }) {
     34    reloadOnTouchChange(true);
     35    await toggleTouchSimulation(ui);
     36    await runTests(ui, [frameName], ["double_tap_zoom"]);
     37    await toggleTouchSimulation(ui);
     38  });
     39 }
     40 
     41 function runTests(ui, frameNames, tests) {
     42  return spawnViewportTask(
     43    ui,
     44    {
     45      tests,
     46      frameNames,
     47      REMOTE_IFRAME_URL,
     48      EXPECTED_TAP_EVENTS,
     49      EXPECTED_DOUBLE_TAP_EVENTS,
     50      EXPECTED_DOUBLE_TAP_ZOOM_EVENTS,
     51      EXPECTED_LONG_TAP_EVENTS,
     52      EXPECTED_DRAG_EVENTS,
     53    },
     54    async args => {
     55      const frames = {
     56        topFrame: content.document.body,
     57        localIFrame: content.document.getElementById("local-iframe"),
     58        remoteIFrame: content.document.getElementById("remote-iframe"),
     59      };
     60 
     61      // Load the remote iframe and wait for it to be loaded.
     62      frames.remoteIFrame.src = args.REMOTE_IFRAME_URL;
     63      await ContentTaskUtils.waitForEvent(frames.remoteIFrame, "load");
     64      // Wait for the remote iframe to be ready to receive events.
     65      await SpecialPowers.spawn(frames.remoteIFrame, [], async () => {
     66        await SpecialPowers.contentTransformsReceived(content);
     67      });
     68 
     69      const body = content.document.body;
     70 
     71      async function checkEventLog(expectedFrame, expectedEvents, test) {
     72        const lastExpectedEvent = expectedEvents.substring(
     73          expectedEvents.lastIndexOf(" ") + 1
     74        );
     75        await waitForEventFromFrame(expectedFrame, lastExpectedEvent, 2000);
     76        // wait some more to ensure there are no unexpected delayed events
     77        await waitForTime(500);
     78 
     79        for (const frameName of ["topFrame", "localIFrame", "remoteIFrame"]) {
     80          const expected =
     81            frameName === expectedFrame ? expectedEvents : undefined;
     82          is(
     83            body.dataset[frameName],
     84            expected,
     85            `${frameName} received the expected events in the ${test} test`
     86          );
     87        }
     88      }
     89 
     90      function clearEventLog() {
     91        for (const key of Object.keys(body.dataset)) {
     92          delete body.dataset[key];
     93        }
     94      }
     95 
     96      function waitForTime(ms) {
     97        return new Promise(resolve => {
     98          content.setTimeout(resolve, ms);
     99        });
    100      }
    101 
    102      function synthesizeMouseEvent(target, type, offsetX, offsetY) {
    103        return new Promise(resolve => {
    104          EventUtils.synthesizeNativeMouseEvent(
    105            {
    106              target,
    107              type,
    108              offsetX,
    109              offsetY,
    110              win: content,
    111            },
    112            resolve
    113          );
    114        });
    115      }
    116 
    117      async function synthesizeClick(target, waitFor) {
    118        await synthesizeMouseEvent(target, "mousedown", 50, 50);
    119        if (waitFor) {
    120          await waitFor();
    121        }
    122        await synthesizeMouseEvent(target, "mouseup", 50, 50);
    123      }
    124 
    125      async function waitForEventFromFrame(frameName, type, timeout = 100) {
    126        await ContentTaskUtils.waitForCondition(
    127          () => body.dataset[frameName]?.split(" ").includes(type),
    128          `Waiting for ${type} event from ${frameName}`,
    129          10,
    130          timeout / 10
    131        );
    132      }
    133 
    134      for (const frameName of args.frameNames) {
    135        const frame = frames[frameName];
    136        for (const test of args.tests) {
    137          clearEventLog();
    138          switch (test) {
    139            case "tap": {
    140              await synthesizeClick(frame);
    141              await checkEventLog(frameName, args.EXPECTED_TAP_EVENTS, test);
    142              break;
    143            }
    144 
    145            case "drag": {
    146              await synthesizeMouseEvent(frame, "mousedown", 50, 50);
    147              await synthesizeMouseEvent(frame, "mousemove", 60, 50);
    148              // wait for the touchmove event to be received before synthesizing the next one
    149              // to ensure the received events are in the expected order
    150              await waitForEventFromFrame(frameName, "touchmove");
    151              await synthesizeMouseEvent(frame, "mouseup", 60, 50);
    152              await checkEventLog(frameName, args.EXPECTED_DRAG_EVENTS, test);
    153              break;
    154            }
    155 
    156            case "long_tap": {
    157              await synthesizeClick(frame, () =>
    158                waitForEventFromFrame(frameName, "contextmenu", 1000)
    159              );
    160              await checkEventLog(
    161                frameName,
    162                args.EXPECTED_LONG_TAP_EVENTS,
    163                test
    164              );
    165              break;
    166            }
    167 
    168            case "double_tap": {
    169              await synthesizeClick(frame);
    170              // wait for the click event to be received before synthesizing the next one
    171              // to ensure the received events are in the expected order
    172              await waitForEventFromFrame(frameName, "click");
    173              await synthesizeClick(frame);
    174              await checkEventLog(
    175                frameName,
    176                args.EXPECTED_DOUBLE_TAP_EVENTS,
    177                test
    178              );
    179              break;
    180            }
    181 
    182            case "double_tap_zoom": {
    183              await synthesizeClick(frame);
    184              await synthesizeClick(frame);
    185              await checkEventLog(
    186                frameName,
    187                args.EXPECTED_DOUBLE_TAP_ZOOM_EVENTS,
    188                test
    189              );
    190              break;
    191            }
    192          }
    193        }
    194      }
    195    }
    196  );
    197 }