summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/test/browser/browser_webconsole_uncaught_exception.js
blob: 48970dd2f68c43673a2085c09cfcb05460b6b0e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

// Test that stack traces are shown when primitive values are thrown instead of
// error objects.

"use strict";

const TEST_URI = `data:text/html,<!DOCTYPE html><meta charset=utf8>Test uncaught exception`;

add_task(async function () {
  const hud = await openNewTabAndConsole(TEST_URI);

  await checkThrowingWithStack(hud, `"tomato"`, "Uncaught tomato");
  await checkThrowingWithStack(hud, `""`, "Uncaught <empty string>");
  await checkThrowingWithStack(hud, `42`, "Uncaught 42");
  await checkThrowingWithStack(hud, `0`, "Uncaught 0");
  await checkThrowingWithStack(hud, `null`, "Uncaught null");
  await checkThrowingWithStack(hud, `undefined`, "Uncaught undefined");
  await checkThrowingWithStack(hud, `false`, "Uncaught false");

  await checkThrowingWithStack(
    hud,
    `new Error("watermelon")`,
    "Uncaught Error: watermelon"
  );

  await checkThrowingWithStack(
    hud,
    `(err = new Error("lettuce"), err.name = "VegetableError", err)`,
    "Uncaught VegetableError: lettuce"
  );

  await checkThrowingWithStack(
    hud,
    `{ fav: "eggplant" }`,
    `Uncaught Object { fav: "eggplant" }`
  );

  info("Check custom error with name and message getters");
  // register the class
  await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
    const script = content.document.createElement("script");
    script.append(
      content.document.createTextNode(
        `
      class CustomError extends Error {
        get name() {
          return "CustomErrorName";
        }

        get message() {
          return "custom-error-message";
        }
      }`.trim()
      )
    );
    content.document.body.append(script);
  });

  await checkThrowingWithStack(
    hud,
    `new CustomError()`,
    "Uncaught CustomErrorName: custom-error-message",
    // Additional frames: the stacktrace contains the CustomError call
    [1]
  );
  info("Check that object in errors can be expanded");
  const rejectedObjectMessage = findErrorMessage(hud, "eggplant");
  const oi = rejectedObjectMessage.querySelector(".tree");
  ok(true, "The object was rendered in an ObjectInspector");

  info("Expanding the object");
  const onOiExpanded = waitFor(() => {
    return oi.querySelectorAll(".node").length === 3;
  });
  oi.querySelector(".arrow").click();
  await onOiExpanded;

  ok(
    oi.querySelector(".arrow").classList.contains("expanded"),
    "Object expanded"
  );

  // The object inspector now looks like:
  // Object { fav: "eggplant" }
  // |  fav: "eggplant"
  // |  <prototype>: Object { ... }

  const oiNodes = oi.querySelectorAll(".node");
  is(oiNodes.length, 3, "There is the expected number of nodes in the tree");

  ok(oiNodes[0].textContent.includes(`Object { fav: "eggplant" }`));
  ok(oiNodes[1].textContent.includes(`fav: "eggplant"`));
  ok(oiNodes[2].textContent.includes(`<prototype>: Object { \u2026 }`));
});

async function checkThrowingWithStack(
  hud,
  expression,
  expectedMessage,
  additionalFrameLines = []
) {
  await SpecialPowers.spawn(
    gBrowser.selectedBrowser,
    [expression],
    function (expr) {
      const script = content.document.createElement("script");
      script.append(
        content.document.createTextNode(`
    a = () => {throw ${expr}};
    b =  () => a();
    c =  () => b();
    d =  () => c();
    d();
    `)
      );
      content.document.body.append(script);
      script.remove();
    }
  );
  return checkMessageStack(hud, expectedMessage, [
    ...additionalFrameLines,
    2,
    3,
    4,
    5,
    6,
  ]);
}