tor-browser

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

network-overrides-test-helpers.js (9642B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 /* import-globals-from head.js */
      7 
      8 /* exported ORIGINAL_SCRIPT */
      9 const ORIGINAL_SCRIPT = `
     10 const div = document.createElement("div");
     11 div.id = "created-by-original";
     12 document.body.appendChild(div);
     13 `;
     14 
     15 /* exported OVERRIDDEN_SCRIPT */
     16 const OVERRIDDEN_SCRIPT = `
     17 const div = document.createElement("div");
     18 div.id = "created-by-override";
     19 document.body.appendChild(div);
     20 `;
     21 
     22 /* exported ORIGINAL_STYLESHEET */
     23 const ORIGINAL_STYLESHEET = `
     24  body {
     25    color: red;
     26  }
     27 `;
     28 
     29 /* exported OVERRIDDEN_STYLESHEET */
     30 const OVERRIDDEN_STYLESHEET = `
     31  body {
     32    color: blue;
     33  }
     34 `;
     35 
     36 /* exported ORIGINAL_HTML */
     37 const ORIGINAL_HTML = `<!DOCTYPE html>
     38 <html>
     39  <head>
     40    <meta charset="utf-8"/>
     41    <title>Original title</title>
     42  </head>
     43  <body>
     44    Original content
     45    <script type="text/javascript" src="/script.js"></script>
     46    <style>@import "/style.css"</style>
     47  </body>
     48 </html>`;
     49 
     50 /* exported OVERRIDDEN_HTML */
     51 const OVERRIDDEN_HTML = `<!DOCTYPE html>
     52 <html>
     53 <head>
     54  <meta charset="utf-8"/>
     55  <title>Overridden title</title>
     56 </head>
     57 <body>
     58  Overridden content
     59 </body>
     60 </html>
     61 `;
     62 
     63 function startOverridesHTTPServer() {
     64  const httpServer = createTestHTTPServer();
     65  const baseURL = `http://localhost:${httpServer.identity.primaryPort}/`;
     66 
     67  httpServer.registerContentType("html", "text/html");
     68  httpServer.registerContentType("js", "application/javascript");
     69 
     70  httpServer.registerPathHandler("/index.html", (request, response) => {
     71    response.setStatusLine(request.httpVersion, 200, "OK");
     72    response.setHeader("Cache-Control", "max-age=60000");
     73    response.write(ORIGINAL_HTML);
     74  });
     75 
     76  httpServer.registerPathHandler("/script.js", (request, response) => {
     77    response.setHeader("Content-Type", "application/javascript");
     78    response.setHeader("Cache-Control", "max-age=60000");
     79    response.write(ORIGINAL_SCRIPT);
     80  });
     81 
     82  httpServer.registerPathHandler("/style.css", (request, response) => {
     83    response.setHeader("Content-Type", "text/css; charset=utf-8");
     84    response.setHeader("Cache-Control", "max-age=60000");
     85    response.write(ORIGINAL_STYLESHEET);
     86  });
     87 
     88  return baseURL;
     89 }
     90 
     91 /* exported assertOverrideColumnStatus */
     92 /**
     93 * Check if the override column is currently visible or not.
     94 *
     95 * @param {object} monitor
     96 *     The netmonitor monitor instance.
     97 * @param {object} options
     98 * @param {boolean} options.visible
     99 *     Whether the column is expected to be visible or not.
    100 */
    101 async function assertOverrideColumnStatus(monitor, { visible }) {
    102  const doc = monitor.panelWin.document;
    103 
    104  // Assert override column is hidden
    105  is(
    106    !!doc.querySelector(`#requests-list-override-button`),
    107    visible,
    108    `Column Override should be ${visible ? "visible" : "hidden"}`
    109  );
    110 
    111  // Assert override column context menu item status.
    112  const overrideColumnToggle = await openContextMenuForItem(
    113    monitor,
    114    // Trigger the column context menu on the status column which should usually
    115    // be available.
    116    doc.querySelector("#requests-list-status-button"),
    117    "request-list-header-override-toggle"
    118  );
    119 
    120  if (visible) {
    121    is(
    122      overrideColumnToggle.getAttribute("checked"),
    123      "true",
    124      "The Override column menu item is checked"
    125    );
    126  } else {
    127    ok(
    128      !overrideColumnToggle.getAttribute("checked"),
    129      "The Override column menu item is unchecked"
    130    );
    131  }
    132 
    133  // Assert that override column is always disabled
    134  is(
    135    overrideColumnToggle.disabled,
    136    true,
    137    "The Override column menu item is disabled"
    138  );
    139 
    140  await hideContextMenu(overrideColumnToggle.parentNode);
    141 }
    142 
    143 /* exported assertOverrideCellStatus */
    144 /**
    145 * Check if the provided cell is displayed as overridden or not.
    146 *
    147 * @param {object} request
    148 *     The request to assert.
    149 * @param {object} options
    150 * @param {boolean} options.overridden
    151 *     Whether the request is expected to be overridden or not.
    152 */
    153 function assertOverrideCellStatus(request, { overridden }) {
    154  is(
    155    request
    156      .querySelector(".requests-list-override")
    157      .classList.contains("request-override-enabled"),
    158    overridden,
    159    `The request is ${overridden ? " " : "not "}shown as overridden`
    160  );
    161 }
    162 
    163 /**
    164 * Open the netmonitor context menu on the provided element
    165 *
    166 * @param {object} monitor
    167 *        The network monitor object
    168 * @param {Element} el
    169 *        The element on which the menu should be opened
    170 * @param {string} id
    171 *        The id of the context menu item
    172 */
    173 async function openContextMenuForItem(monitor, el, id) {
    174  EventUtils.sendMouseEvent({ type: "contextmenu" }, el);
    175  const menuItem = getContextMenuItem(monitor, id);
    176  const popup = menuItem.parentNode;
    177 
    178  if (popup.state != "open") {
    179    await BrowserTestUtils.waitForEvent(popup, "popupshown");
    180  }
    181 
    182  return menuItem;
    183 }
    184 
    185 /* exported setNetworkOverride */
    186 /**
    187 * Setup a network override for the provided monitor, request, override file
    188 * name and content.
    189 *
    190 * @param {object} monitor
    191 *     The netmonitor monitor instance.
    192 * @param {object} request
    193 *     The request to override.
    194 * @param {string} overrideFileName
    195 *     The file name to use for the override.
    196 * @param {string} overrideContent
    197 *     The content to use for the override.
    198 * @returns {string}
    199 *     The path to the overridden file.
    200 * @param {boolean} isEmpty
    201 *     True if the saved file is supposed to be empty.
    202 *     This is a workaround for the case where the response is not available.
    203 */
    204 async function setNetworkOverride(
    205  monitor,
    206  request,
    207  overrideFileName,
    208  overrideContent,
    209  isEmpty = false
    210 ) {
    211  const overridePath = prepareFilePicker(
    212    overrideFileName,
    213    monitor.toolbox.topWindow
    214  );
    215 
    216  info("Select the request to update");
    217  EventUtils.sendMouseEvent({ type: "mousedown" }, request);
    218 
    219  info("Use set override from the context menu");
    220  EventUtils.sendMouseEvent({ type: "contextmenu" }, request);
    221  const waitForSetOverride = waitForDispatch(
    222    monitor.toolbox.store,
    223    "SET_NETWORK_OVERRIDE"
    224  );
    225  await selectContextMenuItem(monitor, "request-list-context-set-override");
    226  await waitForSetOverride;
    227 
    228  info(`Wait for ${overrideFileName} to be saved to disk and re-write it`);
    229  await writeTextContentToPath(overrideContent, overridePath, isEmpty);
    230 
    231  return overridePath;
    232 }
    233 
    234 /* exported removeNetworkOverride */
    235 /**
    236 * Remove a network override for the provided monitor and request.
    237 *
    238 * @param {object} monitor
    239 *     The netmonitor monitor instance.
    240 * @param {object} request
    241 *     The request for which the override should be removed.
    242 */
    243 async function removeNetworkOverride(monitor, request) {
    244  info("Select the request to update");
    245  EventUtils.sendMouseEvent({ type: "mousedown" }, request);
    246 
    247  info("Use remove override from the context menu");
    248  EventUtils.sendMouseEvent({ type: "contextmenu" }, request);
    249  const waitForSetOverride = waitForDispatch(
    250    monitor.toolbox.store,
    251    "REMOVE_NETWORK_OVERRIDE"
    252  );
    253  await selectContextMenuItem(monitor, "request-list-context-remove-override");
    254  await waitForSetOverride;
    255 }
    256 
    257 /* exported prepareFilePicker */
    258 /**
    259 * Mock the file picker.
    260 *
    261 * @param {string} filename
    262 *     The name of the file to create.
    263 * @param {XULWindow} chromeWindow
    264 *     The browser window.
    265 * @returns {string}
    266 *     The path of the mocked file.
    267 */
    268 function prepareFilePicker(filename, chromeWindow) {
    269  const MockFilePicker = SpecialPowers.MockFilePicker;
    270  MockFilePicker.init(chromeWindow.browsingContext);
    271  const nsiFile = new FileUtils.File(
    272    PathUtils.join(PathUtils.tempDir, filename)
    273  );
    274  MockFilePicker.setFiles([nsiFile]);
    275  return nsiFile.path;
    276 }
    277 
    278 /* exported writeTextContentToPath */
    279 /**
    280 * Update the text content of the file at the provided path.
    281 *
    282 * @param {string} textContent
    283 *     The text content to set.
    284 * @param {string} path
    285 *     The path of the file to update.
    286 * @param {boolean} isEmpty
    287 *     True if the saved file is supposed to be empty.
    288 */
    289 async function writeTextContentToPath(textContent, path, isEmpty = false) {
    290  await BrowserTestUtils.waitForCondition(() => IOUtils.exists(path));
    291  await BrowserTestUtils.waitForCondition(async () => {
    292    const { size } = await IOUtils.stat(path);
    293    if (isEmpty) {
    294      return size === 0;
    295    }
    296    return size > 0;
    297  });
    298 
    299  // Bug 1946642: need to cleanup MockFilePicker before potentially creating
    300  // another one. Can't use registerCleanupFunction because it will only run
    301  // at the end of a full test, at this point init() might already have been
    302  // called more than once. Here the MockFilePicker has done its job and can
    303  // be cleaned up.
    304  SpecialPowers.MockFilePicker.cleanup();
    305 
    306  await IOUtils.write(path, new TextEncoder().encode(textContent));
    307 }
    308 
    309 /* exported setupNetworkOverridesTest */
    310 /**
    311 * Sets up a basic server for network overrides tests, adds a tab loading this
    312 * server and starts the netmonitor.
    313 *
    314 * @returns {object}
    315 *     An object with monitor, tab and document properties.
    316 */
    317 async function setupNetworkOverridesTest({ enableCache = false } = {}) {
    318  const baseURL = startOverridesHTTPServer();
    319  const TEST_URL = baseURL + "index.html";
    320 
    321  const { monitor, tab } = await initNetMonitor(TEST_URL, {
    322    requestCount: 3,
    323    enableCache,
    324  });
    325 
    326  const { document, store, windowRequire } = monitor.panelWin;
    327  const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
    328  store.dispatch(Actions.batchEnable(false));
    329 
    330  // Reload to have 3 requests in the list
    331  const waitForEvents = waitForNetworkEvents(monitor, 3);
    332  await navigateTo(TEST_URL);
    333  await waitForEvents;
    334 
    335  return { monitor, tab, document };
    336 }