summaryrefslogtreecommitdiffstats
path: root/devtools/server/tests/browser/inspector-helpers.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--devtools/server/tests/browser/inspector-helpers.js166
1 files changed, 166 insertions, 0 deletions
diff --git a/devtools/server/tests/browser/inspector-helpers.js b/devtools/server/tests/browser/inspector-helpers.js
new file mode 100644
index 0000000000..09d7418e01
--- /dev/null
+++ b/devtools/server/tests/browser/inspector-helpers.js
@@ -0,0 +1,166 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* exported assertOwnershipTrees, checkMissing, waitForMutation,
+ isSrcChange, isUnretained, isChildList */
+
+function serverOwnershipTree(walkerArg) {
+ return SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [[walkerArg.actorID]],
+ function(actorID) {
+ const { require } = ChromeUtils.importESModule(
+ "resource://devtools/shared/loader/Loader.sys.mjs"
+ );
+ const {
+ DevToolsServer,
+ } = require("resource://devtools/server/devtools-server.js");
+ const {
+ DocumentWalker,
+ } = require("resource://devtools/server/actors/inspector/document-walker.js");
+
+ // Convert actorID to current compartment string otherwise
+ // searchAllConnectionsForActor is confused and won't find the actor.
+ actorID = String(actorID);
+ const serverWalker = DevToolsServer.searchAllConnectionsForActor(actorID);
+
+ function sortOwnershipChildrenContentScript(children) {
+ return children.sort((a, b) => a.name.localeCompare(b.name));
+ }
+
+ function serverOwnershipSubtree(walker, node) {
+ const actor = walker.getNode(node);
+ if (!actor) {
+ return undefined;
+ }
+
+ const children = [];
+ const docwalker = new DocumentWalker(node, content);
+ let child = docwalker.firstChild();
+ while (child) {
+ const item = serverOwnershipSubtree(walker, child);
+ if (item) {
+ children.push(item);
+ }
+ child = docwalker.nextSibling();
+ }
+ return {
+ name: actor.actorID,
+ children: sortOwnershipChildrenContentScript(children),
+ };
+ }
+ return {
+ root: serverOwnershipSubtree(serverWalker, serverWalker.rootDoc),
+ orphaned: [...serverWalker._orphaned].map(o =>
+ serverOwnershipSubtree(serverWalker, o.rawNode)
+ ),
+ retained: [...serverWalker._retainedOrphans].map(o =>
+ serverOwnershipSubtree(serverWalker, o.rawNode)
+ ),
+ };
+ }
+ );
+}
+
+function sortOwnershipChildren(children) {
+ return children.sort((a, b) => a.name.localeCompare(b.name));
+}
+
+function clientOwnershipSubtree(node) {
+ return {
+ name: node.actorID,
+ children: sortOwnershipChildren(
+ node.treeChildren().map(child => clientOwnershipSubtree(child))
+ ),
+ };
+}
+
+function clientOwnershipTree(walker) {
+ return {
+ root: clientOwnershipSubtree(walker.rootNode),
+ orphaned: [...walker._orphaned].map(o => clientOwnershipSubtree(o)),
+ retained: [...walker._retainedOrphans].map(o => clientOwnershipSubtree(o)),
+ };
+}
+
+function ownershipTreeSize(tree) {
+ let size = 1;
+ for (const child of tree.children) {
+ size += ownershipTreeSize(child);
+ }
+ return size;
+}
+
+async function assertOwnershipTrees(walker) {
+ const serverTree = await serverOwnershipTree(walker);
+ const clientTree = clientOwnershipTree(walker);
+ is(
+ JSON.stringify(clientTree, null, " "),
+ JSON.stringify(serverTree, null, " "),
+ "Server and client ownership trees should match."
+ );
+
+ return ownershipTreeSize(clientTree.root);
+}
+
+// Verify that an actorID is inaccessible both from the client library and the server.
+function checkMissing({ client }, actorID) {
+ return new Promise(resolve => {
+ const front = client.getFrontByID(actorID);
+ ok(
+ !front,
+ "Front shouldn't be accessible from the client for actorID: " + actorID
+ );
+
+ client
+ .request(
+ {
+ to: actorID,
+ type: "request",
+ },
+ response => {
+ is(
+ response.error,
+ "noSuchActor",
+ "node list actor should no longer be contactable."
+ );
+ resolve(undefined);
+ }
+ )
+ .catch(() => {});
+ });
+}
+
+// Load mutations aren't predictable, so keep accumulating mutations until
+// the one we're looking for shows up.
+function waitForMutation(walker, test, mutations = []) {
+ return new Promise(resolve => {
+ for (const change of mutations) {
+ if (test(change)) {
+ resolve(mutations);
+ }
+ }
+
+ walker.once("mutations", newMutations => {
+ waitForMutation(walker, test, mutations.concat(newMutations)).then(
+ finalMutations => {
+ resolve(finalMutations);
+ }
+ );
+ });
+ });
+}
+
+function isSrcChange(change) {
+ return change.type === "attributes" && change.attributeName === "src";
+}
+
+function isUnretained(change) {
+ return change.type === "unretained";
+}
+
+function isChildList(change) {
+ return change.type === "childList";
+}