summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/test/browser/browser_webconsole_object_inspector_getters.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/webconsole/test/browser/browser_webconsole_object_inspector_getters.js')
-rw-r--r--devtools/client/webconsole/test/browser/browser_webconsole_object_inspector_getters.js664
1 files changed, 664 insertions, 0 deletions
diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_object_inspector_getters.js b/devtools/client/webconsole/test/browser/browser_webconsole_object_inspector_getters.js
new file mode 100644
index 0000000000..f16d07b2d4
--- /dev/null
+++ b/devtools/client/webconsole/test/browser/browser_webconsole_object_inspector_getters.js
@@ -0,0 +1,664 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Check evaluating and expanding getters in the console.
+const TEST_URI =
+ "data:text/html;charset=utf8,<!DOCTYPE html><h1>Object Inspector on Getters</h1>";
+const { ELLIPSIS } = require("resource://devtools/shared/l10n.js");
+
+add_task(async function () {
+ const hud = await openNewTabAndConsole(TEST_URI);
+
+ const LONGSTRING = "ab ".repeat(1e5);
+
+ await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [LONGSTRING],
+ function (longString) {
+ content.wrappedJSObject.console.log(
+ "oi-test",
+ Object.create(
+ null,
+ Object.getOwnPropertyDescriptors({
+ get myStringGetter() {
+ return "hello";
+ },
+ get myNumberGetter() {
+ return 123;
+ },
+ get myUndefinedGetter() {
+ return undefined;
+ },
+ get myNullGetter() {
+ return null;
+ },
+ get myZeroGetter() {
+ return 0;
+ },
+ get myEmptyStringGetter() {
+ return "";
+ },
+ get myFalseGetter() {
+ return false;
+ },
+ get myTrueGetter() {
+ return true;
+ },
+ get myObjectGetter() {
+ return { foo: "bar" };
+ },
+ get myArrayGetter() {
+ return Array.from({ length: 1000 }, (_, i) => i);
+ },
+ get myMapGetter() {
+ return new Map([["foo", { bar: "baz" }]]);
+ },
+ get myProxyGetter() {
+ const handler = {
+ get(target, name) {
+ return name in target ? target[name] : 37;
+ },
+ };
+ return new Proxy({ a: 1 }, handler);
+ },
+ get myThrowingGetter() {
+ throw new Error("myError");
+ },
+ get myLongStringGetter() {
+ return longString;
+ },
+ get ["hyphen-getter"]() {
+ return "---";
+ },
+ get [`"quoted-getter"`]() {
+ return "quoted";
+ },
+ get [`"'\``]() {
+ return "quoted2";
+ },
+ })
+ )
+ );
+ }
+ );
+
+ const node = await waitFor(() => findConsoleAPIMessage(hud, "oi-test"));
+ const oi = node.querySelector(".tree");
+
+ expandObjectInspectorNode(oi);
+ await waitFor(() => getObjectInspectorNodes(oi).length > 1);
+
+ await testStringGetter(oi);
+ await testNumberGetter(oi);
+ await testUndefinedGetter(oi);
+ await testNullGetter(oi);
+ await testZeroGetter(oi);
+ await testEmptyStringGetter(oi);
+ await testFalseGetter(oi);
+ await testTrueGetter(oi);
+ await testObjectGetter(oi);
+ await testArrayGetter(oi);
+ await testMapGetter(oi);
+ await testProxyGetter(oi);
+ await testThrowingGetter(oi);
+ await testLongStringGetter(oi, LONGSTRING);
+ await testHypgenGetter(oi);
+ await testQuotedGetters(oi);
+});
+
+async function testStringGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myStringGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myStringGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myStringGetter");
+ ok(
+ node.textContent.includes(`myStringGetter: "hello"`),
+ "String getter now has the expected text content"
+ );
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+}
+
+async function testNumberGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myNumberGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myNumberGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myNumberGetter");
+ ok(
+ node.textContent.includes(`myNumberGetter: 123`),
+ "Number getter now has the expected text content"
+ );
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+}
+
+async function testUndefinedGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myUndefinedGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myUndefinedGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myUndefinedGetter");
+ ok(
+ node.textContent.includes(`myUndefinedGetter: undefined`),
+ "undefined getter now has the expected text content"
+ );
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+}
+
+async function testNullGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myNullGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myNullGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myNullGetter");
+ ok(
+ node.textContent.includes(`myNullGetter: null`),
+ "null getter now has the expected text content"
+ );
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+}
+
+async function testZeroGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myZeroGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myZeroGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myZeroGetter");
+ ok(
+ node.textContent.includes(`myZeroGetter: 0`),
+ "0 getter now has the expected text content"
+ );
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+}
+
+async function testEmptyStringGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myEmptyStringGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myEmptyStringGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myEmptyStringGetter");
+ ok(
+ node.textContent.includes(`myEmptyStringGetter: ""`),
+ "empty string getter now has the expected text content"
+ );
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+}
+
+async function testFalseGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myFalseGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myFalseGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myFalseGetter");
+ ok(
+ node.textContent.includes(`myFalseGetter: false`),
+ "false getter now has the expected text content"
+ );
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+}
+
+async function testTrueGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myTrueGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myTrueGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myTrueGetter");
+ ok(
+ node.textContent.includes(`myTrueGetter: true`),
+ "false getter now has the expected text content"
+ );
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+}
+
+async function testObjectGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myObjectGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myObjectGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myObjectGetter");
+ ok(
+ node.textContent.includes(`myObjectGetter: Object { foo: "bar" }`),
+ "object getter now has the expected text content"
+ );
+ is(isObjectInspectorNodeExpandable(node), true, "The node can be expanded");
+
+ expandObjectInspectorNode(node);
+ await waitFor(() => !!getObjectInspectorChildrenNodes(node).length);
+ checkChildren(node, [`foo: "bar"`, `<prototype>`]);
+}
+
+async function testArrayGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myArrayGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myArrayGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myArrayGetter");
+ ok(
+ node.textContent.includes(
+ `myArrayGetter: Array(1000) [ 0, 1, 2, ${ELLIPSIS} ]`
+ ),
+ "Array getter now has the expected text content - "
+ );
+ is(isObjectInspectorNodeExpandable(node), true, "The node can be expanded");
+
+ expandObjectInspectorNode(node);
+ await waitFor(() => !!getObjectInspectorChildrenNodes(node).length);
+ const children = getObjectInspectorChildrenNodes(node);
+
+ const firstBucket = children[0];
+ ok(firstBucket.textContent.includes(`[0${ELLIPSIS}99]`), "Array has buckets");
+
+ is(
+ isObjectInspectorNodeExpandable(firstBucket),
+ true,
+ "The bucket can be expanded"
+ );
+ expandObjectInspectorNode(firstBucket);
+ await waitFor(() => !!getObjectInspectorChildrenNodes(firstBucket).length);
+ checkChildren(
+ firstBucket,
+ Array.from({ length: 100 }, (_, i) => `${i}: ${i}`)
+ );
+}
+
+async function testMapGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myMapGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myMapGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myMapGetter");
+ ok(
+ node.textContent.includes(`myMapGetter: Map`),
+ "map getter now has the expected text content"
+ );
+ is(isObjectInspectorNodeExpandable(node), true, "The node can be expanded");
+
+ expandObjectInspectorNode(node);
+ await waitFor(() => !!getObjectInspectorChildrenNodes(node).length);
+ checkChildren(node, [`size`, `<entries>`, `<prototype>`]);
+
+ const entriesNode = findObjectInspectorNode(oi, "<entries>");
+ expandObjectInspectorNode(entriesNode);
+ await waitFor(() => !!getObjectInspectorChildrenNodes(entriesNode).length);
+ checkChildren(entriesNode, [`foo → Object { bar: "baz" }`]);
+
+ const entryNode = getObjectInspectorChildrenNodes(entriesNode)[0];
+ expandObjectInspectorNode(entryNode);
+ await waitFor(() => !!getObjectInspectorChildrenNodes(entryNode).length);
+ checkChildren(entryNode, [`<key>: "foo"`, `<value>: Object { bar: "baz" }`]);
+}
+
+async function testProxyGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myProxyGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myProxyGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myProxyGetter");
+ ok(
+ node.textContent.includes(`myProxyGetter: Proxy`),
+ "proxy getter now has the expected text content"
+ );
+ is(isObjectInspectorNodeExpandable(node), true, "The node can be expanded");
+
+ expandObjectInspectorNode(node);
+ await waitFor(() => !!getObjectInspectorChildrenNodes(node).length);
+ checkChildren(node, [`<target>`, `<handler>`]);
+
+ const targetNode = findObjectInspectorNode(oi, "<target>");
+ expandObjectInspectorNode(targetNode);
+ await waitFor(() => !!getObjectInspectorChildrenNodes(targetNode).length);
+ checkChildren(targetNode, [`a: 1`, `<prototype>`]);
+
+ const handlerNode = findObjectInspectorNode(oi, "<handler>");
+ expandObjectInspectorNode(handlerNode);
+ await waitFor(() => !!getObjectInspectorChildrenNodes(handlerNode).length);
+ checkChildren(handlerNode, [`get:`, `<prototype>`]);
+}
+
+async function testThrowingGetter(oi) {
+ let node = findObjectInspectorNode(oi, "myThrowingGetter");
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () =>
+ !getObjectInspectorInvokeGetterButton(
+ findObjectInspectorNode(oi, "myThrowingGetter")
+ )
+ );
+
+ node = findObjectInspectorNode(oi, "myThrowingGetter");
+ ok(
+ node.textContent.includes(`myThrowingGetter: Error`),
+ "throwing getter does show the error"
+ );
+ is(isObjectInspectorNodeExpandable(node), true, "The node can be expanded");
+
+ expandObjectInspectorNode(node);
+ await waitFor(() => !!getObjectInspectorChildrenNodes(node).length);
+ checkChildren(node, [
+ `columnNumber`,
+ `fileName`,
+ `lineNumber`,
+ `message`,
+ `stack`,
+ `<prototype>`,
+ ]);
+}
+
+async function testLongStringGetter(oi, longString) {
+ const getLongStringNode = () =>
+ findObjectInspectorNode(oi, "myLongStringGetter");
+ const node = getLongStringNode();
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(() =>
+ getLongStringNode().textContent.includes(`myLongStringGetter: "ab ab`)
+ );
+ ok(true, "longstring getter shows the initial text");
+ is(
+ isObjectInspectorNodeExpandable(getLongStringNode()),
+ true,
+ "The node can be expanded"
+ );
+
+ expandObjectInspectorNode(getLongStringNode());
+ await waitFor(() =>
+ getLongStringNode().textContent.includes(
+ `myLongStringGetter: "${longString}"`
+ )
+ );
+ ok(true, "the longstring was expanded");
+}
+
+async function testHypgenGetter(oi) {
+ const findHyphenGetterNode = () =>
+ findObjectInspectorNode(oi, `"hyphen-getter"`);
+ let node = findHyphenGetterNode();
+
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+ const invokeButton = getObjectInspectorInvokeGetterButton(node);
+ ok(invokeButton, "There is an invoke button as expected");
+
+ invokeButton.click();
+ await waitFor(
+ () => !getObjectInspectorInvokeGetterButton(findHyphenGetterNode())
+ );
+
+ node = findHyphenGetterNode();
+ ok(
+ node.textContent.includes(`"hyphen-getter": "---"`),
+ "Node now has the expected text content"
+ );
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ "The node can't be expanded"
+ );
+}
+
+async function testQuotedGetters(oi) {
+ const nodes = [
+ {
+ name: `'"quoted-getter"'`,
+ expected: `"quoted"`,
+ expandable: false,
+ },
+ {
+ name: `"\\"'\`"`,
+ expected: `"quoted2"`,
+ expandable: false,
+ },
+ ];
+
+ for (const { name, expected, expandable } of nodes) {
+ await testGetter(oi, name, expected, expandable);
+ }
+}
+
+async function testGetter(oi, propertyName, expectedResult, resultExpandable) {
+ info(`Check «${propertyName}» getter`);
+ const findNode = () => findObjectInspectorNode(oi, propertyName);
+
+ let node = findNode();
+ is(
+ isObjectInspectorNodeExpandable(node),
+ false,
+ `«${propertyName}» can't be expanded`
+ );
+ getObjectInspectorInvokeGetterButton(node).click();
+ await waitFor(() => !getObjectInspectorInvokeGetterButton(findNode()));
+
+ node = findNode();
+ ok(
+ node.textContent.includes(`${propertyName}: ${expectedResult}`),
+ `«${propertyName}» now has the expected text content («${expectedResult}»)`
+ );
+ is(
+ isObjectInspectorNodeExpandable(node),
+ resultExpandable,
+ `«${propertyName}» ${resultExpandable ? "now can" : "can't"} be expanded`
+ );
+}
+
+function checkChildren(node, expectedChildren) {
+ const children = getObjectInspectorChildrenNodes(node);
+ is(
+ children.length,
+ expectedChildren.length,
+ "There is the expected number of children"
+ );
+ children.forEach((child, index) => {
+ ok(
+ child.textContent.includes(expectedChildren[index]),
+ `Expected "${child.textContent}" to include "${expectedChildren[index]}"`
+ );
+ });
+}