browser_webconsole_object_inspector_entries.js (3732B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 requestLongerTimeout(2); 7 8 const { JSObjectsTestUtils, CONTEXTS } = ChromeUtils.importESModule( 9 "resource://testing-common/JSObjectsTestUtils.sys.mjs" 10 ); 11 add_setup(function () { 12 JSObjectsTestUtils.init(this); 13 }); 14 15 const EXPECTED_VALUES_FILE = 16 "browser_webconsole_object_inspector_entries.snapshot.mjs"; 17 18 add_task(async function () { 19 // nsHttpServer does not support https 20 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 21 const hud = await openNewTabAndConsole("http://example.com"); 22 const outputScroller = hud.ui.outputScroller; 23 24 let count = 0; 25 await JSObjectsTestUtils.runTest( 26 EXPECTED_VALUES_FILE, 27 async function ({ context, expression }) { 28 if (context == CONTEXTS.CHROME) { 29 return undefined; 30 } 31 32 await SpecialPowers.spawn( 33 gBrowser.selectedBrowser, 34 [expression, count], 35 function (exp, i) { 36 let value; 37 try { 38 value = content.eval(exp); 39 } catch (e) { 40 value = e; 41 } 42 content.console.log("test message " + i, value); 43 } 44 ); 45 46 const messageNode = await waitFor(() => { 47 // Expanding objects disables the "pinned-to-bottom" state, and because of virtualization 48 // we might miss the last emitted message. Let's always scroll to the bottom before 49 // checking for the message. 50 outputScroller.scrollTop = outputScroller.scrollHeight; 51 return findConsoleAPIMessage(hud, "test message " + count); 52 }); 53 count++; 54 const oi = messageNode.querySelector(".tree"); 55 56 if (oi) { 57 const preview = []; 58 59 // Expand the root node, otherwise the object is collapsed by default. 60 await expandObjectInspectorNode(oi.querySelector(".tree-node")); 61 62 // Do a first lookup to expand all the "<entries>" nodes, 63 // as well as their immediate first entries. 64 // This will generate new ".tree-node"'s. 65 for (const node of oi.querySelectorAll(".tree-node")) { 66 const label = node.textContent.replace(/\u200B/g, ""); 67 68 if (label == "<entries>") { 69 await expandObjectInspectorNode(node); 70 const firstEntry = node.nextSibling; 71 if (isObjectInspectorNodeExpandable(firstEntry)) { 72 await expandObjectInspectorNode(firstEntry); 73 } 74 } 75 } 76 77 // Generate a human-friendly representation of the state of the object inspector 78 for (const node of oi.querySelectorAll(".tree-node")) { 79 const label = node.textContent.replace(/\u200B/g, ""); 80 81 let icon = "\u251C "; // "|-" character 82 if (isObjectInspectorNodeExpandable(node)) { 83 icon = node 84 .querySelector(".theme-twisty") 85 .classList.contains("open") 86 ? "▼ " 87 : "▶︎ "; 88 } 89 const level = node.getAttribute("aria-level"); 90 const indent = " ".repeat(parseInt(level, 10) - 1); 91 92 preview.push(indent + icon + label); 93 } 94 95 // Help debug the test by scrolling to the very last node, 96 // so that the object inspector is fully visible. 97 const nodes = oi.querySelectorAll(".node"); 98 const lastNode = nodes[nodes.length - 1]; 99 lastNode.scrollIntoView(); 100 101 return preview; 102 } 103 104 // If this is a primitive data type, there won't be an object inspector, 105 // but only a simple Rep that we can only stringify. 106 const object = messageNode.querySelectorAll(".message-body > *")[1]; 107 return object.textContent; 108 } 109 ); 110 });