tor-browser

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

browser_webconsole_uncaught_exception.js (3647B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 // Test that stack traces are shown when primitive values are thrown instead of
      5 // error objects.
      6 
      7 "use strict";
      8 
      9 const TEST_URI = `data:text/html,<!DOCTYPE html><meta charset=utf8>Test uncaught exception`;
     10 
     11 add_task(async function () {
     12  const hud = await openNewTabAndConsole(TEST_URI);
     13 
     14  await checkThrowingWithStack(hud, `"tomato"`, "Uncaught tomato");
     15  await checkThrowingWithStack(hud, `""`, "Uncaught <empty string>");
     16  await checkThrowingWithStack(hud, `42`, "Uncaught 42");
     17  await checkThrowingWithStack(hud, `0`, "Uncaught 0");
     18  await checkThrowingWithStack(hud, `null`, "Uncaught null");
     19  await checkThrowingWithStack(hud, `undefined`, "Uncaught undefined");
     20  await checkThrowingWithStack(hud, `false`, "Uncaught false");
     21 
     22  await checkThrowingWithStack(
     23    hud,
     24    `new Error("watermelon")`,
     25    "Uncaught Error: watermelon"
     26  );
     27 
     28  await checkThrowingWithStack(
     29    hud,
     30    `(err = new Error("lettuce"), err.name = "VegetableError", err)`,
     31    "Uncaught VegetableError: lettuce"
     32  );
     33 
     34  await checkThrowingWithStack(
     35    hud,
     36    `{ fav: "eggplant" }`,
     37    `Uncaught Object { fav: "eggplant" }`
     38  );
     39 
     40  info("Check custom error with name and message getters");
     41  // register the class
     42  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
     43    const script = content.document.createElement("script");
     44    script.append(
     45      content.document.createTextNode(
     46        `
     47      class CustomError extends Error {
     48        get name() {
     49          return "CustomErrorName";
     50        }
     51 
     52        get message() {
     53          return "custom-error-message";
     54        }
     55      }`.trim()
     56      )
     57    );
     58    content.document.body.append(script);
     59  });
     60 
     61  await checkThrowingWithStack(
     62    hud,
     63    `new CustomError()`,
     64    "Uncaught CustomErrorName: custom-error-message",
     65    // Additional frames: the stacktrace contains the CustomError call
     66    [1]
     67  );
     68  info("Check that object in errors can be expanded");
     69  const rejectedObjectMessage = findErrorMessage(hud, "eggplant");
     70  const oi = rejectedObjectMessage.querySelector(".tree");
     71  ok(true, "The object was rendered in an ObjectInspector");
     72 
     73  info("Expanding the object");
     74  const onOiExpanded = waitFor(() => {
     75    return oi.querySelectorAll(".node").length === 3;
     76  });
     77  oi.querySelector(".theme-twisty").click();
     78  await onOiExpanded;
     79 
     80  ok(
     81    oi.querySelector(".theme-twisty").classList.contains("open"),
     82    "Object expanded"
     83  );
     84 
     85  // The object inspector now looks like:
     86  // Object { fav: "eggplant" }
     87  // |  fav: "eggplant"
     88  // |  <prototype>: Object { ... }
     89 
     90  const oiNodes = oi.querySelectorAll(".node");
     91  is(oiNodes.length, 3, "There is the expected number of nodes in the tree");
     92 
     93  ok(oiNodes[0].textContent.includes(`Object { fav: "eggplant" }`));
     94  ok(oiNodes[1].textContent.includes(`fav: "eggplant"`));
     95  ok(oiNodes[2].textContent.includes(`<prototype>: Object { \u2026 }`));
     96 });
     97 
     98 async function checkThrowingWithStack(
     99  hud,
    100  expression,
    101  expectedMessage,
    102  additionalFrameLines = []
    103 ) {
    104  await SpecialPowers.spawn(
    105    gBrowser.selectedBrowser,
    106    [expression],
    107    function (expr) {
    108      const script = content.document.createElement("script");
    109      script.append(
    110        content.document.createTextNode(`
    111    a = () => {throw ${expr}};
    112    b =  () => a();
    113    c =  () => b();
    114    d =  () => c();
    115    d();
    116    `)
    117      );
    118      content.document.body.append(script);
    119      script.remove();
    120    }
    121  );
    122  return checkMessageStack(hud, expectedMessage, [
    123    ...additionalFrameLines,
    124    2,
    125    3,
    126    4,
    127    5,
    128    6,
    129  ]);
    130 }