fune/devtools/client/debugger/test/mochitest/browser_dbg-preview.js
Nicolas Chevobbe 9e7b563e31 Bug 1815472 - [devtools] Fix variable tooltip when location is impacted by inline preview or wrapping. r=devtools-reviewers,bomsy.
In `getTokenLocation`, the call to `coordsChar` needed an extra parameter so the
coordinates are relative to the top left corner fo the currently visible window.
We were passing the center of the bounding client rect to `getTokenLocation`, but
a token could wrap and have it's bounding rect center not being on the token.
To fix this we're passing the center of the first box quads of the token.

The inline preview widgets were causing some troubles on CodeMirror internal
state too. Since we're using React to populate the bookmark we set on the line,
and given that React.render is asynchronous, we were setting an empty element
as a bookmark on the editor, which React populates later. But CodeMirror probably
update its internal state when the bookmark is added, so that was causing wrong
computation later.
To avoid that, we only set the bookmark once React actually rendered the element
in the DOM.

Finally, while codeMirror already listen for window resize to update its internal
state, the Editor can be resized without the window being resized,
when primary/secondary panels are resized. In such case, we manually trigger
a codeMirror refresh.

We add a test to cover this, and also modify test helpers so we would query
the DOM instead of relying on CodeMirror methods.

Differential Revision: https://phabricator.services.mozilla.com/D190272
2023-10-23 08:24:28 +00:00

158 lines
4.3 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
// Test hovering on an object, which will show a popup and on a
// simple value, which will show a tooltip.
"use strict";
// Showing/hiding the preview tooltip can be slow as we wait for CodeMirror scroll...
requestLongerTimeout(2);
add_task(async function () {
const dbg = await initDebugger("doc-preview.html", "preview.js");
await testPreviews(dbg, "testInline", [
{ line: 17, column: 16, expression: "prop", result: 2 },
]);
await selectSource(dbg, "preview.js");
await testBucketedArray(dbg);
await testPreviews(dbg, "empties", [
{ line: 6, column: 9, expression: "a", result: '""' },
{ line: 7, column: 9, expression: "b", result: "false" },
{ line: 8, column: 9, expression: "c", result: "undefined" },
{ line: 9, column: 9, expression: "d", result: "null" },
]);
await testPreviews(dbg, "objects", [
{ line: 27, column: 10, expression: "empty", result: "Object" },
{ line: 28, column: 22, expression: "foo", result: 1 },
]);
await testPreviews(dbg, "smalls", [
{ line: 14, column: 9, expression: "a", result: '"..."' },
{ line: 15, column: 9, expression: "b", result: "true" },
{ line: 16, column: 9, expression: "c", result: "1" },
{
line: 17,
column: 9,
expression: "d",
fields: [["length", "0"]],
},
]);
await testPreviews(dbg, "classPreview", [
{ line: 50, column: 20, expression: "x", result: 1 },
{ line: 50, column: 29, expression: "#privateVar", result: 2 },
{
line: 50,
column: 47,
expression: "#privateStatic",
fields: [
["first", `"a"`],
["second", `"b"`],
],
},
{
line: 51,
column: 26,
expression: "this",
fields: [
["x", "1"],
["#privateVar", "2"],
],
},
{ line: 51, column: 39, expression: "#privateVar", result: 2 },
]);
info(
"Check that closing the preview tooltip doesn't release the underlying object actor"
);
invokeInTab("classPreview");
await waitForPaused(dbg);
info("Display popup a first time and hide it");
await assertPreviews(dbg, [
{
line: 60,
column: 7,
expression: "y",
fields: [["hello", "{…}"]],
},
]);
info("Display the popup again and try to expand a property");
const { element: popupEl, tokenEl } = await tryHovering(
dbg,
60,
7,
"previewPopup"
);
const nodes = popupEl.querySelectorAll(".preview-popup .node");
const initialNodesLength = nodes.length;
nodes[1].querySelector(".arrow").click();
await waitFor(
() =>
popupEl.querySelectorAll(".preview-popup .node").length >
initialNodesLength
);
ok(true, `"hello" was expanded`);
await closePreviewForToken(dbg, tokenEl, "popup");
await resume(dbg);
});
async function testPreviews(dbg, fnName, previews) {
invokeInTab(fnName);
await waitForPaused(dbg);
await assertPreviews(dbg, previews);
await resume(dbg);
info(`Ran tests for ${fnName}`);
}
async function testBucketedArray(dbg) {
invokeInTab("largeArray");
await waitForPaused(dbg);
const { element: popupEl, tokenEl } = await tryHovering(
dbg,
34,
10,
"previewPopup"
);
info("Wait for top level node to expand and child nodes to load");
await waitUntil(
() => popupEl.querySelectorAll(".preview-popup .node").length > 1
);
const oiNodes = Array.from(popupEl.querySelectorAll(".preview-popup .node"));
const displayedPropertyNames = oiNodes.map(
oiNode => oiNode.querySelector(".object-label")?.textContent
);
Assert.deepEqual(displayedPropertyNames, [
null, // No property name is displayed for the root node
"[0…99]",
"[100…100]",
"length",
"<prototype>",
]);
const node = oiNodes.find(
oiNode => oiNode.querySelector(".object-label")?.textContent === "length"
);
if (!node) {
ok(false, `The "length" property is not displayed in the popup`);
} else {
is(
node.querySelector(".objectBox").textContent,
"101",
`The "length" property has the expected value`
);
}
await closePreviewForToken(dbg, tokenEl, "popup");
await resume(dbg);
}