tor-browser

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

browser_console_modes.js (7844B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 // Test that messages from different contexts appears in the Browser Console and that their
      6 // visibility can be controlled through the UI (either with the ChromeDebugToolbar mode whe
      7 // Fission is enabled, or through the "Show Content Messages" setting when it's not).
      8 
      9 "use strict";
     10 
     11 const FILTER_PREFIX = "BC_TEST|";
     12 
     13 const contentArgs = {
     14  log: FILTER_PREFIX + "MyLog",
     15  warn: FILTER_PREFIX + "MyWarn",
     16  error: FILTER_PREFIX + "MyError",
     17  exception: FILTER_PREFIX + "MyException",
     18  info: FILTER_PREFIX + "MyInfo",
     19  debug: FILTER_PREFIX + "MyDebug",
     20  counterName: FILTER_PREFIX + "MyCounter",
     21  timerName: FILTER_PREFIX + "MyTimer",
     22 };
     23 
     24 const TEST_URI = `data:text/html,<!DOCTYPE html><meta charset=utf8>console API calls<script>
     25  console.log("${contentArgs.log}", {hello: "world"});
     26  console.warn("${contentArgs.warn}", {hello: "world"});
     27  console.error("${contentArgs.error}", {hello: "world"});
     28  console.exception("${contentArgs.exception}", {hello: "world"});
     29  console.info("${contentArgs.info}", {hello: "world"});
     30  console.debug("${contentArgs.debug}", {hello: "world"});
     31  console.count("${contentArgs.counterName}");
     32  console.time("${contentArgs.timerName}");
     33  console.timeLog("${contentArgs.timerName}", "MyTimeLog", {hello: "world"});
     34  console.timeEnd("${contentArgs.timerName}");
     35  console.trace("${FILTER_PREFIX}", {hello: "world"});
     36  console.assert(false, "${FILTER_PREFIX}", {hello: "world"});
     37  console.table(["${FILTER_PREFIX}", {hello: "world"}]);
     38 </script>`;
     39 
     40 // Test can be a bit long
     41 requestLongerTimeout(2);
     42 
     43 add_task(async function () {
     44  // Show the content messages
     45  await pushPref("devtools.browsertoolbox.scope", "everything");
     46  // Show context selector
     47  await pushPref("devtools.chrome.enabled", true);
     48 
     49  // Open the WebConsole on the tab to check changing mode won't focus the tab
     50  await openNewTabAndConsole(TEST_URI);
     51 
     52  // Open the Browser Console
     53  const hud = await BrowserConsoleManager.toggleBrowserConsole();
     54  // Set a filter to have predictable results, otherwise we may get messages from Firefox
     55  // polluting the test.
     56  await setFilterState(hud, { text: FILTER_PREFIX });
     57 
     58  const chromeDebugToolbar = hud.ui.document.querySelector(
     59    ".chrome-debug-toolbar"
     60  );
     61  ok(
     62    !!chromeDebugToolbar,
     63    "ChromeDebugToolbar is displayed when the Browser Console has fission support"
     64  );
     65  is(
     66    hud.chromeWindow.document.title,
     67    "Multiprocess Browser Console",
     68    "Browser Console window has expected title"
     69  );
     70 
     71  const evaluationContextSelectorButton = await waitFor(() =>
     72    hud.ui.outputNode.querySelector(".webconsole-evaluation-selector-button")
     73  );
     74 
     75  info("Select the content process target");
     76  const pid =
     77    gBrowser.selectedTab.linkedBrowser.browsingContext.currentWindowGlobal
     78      .osPid;
     79  getContextSelectorItems(hud)
     80    .find(item =>
     81      item.querySelector(".label")?.innerText?.startsWith(`(pid ${pid})`)
     82    )
     83    .click();
     84 
     85  await waitFor(() =>
     86    evaluationContextSelectorButton.classList.contains("checked")
     87  );
     88 
     89  // We can't directly throw in the script as it would be treated as an evaluation result
     90  // and wouldn't be hidden when switching modes.
     91  // Here we use an async-iife in which we throw so this will trigger the proper error
     92  // reporting path.
     93  await executeAndWaitForResultMessage(
     94    hud,
     95    `(async function(){
     96        throw new Error("${FILTER_PREFIX}Content error")
     97      })();
     98      21+21`,
     99    42
    100  );
    101 
    102  await waitFor(() => findErrorMessage(hud, "Content error"));
    103  ok(true, "Error message from content process is displayed");
    104 
    105  // Emit an error message from the parent process
    106  executeSoon(() => {
    107    expectUncaughtException();
    108    throw new Error(`${FILTER_PREFIX}Parent error`);
    109  });
    110 
    111  await waitFor(() => findErrorMessage(hud, "Parent error"));
    112  ok(true, "Parent process message is displayed");
    113 
    114  const suffix = ` Object { hello: "world" }`;
    115  const expectedMessages = [
    116    contentArgs.log + suffix,
    117    contentArgs.warn + suffix,
    118    contentArgs.error + suffix,
    119    contentArgs.exception + suffix,
    120    contentArgs.info + suffix,
    121    contentArgs.debug + suffix,
    122    `${contentArgs.counterName}: 1`,
    123    `MyTimeLog${suffix}`,
    124    `timer ended`,
    125    `console.trace() ${FILTER_PREFIX}${suffix}`,
    126    `Assertion failed: ${FILTER_PREFIX}${suffix}`,
    127    `console.table()`,
    128  ];
    129 
    130  info("wait for all the messages to be displayed");
    131  await waitFor(
    132    () =>
    133      expectedMessages.every(
    134        expectedMessage =>
    135          findMessagePartsByType(hud, {
    136            text: expectedMessage,
    137            typeSelector: ".console-api",
    138            partSelector: ".message-body",
    139          }).length == 1
    140      ),
    141    "wait for all the messages to be displayed",
    142    100
    143  );
    144  ok(true, "Expected messages are displayed in the browser console");
    145 
    146  const tableMessage = findConsoleAPIMessage(hud, "console.table()", ".table");
    147 
    148  const table = await waitFor(() =>
    149    tableMessage.querySelector(".consoletable")
    150  );
    151  ok(table, "There is a table element");
    152  const tableTextContent = table.textContent;
    153  ok(
    154    tableTextContent.includes(FILTER_PREFIX) &&
    155      tableTextContent.includes(`world`) &&
    156      tableTextContent.includes(`hello`),
    157    "Table has expected content"
    158  );
    159 
    160  info("Set Browser Console Mode to parent process only");
    161  chromeDebugToolbar
    162    .querySelector(
    163      `.chrome-debug-toolbar input[name="chrome-debug-mode"][value="parent-process"]`
    164    )
    165    .click();
    166  info("Wait for content messages to be hidden");
    167  await waitFor(() => !findConsoleAPIMessage(hud, contentArgs.log));
    168 
    169  for (const expectedMessage of expectedMessages) {
    170    ok(
    171      !findConsoleAPIMessage(hud, expectedMessage),
    172      `"${expectedMessage}" is hidden`
    173    );
    174  }
    175 
    176  is(
    177    hud.chromeWindow.document.title,
    178    "Parent process Browser Console",
    179    "Browser Console window title was updated"
    180  );
    181 
    182  ok(hud.iframeWindow.document.hasFocus(), "Browser Console is still focused");
    183 
    184  await waitFor(
    185    () => !evaluationContextSelectorButton.classList.contains("checked")
    186  );
    187  ok(true, "Changing mode did reset the context selector");
    188  ok(
    189    findMessageByType(hud, "21+21", ".command"),
    190    "The evaluation message is still displayed"
    191  );
    192  ok(
    193    findEvaluationResultMessage(hud, `42`),
    194    "The evaluation result is still displayed"
    195  );
    196 
    197  info(
    198    "Check that message from parent process is still visible in the Browser Console"
    199  );
    200  ok(
    201    !!findErrorMessage(hud, "Parent error"),
    202    "Parent process message is still displayed"
    203  );
    204 
    205  info("Set Browser Console Mode to Multiprocess");
    206  chromeDebugToolbar
    207    .querySelector(
    208      `.chrome-debug-toolbar input[name="chrome-debug-mode"][value="everything"]`
    209    )
    210    .click();
    211 
    212  info("Wait for content messages to be displayed");
    213  await waitFor(() =>
    214    expectedMessages.every(expectedMessage =>
    215      findConsoleAPIMessage(hud, expectedMessage)
    216    )
    217  );
    218 
    219  for (const expectedMessage of expectedMessages) {
    220    // Search into the message body as the message location could have some of the
    221    // searched text.
    222    is(
    223      findMessagePartsByType(hud, {
    224        text: expectedMessage,
    225        typeSelector: ".console-api",
    226        partSelector: ".message-body",
    227      }).length,
    228      1,
    229      `"${expectedMessage}" is visible`
    230    );
    231  }
    232 
    233  is(
    234    findErrorMessages(hud, "Content error").length,
    235    1,
    236    "error message from content process is only displayed once"
    237  );
    238 
    239  is(
    240    hud.chromeWindow.document.title,
    241    "Multiprocess Browser Console",
    242    "Browser Console window title was updated again"
    243  );
    244 
    245  info("Clear and close the Browser Console");
    246  await safeCloseBrowserConsole({ clearOutput: true });
    247 });