summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/test/browser/browser_webconsole_custom_formatters_errors.js
blob: 780a1b3ec1061d68b1d5bfaabe850fadef42734c (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

// Check display of custom formatters.
const TEST_URI =
  "https://example.com/browser/devtools/client/webconsole/" +
  "test/browser/test-console-custom-formatters-errors.html";

add_task(async function () {
  await pushPref("devtools.custom-formatters.enabled", true);

  const hud = await openNewTabAndConsole(TEST_URI);

  // Reload the browser to ensure the custom formatters are picked up
  await reloadBrowser();

  await testHeaderNotAFunction(hud);
  await testHeaderNotReturningJsonMl(hud);
  await testHeaderNotReturningElementType(hud);
  await testHeaderThrowing(hud);
  await testHasBodyNotAFunction(hud);
  await testHasBodyThrowing(hud);
  await testBodyNotAFunction(hud);
  await testBodyReturningNull(hud);
  await testBodyNotReturningJsonMl(hud);
  await testBodyNotReturningElementType(hud);
  await testBodyThrowing(hud);
  await testIncorrectObjectTag(hud);
  await testInvalidTagname(hud);
  await testNoPrivilegedAccess(hud);
  await testErrorsLoggedOnce(hud);
});

async function testHeaderNotAFunction(hud) {
  info(`Test for "header" not being a function`);
  await testCustomFormatting(hud, {
    messageText: `Custom formatter failed: devtoolsFormatters[0].header should be a function, got number`,
  });
}

async function testHeaderNotReturningJsonMl(hud) {
  info(`Test for "header" not returning JsonML`);
  await testCustomFormatting(hud, {
    messageText: `Custom formatter failed: devtoolsFormatters[1].header should return an array, got number`,
    source: "test-console-custom-formatters-errors.html:19:19",
  });
}

async function testHeaderNotReturningElementType(hud) {
  info(`Test for "header" function returning array without element type`);
  await testCustomFormatting(hud, {
    messageText: `Custom formatter failed: devtoolsFormatters[2].header returned an empty array`,
  });
}

async function testHeaderThrowing(hud) {
  info(`Test for "header" function throwing`);
  await testCustomFormatting(hud, {
    messageText: `Custom formatter failed: devtoolsFormatters[3].header threw: ERROR`,
  });
}

async function testHasBodyNotAFunction(hud) {
  info(`Test for "hasBody" not being a function`);
  await testCustomFormatting(hud, {
    messageText: `Custom formatter failed: devtoolsFormatters[4].hasBody should be a function, got number`,
  });
}

async function testHasBodyThrowing(hud) {
  info(`Test for "hasBody" function throwing`);
  await testCustomFormatting(hud, {
    messageText: `Custom formatter failed: devtoolsFormatters[5].hasBody threw: ERROR`,
  });
}

async function testBodyNotAFunction(hud) {
  info(`Test for "body" not being a function`);
  await testCustomFormatting(hud, {
    messageText: "body not a function",
    bodyText: `Custom formatter failed: devtoolsFormatters[6].body should be a function, got number`,
  });
}

async function testBodyReturningNull(hud) {
  info(`Test for "body" returning null`);
  await testCustomFormatting(hud, {
    messageText: "body returns null",
    bodyText: `Custom formatter failed: devtoolsFormatters[7].body should return an array, got null`,
  });
}

async function testBodyNotReturningJsonMl(hud) {
  info(`Test for "body" not returning JsonML`);
  await testCustomFormatting(hud, {
    messageText: "body doesn't return JsonML",
    bodyText: `Custom formatter failed: devtoolsFormatters[8].body should return an array, got number`,
  });
}

async function testBodyNotReturningElementType(hud) {
  info(`Test for "body" function returning array without element type`);
  await testCustomFormatting(hud, {
    messageText: "body array misses element type",
    bodyText: `Custom formatter failed: devtoolsFormatters[9].body returned an empty array`,
  });
}

async function testBodyThrowing(hud) {
  info(`Test for "body" function throwing`);
  await testCustomFormatting(hud, {
    messageText: "body throws",
    bodyText: `Custom formatter failed: devtoolsFormatters[10].body threw: ERROR`,
  });
}

async function testErrorsLoggedOnce(hud) {
  const messages = findMessagesByType(hud, "custom formatter failed", ".error");

  messages.forEach(async message => {
    await checkUniqueMessageExists(hud, message.textContent, ".error");
  });
}

async function testIncorrectObjectTag(hud) {
  info(`Test for "object" tag without attribute`);
  await testCustomFormatting(hud, {
    messageText: `Custom formatter failed: devtoolsFormatters[11] couldn't be run: "object" tag should have attributes`,
  });

  info(`Test for "object" tag without "object" attribute`);
  await testCustomFormatting(hud, {
    messageText: `Custom formatter failed: devtoolsFormatters[12] couldn't be run: attribute of "object" tag should have an "object" property`,
  });

  info(`Test for infinite "object" tag`);
  await testCustomFormatting(hud, {
    messageText: `Custom formatter failed: Too deep hierarchy of inlined custom previews`,
  });
}

async function testInvalidTagname(hud) {
  info(`Test invalid tagname in the returned JsonML`);
  await testCustomFormatting(hud, {
    messageText: `Custom formatter failed: devtoolsFormatters[14] couldn't be run: tagName should be a string, got number`,
  });
}

async function testNoPrivilegedAccess(hud) {
  info(`Test for denied access to windowUtils from hook`);
  const node = await testCustomFormatting(hud, {
    messageText: `Custom formatter failed: devtoolsFormatters[17].header threw`,
  });
  ok(
    node.textContent.includes("window.windowUtils is undefined"),
    "Access to windowUtils triggered expected error"
  );
}

async function testCustomFormatting(hud, { messageText, source, bodyText }) {
  const headerNode = bodyText
    ? await waitFor(() => {
        return findConsoleAPIMessage(hud, messageText);
      })
    : await waitFor(() => {
        return findErrorMessage(hud, messageText);
      });

  ok(true, `Got expected message: ${messageText}`);

  if (source) {
    const sourceLink = headerNode.querySelector(".message-location");
    is(sourceLink?.textContent, source, "Source location is correct");
  }

  if (bodyText) {
    const arrow = headerNode.querySelector(".collapse-button");

    ok(arrow, "There must be a toggle arrow for the header");

    info("Expanding the Object");
    const bodyErrorNode = waitFor(() => {
      return findErrorMessage(hud, bodyText);
    });

    arrow.click();
    await bodyErrorNode;

    ok(
      headerNode
        .querySelector(".collapse-button")
        .classList.contains("expanded"),
      "The arrow of the node has the expected class after clicking on it"
    );
  }

  return headerNode;
}