tor-browser

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

browser_console.js (9662B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 // Test the basic features of the Browser Console.
      5 
      6 "use strict";
      7 
      8 requestLongerTimeout(2);
      9 
     10 const TEST_URI =
     11  "http://example.com/browser/devtools/client/webconsole/" +
     12  "test/browser/test-console.html?" +
     13  Date.now();
     14 
     15 const TEST_XHR_ERROR_URI = `http://example.com/404.html?${Date.now()}`;
     16 
     17 const TEST_IMAGE =
     18  "http://example.com/browser/devtools/client/webconsole/" +
     19  "test/test-image.png";
     20 
     21 add_task(async function () {
     22  // Needed for the execute() call in `testMessages`.
     23  await pushPref("security.allow_parent_unrestricted_js_loads", true);
     24  await pushPref("devtools.browserconsole.enableNetworkMonitoring", true);
     25  await pushPref("devtools.browsertoolbox.scope", "everything");
     26 
     27  // Open a parent process tab to check it doesn't have impact
     28  const aboutRobotsTab = await addTab("about:robots");
     29  // And open the "actual" test tab
     30  const tab = await addTab(TEST_URI);
     31 
     32  await testMessages();
     33 
     34  info("Close tab");
     35  await removeTab(tab);
     36  await removeTab(aboutRobotsTab);
     37 });
     38 
     39 async function testMessages() {
     40  const opened = waitForBrowserConsole();
     41  let hud = BrowserConsoleManager.getBrowserConsole();
     42  ok(!hud, "browser console is not open");
     43 
     44  // The test harness does override the global's console property to replace it with
     45  // a Console.sys.mjs instance (https://searchfox.org/mozilla-central/rev/c5c002f81f08a73e04868e0c2bf0eb113f200b03/testing/mochitest/api.js#75-78)
     46  // So here we reset the console property with the native console (which is luckily
     47  // stored in `nativeConsole`).
     48  const overriddenConsole = globalThis.console;
     49  globalThis.console = globalThis.nativeConsole;
     50 
     51  info("wait for the browser console to open with ctrl-shift-j");
     52  EventUtils.synthesizeKey("j", { accelKey: true, shiftKey: true }, window);
     53 
     54  hud = await opened;
     55  ok(hud, "browser console opened");
     56 
     57  info("Check that we don't display the non-native console API warning");
     58  // Wait a bit to let room for the message to be displayed
     59  await wait(1000);
     60  is(
     61    await findMessageVirtualizedByType({
     62      hud,
     63      text: "The Web Console logging API",
     64      typeSelector: ".warn",
     65    }),
     66    undefined,
     67    "The message about disabled console API is not displayed"
     68  );
     69  // Set the overidden console back.
     70  globalThis.console = overriddenConsole;
     71 
     72  await clearOutput(hud);
     73 
     74  await setFilterState(hud, {
     75    netxhr: true,
     76    css: true,
     77  });
     78 
     79  executeSoon(() => {
     80    expectUncaughtException();
     81    // eslint-disable-next-line no-undef
     82    foobarException();
     83  });
     84 
     85  // Add a message from a chrome window.
     86  hud.iframeWindow.console.log("message from chrome window");
     87 
     88  // Spawn worker from a chrome window and log a message and an error
     89  const chromeSpawnedWorker = new hud.iframeWindow.Worker(
     90    getRootDirectory(gTestPath) + "test-parent-worker.js"
     91  );
     92 
     93  // Spawn Chrome worker from a chrome window and log a message
     94  // It's important to use the browser console global so the message gets assigned
     95  // a non-numeric innerID in Console.cpp
     96  const browserConsoleGlobal = Cu.getGlobalForObject(hud);
     97  const chromeWorker = new browserConsoleGlobal.ChromeWorker(
     98    URL.createObjectURL(
     99      new browserConsoleGlobal.Blob(
    100        [`console.log("message in chrome worker")`],
    101        {
    102          type: "application/javascript",
    103        }
    104      )
    105    )
    106  );
    107 
    108  const sandbox = new Cu.Sandbox(null, {
    109    wantComponents: false,
    110    wantGlobalProperties: ["URL", "URLSearchParams"],
    111  });
    112  const error = Cu.evalInSandbox(
    113    `new Error("error from nuked globals");`,
    114    sandbox
    115  );
    116  console.error(error);
    117  Cu.nukeSandbox(sandbox);
    118 
    119  const componentsException = new Components.Exception("Components.Exception");
    120  console.error(componentsException);
    121 
    122  // Check privileged error message from a content process
    123  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    124    (async function () {
    125      throw new Error("privileged content process error message");
    126    })();
    127  });
    128 
    129  // Add a message from a content window.
    130  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    131    content.wrappedJSObject.console.log("message from content window");
    132    content.wrappedJSObject.throwError("error from content window");
    133 
    134    content.testWorker = new content.Worker("./test-worker.js");
    135    content.testWorker.postMessage({
    136      type: "log",
    137      message: "message in content worker",
    138    });
    139    content.testWorker.postMessage({
    140      type: "error",
    141      message: "error in content worker",
    142    });
    143  });
    144 
    145  // Test eval.
    146  execute(hud, "`Parent Process Location: ${document.location.href}`");
    147 
    148  // Test eval frame script
    149  gBrowser.selectedBrowser.messageManager.loadFrameScript(
    150    `data:application/javascript,console.log("framescript-message")`,
    151    false
    152  );
    153 
    154  // Check for network requests.
    155  const xhr = new XMLHttpRequest();
    156  xhr.onload = () => console.log("xhr loaded, status is: " + xhr.status);
    157  xhr.open("get", TEST_URI, true);
    158  xhr.send();
    159 
    160  // Check for xhr error.
    161  const xhrErr = new XMLHttpRequest();
    162  xhrErr.onload = () => {
    163    console.log("xhr error loaded, status is: " + xhrErr.status);
    164  };
    165  xhrErr.open("get", TEST_XHR_ERROR_URI, true);
    166  xhrErr.send();
    167 
    168  // Check that Fetch requests are categorized as "XHR".
    169  await fetch(TEST_IMAGE);
    170  console.log("fetch loaded");
    171 
    172  // Check messages logged with Services.console.logMessage
    173  const scriptErrorMessage = Cc["@mozilla.org/scripterror;1"].createInstance(
    174    Ci.nsIScriptError
    175  );
    176  scriptErrorMessage.initWithWindowID(
    177    "Error from Services.console.logMessage",
    178    gBrowser.currentURI.prePath,
    179    0,
    180    0,
    181    Ci.nsIScriptError.warningFlag,
    182    // platform-specific category to test case for Bug 1770160
    183    "chrome javascript",
    184    gBrowser.selectedBrowser.innerWindowID
    185  );
    186  Services.console.logMessage(scriptErrorMessage);
    187 
    188  // Check messages logged in content with Log.sys.mjs
    189  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    190    const { Log } = ChromeUtils.importESModule(
    191      "resource://gre/modules/Log.sys.mjs"
    192    );
    193    const logger = Log.repository.getLogger("TEST_LOGGER_" + Date.now());
    194    logger.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
    195    logger.level = Log.Level.Info;
    196    logger.info("Log.sys.mjs content process messsage");
    197  });
    198 
    199  // Check CSS warnings in parent process
    200  await execute(hud, `document.body.style.backgroundColor = "rainbow"`);
    201 
    202  // Wait enough so any duplicated message would have the time to be rendered
    203  await wait(1000);
    204 
    205  await checkUniqueMessageExists(
    206    hud,
    207    "message from chrome window",
    208    ".console-api"
    209  );
    210  await checkUniqueMessageExists(hud, "error from nuked globals", ".error");
    211  await checkUniqueMessageExists(
    212    hud,
    213    "privileged content process error message",
    214    ".error"
    215  );
    216  await checkUniqueMessageExists(
    217    hud,
    218    "message from content window",
    219    ".console-api"
    220  );
    221  await checkUniqueMessageExists(hud, "error from content window", ".error");
    222  await checkUniqueMessageExists(
    223    hud,
    224    `"Parent Process Location: chrome://browser/content/browser.xhtml"`,
    225    ".result"
    226  );
    227  await checkUniqueMessageExists(hud, "framescript-message", ".console-api");
    228  await checkUniqueMessageExists(
    229    hud,
    230    "Error from Services.console.logMessage",
    231    ".warn"
    232  );
    233  await checkUniqueMessageExists(hud, "foobarException", ".error");
    234  await checkUniqueMessageExists(hud, "test-console.html", ".network");
    235  await checkUniqueMessageExists(hud, "404.html", ".network");
    236  await checkUniqueMessageExists(hud, "test-image.png", ".network");
    237  await checkUniqueMessageExists(
    238    hud,
    239    "Log.sys.mjs content process messsage",
    240    ".console-api"
    241  );
    242  await checkUniqueMessageExists(
    243    hud,
    244    "message in content worker",
    245    ".console-api"
    246  );
    247  await checkUniqueMessageExists(hud, "error in content worker", ".error");
    248  await checkUniqueMessageExists(
    249    hud,
    250    "message in parent worker",
    251    ".console-api"
    252  );
    253  await checkUniqueMessageExists(hud, "error in parent worker", ".error");
    254  await checkUniqueMessageExists(
    255    hud,
    256    "message in chrome worker",
    257    ".console-api"
    258  );
    259  await checkUniqueMessageExists(
    260    hud,
    261    "Expected color but found ‘rainbow’",
    262    ".warn"
    263  );
    264  await checkUniqueMessageExists(
    265    hud,
    266    "Expected color but found ‘bled’",
    267    ".warn"
    268  );
    269 
    270  await checkComponentExceptionMessage(hud, componentsException);
    271 
    272  await resetFilters(hud);
    273 
    274  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
    275    content.testWorker.terminate();
    276    delete content.testWorker;
    277  });
    278  chromeSpawnedWorker.terminate();
    279  chromeWorker.terminate();
    280  info("Close the Browser Console");
    281  await safeCloseBrowserConsole();
    282 }
    283 
    284 async function checkComponentExceptionMessage(hud, exception) {
    285  const msgNode = await checkUniqueMessageExists(
    286    hud,
    287    "Components.Exception",
    288    ".error"
    289  );
    290  const framesNode = await waitFor(() => msgNode.querySelector(".pane.frames"));
    291  ok(framesNode, "The Components.Exception stack is displayed right away");
    292 
    293  const frameNodes = framesNode.querySelectorAll(".frame");
    294  Assert.greater(frameNodes.length, 1, "Got at least one frame in the stack");
    295  is(
    296    frameNodes[0].querySelector(".line").textContent,
    297    String(exception.lineNumber),
    298    "The stack displayed by default refers to Components.Exception passed as argument"
    299  );
    300 
    301  const [, line] = msgNode
    302    .querySelector(".frame-link-line")
    303    .textContent.split(":");
    304  is(
    305    line,
    306    String(exception.lineNumber + 1),
    307    "The link on the top right refers to the console.error callsite"
    308  );
    309 }