Bug 1078374 - Move helper_shadowdom in markup-view head.js;r=bgrins draft
authorJulian Descottes <jdescottes@mozilla.com>
Sat, 23 Jun 2018 08:42:33 +0200
changeset 810774 615e49721e6e7b527255d3dde910de931d33ccae
parent 810773 be16034feeac2868938bc9a88ec30162f4d99433
child 810775 3f37819f8305e6c373d957f93da2ff7d63c38ce5
push id114098
push userjdescottes@mozilla.com
push dateTue, 26 Jun 2018 13:21:46 +0000
reviewersbgrins
bugs1078374
milestone62.0a1
Bug 1078374 - Move helper_shadowdom in markup-view head.js;r=bgrins MozReview-Commit-ID: C3O5LjSfxqS
devtools/client/inspector/markup/test/browser.ini
devtools/client/inspector/markup/test/browser_markup_shadowdom.js
devtools/client/inspector/markup/test/browser_markup_shadowdom_clickreveal.js
devtools/client/inspector/markup/test/browser_markup_shadowdom_delete.js
devtools/client/inspector/markup/test/browser_markup_shadowdom_maxchildren.js
devtools/client/inspector/markup/test/browser_markup_shadowdom_mutations_shadow.js
devtools/client/inspector/markup/test/browser_markup_shadowdom_noslot.js
devtools/client/inspector/markup/test/browser_markup_shadowdom_slotupdate.js
devtools/client/inspector/markup/test/head.js
devtools/client/inspector/markup/test/helper_shadowdom.js
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -44,17 +44,16 @@ support-files =
   events_bundle.js.map
   events_original.js
   head.js
   helper_attributes_test_runner.js
   helper_diff.js
   helper_events_test_runner.js
   helper_markup_accessibility_navigation.js
   helper_outerhtml_test_runner.js
-  helper_shadowdom.js
   helper_style_attr_test_runner.js
   lib_babel_6.21.0_min.js
   lib_jquery_1.0.js
   lib_jquery_1.1.js
   lib_jquery_1.2_min.js
   lib_jquery_1.3_min.js
   lib_jquery_1.4_min.js
   lib_jquery_1.6_min.js
--- a/devtools/client/inspector/markup/test/browser_markup_shadowdom.js
+++ b/devtools/client/inspector/markup/test/browser_markup_shadowdom.js
@@ -1,18 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/* import-globals-from helper_shadowdom.js */
-
 "use strict";
 
