summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/test/browser/browser_webconsole_custom_formatters.js
blob: 7fd026fe8026aff5a23c256200fa8bf9930ed465 (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
201
202
203
204
205
/* 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.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 testString(hud);
  await testNumber(hud);
  await testObjectWithoutFormatting(hud);
  await testObjectWithFormattedHeader(hud);
  await testObjectWithFormattedHeaderAndBody(hud);
  await testCustomFormatterWithObjectTag(hud);
  await testProxyObject(hud);
});

async function testString(hud) {
  info("Test for string not being custom formatted");
  await testCustomFormatting(hud, {
    hasCustomFormatter: false,
    messageText: "string",
  });
}

async function testNumber(hud) {
  info("Test for number not being custom formatted");
  await testCustomFormatting(hud, {
    hasCustomFormatter: false,
    messageText: 1337,
  });
}

async function testObjectWithoutFormatting(hud) {
  info("Test for object not being custom formatted");
  await testCustomFormatting(hud, {
    hasCustomFormatter: false,
    messageText: "Object { noFormat: true }",
  });
}

async function testObjectWithFormattedHeader(hud) {
  info("Simple test for custom formatted header");
  await testCustomFormatting(hud, {
    hasCustomFormatter: true,
    messageText: "custom formatted header",
    headerStyles: "font-size: 3rem;",
  });
}

async function testObjectWithFormattedHeaderAndBody(hud) {
  info("Simple test for custom formatted header with body");
  await testCustomFormatting(hud, {
    hasCustomFormatter: true,
    messageText: "custom formatted body",
    headerStyles: "font-style: italic;",
    bodyText: "body",
    bodyStyles: "font-size: 2rem; font-family: serif;",
  });
}

async function testCustomFormatterWithObjectTag(hud) {
  info(`Test for custom formatted object with "object" tag in the jsonMl`);
  const node = await waitFor(() => {
    return findConsoleAPIMessage(hud, "object tag");
  });

  const headerJsonMlNode = node.querySelector(".objectBox-jsonml");
  is(
    headerJsonMlNode.getAttribute("style"),
    "color: purple;",
    "The custom formatting of the header is correct"
  );
  const [buttonEl, child1, child2, child3, child4] =
    headerJsonMlNode.childNodes;
  is(child1.textContent, "object tag", "Got expected first item");
  is(
    child2.textContent,
    `~[1,"a"]~`,
    "Got expected second item, the replaced object, custom formatted"
  );
  ok(
    child3.classList.contains("objectBox-null"),
    "Got expected third item, an actual NullRep"
  );
  is(child3.textContent, `null`, "third item has expected content");

  is(
    child4.textContent,
    ` | serialized: 42n undefined null Infinity [object Object]`,
    "Got expected fourth item, serialized values"
  );

  buttonEl.click();
  const bodyLevel1 = await waitFor(() =>
    node.querySelector(".objectBox-jsonml-body-wrapper .objectBox-jsonml")
  );
  const [bodyChild1, bodyChild2] = bodyLevel1.childNodes;
  is(bodyChild1.textContent, "body");

  const bodyCustomFormattedChild = await waitFor(() =>
    bodyChild2.querySelector(".objectBox-jsonml")
  );
  const [subButtonEl, subChild1, subChild2, subChild3] =
    bodyCustomFormattedChild.childNodes;
  ok(!!subButtonEl, "The body child can also be expanded");
  is(subChild1.textContent, "object tag", "Got expected first item");
  is(
    subChild2.textContent,
    `~[2,"b"]~`,
    "Got expected body second item, the replaced object, custom formatted"
  );
  ok(
    subChild3.classList.contains("object-inspector"),
    "Got expected body third item, an actual ObjectInspector"
  );
  is(
    subChild3.textContent,
    `Array [ 2, "b" ]`,
    "body third item has expected content"
  );
}

async function testProxyObject(hud) {
  info("Test that Proxy objects can be handled by custom formatter");
  await testCustomFormatting(hud, {
    hasCustomFormatter: true,
    messageText: "Formatted Proxy",
    headerStyles: "font-weight: bold;",
  });
}

async function testCustomFormatting(
  hud,
  { hasCustomFormatter, messageText, headerStyles, bodyText, bodyStyles }
) {
  const node = await waitFor(() => {
    return findMessageVirtualizedByType({
      hud,
      text: messageText,
      typeSelector: ".console-api",
    });
  });

  const headerJsonMlNode = node.querySelector(".objectBox-jsonml");
  if (hasCustomFormatter) {
    ok(headerJsonMlNode, "The message is custom formatted");

    if (!headerJsonMlNode) {
      return;
    }

    is(
      headerJsonMlNode.getAttribute("style"),
      headerStyles,
      "The custom formatting of the header is correct"
    );

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

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

      info("Expanding the Object");
      const onBodyRendered = waitFor(
        () =>
          !!node.querySelector(
            ".objectBox-jsonml-body-wrapper .objectBox-jsonml"
          )
      );

      arrow.click();
      await onBodyRendered;

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

      const bodyJsonMlNode = node.querySelector(
        ".objectBox-jsonml-body-wrapper > .objectBox-jsonml"
      );
      ok(bodyJsonMlNode, "The body is custom formatted");

      is(bodyJsonMlNode?.textContent, bodyText, "The body text is correct");
      is(
        bodyJsonMlNode.getAttribute("style"),
        bodyStyles,
        "The custom formatting of the body is correct"
      );
    }
  } else {
    ok(!headerJsonMlNode, "The message is not custom formatted");
  }
}