From f49f3db6d781e4bb965e4fae35fbbbac35512966 Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Wed, 9 Jan 2019 01:47:34 +0000 Subject: [PATCH] Bug 1515046 - Let reps invoke the right getter when it's shadowed. r=nchevobbe Depends on D15788 Differential Revision: https://phabricator.services.mozilla.com/D15789 --HG-- extra : moz-landing-system : lando --- .../client/shared/components/reps/reps.js | 32 ++++++-- .../webconsole/test/mochitest/browser.ini | 1 + ...nsole_object_inspector_getters_shadowed.js | 79 +++++++++++++++++++ 3 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 devtools/client/webconsole/test/mochitest/browser_webconsole_object_inspector_getters_shadowed.js diff --git a/devtools/client/shared/components/reps/reps.js b/devtools/client/shared/components/reps/reps.js index bea1935dbf70..f94889e3ef3c 100644 --- a/devtools/client/shared/components/reps/reps.js +++ b/devtools/client/shared/components/reps/reps.js @@ -3688,13 +3688,26 @@ function getClosestNonBucketNode(item) { return getClosestNonBucketNode(parent); } -function getNonPrototypeParentGripValue(item) { +function getParentGripNode(item) { const parentNode = getParent(item); if (!parentNode) { return null; } - const parentGripNode = getClosestGripNode(parentNode); + return getClosestGripNode(parentNode); +} + +function getParentGripValue(item) { + const parentGripNode = getParentGripNode(item); + if (!parentGripNode) { + return null; + } + + return getValue(parentGripNode); +} + +function getNonPrototypeParentGripValue(item) { + const parentGripNode = getParentGripNode(item); if (!parentGripNode) { return null; } @@ -3716,6 +3729,7 @@ module.exports = { getClosestGripNode, getClosestNonBucketNode, getParent, + getParentGripValue, getNonPrototypeParentGripValue, getNumericalPropertiesCount, getValue, @@ -6406,11 +6420,11 @@ function releaseActors(state, client) { } } -function invokeGetter(node, grip, getterName) { +function invokeGetter(node, targetGrip, receiverId, getterName) { return async ({ dispatch, client, getState }) => { try { - const objectClient = client.createObjectClient(grip); - const result = await objectClient.getPropertyValue(getterName, null); + const objectClient = client.createObjectClient(targetGrip); + const result = await objectClient.getPropertyValue(getterName, receiverId); dispatch({ type: "GETTER_INVOKED", data: { @@ -7004,6 +7018,7 @@ const { nodeIsLongString, nodeHasFullText, nodeHasGetter, + getParentGripValue, getNonPrototypeParentGripValue } = Utils.node; @@ -7078,10 +7093,11 @@ class ObjectInspectorItem extends Component { } if (nodeHasGetter(item)) { - const parentGrip = getNonPrototypeParentGripValue(item); - if (parentGrip) { + const targetGrip = getParentGripValue(item); + const receiverGrip = getNonPrototypeParentGripValue(item); + if (targetGrip && receiverGrip) { Object.assign(repProps, { - onInvokeGetterButtonClick: () => this.props.invokeGetter(item, parentGrip, item.name) + onInvokeGetterButtonClick: () => this.props.invokeGetter(item, targetGrip, receiverGrip.actor, item.name) }); } } diff --git a/devtools/client/webconsole/test/mochitest/browser.ini b/devtools/client/webconsole/test/mochitest/browser.ini index 70d1dbcb2fe4..27dd8f8f3c56 100644 --- a/devtools/client/webconsole/test/mochitest/browser.ini +++ b/devtools/client/webconsole/test/mochitest/browser.ini @@ -355,6 +355,7 @@ skip-if = true # Bug 1438979 [browser_webconsole_object_inspector_entries.js] [browser_webconsole_object_inspector_getters.js] [browser_webconsole_object_inspector_getters_prototype.js] +[browser_webconsole_object_inspector_getters_shadowed.js] [browser_webconsole_object_inspector_key_sorting.js] [browser_webconsole_object_inspector_local_session_storage.js] [browser_webconsole_object_inspector_selected_text.js] diff --git a/devtools/client/webconsole/test/mochitest/browser_webconsole_object_inspector_getters_shadowed.js b/devtools/client/webconsole/test/mochitest/browser_webconsole_object_inspector_getters_shadowed.js new file mode 100644 index 000000000000..bdfc30423b23 --- /dev/null +++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_object_inspector_getters_shadowed.js @@ -0,0 +1,79 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Check evaluating shadowed getters in the console. +const TEST_URI = "data:text/html;charset=utf8,

Object Inspector on Getters

"; + +add_task(async function() { + const hud = await openNewTabAndConsole(TEST_URI); + + await ContentTask.spawn(gBrowser.selectedBrowser, null, function() { + const a = { + getter: "[A]", + __proto__: { + get getter() { + return "[B]"; + }, + __proto__: { + get getter() { + return "[C]"; + }, + }, + }, + }; + const b = { + value: 1, + get getter() { + return `[A-${this.value}]`; + }, + __proto__: { + value: 2, + get getter() { + return `[B-${this.value}]`; + }, + }, + }; + content.wrappedJSObject.console.log("oi-test", a, b); + }); + + const node = await waitFor(() => findMessage(hud, "oi-test")); + const [a, b] = node.querySelectorAll(".tree"); + + await testObject(a, [null, "[B]", "[C]"]); + await testObject(b, ["[A-1]", "[B-1]"]); +}); + +async function testObject(oi, values) { + let node = oi.querySelector(".tree-node"); + for (const value of values) { + await expand(node); + if (value != null) { + const getter = findObjectInspectorNodeChild(node, "getter"); + await invokeGetter(getter); + ok(getter.textContent.includes(`getter: "${value}"`), + `Getter now has the expected "${value}" content`); + } + node = findObjectInspectorNodeChild(node, ""); + } +} + +function expand(node) { + expandObjectInspectorNode(node); + return waitFor(() => getObjectInspectorChildrenNodes(node).length > 0); +} + +function invokeGetter(node) { + getObjectInspectorInvokeGetterButton(node).click(); + return waitFor(() => !getObjectInspectorInvokeGetterButton(node)); +} + +function findObjectInspectorNodeChild(node, nodeLabel) { + return getObjectInspectorChildrenNodes(node).find(child => { + const label = child.querySelector(".object-label"); + return label && label.textContent === nodeLabel; + }); +}