tor-browser

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

browser_aboutdebugging_addons_debug_popup.js (8169B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 "use strict";
      4 
      5 /* import-globals-from helper-addons.js */
      6 Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-addons.js", this);
      7 
      8 /* import-globals-from ../../../inspector/test/shared-head.js */
      9 Services.scriptloader.loadSubScript(
     10  "chrome://mochitests/content/browser/devtools/client/inspector/test/shared-head.js",
     11  this
     12 );
     13 
     14 // There are shutdown issues for which multiple rejections are left uncaught.
     15 // See bug 1018184 for resolving these issues.
     16 const { PromiseTestUtils } = ChromeUtils.importESModule(
     17  "resource://testing-common/PromiseTestUtils.sys.mjs"
     18 );
     19 PromiseTestUtils.allowMatchingRejectionsGlobally(/File closed/);
     20 
     21 // Avoid test timeouts that can occur while waiting for the "addon-console-works" message.
     22 requestLongerTimeout(2);
     23 
     24 const ADDON_ID = "test-devtools-webextension@mozilla.org";
     25 const ADDON_NAME = "test-devtools-webextension";
     26 
     27 /**
     28 * This test file ensures that the webextension addon developer toolbox:
     29 * - has a frame list menu and the noautohide toolbar toggle button, and they
     30 *   can be used to switch the current target to the extension popup page.
     31 */
     32 add_task(async function testWebExtensionsToolboxWebConsole() {
     33  await enableExtensionDebugging();
     34 
     35  // Bug 1686922: Disable the error count button to avoid intermittent failures.
     36  await pushPref("devtools.command-button-errorcount.enabled", false);
     37 
     38  is(
     39    Services.prefs.getBoolPref("ui.popup.disable_autohide"),
     40    false,
     41    "disable_autohide should be initially false"
     42  );
     43 
     44  const {
     45    document,
     46    tab,
     47    window: aboutDebuggingWindow,
     48  } = await openAboutDebugging();
     49  await selectThisFirefoxPage(
     50    document,
     51    aboutDebuggingWindow.AboutDebugging.store
     52  );
     53 
     54  const extension = await installTestAddon(document);
     55 
     56  const onBackgroundFunctionCalled = waitForExtensionTestMessage(
     57    extension,
     58    "onBackgroundFunctionCalled"
     59  );
     60  const onPopupPageFunctionCalled = waitForExtensionTestMessage(
     61    extension,
     62    "onPopupPageFunctionCalled"
     63  );
     64 
     65  info("Open a toolbox to debug the addon");
     66  const { devtoolsWindow } = await openAboutDevtoolsToolbox(
     67    document,
     68    tab,
     69    aboutDebuggingWindow,
     70    ADDON_NAME
     71  );
     72 
     73  const toolbox = getToolbox(devtoolsWindow);
     74  const webconsole = await toolbox.selectTool("webconsole");
     75 
     76  info("Clicking the menu button to disable autohide");
     77  await disablePopupAutohide(toolbox);
     78 
     79  info("Check that console messages are evaluated in the background context");
     80  const consoleWrapper = webconsole.hud.ui.wrapper;
     81  consoleWrapper.dispatchEvaluateExpression("backgroundFunction()");
     82  await onBackgroundFunctionCalled;
     83 
     84  clickOnAddonWidget(ADDON_ID);
     85 
     86  info("Wait until the frames list button is displayed");
     87  const btn = await waitFor(() =>
     88    toolbox.doc.getElementById("command-button-frames")
     89  );
     90 
     91  info("Clicking the frame list button");
     92  btn.click();
     93 
     94  const menuList = toolbox.doc.getElementById("toolbox-frame-menu");
     95  await waitFor(
     96    () => menuList.querySelectorAll(".command").length == 3,
     97    "Wait for fallback, background and popup documents to be listed"
     98  );
     99  const frames = Array.from(menuList.querySelectorAll(".command"));
    100  is(frames.length, 3, "Has the expected number of frames");
    101 
    102  const popupFrameBtn = frames
    103    .filter(frame => {
    104      return frame.querySelector(".label").textContent.endsWith("popup.html");
    105    })
    106    .pop();
    107 
    108  ok(popupFrameBtn, "Extension Popup frame found in the listed frames");
    109 
    110  info(
    111    "Click on the extension popup frame and wait for a `dom-complete` resource"
    112  );
    113  const { onResource: onDomCompleteResource } =
    114    await toolbox.commands.resourceCommand.waitForNextResource(
    115      toolbox.commands.resourceCommand.TYPES.DOCUMENT_EVENT,
    116      {
    117        ignoreExistingResources: true,
    118        predicate: resource => resource.name === "dom-complete",
    119      }
    120    );
    121  popupFrameBtn.click();
    122  await onDomCompleteResource;
    123 
    124  info("Execute `popupPageFunction()`");
    125  consoleWrapper.dispatchEvaluateExpression("popupPageFunction()");
    126 
    127  const args = await onPopupPageFunctionCalled;
    128  ok(true, "Received console message from the popup page function as expected");
    129  is(args[0], "onPopupPageFunctionCalled", "Got the expected console message");
    130  is(
    131    args[1] && args[1].name,
    132    ADDON_NAME,
    133    "Got the expected manifest from WebExtension API"
    134  );
    135 
    136  info("Check that node screenshots work in webextension targets");
    137  const inspector = await toolbox.selectTool("inspector");
    138  await selectNode("#node-to-screenshot", inspector);
    139  const redScreenshot = await takeNodeScreenshot(inspector);
    140  await assertSingleColorScreenshotImage(redScreenshot, 10, 10, {
    141    r: 255,
    142    g: 0,
    143    b: 0,
    144  });
    145 
    146  await closeWebExtAboutDevtoolsToolbox(devtoolsWindow, aboutDebuggingWindow);
    147 
    148  is(
    149    Services.prefs.getBoolPref("ui.popup.disable_autohide"),
    150    false,
    151    "disable_autohide should be reset to false when the toolbox is closed"
    152  );
    153 
    154  await removeTemporaryExtension(ADDON_NAME, document);
    155  await removeTab(tab);
    156 });
    157 
    158 /**
    159 * Helper to wait for a specific message on an Extension instance.
    160 */
    161 function waitForExtensionTestMessage(extension, expectedMessage) {
    162  return new Promise(done => {
    163    extension.on("test-message", function testLogListener(evt, ...args) {
    164      const [message] = args;
    165 
    166      if (message !== expectedMessage) {
    167        return;
    168      }
    169 
    170      extension.off("test-message", testLogListener);
    171      done(args);
    172    });
    173  });
    174 }
    175 
    176 /**
    177 * Install the addon used for this test.
    178 * Returns a Promise that resolve the Extension instance that was just
    179 * installed.
    180 */
    181 async function installTestAddon(doc) {
    182  // Start watching for the extension on the Extension Management before we
    183  // install it.
    184  const onExtensionReady = waitForExtension(ADDON_NAME);
    185 
    186  // Install the extension.
    187  await installTemporaryExtensionFromXPI(
    188    {
    189      background() {
    190        const { browser } = this;
    191        window.backgroundFunction = function () {
    192          browser.test.sendMessage("onBackgroundFunctionCalled");
    193        };
    194      },
    195      extraProperties: {
    196        browser_action: {
    197          default_title: "WebExtension Popup Debugging",
    198          default_popup: "popup.html",
    199          default_area: "navbar",
    200        },
    201      },
    202      files: {
    203        "popup.html": `<!DOCTYPE html>
    204        <html>
    205          <head>
    206            <meta charset="utf-8">
    207            <script src="popup.js"></script>
    208          </head>
    209          <body>
    210            Background Page Body Test Content
    211            <div
    212              id="node-to-screenshot"
    213              style="height: 10px; width: 10px; background: red;">
    214            </div>
    215          </body>
    216        </html>
    217      `,
    218        "popup.js": function () {
    219          const { browser } = this;
    220          window.popupPageFunction = function () {
    221            browser.test.sendMessage(
    222              "onPopupPageFunctionCalled",
    223              browser.runtime.getManifest()
    224            );
    225          };
    226        },
    227      },
    228      id: ADDON_ID,
    229      name: ADDON_NAME,
    230    },
    231    doc
    232  );
    233 
    234  // The onExtensionReady promise will resolve the extension instance.
    235  return onExtensionReady;
    236 }
    237 
    238 /**
    239 * Helper to retrieve the Extension instance.
    240 */
    241 async function waitForExtension(addonName) {
    242  const { Management } = ChromeUtils.importESModule(
    243    "resource://gre/modules/Extension.sys.mjs"
    244  );
    245 
    246  return new Promise(resolve => {
    247    Management.on("startup", function listener(event, extension) {
    248      if (extension.name != addonName) {
    249        return;
    250      }
    251 
    252      Management.off("startup", listener);
    253      resolve(extension);
    254    });
    255  });
    256 }
    257 
    258 /**
    259 * Disables the popup autohide feature, which is mandatory to debug webextension
    260 * popups.
    261 */
    262 function disablePopupAutohide(toolbox) {
    263  return new Promise(resolve => {
    264    toolbox.doc.addEventListener(
    265      "popupshown",
    266      () => {
    267        const menuItem = toolbox.doc.getElementById(
    268          "toolbox-meatball-menu-noautohide"
    269        );
    270        menuItem.click();
    271        resolve();
    272      },
    273      { once: true }
    274    );
    275    toolbox.doc.getElementById("toolbox-meatball-menu-button").click();
    276  });
    277 }