tor-browser

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

head.js (7744B)


      1 /* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* Any copyright is dedicated to the Public Domain.
      4   http://creativecommons.org/publicdomain/zero/1.0/ */
      5 
      6 "use strict";
      7 
      8 const kPasteMenuPopupId = "clipboardReadPasteMenuPopup";
      9 const kPasteMenuItemId = "clipboardReadPasteMenuItem";
     10 
     11 const kBaseUrlForContent = getRootDirectory(gTestPath).replace(
     12  "chrome://mochitests/content",
     13  "https://example.com"
     14 );
     15 
     16 const kPasteCommandTests = [
     17  { description: "Test paste command without editing" },
     18  {
     19    description: "Test paste command on <textarea>",
     20    setupFn: aBrowser => {
     21      return SpecialPowers.spawn(aBrowser, [], () => {
     22        const textarea = content.document.createElement("textarea");
     23        content.document.body.appendChild(textarea);
     24        textarea.focus();
     25      });
     26    },
     27    additionalCheckFunc: (aBrowser, aClipboardData) => {
     28      return SpecialPowers.spawn(aBrowser, [aClipboardData], aClipboardData => {
     29        const textarea = content.document.querySelector("textarea");
     30        is(textarea.value, aClipboardData, "check <textarea> value");
     31      });
     32    },
     33  },
     34  {
     35    description: "Test paste command on <div contenteditable=true>",
     36    setupFn: aBrowser => {
     37      return SpecialPowers.spawn(aBrowser, [], () => {
     38        const div = content.document.createElement("div");
     39        div.setAttribute("contenteditable", "true");
     40        content.document.body.appendChild(div);
     41        div.focus();
     42      });
     43    },
     44    additionalCheckFunc: (aBrowser, aClipboardData) => {
     45      return SpecialPowers.spawn(aBrowser, [aClipboardData], aClipboardData => {
     46        const div = content.document.querySelector("div");
     47        is(div.innerText, aClipboardData, "check contenteditable innerText");
     48      });
     49    },
     50  },
     51 ];
     52 
     53 Services.scriptloader.loadSubScript(
     54  "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js",
     55  this
     56 );
     57 
     58 function promiseWritingRandomTextToClipboard() {
     59  const clipboardText = "X" + Math.random();
     60  return navigator.clipboard.writeText(clipboardText).then(() => {
     61    return clipboardText;
     62  });
     63 }
     64 
     65 function promiseBrowserReflow() {
     66  return new Promise(resolve =>
     67    requestAnimationFrame(() => requestAnimationFrame(resolve))
     68  );
     69 }
     70 
     71 function waitForPasteMenuPopupEvent(aEventSuffix) {
     72  // The element with id `kPasteMenuPopupId` is inserted dynamically, hence
     73  // calling `BrowserTestUtils.waitForEvent` instead of
     74  // `BrowserTestUtils.waitForPopupEvent`.
     75  return BrowserTestUtils.waitForEvent(
     76    document,
     77    "popup" + aEventSuffix,
     78    false /* capture */,
     79    e => {
     80      return e.target.getAttribute("id") == kPasteMenuPopupId;
     81    }
     82  );
     83 }
     84 
     85 function promisePasteButtonIsShown() {
     86  return waitForPasteMenuPopupEvent("shown").then(async () => {
     87    ok(true, "Witnessed 'popupshown' event for 'Paste' button.");
     88 
     89    const pasteButton = document.getElementById(kPasteMenuItemId);
     90    if (Services.prefs.getIntPref("security.dialog_enable_delay") > 0) {
     91      ok(
     92        pasteButton.disabled,
     93        "Paste button should be shown with disabled by default"
     94      );
     95    }
     96    await BrowserTestUtils.waitForMutationCondition(
     97      pasteButton,
     98      { attributeFilter: ["disabled"] },
     99      () => !pasteButton.disabled,
    100      "Wait for paste button enabled"
    101    );
    102 
    103    return promiseBrowserReflow().then(() => {
    104      return coordinatesRelativeToScreen({
    105        target: pasteButton,
    106        offsetX: 0,
    107        offsetY: 0,
    108      });
    109    });
    110  });
    111 }
    112 
    113 function promisePasteButtonIsHidden() {
    114  return waitForPasteMenuPopupEvent("hidden").then(() => {
    115    ok(true, "Witnessed 'popuphidden' event for 'Paste' button.");
    116    return promiseBrowserReflow();
    117  });
    118 }
    119 
    120 function promiseClickPasteButton() {
    121  const pasteButton = document.getElementById(kPasteMenuItemId);
    122  const popup = document.getElementById(kPasteMenuPopupId);
    123  let promise = BrowserTestUtils.waitForEvent(pasteButton, "command");
    124  popup.activateItem(pasteButton);
    125  return promise;
    126 }
    127 
    128 function getMouseCoordsRelativeToScreenInDevicePixels() {
    129  let mouseXInCSSPixels = {};
    130  let mouseYInCSSPixels = {};
    131  window.windowUtils.getLastOverWindowPointerLocationInCSSPixels(
    132    mouseXInCSSPixels,
    133    mouseYInCSSPixels
    134  );
    135 
    136  return {
    137    x:
    138      (mouseXInCSSPixels.value + window.mozInnerScreenX) *
    139      window.devicePixelRatio,
    140    y:
    141      (mouseYInCSSPixels.value + window.mozInnerScreenY) *
    142      window.devicePixelRatio,
    143  };
    144 }
    145 
    146 function isCloselyLeftOnTopOf(aCoordsP1, aCoordsP2, aDelta = 10) {
    147  return (
    148    Math.abs(aCoordsP2.x - aCoordsP1.x) <= aDelta &&
    149    Math.abs(aCoordsP2.y - aCoordsP1.y) <= aDelta
    150  );
    151 }
    152 
    153 async function promiseDismissPasteButton() {
    154  // We intentionally turn off this a11y check, because the following click
    155  // is send on the <body> to dismiss the pending popup using an alternative way
    156  // of the popup dismissal, where the other way like `Esc` key is available,
    157  // therefore this test can be ignored.
    158  AccessibilityUtils.setEnv({
    159    mustHaveAccessibleRule: false,
    160  });
    161  // nsXULPopupManager rollup is handled in widget code, so we have to
    162  // synthesize native mouse events.
    163  await EventUtils.promiseNativeMouseEvent({
    164    type: "click",
    165    target: document.body,
    166    // Relies on the assumption that the center of chrome document doesn't
    167    // overlay with the paste button showed for clipboard readText request.
    168    atCenter: true,
    169  });
    170  // Move mouse away to avoid subsequence tests showing paste button in
    171  // thie dismissing location.
    172  await EventUtils.promiseNativeMouseEvent({
    173    type: "mousemove",
    174    target: document.body,
    175    offsetX: 100,
    176    offsetY: 100,
    177  });
    178  AccessibilityUtils.resetEnv();
    179 }
    180 
    181 // @param aBrowser browser object of the content tab.
    182 // @param aContentElementId the ID of the element to be clicked.
    183 async function promiseClickContentElement(aBrowser, aContentElementId) {
    184  // We intentionally turn off this a11y check, because the following click
    185  // is send on an arbitrary web content that is not expected to be tested
    186  // by itself with the browser mochitests, therefore this rule check shall
    187  // be ignored by a11y-checks suite.
    188  AccessibilityUtils.setEnv({
    189    mustHaveAccessibleRule: false,
    190  });
    191  let result = await SpecialPowers.spawn(
    192    aBrowser,
    193    [aContentElementId],
    194    async _contentElementId => {
    195      const contentElement = content.document.getElementById(_contentElementId);
    196      let promise = new Promise(resolve => {
    197        contentElement.addEventListener(
    198          "click",
    199          function (e) {
    200            resolve({ x: e.screenX, y: e.screenY });
    201          },
    202          { once: true }
    203        );
    204      });
    205 
    206      EventUtils.synthesizeMouseAtCenter(contentElement, {}, content.window);
    207 
    208      return promise;
    209    }
    210  );
    211  AccessibilityUtils.resetEnv();
    212  return result;
    213 }
    214 
    215 // @param aBrowser browser object of the content tab.
    216 // @param aContentElementId the ID of the element to observe.
    217 function promiseMutatedTextContentFromContentElement(
    218  aBrowser,
    219  aContentElementId
    220 ) {
    221  return SpecialPowers.spawn(
    222    aBrowser,
    223    [aContentElementId],
    224    async _contentElementId => {
    225      const contentElement = content.document.getElementById(_contentElementId);
    226 
    227      const promiseTextContentResult = new Promise(resolve => {
    228        const mutationObserver = new content.MutationObserver(
    229          (aMutationRecord, aMutationObserver) => {
    230            info("Observed mutation.");
    231            aMutationObserver.disconnect();
    232            resolve(contentElement.textContent);
    233          }
    234        );
    235 
    236        mutationObserver.observe(contentElement, {
    237          childList: true,
    238        });
    239      });
    240 
    241      return await promiseTextContentResult;
    242    }
    243  );
    244 }