tor-browser

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

browser_aboutdebugging_addons_debug_reload.js (9256B)


      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 // There are shutdown issues for which multiple rejections are left uncaught.
      9 // See bug 1018184 for resolving these issues.
     10 const { PromiseTestUtils } = ChromeUtils.importESModule(
     11  "resource://testing-common/PromiseTestUtils.sys.mjs"
     12 );
     13 PromiseTestUtils.allowMatchingRejectionsGlobally(/File closed/);
     14 
     15 const { AddonTestUtils } = ChromeUtils.importESModule(
     16  "resource://testing-common/AddonTestUtils.sys.mjs"
     17 );
     18 AddonTestUtils.initMochitest(this);
     19 
     20 // Avoid test timeouts that can occur while waiting for the "addon-console-works" message.
     21 requestLongerTimeout(2);
     22 
     23 const ADDON_ID = "test-devtools-webextension@mozilla.org";
     24 const ADDON_NAME = "test-devtools-webextension";
     25 
     26 const L10N = new LocalizationHelper(
     27  "devtools/client/locales/toolbox.properties"
     28 );
     29 
     30 // When an extension with sidebar_action gets installed, the sidebar launcher may open.
     31 // Ensure it gets closed to avoid side-effects in later tests.
     32 const initialSidebarState = { ...SidebarController.getUIState(), command: "" };
     33 registerCleanupFunction(async function () {
     34  info("Restoring to initial sidebar state");
     35  await SidebarController.initializeUIState(initialSidebarState);
     36 });
     37 
     38 // Check that addon browsers can be reloaded via the toolbox reload shortcuts
     39 add_task(async function testWebExtensionToolboxReload() {
     40  await enableExtensionDebugging();
     41  const { document, tab, window } = await openAboutDebugging();
     42  await selectThisFirefoxPage(document, window.AboutDebugging.store);
     43 
     44  // Build and install the add-on manually (without installTemporaryExtensionFromXPI)
     45  // in order to be able to make changes to the add-on files before reloads
     46  const manifest = JSON.stringify({
     47    manifest_version: 2,
     48    version: "1.0",
     49    name: ADDON_NAME,
     50    background: {
     51      scripts: ["background.js"],
     52    },
     53    sidebar_action: {
     54      default_title: "Sidebar",
     55      default_icon: {
     56        64: "icon.png",
     57      },
     58      default_panel: "sidebar.html",
     59    },
     60  });
     61  const files = {
     62    "manifest.json": manifest,
     63    "background.js": `
     64      fetch("data:text/html,fooo");
     65      console.log("background script executed " + Math.random());
     66      throw new Error("background exception")
     67    `,
     68    "sidebar.html": `<!DOCTYPE html>
     69      <html>
     70        <head>
     71          <meta charset="utf-8">
     72        </head>
     73        <body>
     74          Sidebar
     75        </body>
     76      </html>
     77    `,
     78  };
     79  const tempAddonDir = AddonTestUtils.tempDir.clone();
     80  const addonDir = await AddonTestUtils.promiseWriteFilesToExtension(
     81    tempAddonDir.path,
     82    ADDON_ID,
     83    files,
     84    true
     85  );
     86 
     87  const addon = await AddonManager.installTemporaryAddon(addonDir);
     88 
     89  // Select the debugger right away to avoid any noise coming from the inspector.
     90  await pushPref("devtools.toolbox.selectedTool", "webconsole");
     91  const { devtoolsDocument, devtoolsWindow } = await openAboutDevtoolsToolbox(
     92    document,
     93    tab,
     94    window,
     95    ADDON_NAME
     96  );
     97  const toolbox = getToolbox(devtoolsWindow);
     98 
     99  ok(
    100    devtoolsDocument.querySelector(".qa-reload-button"),
    101    "Reload button is visible"
    102  );
    103  ok(
    104    !devtoolsDocument.querySelector(".qa-back-button"),
    105    "Back button is hidden"
    106  );
    107  ok(
    108    !devtoolsDocument.querySelector(".qa-forward-button"),
    109    "Forward button is hidden"
    110  );
    111  ok(
    112    !devtoolsDocument.querySelector(".debug-target-url-form"),
    113    "URL form is hidden"
    114  );
    115  ok(
    116    devtoolsDocument.getElementById("toolbox-meatball-menu-noautohide"),
    117    "Disable popup autohide button is displayed"
    118  );
    119  ok(
    120    !devtoolsDocument.getElementById(
    121      "toolbox-meatball-menu-pseudo-locale-accented"
    122    ),
    123    "Accented locale is not displayed (only on browser toolbox)"
    124  );
    125 
    126  // Ensure opening the netmonitor to handle requests before reloading
    127  await toolbox.selectTool("netmonitor");
    128 
    129  const webconsole = await toolbox.selectTool("webconsole");
    130  const { hud } = webconsole;
    131 
    132  info("Wait for the initial background message to appear in the console");
    133  const initialMessage = await waitFor(() =>
    134    findMessageByType(hud, "background script executed", ".console-api")
    135  );
    136  ok(initialMessage, "Found the expected message from the background script");
    137 
    138  await waitFor(
    139    () => findMessageByType(hud, "background exception", ".error"),
    140    "Found the background page exception"
    141  );
    142 
    143  let loadedTargets = 0;
    144  await toolbox.commands.resourceCommand.watchResources(
    145    [toolbox.commands.resourceCommand.TYPES.DOCUMENT_EVENT],
    146    {
    147      ignoreExistingResources: true,
    148      onAvailable(resources) {
    149        for (const resource of resources) {
    150          if (resource.name == "dom-complete") {
    151            loadedTargets++;
    152          }
    153        }
    154      },
    155    }
    156  );
    157 
    158  info("Reload the addon using a toolbox reload shortcut");
    159  toolbox.win.focus();
    160  synthesizeKeyShortcut(L10N.getStr("toolbox.reload.key"), toolbox.win);
    161 
    162  info("Wait until a new background log message is logged");
    163  const secondMessage = await waitFor(() => {
    164    const newMessage = findMessageByType(
    165      hud,
    166      "background script executed",
    167      ".console-api"
    168    );
    169    if (newMessage && newMessage !== initialMessage) {
    170      return newMessage;
    171    }
    172    return false;
    173  });
    174 
    175  await waitFor(
    176    () => loadedTargets == 2,
    177    "Wait for background and popup targets to be reloaded"
    178  );
    179  let menuList = toolbox.doc.getElementById("toolbox-frame-menu");
    180  await waitFor(
    181    () => menuList.querySelectorAll(".command").length == 3,
    182    "Wait for fallback, background and sidebar documents to visible in the iframe dropdown"
    183  );
    184 
    185  info("Reload via the debug target info bar button");
    186  loadedTargets = 0;
    187  clickReload(devtoolsDocument);
    188 
    189  info("Wait until yet another background log message is logged");
    190  await waitFor(() => {
    191    const newMessage = findMessageByType(
    192      hud,
    193      "background script executed",
    194      ".console-api"
    195    );
    196    return (
    197      newMessage &&
    198      newMessage !== initialMessage &&
    199      newMessage !== secondMessage
    200    );
    201  });
    202 
    203  await waitFor(
    204    () => loadedTargets == 2,
    205    "Wait for background and popup targets to be reloaded"
    206  );
    207  menuList = toolbox.doc.getElementById("toolbox-frame-menu");
    208  await waitFor(
    209    () => menuList.querySelectorAll(".command").length == 3,
    210    "Wait for fallback, background and sidebar documents to visible in the iframe dropdown"
    211  );
    212 
    213  // Verify that we got the data: URI request made from the background page
    214  const netmonitor = await toolbox.selectTool("netmonitor");
    215  is(
    216    netmonitor.panelWin.store.getState().requests.requests.length,
    217    1,
    218    "There is a the request for the data: URI done from the background page"
    219  );
    220 
    221  await toolbox.selectTool("webconsole");
    222 
    223  info("Introduce a typo in the manifest before reloading");
    224  loadedTargets = 0;
    225  // Add an unexpected character at the end of the JSON
    226  files["manifest.json"] += `x`;
    227  await AddonTestUtils.promiseWriteFilesToExtension(
    228    tempAddonDir.path,
    229    ADDON_ID,
    230    files,
    231    true
    232  );
    233  clickReload(devtoolsDocument);
    234 
    235  const notification = await waitFor(
    236    () => toolbox.doc.querySelector(`.notification[data-key="reload-error"]`),
    237    "Wait for the error to be shown"
    238  );
    239  Assert.stringContains(
    240    notification.textContent,
    241    "unexpected non-whitespace character after JSON data",
    242    "The error message is correct"
    243  );
    244  is(loadedTargets, 0, "No target is loaded when the add-on fails loading");
    245 
    246  info("Restore to the valid manifest and reload again");
    247  files["manifest.json"] = manifest;
    248  // Empty the background page to prevent throwing the exception
    249  files["background.js"] = `console.log("background log");`;
    250  await AddonTestUtils.promiseWriteFilesToExtension(
    251    tempAddonDir.path,
    252    ADDON_ID,
    253    files,
    254    true
    255  );
    256  clickReload(devtoolsDocument);
    257 
    258  await waitFor(
    259    () => !toolbox.doc.querySelector(`.notification[data-key="reload-error"]`),
    260    "Wait for the error to be hidden"
    261  );
    262  await waitFor(
    263    () => loadedTargets == 2,
    264    "Wait for background and popup targets to be reloaded"
    265  );
    266  await waitFor(
    267    () => findMessageByType(hud, "background log", ".console-api"),
    268    "Found the background page console api call"
    269  );
    270  ok(
    271    !findMessageByType(hud, "background exception", ".error"),
    272    "The background page exception is no longer visible"
    273  );
    274  is(
    275    netmonitor.panelWin.store.getState().requests.requests.length,
    276    0,
    277    "The netmonitor is also cleared"
    278  );
    279 
    280  info("Enable log persistance in the console");
    281  devtoolsDocument
    282    .querySelector(".webconsole-console-settings-menu-item-persistentLogs")
    283    .click();
    284  await waitUntil(
    285    () => hud.ui.wrapper.getStore().getState().ui.persistLogs === true
    286  );
    287 
    288  clickReload(devtoolsDocument);
    289 
    290  info("Wait for the reloaded message in the console");
    291  await waitFor(() => findMessageByType(hud, "Reloaded", ".navigationMarker"));
    292 
    293  await closeWebExtAboutDevtoolsToolbox(devtoolsWindow, window);
    294  await addon.uninstall();
    295  await removeTab(tab);
    296 });
    297 
    298 function clickReload(devtoolsDocument) {
    299  devtoolsDocument.querySelector(".qa-reload-button").click();
    300 }