Bug 1258872 - Port test_mutationobserver_anonymous.html to mochitest-plain so that it can be turned on in e10s mode; r=mrbkap
authorEhsan Akhgari <ehsan@mozilla.com>
Mon, 21 Mar 2016 17:26:52 -0400
changeset 290082 8cf36e4c54fe453e13dceceb9e98fdc61c651c8c
parent 290081 52195522dbac492ed85a0375369f86f0bfa6f59a
child 290083 7e807a003ea4c3a4680f2f0c7bbab8883a1a4db7
push id30114
push usercbook@mozilla.com
push dateThu, 24 Mar 2016 15:15:54 +0000
treeherdermozilla-central@24c5fbde4488 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1258872
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1258872 - Port test_mutationobserver_anonymous.html to mochitest-plain so that it can be turned on in e10s mode; r=mrbkap
dom/base/test/chrome/chrome.ini
dom/base/test/chrome/test_mutationobserver_anonymous.html
dom/base/test/mochitest.ini
dom/base/test/test_mutationobserver_anonymous.html
testing/specialpowers/content/specialpowersAPI.js
--- a/dom/base/test/chrome/chrome.ini
+++ b/dom/base/test/chrome/chrome.ini
@@ -59,17 +59,16 @@ skip-if = buildapp == 'mulet'
 [test_bug914381.html]
 [test_bug990812.xul]
 [test_bug1063837.xul]
 [test_bug1139964.xul]
 [test_bug1209621.xul]
 [test_cpows.xul]
 skip-if = buildapp == 'mulet'
 [test_document_register.xul]
-[test_mutationobserver_anonymous.html]
 [test_registerElement_content.xul]
 [test_registerElement_ep.xul]
 [test_domparsing.xul]
 [test_fileconstructor.xul]
 [test_fileconstructor_tempfile.xul]
 [test_nsITextInputProcessor.xul]
 [test_title.xul]
 [test_windowroot.xul]
