tor-browser

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

AppUiTestDelegate.sys.mjs (6622B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 import { Assert } from "resource://testing-common/Assert.sys.mjs";
      5 import { BrowserTestUtils } from "resource://testing-common/BrowserTestUtils.sys.mjs";
      6 
      7 const lazy = {};
      8 
      9 ChromeUtils.defineESModuleGetters(lazy, {
     10  CustomizableUI:
     11    "moz-src:///browser/components/customizableui/CustomizableUI.sys.mjs",
     12 });
     13 
     14 async function promiseAnimationFrame(window) {
     15  await new Promise(resolve => window.requestAnimationFrame(resolve));
     16 
     17  let { tm } = Services;
     18  return new Promise(resolve => tm.dispatchToMainThread(resolve));
     19 }
     20 
     21 function makeWidgetId(id) {
     22  id = id.toLowerCase();
     23  return id.replace(/[^a-z0-9_-]/g, "_");
     24 }
     25 
     26 async function getPageActionButtonId(window, extensionId) {
     27  // This would normally be set automatically on navigation, and cleared
     28  // when the user types a value into the URL bar, to show and hide page
     29  // identity info and icons such as page action buttons.
     30  //
     31  // Unfortunately, that doesn't happen automatically in browser chrome
     32  // tests.
     33  window.gURLBar.setPageProxyState("valid");
     34 
     35  let { gIdentityHandler } = window.gBrowser.ownerGlobal;
     36  // If the current tab is blank and the previously selected tab was an internal
     37  // page, the urlbar will now be showing the internal identity box due to the
     38  // setPageProxyState call above.  The page action button is hidden in that
     39  // case, so make sure we're not showing the internal identity box.
     40  gIdentityHandler._identityBox.classList.remove("chromeUI");
     41 
     42  await promiseAnimationFrame(window);
     43 
     44  return window.BrowserPageActions.urlbarButtonNodeIDForActionID(
     45    makeWidgetId(extensionId)
     46  );
     47 }
     48 
     49 async function getPageActionButton(window, extensionId) {
     50  let pageActionId = await getPageActionButtonId(window, extensionId);
     51  return window.document.getElementById(pageActionId);
     52 }
     53 
     54 async function clickPageAction(window, extensionId, modifiers = {}) {
     55  let pageActionId = await getPageActionButtonId(window, extensionId);
     56  await BrowserTestUtils.synthesizeMouseAtCenter(
     57    `#${pageActionId}`,
     58    modifiers,
     59    window.browsingContext
     60  );
     61  return new Promise(resolve => Services.tm.dispatchToMainThread(resolve));
     62 }
     63 
     64 function getBrowserActionWidgetId(extensionId) {
     65  return makeWidgetId(extensionId) + "-browser-action";
     66 }
     67 
     68 function getBrowserActionWidget(extensionId) {
     69  return lazy.CustomizableUI.getWidget(getBrowserActionWidgetId(extensionId));
     70 }
     71 
     72 async function showBrowserAction(window, extensionId) {
     73  let group = getBrowserActionWidget(extensionId);
     74  let widget = group.forWindow(window);
     75  if (!widget.node) {
     76    return;
     77  }
     78 
     79  let navbar = window.document.getElementById("nav-bar");
     80  if (group.areaType == lazy.CustomizableUI.TYPE_TOOLBAR) {
     81    Assert.equal(
     82      widget.overflowed,
     83      navbar.hasAttribute("overflowing"),
     84      "Expect widget overflow state to match toolbar"
     85    );
     86  } else if (group.areaType == lazy.CustomizableUI.TYPE_PANEL) {
     87    let panel = window.gUnifiedExtensions.panel;
     88    let shown = BrowserTestUtils.waitForPopupEvent(panel, "shown");
     89    window.gUnifiedExtensions.togglePanel();
     90    await shown;
     91  }
     92 }
     93 
     94 async function clickBrowserAction(window, extensionId, modifiers) {
     95  await promiseAnimationFrame(window);
     96  await showBrowserAction(window, extensionId);
     97 
     98  if (modifiers) {
     99    let widgetId = getBrowserActionWidgetId(extensionId);
    100    BrowserTestUtils.synthesizeMouseAtCenter(
    101      `#${widgetId}`,
    102      modifiers,
    103      window.browsingContext
    104    );
    105  } else {
    106    let widget = getBrowserActionWidget(extensionId).forWindow(window);
    107    widget.node.querySelector(".unified-extensions-item-action-button").click();
    108  }
    109 }
    110 
    111 async function promisePopupShown(popup) {
    112  return new Promise(resolve => {
    113    if (popup.state == "open") {
    114      resolve();
    115    } else {
    116      let onPopupShown = () => {
    117        popup.removeEventListener("popupshown", onPopupShown);
    118        resolve();
    119      };
    120      popup.addEventListener("popupshown", onPopupShown);
    121    }
    122  });
    123 }
    124 
    125 function awaitBrowserLoaded(browser) {
    126  if (
    127    browser.ownerGlobal.document.readyState === "complete" &&
    128    browser.currentURI.spec !== "about:blank"
    129  ) {
    130    return Promise.resolve();
    131  }
    132  return new Promise(resolve => {
    133    const listener = () => {
    134      if (browser.currentURI.spec === "about:blank") {
    135        return;
    136      }
    137      browser.removeEventListener("AppTestDelegate:load", listener);
    138      resolve();
    139    };
    140    browser.addEventListener("AppTestDelegate:load", listener);
    141  });
    142 }
    143 
    144 function getPanelForNode(node) {
    145  return node.closest("panel");
    146 }
    147 
    148 async function awaitExtensionPanel(window, extensionId, awaitLoad = true) {
    149  let { originalTarget: browser } = await BrowserTestUtils.waitForEvent(
    150    window.document,
    151    "WebExtPopupLoaded",
    152    true,
    153    event => event.detail.extension.id === extensionId
    154  );
    155 
    156  await Promise.all([
    157    promisePopupShown(getPanelForNode(browser)),
    158 
    159    awaitLoad && awaitBrowserLoaded(browser),
    160  ]);
    161 
    162  return browser;
    163 }
    164 
    165 function closeBrowserAction(window, extensionId) {
    166  let group = getBrowserActionWidget(extensionId);
    167 
    168  let node = window.document.getElementById(group.viewId);
    169  lazy.CustomizableUI.hidePanelForNode(node);
    170 
    171  return Promise.resolve();
    172 }
    173 
    174 function getPageActionPopup(window, extensionId) {
    175  let panelId = makeWidgetId(extensionId) + "-panel";
    176  return window.document.getElementById(panelId);
    177 }
    178 
    179 function closePageAction(window, extensionId) {
    180  let node = getPageActionPopup(window, extensionId);
    181  if (node) {
    182    return promisePopupShown(node).then(() => {
    183      node.hidePopup();
    184    });
    185  }
    186 
    187  return Promise.resolve();
    188 }
    189 
    190 function openNewForegroundTab(window, url, waitForLoad = true) {
    191  return BrowserTestUtils.openNewForegroundTab(
    192    window.gBrowser,
    193    url,
    194    waitForLoad
    195  );
    196 }
    197 
    198 async function removeTab(tab) {
    199  BrowserTestUtils.removeTab(tab);
    200 }
    201 
    202 // These methods are exported so that they can be used in head.js but are
    203 // *not* part of the AppUiTestDelegate API.
    204 export var AppUiTestInternals = {
    205  awaitBrowserLoaded,
    206  getBrowserActionWidget,
    207  getBrowserActionWidgetId,
    208  getPageActionButton,
    209  getPageActionPopup,
    210  getPanelForNode,
    211  makeWidgetId,
    212  promiseAnimationFrame,
    213  promisePopupShown,
    214  showBrowserAction,
    215 };
    216 
    217 // These methods are part of the AppUiTestDelegate API. All implementations need
    218 // to be kept in sync. For details, see:
    219 // testing/specialpowers/content/AppTestDelegateParent.sys.mjs
    220 export var AppUiTestDelegate = {
    221  awaitExtensionPanel,
    222  clickBrowserAction,
    223  clickPageAction,
    224  closeBrowserAction,
    225  closePageAction,
    226  openNewForegroundTab,
    227  removeTab,
    228 };