-loadHelperScript("helper_shadowdom.js");
-
 requestLongerTimeout(2);
 
 // Test a few static pages using webcomponents and check that they are displayed as
 // expected in the markup view.
 
 const TEST_DATA = [
   {
     // Test that expanding a shadow host shows a shadow root node and direct children.
@@ -201,17 +197,17 @@ const TEST_DATA = [
 ];
 
 for (const {url, tree, title} of TEST_DATA) {
   // Test each configuration in both open and closed modes
   add_task(async function() {
     info(`Testing: [${title}] in OPEN mode`);
     await enableWebComponents();
     const {inspector} = await openInspectorForURL(url.replace("#MODE#", "open"));
-    await checkTreeFromRootSelector(tree, "test-component", inspector);
+    await assertMarkupViewAsTree(tree, "test-component", inspector);
   });
   add_task(async function() {
     info(`Testing: [${title}] in CLOSED mode`);
     await enableWebComponents();
     const {inspector} = await openInspectorForURL(url.replace("#MODE#", "closed"));
-    await checkTreeFromRootSelector(tree, "test-component", inspector);
+    await assertMarkupViewAsTree(tree, "test-component", inspector);
   });
 }
--- a/devtools/client/inspector/markup/test/browser_markup_shadowdom_clickreveal.js
+++ b/devtools/client/inspector/markup/test/browser_markup_shadowdom_clickreveal.js
@@ -1,18 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/* import-globals-from helper_shadowdom.js */
-
 "use strict";
 
-loadHelperScript("helper_shadowdom.js");
-
 // Test that the corresponding non-slotted node container gets selected when clicking on
 // the reveal link for a slotted node.
 
 const TEST_URL = `data:text/html;charset=utf-8,
   <test-component>
     <div slot="slot1" id="el1">slot1-1</div>
     <div slot="slot1" id="el2">slot1-2</div>
   </test-component>
--- a/devtools/client/inspector/markup/test/browser_markup_shadowdom_delete.js
+++ b/devtools/client/inspector/markup/test/browser_markup_shadowdom_delete.js
@@ -1,18 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/* import-globals-from helper_shadowdom.js */
-
 "use strict";
 
-loadHelperScript("helper_shadowdom.js");
-
 // Test that slot elements are correctly updated when slotted elements are being removed
 // from the DOM.
 
 const TEST_URL = `data:text/html;charset=utf-8,
   <test-component>
     <div slot="slot1" id="el1">slot1-1</div>
     <div slot="slot1" id="el2">slot1-2</div>
   </test-component>
@@ -40,40 +36,40 @@ add_task(async function() {
   await waitForMultipleChildrenUpdates(inspector);
 
   info("Test that expanding a shadow host shows shadow root and direct host children.");
   const {markup} = inspector;
   const hostContainer = markup.getContainer(hostFront);
   const childContainers = hostContainer.getChildContainers();
 
   is(childContainers.length, 3, "Expecting 3 children: shadowroot, 2 host children");
-  checkText(childContainers[0], "#shadow-root");
-  checkText(childContainers[1], "div");
-  checkText(childContainers[2], "div");
+  assertContainerHasText(childContainers[0], "#shadow-root");
+  assertContainerHasText(childContainers[1], "div");
+  assertContainerHasText(childContainers[2], "div");
 
   info("Expand the shadow root");
   const shadowRootContainer = childContainers[0];
   await expandContainer(inspector, shadowRootContainer);
 
   const shadowChildContainers = shadowRootContainer.getChildContainers();
   is(shadowChildContainers.length, 1, "Expecting 1 child slot");
-  checkText(shadowChildContainers[0], "slot");
+  assertContainerHasText(shadowChildContainers[0], "slot");
 
   info("Expand the slot");
   const slotContainer = shadowChildContainers[0];
   await expandContainer(inspector, slotContainer);
 
   let slotChildContainers = slotContainer.getChildContainers();
   is(slotChildContainers.length, 2, "Expecting 2 slotted children");
-  slotChildContainers.forEach(container => checkSlotted(container));
+  slotChildContainers.forEach(container => assertContainerSlotted(container));
 
   await deleteNode(inspector, "#el1");
   slotChildContainers = slotContainer.getChildContainers();
   is(slotChildContainers.length, 1, "Expecting 1 slotted child");
-  checkSlotted(slotChildContainers[0]);
+  assertContainerSlotted(slotChildContainers[0]);
 
   await deleteNode(inspector, "#el2");
   slotChildContainers = slotContainer.getChildContainers();
   // After deleting the last host direct child we expect the slot to show the default
   // content <div>default</div>
   is(slotChildContainers.length, 1, "Expecting 1 child");
   ok(!slotChildContainers[0].isSlotted(), "Container is a not slotted container");
 });
--- a/devtools/client/inspector/markup/test/browser_markup_shadowdom_maxchildren.js
+++ b/devtools/client/inspector/markup/test/browser_markup_shadowdom_maxchildren.js
@@ -1,18 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/* import-globals-from helper_shadowdom.js */
-
 "use strict";
 
-loadHelperScript("helper_shadowdom.js");
-
 // Test that the markup view properly displays the "more nodes" button both for host
 // elements and for slot elements.
 
 const TEST_URL = `data:text/html;charset=utf-8,
 <test-component>
   <div>node 1</div><div>node 2</div><div>node 3</div>
   <div>node 4</div><div>node 5</div><div>node 6</div>
 </test-component>
@@ -43,61 +39,61 @@ add_task(async function() {
   await waitForMultipleChildrenUpdates(inspector);
 
   info("Test that expanding a shadow host shows shadow root and direct host children.");
   const {markup} = inspector;
   const hostContainer = markup.getContainer(hostFront);
   let childContainers = hostContainer.getChildContainers();
 
   is(childContainers.length, 6, "Expecting 6 children: shadowroot, 5 host children");
-  checkText(childContainers[0], "#shadow-root");
+  assertContainerHasText(childContainers[0], "#shadow-root");
   for (let i = 1; i < 6; i++) {
-    checkText(childContainers[i], "div");
-    checkText(childContainers[i], "node " + i);
+    assertContainerHasText(childContainers[i], "div");
+    assertContainerHasText(childContainers[i], "node " + i);
   }
 
   info("Click on the more nodes button under the host element");
   let moreNodesLink = hostContainer.elt.querySelector(".more-nodes");
   ok(!!moreNodesLink, "A 'more nodes' button is displayed in the host container");
   moreNodesLink.querySelector("button").click();
   await inspector.markup._waitForChildren();
 
   childContainers = hostContainer.getChildContainers();
   is(childContainers.length, 7, "Expecting one additional host child");
-  checkText(childContainers[6], "div");
-  checkText(childContainers[6], "node 6");
+  assertContainerHasText(childContainers[6], "div");
+  assertContainerHasText(childContainers[6], "node 6");
 
   info("Expand the shadow root");
   const shadowRootContainer = childContainers[0];
   const shadowRootFront = shadowRootContainer.node;
   await inspector.markup.expandNode(shadowRootFront);
   await waitForMultipleChildrenUpdates(inspector);
 
   const shadowChildContainers = shadowRootContainer.getChildContainers();
   is(shadowChildContainers.length, 1, "Expecting 1 slot child");
-  checkText(shadowChildContainers[0], "slot");
+  assertContainerHasText(shadowChildContainers[0], "slot");
 
   info("Expand the slot");
   const slotContainer = shadowChildContainers[0];
   const slotFront = slotContainer.node;
   await inspector.markup.expandNode(slotFront);
   await waitForMultipleChildrenUpdates(inspector);
 
   let slotChildContainers = slotContainer.getChildContainers();
   is(slotChildContainers.length, 5, "Expecting 5 slotted children");
   for (const slotChildContainer of slotChildContainers) {
-    checkText(slotChildContainer, "div");
+    assertContainerHasText(slotChildContainer, "div");
     ok(slotChildContainer.elt.querySelector(".reveal-link"),
       "Slotted container has a reveal link element");
   }
 
   info("Click on the more nodes button under the slot element");
   moreNodesLink = slotContainer.elt.querySelector(".more-nodes");
   ok(!!moreNodesLink, "A 'more nodes' button is displayed in the host container");
   EventUtils.sendMouseEvent({type: "click"}, moreNodesLink.querySelector("button"));
   await inspector.markup._waitForChildren();
 
   slotChildContainers = slotContainer.getChildContainers();
   is(slotChildContainers.length, 6, "Expecting one additional slotted element");
-  checkText(slotChildContainers[5], "div");
+  assertContainerHasText(slotChildContainers[5], "div");
   ok(slotChildContainers[5].elt.querySelector(".reveal-link"),
     "Slotted container has a reveal link element");
 });
--- a/devtools/client/inspector/markup/test/browser_markup_shadowdom_mutations_shadow.js
+++ b/devtools/client/inspector/markup/test/browser_markup_shadowdom_mutations_shadow.js
@@ -1,18 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/* import-globals-from helper_shadowdom.js */
-
 "use strict";
 
-loadHelperScript("helper_shadowdom.js");
-
 // Test that the markup view is correctly updated when elements under a shadow root are
 // deleted or updated.
 
 const TEST_URL = `data:text/html;charset=utf-8,
   <test-component>
     <div slot="slot1" id="el1">slot1-1</div>
     <div slot="slot1" id="el2">slot1-2</div>
   </test-component>
@@ -41,44 +37,44 @@ add_task(async function() {
       #shadow-root
         slot1-container
           slot
             div!slotted
             div!slotted
         another-div
       div
       div`;
-  await checkTreeFromRootSelector(tree, "test-component", inspector);
+  await assertMarkupViewAsTree(tree, "test-component", inspector);
 
   info("Delete a shadow dom element and check the updated markup view");
   let mutated = waitForMutation(inspector, "childList");
   ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
     const shadowRoot = content.document.querySelector("test-component").shadowRoot;
     const slotContainer = shadowRoot.getElementById("slot1-container");
     slotContainer.remove();
   });
   await mutated;
 
   const treeAfterDelete = `
     test-component
       #shadow-root
         another-div
       div
       div`;
-  await checkTreeFromRootSelector(treeAfterDelete, "test-component", inspector);
+  await assertMarkupViewAsTree(treeAfterDelete, "test-component", inspector);
 
   mutated = inspector.once("markupmutation");
   ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
     const shadowRoot = content.document.querySelector("test-component").shadowRoot;
     const shadowDiv = shadowRoot.getElementById("another-div");
     shadowDiv.setAttribute("random-attribute", "1");
   });
   await mutated;
 
   info("Add an attribute on a shadow dom element and check the updated markup view");
   const treeAfterAttrChange = `
     test-component
       #shadow-root
         random-attribute
       div
       div`;
-  await checkTreeFromRootSelector(treeAfterAttrChange, "test-component", inspector);
+  await assertMarkupViewAsTree(treeAfterAttrChange, "test-component", inspector);
 });
--- a/devtools/client/inspector/markup/test/browser_markup_shadowdom_noslot.js
+++ b/devtools/client/inspector/markup/test/browser_markup_shadowdom_noslot.js
@@ -1,18 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/* import-globals-from helper_shadowdom.js */
-
 "use strict";
 
-loadHelperScript("helper_shadowdom.js");
-
 // Test that the markup view is correctly displayed when a component has children but no
 // slots are available under the shadow root.
 
 const TEST_URL = `data:text/html;charset=utf-8,
   <style>
     .has-before::before { content: "before-content" }
   </style>
 
@@ -69,17 +65,17 @@ add_task(async function() {
       #shadow-root
         slot
           div!slotted
           div!slotted
       class="not-nested"
       class="nested"
         class="has-before"
           ::before`;
-  await checkTreeFromRootSelector(beforeTree, ".root", inspector);
+  await assertMarkupViewAsTree(beforeTree, ".root", inspector);
 
   info("Move the non-slotted element with class has-before and check the pseudo appears");
   const mutated = waitForNMutations(inspector, "childList", 2);
   const pseudoMutated = waitForMutation(inspector, "nativeAnonymousChildList");
   ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
     const root = content.document.querySelector(".root");
     const hasBeforeEl = content.document.querySelector("no-slot-component .has-before");
     root.appendChild(hasBeforeEl);
@@ -103,10 +99,10 @@ add_task(async function() {
             div!slotted
             div!slotted
         class="not-nested"
         class="nested"
           class="has-before"
             ::before
       class="has-before"
         ::before`;
-  await checkTreeFromRootSelector(afterTree, ".root", inspector);
+  await assertMarkupViewAsTree(afterTree, ".root", inspector);
 });
--- a/devtools/client/inspector/markup/test/browser_markup_shadowdom_slotupdate.js
+++ b/devtools/client/inspector/markup/test/browser_markup_shadowdom_slotupdate.js
@@ -1,18 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/* import-globals-from helper_shadowdom.js */
-
 "use strict";
 
-loadHelperScript("helper_shadowdom.js");
-
 // Test that slotted elements are correctly updated when the slot attribute is modified
 // on already slotted elements.
 
 const TEST_URL = `data:text/html;charset=utf-8,
   <test-component>
     <div slot="slot1">slot1-1</div>
     <div slot="slot1">slot1-2</div>
     <div slot="slot2" id="to-update">slot2-1</div>
@@ -43,17 +39,17 @@ add_task(async function() {
           div!slotted
         name="slot2"
           div!slotted
           div!slotted
       slot1-1
       slot1-2
       slot2-1
       slot2-2`;
-  await checkTreeFromRootSelector(tree, "test-component", inspector);
+  await assertMarkupViewAsTree(tree, "test-component", inspector);
 
   info("Listening for the markupmutation event");
   const mutated = inspector.once("markupmutation");
   ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
     content.document.getElementById("to-update").setAttribute("slot", "slot1");
   });
   await mutated;
 
@@ -66,10 +62,10 @@ add_task(async function() {
           div!slotted
           div!slotted
         name="slot2"
           div!slotted
       slot1-1
       slot1-2
       slot2-1
       slot2-2`;
-  await checkTreeFromRootSelector(mutatedTree, "test-component", inspector);
+  await assertMarkupViewAsTree(mutatedTree, "test-component", inspector);
 });
--- a/devtools/client/inspector/markup/test/head.js
+++ b/devtools/client/inspector/markup/test/head.js
@@ -608,8 +608,167 @@ async function checkDeleteAndSelection(i
   let node = await getNodeFront(selector, inspector);
   ok(!node, "The node can't be found in the page anymore");
 
   info("Undo the deletion to restore the original markup");
   await undoChange(inspector);
   node = await getNodeFront(selector, inspector);
   ok(node, "The node is back");
 }
+
+/**
+ * Temporarily flip all the preferences needed to enable web components.
+ */
+async function enableWebComponents() {
+  await pushPref("dom.webcomponents.shadowdom.enabled", true);
+  await pushPref("dom.webcomponents.customelements.enabled", true);
+}
+
+/**
+ * Assert whether the provided container is slotted.
+ */
+function assertContainerSlotted(container) {
+  ok(container.isSlotted(), "Container is a slotted container");
+  ok(container.elt.querySelector(".reveal-link"),
+     "Slotted container has a reveal link element");
+}
+
+/**
+ * Check if the provided text can be matched anywhere in the text content for the provided
+ * container.
+ */
+function assertContainerHasText(container, expectedText) {
+  const textContent = container.elt.textContent;
+  ok(textContent.includes(expectedText), "Container has expected text: " + expectedText);
+}
+
+/**
+ * Assert method to compare the current content of the markupview to a text based tree.
+ *
+ * @param {String} tree
+ *        Multiline string representing the markup view tree, for instance:
+ *        `root
+ *           child1
+ *             subchild1
+ *             subchild2
+ *           child2
+ *             subchild3!slotted`
+ *        Each sub level should be indented by 2 spaces.
+ * @param {String} selector
+ *        A CSS selector that will uniquely match the "root" element from the tree
+ * @param {Inspector} inspector
+ *        The inspector instance.
+ */
+async function assertMarkupViewAsTree(tree, selector, inspector) {
+  const {markup} = inspector;
+
+  info(`Find and expand the shadow DOM host matching selector ${selector}.`);
+  const rootFront = await getNodeFront(selector, inspector);
+  const rootContainer = markup.getContainer(rootFront);
+
+  const parsedTree = _parseMarkupViewTree(tree);
+  const treeRoot = parsedTree.children[0];
+  await _checkMarkupViewNode(treeRoot, rootContainer, inspector);
+}
+
+async function _checkMarkupViewNode(treeNode, container, inspector) {
+  const {node, children, path} = treeNode;
+  info("Checking [" + path + "]");
+  info("Checking node: " + node);
+
+  const slotted = node.includes("!slotted");
+  if (slotted) {
+    const nodeName = node.replace("!slotted", "");
+    assertContainerHasText(container, nodeName);
+    assertContainerSlotted(container);
+  } else {
+    assertContainerHasText(container, node);
+  }
+
+  if (!children.length) {
+    ok(!container.canExpand, "Container for [" + path + "] has no children");
+    return;
+  }
+
+  // Expand the container if not already done.
+  if (!container.expanded) {
+    await expandContainer(inspector, container);
+  }
+
+  const containers = container.getChildContainers();
+  is(containers.length, children.length,
+     "Node [" + path + "] has the expected number of children");
+  for (let i = 0; i < children.length; i++) {
+    await _checkMarkupViewNode(children[i], containers[i], inspector);
+  }
+}
+
+/**
+ * Helper designed to parse a tree represented as:
+ * root
+ *   child1
+ *     subchild1
+ *     subchild2
+ *   child2
+ *     subchild3!slotted
+ *
+ * Lines represent a simplified view of the markup, where the trimmed line is supposed to
+ * be included in the text content of the actual markupview container.
+ * This method returns an object that can be passed to _checkMarkupViewNode() to verify
+ * the current markup view displays the expected structure.
+ */
+function _parseMarkupViewTree(inputString) {
+  const tree = {
+    level: 0,
+    children: []
+  };
+  let lines = inputString.split("\n");
+  lines = lines.filter(l => l.trim());
+
+  let currentNode = tree;
+  for (const line of lines) {
+    const nodeString = line.trim();
+    const level = line.split("  ").length;
+
+    let parent;
+    if (level > currentNode.level) {
+      parent = currentNode;
+    } else {
+      parent = currentNode.parent;
+      for (let i = 0; i < currentNode.level - level; i++) {
+        parent = parent.parent;
+      }
+    }
+
+    const node = {
+      node: nodeString,
+      children: [],
+      parent,
+      level,
+      path: parent.path + " " + nodeString
+    };
+
+    parent.children.push(node);
+    currentNode = node;
+  }
+
+  return tree;
+}
+
+function waitForMutation(inspector, type) {
+  return waitForNMutations(inspector, type, 1);
+}
+
+function waitForNMutations(inspector, type, count) {
+  info(`Expecting ${count} markupmutation of type ${type}`);
+  let receivedMutations = 0;
+  return new Promise(resolve => {
+    inspector.on("markupmutation", function onMutation(mutations) {
+      const validMutations = mutations.filter(m => m.type === type).length;
+      receivedMutations = receivedMutations + validMutations;
+      if (receivedMutations == count) {
+        inspector.off("markupmutation", onMutation);
+        resolve();
+      }
+    });
+  });
+}
+
deleted file mode 100644
--- a/devtools/client/inspector/markup/test/helper_shadowdom.js
+++ /dev/null
@@ -1,144 +0,0 @@
-/* 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/. */
-
-/* eslint no-unused-vars: [2, {"vars": "local"}] */
-
-/* import-globals-from head.js */
-
-"use strict";
-
-async function checkTreeFromRootSelector(tree, selector, inspector) {
-  const {markup} = inspector;
-
-  info(`Find and expand the shadow DOM host matching selector ${selector}.`);
-  const rootFront = await getNodeFront(selector, inspector);
-  const rootContainer = markup.getContainer(rootFront);
-
-  const parsedTree = parseTree(tree);
-  const treeRoot = parsedTree.children[0];
-  await checkNode(treeRoot, rootContainer, inspector);
-}
-
-async function checkNode(treeNode, container, inspector) {
-  const {node, children, path} = treeNode;
-  info("Checking [" + path + "]");
-  info("Checking node: " + node);
-
-  const slotted = node.includes("!slotted");
-  if (slotted) {
-    checkSlotted(container, node.replace("!slotted", ""));
-  } else {
-    checkText(container, node);
-  }
-
-  if (!children.length) {
-    ok(!container.canExpand, "Container for [" + path + "] has no children");
-    return;
-  }
-
-  // Expand the container if not already done.
-  if (!container.expanded) {
-    await expandContainer(inspector, container);
-  }
-
-  const containers = container.getChildContainers();
-  is(containers.length, children.length,
-     "Node [" + path + "] has the expected number of children");
-  for (let i = 0; i < children.length; i++) {
-    await checkNode(children[i], containers[i], inspector);
-  }
-}
-
-/**
- * Helper designed to parse a tree represented as:
- * root
- *   child1
- *     subchild1
- *     subchild2
- *   child2
- *     subchild3!slotted
- *
- * Lines represent a simplified view of the markup, where the trimmed line is supposed to
- * be included in the text content of the actual markupview container.
- * This method returns an object that can be passed to checkNode() to verify the current
- * markup view displays the expected structure.
- */
-function parseTree(inputString) {
-  const tree = {
-    level: 0,
-    children: []
-  };
-  let lines = inputString.split("\n");
-  lines = lines.filter(l => l.trim());
-
-  let currentNode = tree;
-  for (const line of lines) {
-    const nodeString = line.trim();
-    const level = line.split("  ").length;
-
-    let parent;
-    if (level > currentNode.level) {
-      parent = currentNode;
-    } else {
-      parent = currentNode.parent;
-      for (let i = 0; i < currentNode.level - level; i++) {
-        parent = parent.parent;
-      }
-    }
-
-    const path = (parent.path ? parent.path + " " : "") + nodeString;
-
-    const node = {
-      node: nodeString,
-      children: [],
-      parent,
-      level,
-      path
-    };
-
-    parent.children.push(node);
-    currentNode = node;
-  }
-
-  return tree;
-}
-
-function checkSlotted(container, expectedType = "div") {
-  checkText(container, expectedType);
-  ok(container.isSlotted(), "Container is a slotted container");
-  ok(container.elt.querySelector(".reveal-link"),
-     "Slotted container has a reveal link element");
-}
-
-function checkText(container, expectedText) {
-  const textContent = container.elt.textContent;
-  ok(textContent.includes(expectedText), "Container has expected text: " + expectedText);
-}
-
-function waitForMutation(inspector, type) {
-  return waitForNMutations(inspector, type, 1);
-}
-
-function waitForNMutations(inspector, type, count) {
-  info(`Expecting ${count} markupmutation of type ${type}`);
-  let receivedMutations = 0;
-  return new Promise(resolve => {
-    inspector.on("markupmutation", function onMutation(mutations) {
-      const validMutations = mutations.filter(m => m.type === type).length;
-      receivedMutations = receivedMutations + validMutations;
-      if (receivedMutations == count) {
-        inspector.off("markupmutation", onMutation);
-        resolve();
-      }
-    });
-  });
-}
-
-/**
- * Temporarily flip all the preferences needed to enable web components.
- */
-async function enableWebComponents() {
-  await pushPref("dom.webcomponents.shadowdom.enabled", true);
-  await pushPref("dom.webcomponents.customelements.enabled", true);
-}