deleted file mode 100644
--- a/dom/base/test/chrome/test_mutationobserver_anonymous.html
+++ /dev/null
@@ -1,251 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1034110
--->
-<head>
-  <title>Test for Bug 1034110</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="application/javascript"  src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
-  <script type="application/javascript"  src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1034110">Mozilla Bug 1034110</a>
-<style type="text/css">
-  #pseudo.before::before { content: "before"; }
-  #pseudo.after::after { content: "after"; }
-</style>
-<div id="pseudo"></div>
-<video id="video"></video>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-
-<pre id="test">
-<script type="application/javascript;version=1.7">
-
-/** Test for Bug 1034110 **/
-
-SimpleTest.waitForExplicitFinish();
-const {Cc, Ci, Cu} = SpecialPowers;
-
-function getWalker(node) {
-  let walker = Cc["@mozilla.org/inspector/deep-tree-walker;1"].createInstance(Ci.inIDeepTreeWalker);
-  walker.showAnonymousContent = true;
-  walker.init(node.ownerDocument, Ci.nsIDOMNodeFilter.SHOW_ALL);
-  walker.currentNode = node;
-  return walker;
-}
-
-function getFirstChild(parent) {
-  return SpecialPowers.unwrap(getWalker(parent).firstChild());
-}
-
-function getLastChild(parent) {
-  return SpecialPowers.unwrap(getWalker(parent).lastChild());
-}
-
-function assertSamePseudoElement(which, node1, node2) {
-  is(node1.nodeName, "_moz_generated_content_" + which,
-     "Correct pseudo element type");
-  is(node1, node2,
-     "Referencing the same ::after element");
-}
-
-window.onload = function () {
-  testOneAdded();
-};
-
-function testOneAdded() {
-  let parent = document.getElementById("pseudo");
-  var m = new MutationObserver(function(records, observer) {
-    is(records.length, 1, "Correct number of records");
-    is(records[0].type, "nativeAnonymousChildList", "Correct record type");
-    is(records[0].target, parent, "Correct target");
-
-    is(records[0].addedNodes.length, 1, "Should have got addedNodes");
-    assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
-    is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
-
-    observer.disconnect();
-    testAddedAndRemoved();
-  });
-
-  m.observe(parent, { nativeAnonymousChildList: true});
-  parent.className = "before";
-}
-
-function testAddedAndRemoved() {
-  let parent = document.getElementById("pseudo");
-  let originalBeforeElement = getFirstChild(parent);
-  var m = new MutationObserver(function(records, observer) {
-    is(records.length, 2, "Correct number of records");
-    is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
-    is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
-    is(records[0].target, parent, "Correct target (1)");
-    is(records[1].target, parent, "Correct target (2)");
-
-    // Two records are sent - one for removed and one for added.
-    is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
-    is(records[0].removedNodes.length, 1, "Should have got removedNodes");
-    assertSamePseudoElement("before", records[0].removedNodes[0], originalBeforeElement);
-
-    is(records[1].addedNodes.length, 1, "Should have got addedNodes");
-    assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
-    is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
-
-    observer.disconnect();
-    testRemoved();
-  });
-
-  m.observe(parent, { nativeAnonymousChildList: true});
-  parent.className = "after";
-}
-
-function testRemoved() {
-  let parent = document.getElementById("pseudo");
-  let originalAfterElement = getLastChild(parent);
-  var m = new MutationObserver(function(records, observer) {
-    is(records.length, 1, "Correct number of records");
-    is(records[0].type, "nativeAnonymousChildList", "Correct record type");
-    is(records[0].target, parent, "Correct target");
-
-    is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
-    is(records[0].removedNodes.length, 1, "Should have got removedNodes");
-    assertSamePseudoElement("after", records[0].removedNodes[0], originalAfterElement);
-
-    observer.disconnect();
-    testMultipleAdded();
-  });
-
-  m.observe(parent, { nativeAnonymousChildList: true });
-  parent.className = "";
-}
-
-function testMultipleAdded() {
-  let parent = document.getElementById("pseudo");
-  var m = new MutationObserver(function(records, observer) {
-    is(records.length, 2, "Correct number of records");
-    is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
-    is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
-    is(records[0].target, parent, "Correct target (1)");
-    is(records[1].target, parent, "Correct target (2)");
-
-    is(records[0].addedNodes.length, 1, "Should have got addedNodes");
-    assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
-    is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
-
-    is(records[1].addedNodes.length, 1, "Should have got addedNodes");
-    assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
-    is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
-
-    observer.disconnect();
-    testRemovedDueToDisplay();
-  });
-
-  m.observe(parent, { nativeAnonymousChildList: true });
-  parent.className = "before after";
-}
-
-function testRemovedDueToDisplay() {
-  let parent = document.getElementById("pseudo");
-  let originalBeforeElement = getFirstChild(parent);
-  let originalAfterElement = getLastChild(parent);
-  var m = new MutationObserver(function(records, observer) {
-    is(records.length, 2, "Correct number of records");
-    is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
-    is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
-    is(records[0].target, parent, "Correct target (1)");
-    is(records[1].target, parent, "Correct target (2)");
-
-    is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
-    is(records[0].removedNodes.length, 1, "Should have got removedNodes");
-    assertSamePseudoElement("before", records[0].removedNodes[0], originalBeforeElement);
-
-    is(records[1].addedNodes.length, 0, "Shouldn't have got addedNodes");
-    is(records[1].removedNodes.length, 1, "Should have got removedNodes");
-    assertSamePseudoElement("after", records[1].removedNodes[0], originalAfterElement);
-
-    observer.disconnect();
-    testAddedDueToDisplay();
-  });
-
-  m.observe(parent, { nativeAnonymousChildList: true });
-  parent.style.display = "none";
-}
-
-function testAddedDueToDisplay() {
-  let parent = document.getElementById("pseudo");
-  var m = new MutationObserver(function(records, observer) {
-    is(records.length, 2, "Correct number of records");
-    is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
-    is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
-    is(records[0].target, parent, "Correct target (1)");
-    is(records[1].target, parent, "Correct target (2)");
-
-    is(records[0].addedNodes.length, 1, "Should have got addedNodes");
-    assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
-    is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
-
-    is(records[1].addedNodes.length, 1, "Should have got addedNodes");
-    assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
-    is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
-
-    observer.disconnect();
-    testDifferentTargetNoSubtree();
-  });
-
-  m.observe(parent, { nativeAnonymousChildList: true });
-  parent.style.display = "block";
-}
-
-function testDifferentTargetNoSubtree() {
-  let parent = document.getElementById("pseudo");
-  var m = new MutationObserver(function(records, observer) {
-    ok(false,
-       "No mutation should fire when observing on a parent without subtree option.");
-  });
-  m.observe(document, { nativeAnonymousChildList: true });
-  parent.style.display = "none";
-
-  // Wait for the actual mutation to come through, making sure that
-  // the original observer never fires.
-  var m2 = new MutationObserver(function(records, observer) {
-    ok(!getFirstChild(parent), "Pseudo element has been removed, but no mutation");
-    ok(!getLastChild(parent), "Pseudo element has been removed, but no mutation");
-    observer.disconnect();
-    testSubtree();
-  });
-  m2.observe(parent, { nativeAnonymousChildList: true });
-}
-
-function testSubtree() {
-  let parent = document.getElementById("pseudo");
-  var m = new MutationObserver(function(records, observer) {
-    is(records.length, 2, "Correct number of records");
-    is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
-    is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
-    is(records[0].target, parent, "Correct target (1)");
-    is(records[1].target, parent, "Correct target (2)");
-
-    is(records[0].addedNodes.length, 1, "Should have got addedNodes");
-    assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
-    is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
-
-    is(records[1].addedNodes.length, 1, "Should have got addedNodes");
-    assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
-    is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
-
-    observer.disconnect();
-    SimpleTest.finish();
-  });
-  m.observe(document, { nativeAnonymousChildList: true, subtree: true });
-  parent.style.display = "block";
-}
-
-</script>
-</pre>
-</body>
-</html>
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -788,16 +788,17 @@ skip-if = (os != 'b2g' && os != 'android
 skip-if = (os != 'b2g' && os != 'android')    # meta-viewport tag support is mobile-only
 [test_meta_viewport6.html]
 skip-if = (os != 'b2g' && os != 'android')    # meta-viewport tag support is mobile-only
 [test_meta_viewport7.html]
 skip-if = (os != 'b2g' && os != 'android')    # meta-viewport tag support is mobile-only
 [test_mozfiledataurl.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_mozMatchesSelector.html]
+[test_mutationobserver_anonymous.html]
 [test_mutationobservers.html]
 skip-if = buildapp == 'b2g' # b2g(bug 901385, showmodaldialog) b2g-debug(bug 901385, showmodaldialog) b2g-desktop(bug 901385, showmodaldialog)
 [test_nodelist_holes.html]
 [test_plugin_freezing.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #CLICK_TO_PLAY
 [test_processing_instruction_update_stylesheet.xhtml]
 [test_progress_events_for_gzip_data.html]
 [test_range_bounds.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_mutationobserver_anonymous.html
@@ -0,0 +1,245 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1034110
+-->
+<head>
+  <title>Test for Bug 1034110</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"  src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1034110">Mozilla Bug 1034110</a>
+<style type="text/css">
+  #pseudo.before::before { content: "before"; }
+  #pseudo.after::after { content: "after"; }
+</style>
+<div id="pseudo"></div>
+<video id="video"></video>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+
+<pre id="test">
+<script type="application/javascript;version=1.7">
+
+/** Test for Bug 1034110 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function getWalker(node) {
+  return SpecialPowers.createDOMWalker(node, true);
+}
+
+function getFirstChild(parent) {
+  return SpecialPowers.unwrap(getWalker(parent).firstChild);
+}
+
+function getLastChild(parent) {
+  return SpecialPowers.unwrap(getWalker(parent).lastChild);
+}
+
+function assertSamePseudoElement(which, node1, node2) {
+  is(SpecialPowers.wrap(node1).nodeName, "_moz_generated_content_" + which,
+     "Correct pseudo element type");
+  is(node1, node2,
+     "Referencing the same ::after element");
+}
+
+window.onload = function () {
+  testOneAdded();
+};
+
+function testOneAdded() {
+  let parent = document.getElementById("pseudo");
+  var m = new MutationObserver(function(records, observer) {
+    is(records.length, 1, "Correct number of records");
+    is(records[0].type, "nativeAnonymousChildList", "Correct record type");
+    is(records[0].target, parent, "Correct target");
+
+    is(records[0].addedNodes.length, 1, "Should have got addedNodes");
+    assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
+    is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
+
+    observer.disconnect();
+    testAddedAndRemoved();
+  });
+
+  SpecialPowers.observeMutationEvents(m, parent, true);
+  parent.className = "before";
+}
+
+function testAddedAndRemoved() {
+  let parent = document.getElementById("pseudo");
+  let originalBeforeElement = getFirstChild(parent);
+  var m = new MutationObserver(function(records, observer) {
+    is(records.length, 2, "Correct number of records");
+    is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
+    is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
+    is(records[0].target, parent, "Correct target (1)");
+    is(records[1].target, parent, "Correct target (2)");
+
+    // Two records are sent - one for removed and one for added.
+    is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
+    is(records[0].removedNodes.length, 1, "Should have got removedNodes");
+    assertSamePseudoElement("before", records[0].removedNodes[0], originalBeforeElement);
+
+    is(records[1].addedNodes.length, 1, "Should have got addedNodes");
+    assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
+    is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
+
+    observer.disconnect();
+    testRemoved();
+  });
+
+  SpecialPowers.observeMutationEvents(m, parent, true);
+  parent.className = "after";
+}
+
+function testRemoved() {
+  let parent = document.getElementById("pseudo");
+  let originalAfterElement = getLastChild(parent);
+  var m = new MutationObserver(function(records, observer) {
+    is(records.length, 1, "Correct number of records");
+    is(records[0].type, "nativeAnonymousChildList", "Correct record type");
+    is(records[0].target, parent, "Correct target");
+
+    is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
+    is(records[0].removedNodes.length, 1, "Should have got removedNodes");
+    assertSamePseudoElement("after", records[0].removedNodes[0], originalAfterElement);
+
+    observer.disconnect();
+    testMultipleAdded();
+  });
+
+  SpecialPowers.observeMutationEvents(m, parent, true);
+  parent.className = "";
+}
+
+function testMultipleAdded() {
+  let parent = document.getElementById("pseudo");
+  var m = new MutationObserver(function(records, observer) {
+    is(records.length, 2, "Correct number of records");
+    is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
+    is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
+    is(records[0].target, parent, "Correct target (1)");
+    is(records[1].target, parent, "Correct target (2)");
+
+    is(records[0].addedNodes.length, 1, "Should have got addedNodes");
+    assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
+    is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
+
+    is(records[1].addedNodes.length, 1, "Should have got addedNodes");
+    assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
+    is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
+
+    observer.disconnect();
+    testRemovedDueToDisplay();
+  });
+
+  SpecialPowers.observeMutationEvents(m, parent, true);
+  parent.className = "before after";
+}
+
+function testRemovedDueToDisplay() {
+  let parent = document.getElementById("pseudo");
+  let originalBeforeElement = getFirstChild(parent);
+  let originalAfterElement = getLastChild(parent);
+  var m = new MutationObserver(function(records, observer) {
+    is(records.length, 2, "Correct number of records");
+    is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
+    is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
+    is(records[0].target, parent, "Correct target (1)");
+    is(records[1].target, parent, "Correct target (2)");
+
+    is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
+    is(records[0].removedNodes.length, 1, "Should have got removedNodes");
+    assertSamePseudoElement("before", records[0].removedNodes[0], originalBeforeElement);
+
+    is(records[1].addedNodes.length, 0, "Shouldn't have got addedNodes");
+    is(records[1].removedNodes.length, 1, "Should have got removedNodes");
+    assertSamePseudoElement("after", records[1].removedNodes[0], originalAfterElement);
+
+    observer.disconnect();
+    testAddedDueToDisplay();
+  });
+
+  SpecialPowers.observeMutationEvents(m, parent, true);
+  parent.style.display = "none";
+}
+
+function testAddedDueToDisplay() {
+  let parent = document.getElementById("pseudo");
+  var m = new MutationObserver(function(records, observer) {
+    is(records.length, 2, "Correct number of records");
+    is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
+    is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
+    is(records[0].target, parent, "Correct target (1)");
+    is(records[1].target, parent, "Correct target (2)");
+
+    is(records[0].addedNodes.length, 1, "Should have got addedNodes");
+    assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
+    is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
+
+    is(records[1].addedNodes.length, 1, "Should have got addedNodes");
+    assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
+    is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
+
+    observer.disconnect();
+    testDifferentTargetNoSubtree();
+  });
+
+  SpecialPowers.observeMutationEvents(m, parent, true);
+  parent.style.display = "block";
+}
+
+function testDifferentTargetNoSubtree() {
+  let parent = document.getElementById("pseudo");
+  var m = new MutationObserver(function(records, observer) {
+    ok(false,
+       "No mutation should fire when observing on a parent without subtree option.");
+  });
+  SpecialPowers.observeMutationEvents(m, document, true);
+  parent.style.display = "none";
+
+  // Wait for the actual mutation to come through, making sure that
+  // the original observer never fires.
+  var m2 = new MutationObserver(function(records, observer) {
+    ok(!getFirstChild(parent), "Pseudo element has been removed, but no mutation");
+    ok(!getLastChild(parent), "Pseudo element has been removed, but no mutation");
+    observer.disconnect();
+    testSubtree();
+  });
+  SpecialPowers.observeMutationEvents(m2, parent, true);
+}
+
+function testSubtree() {
+  let parent = document.getElementById("pseudo");
+  var m = new MutationObserver(function(records, observer) {
+    is(records.length, 2, "Correct number of records");
+    is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
+    is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
+    is(records[0].target, parent, "Correct target (1)");
+    is(records[1].target, parent, "Correct target (2)");
+
+    is(records[0].addedNodes.length, 1, "Should have got addedNodes");
+    assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
+    is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
+
+    is(records[1].addedNodes.length, 1, "Should have got addedNodes");
+    assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
+    is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
+
+    observer.disconnect();
+    SimpleTest.finish();
+  });
+  SpecialPowers.observeMutationEvents(m, document, true, true);
+  parent.style.display = "block";
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -2018,13 +2018,35 @@ SpecialPowersAPI.prototype = {
         let baseURI = baseURL ? NetUtil.newURI(baseURL) : null;
         return pu.parseFragment(unwrapIfWrapped(fragment),
                                 flags, isXML, baseURI,
                                 unwrapIfWrapped(element));
       },
     };
     return this._pu;
   },
+
+  createDOMWalker: function(node, showAnonymousContent) {
+    node = unwrapIfWrapped(node);
+    let walker = Cc["@mozilla.org/inspector/deep-tree-walker;1"].
+                 createInstance(Ci.inIDeepTreeWalker);
+    walker.showAnonymousContent = showAnonymousContent;
+    walker.init(node.ownerDocument, Ci.nsIDOMNodeFilter.SHOW_ALL);
+    walker.currentNode = node;
+    return {
+      get firstChild() {
+        return wrapIfUnwrapped(walker.firstChild());
+      },
+      get lastChild() {
+        return wrapIfUnwrapped(walker.lastChild());
+      },
+    };
+  },
+
+  observeMutationEvents: function(mo, node, nativeAnonymousChildList, subtree) {
+    unwrapIfWrapped(mo).observe(unwrapIfWrapped(node),
+                                {nativeAnonymousChildList, subtree});
+  },
 };
 
 this.SpecialPowersAPI = SpecialPowersAPI;
 this.bindDOMWindowUtils = bindDOMWindowUtils;
 this.getRawComponents = getRawComponents;