tor-browser

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

browser_webconsole_errors.js (10961B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 // Check if errors are logged as expected
      5 
      6 "use strict";
      7 
      8 const TEST_URI = `data:text/html;charset=utf8,<!DOCTYPE html>Errors`;
      9 
     10 add_task(async function () {
     11  const hud = await openNewTabAndConsole(TEST_URI);
     12 
     13  const TEST_DATA = [
     14    {
     15      desc: "ReferenceError: asdf is not defined",
     16      expression: `
     17        function bar() {
     18          asdf()
     19        }
     20        function foo() {
     21          bar()
     22        }
     23 
     24        foo()`,
     25      expected: `Uncaught ReferenceError: asdf is not defined`,
     26    },
     27 
     28    {
     29      desc: "SyntaxError: redeclaration of let a",
     30      expression: `let a, a;`,
     31      expected: `SyntaxError: redeclaration of let a`,
     32      assert: messageEl => {
     33        info("Check that error notes are displayed");
     34        const notes = messageEl.querySelectorAll(".error-note .message-body");
     35        is(notes.length, 1, "There's only one note");
     36        is(notes[0].innerText, "note: Previously declared at line 1, column 5");
     37      },
     38    },
     39 
     40    {
     41      desc: "TypeError longString message",
     42      expression: `throw new Error("Long error ".repeat(10000))`,
     43      expected: `Uncaught Error: Long error Long error`,
     44    },
     45 
     46    {
     47      desc: `throw string with URL`,
     48      expression: `throw "“https://evil.com/?${"a".repeat(
     49        200
     50      )}“ is evil and “https://not-so-evil.com/?${"b".repeat(
     51        200
     52      )}“ is not good either"`,
     53      expected: `Uncaught “https://evil.com/?${"a".repeat(
     54        200
     55      )}“ is evil and “https://not-so-evil.com/?${"b".repeat(
     56        200
     57      )}“ is not good either`,
     58      assert: messageEl => {
     59        const links = messageEl.querySelectorAll(".message-body a.cropped-url");
     60        is(links.length, 2, "2 links are displayed");
     61 
     62        const evilURL = `https://evil.com/?${"a".repeat(200)}`;
     63        const badURL = `https://not-so-evil.com/?${"b".repeat(200)}`;
     64 
     65        is(
     66          links[0].getAttribute("href"),
     67          evilURL,
     68          "first link has expected href"
     69        );
     70        is(
     71          links[0].getAttribute("title"),
     72          evilURL,
     73          "first link has expected title"
     74        );
     75 
     76        is(
     77          links[1].getAttribute("href"),
     78          badURL,
     79          "second link has expected href"
     80        );
     81        is(
     82          links[1].getAttribute("title"),
     83          badURL,
     84          "second link has expected title"
     85        );
     86      },
     87    },
     88 
     89    {
     90      desc: `throw ""`,
     91      expression: `throw ""`,
     92      expected: `Uncaught <empty string>`,
     93    },
     94    {
     95      desc: `throw "tomato"`,
     96      expression: `throw "tomato"`,
     97      expected: `Uncaught tomato`,
     98    },
     99    {
    100      desc: `throw false`,
    101      expression: `throw false`,
    102      expected: `Uncaught false`,
    103    },
    104    { desc: `throw 0`, expression: `throw 0`, expected: `Uncaught 0` },
    105    { desc: `throw null`, expression: `throw null`, expected: `Uncaught null` },
    106    {
    107      desc: `throw undefined`,
    108      expression: `throw undefined`,
    109      expected: `Uncaught undefined`,
    110    },
    111    {
    112      desc: `throw Symbol`,
    113      expression: `throw Symbol("potato")`,
    114      expected: `Uncaught Symbol("potato")`,
    115    },
    116    {
    117      desc: `throw Object`,
    118      expression: `throw {vegetable: "cucumber"}`,
    119      expected: `Uncaught Object { vegetable: "cucumber" }`,
    120    },
    121    {
    122      desc: `throw Error Object`,
    123      expression: `throw new Error("pumpkin")`,
    124      expected: `Uncaught Error: pumpkin`,
    125    },
    126    {
    127      desc: `throw Error Object with custom name`,
    128      expression: `
    129        var err = new Error("pineapple");
    130        err.name = "JuicyError";
    131        err.flavor = "delicious";
    132        throw err;`,
    133      expected: `Uncaught JuicyError: pineapple`,
    134    },
    135    {
    136      desc: `throw Error Object with error cause`,
    137      expression: `
    138        var originalError = new SyntaxError("original error")
    139        var err = new Error("something went wrong", {
    140          cause: originalError
    141        });
    142        throw err;`,
    143      expected: `Uncaught Error: something went wrong`,
    144      assert: messageEl => {
    145        const causeEl = messageEl.querySelector(".error-rep-cause");
    146        is(
    147          causeEl.innerText,
    148          `Caused by: SyntaxError: original error`,
    149          "Caused by show expected"
    150        );
    151      },
    152    },
    153    {
    154      desc: `throw Error Object with cause chain`,
    155      expression: `
    156        var a = new Error("err-a")
    157        var b = new Error("err-b", { cause: a })
    158        var c = new Error("err-c", { cause: b })
    159        var d = new Error("err-d", { cause: c })
    160        throw d;`,
    161      expected: `Uncaught Error: err-d`,
    162      assert: messageEl => {
    163        const causeEl = messageEl.querySelector(".error-rep-cause");
    164        is(
    165          causeEl.innerText,
    166          [
    167            "Caused by: Error: err-c",
    168            "Caused by: Error: err-b",
    169            "Caused by: Error: err-a",
    170          ].join("\n"),
    171          "The cause chain is properly displayed"
    172        );
    173      },
    174    },
    175    {
    176      desc: `throw Error Object with cyclical cause chain`,
    177      expression: `
    178        var a = new Error("err-a", { cause: b})
    179        var b = new Error("err-b", { cause: a })
    180        throw b;`,
    181      expected: `Uncaught Error: err-b`,
    182      assert: messageEl => {
    183        const causeEl = messageEl.querySelector(".error-rep-cause");
    184        is(
    185          causeEl.innerText,
    186          // TODO: This is not how we should display cyclical cause chain, but we have it here
    187          // to ensure it's displaying something that makes _some_ sense.
    188          // This should be properly handled in Bug 1719605.
    189          [
    190            "Caused by: Error: err-a",
    191            "Caused by: Error: err-b",
    192            "Caused by: Error: err-a",
    193          ].join("\n"),
    194          "The cyclical cause chain is properly displayed"
    195        );
    196      },
    197    },
    198    {
    199      desc: `throw Error Object with falsy cause`,
    200      expression: `throw new Error("null cause", { cause: null });`,
    201      expected: `Uncaught Error: null cause`,
    202      assert: messageEl => {
    203        const causeEl = messageEl.querySelector(".error-rep-cause");
    204        is(
    205          causeEl.innerText,
    206          "Caused by: null",
    207          "The null cause is properly displayed"
    208        );
    209      },
    210    },
    211    {
    212      desc: `throw Error Object with number cause`,
    213      expression: `throw new Error("number cause", { cause: 0 });`,
    214      expected: `Uncaught Error: number cause`,
    215      assert: messageEl => {
    216        const causeEl = messageEl.querySelector(".error-rep-cause");
    217        is(
    218          causeEl.innerText,
    219          "Caused by: 0",
    220          "The 0 cause is properly displayed"
    221        );
    222      },
    223    },
    224    {
    225      desc: `throw Error Object with string cause`,
    226      expression: `throw new Error("string cause", { cause: "cause message" });`,
    227      expected: `Uncaught Error: string cause`,
    228      assert: messageEl => {
    229        const causeEl = messageEl.querySelector(".error-rep-cause");
    230        is(
    231          causeEl.innerText,
    232          `Caused by: "cause message"`,
    233          "The string cause is properly displayed"
    234        );
    235      },
    236    },
    237    {
    238      desc: `throw Error Object with object cause`,
    239      expression: `throw new Error("object cause", { cause: { code: 234, message: "ERR_234"} });`,
    240      expected: `Uncaught Error: object cause`,
    241      assert: messageEl => {
    242        const causeEl = messageEl.querySelector(".error-rep-cause");
    243        is(
    244          causeEl.innerText,
    245          `Caused by: Object { … }`,
    246          "The object cause is properly displayed"
    247        );
    248      },
    249    },
    250    {
    251      desc: `Promise reject ""`,
    252      expression: `Promise.reject("")`,
    253      expected: `Uncaught (in promise) <empty string>`,
    254    },
    255    {
    256      desc: `Promise reject "tomato"`,
    257      expression: `Promise.reject("tomato")`,
    258      expected: `Uncaught (in promise) tomato`,
    259    },
    260    {
    261      desc: `Promise reject false`,
    262      expression: `Promise.reject(false)`,
    263      expected: `Uncaught (in promise) false`,
    264    },
    265    {
    266      desc: `Promise reject 0`,
    267      expression: `Promise.reject(0)`,
    268      expected: `Uncaught (in promise) 0`,
    269    },
    270    {
    271      desc: `Promise reject null`,
    272      expression: `Promise.reject(null)`,
    273      expected: `Uncaught (in promise) null`,
    274    },
    275    {
    276      desc: `Promise reject undefined`,
    277      expression: `Promise.reject(undefined)`,
    278      expected: `Uncaught (in promise) undefined`,
    279    },
    280    {
    281      desc: `Promise reject Symbol`,
    282      expression: `Promise.reject(Symbol("potato"))`,
    283      expected: `Uncaught (in promise) Symbol("potato")`,
    284    },
    285    {
    286      desc: `Promise reject Object`,
    287      expression: `Promise.reject({vegetable: "cucumber"})`,
    288      expected: `Uncaught (in promise) Object { vegetable: "cucumber" }`,
    289    },
    290    {
    291      desc: `Promise reject Error Object`,
    292      expression: `Promise.reject(new Error("pumpkin"))`,
    293      expected: `Uncaught (in promise) Error: pumpkin`,
    294    },
    295    {
    296      desc: `Promise reject Error Object with custom name`,
    297      expression: `
    298        var err = new Error("pineapple");
    299        err.name = "JuicyError";
    300        err.flavor = "delicious";
    301        Promise.reject(err);`,
    302      expected: `Uncaught (in promise) JuicyError: pineapple`,
    303    },
    304    {
    305      desc: `Promise reject Error Object with error cause`,
    306      expression: `Promise.resolve().then(() => {
    307        try {
    308          unknownFunc();
    309        } catch(e) {
    310          throw new Error("something went wrong", { cause: e })
    311        }
    312      })`,
    313      expected: `Uncaught (in promise) Error: something went wrong`,
    314      assert: messageEl => {
    315        const causeEl = messageEl.querySelector(".error-rep-cause");
    316        is(
    317          causeEl.innerText,
    318          `Caused by: ReferenceError: unknownFunc is not defined`,
    319          "The cause is properly displayed"
    320        );
    321      },
    322    },
    323  ];
    324 
    325  // javascript.options.experimental.explicit_resource_management is set to true, but it's
    326  // only supported on Nightly at the moment
    327  if (AppConstants.ENABLE_EXPLICIT_RESOURCE_MANAGEMENT) {
    328    TEST_DATA.push({
    329      desc: `SuppressedError`,
    330      expression: `throw new SuppressedError(
    331          new Error("foo"),
    332          new Error("bar"),
    333          "the suppressed error message"
    334        )`,
    335      expected: `Uncaught SuppressedError: the suppressed error message`,
    336    });
    337  }
    338 
    339  for (const { desc, expression, expected, assert } of TEST_DATA) {
    340    info(`Check error: ${desc}`);
    341 
    342    const onErrorLogged = waitForMessageByType(hud, expected, ".error");
    343 
    344    await SpecialPowers.spawn(
    345      gBrowser.selectedBrowser,
    346      [expression],
    347      function (expr) {
    348        const script = content.document.createElement("script");
    349        script.append(content.document.createTextNode(expr));
    350        content.document.body.append(script);
    351        script.remove();
    352      }
    353    );
    354 
    355    const message = await onErrorLogged;
    356    if (assert) {
    357      assert(message.node);
    358    }
    359  }
    360 });