Bug 1252099 - Remove usage of getNode and content in markupview tests; r=ochameau
authorPatrick Brosset <pbrosset@mozilla.com>
Thu, 03 Mar 2016 16:35:21 +0100
changeset 325132 ea1e990cbed00987c08886a2358379e1fc2778dc
parent 325131 6623a3cc2457224adbc8e40974ea72af48baa0c7
child 325133 34c795c24d3178e5492e3f0989c13149e5c09e41
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau
bugs1252099
milestone47.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 1252099 - Remove usage of getNode and content in markupview tests; r=ochameau MozReview-Commit-ID: F58e1CcwHNs
devtools/client/inspector/layout/test/browser_layout_update-after-reload.js
devtools/client/inspector/markup/test/browser.ini
devtools/client/inspector/markup/test/browser_markup_html_edit_01.js
devtools/client/inspector/markup/test/browser_markup_html_edit_02.js
devtools/client/inspector/markup/test/browser_markup_html_edit_03.js
devtools/client/inspector/markup/test/browser_markup_image_tooltip.js
devtools/client/inspector/markup/test/browser_markup_links_03.js
devtools/client/inspector/markup/test/browser_markup_load_01.js
devtools/client/inspector/markup/test/browser_markup_mutation_01.js
devtools/client/inspector/markup/test/browser_markup_mutation_02.js
devtools/client/inspector/markup/test/browser_markup_node_not_displayed_02.js
devtools/client/inspector/markup/test/browser_markup_pagesize_02.js
devtools/client/inspector/markup/test/browser_markup_remove_xul_attributes.js
devtools/client/inspector/markup/test/browser_markup_tag_edit_03.js
devtools/client/inspector/markup/test/browser_markup_tag_edit_04.js
devtools/client/inspector/markup/test/browser_markup_tag_edit_07.js
devtools/client/inspector/markup/test/browser_markup_tag_edit_08.js
devtools/client/inspector/markup/test/browser_markup_textcontent_edit_01.js
devtools/client/inspector/markup/test/browser_markup_toggle_01.js
devtools/client/inspector/markup/test/browser_markup_toggle_02.js
devtools/client/inspector/markup/test/browser_markup_update-on-navigtion.js
devtools/client/inspector/markup/test/doc_markup_image_and_canvas_2.html
devtools/client/inspector/markup/test/head.js
devtools/client/inspector/markup/test/helper_attributes_test_runner.js
devtools/client/inspector/markup/test/helper_events_test_runner.js
devtools/client/inspector/markup/test/helper_outerhtml_test_runner.js
devtools/client/inspector/rules/test/head.js
devtools/client/shared/test/test-actor.js
--- a/devtools/client/inspector/layout/test/browser_layout_update-after-reload.js
+++ b/devtools/client/inspector/layout/test/browser_layout_update-after-reload.js
@@ -9,17 +9,17 @@
 add_task(function*() {
   yield addTab(URL_ROOT + "doc_layout_iframe1.html");
   let {inspector, view, testActor} = yield openLayoutView();
 
   info("Test that the layout-view works on the first page");
   yield assertLayoutView(inspector, view, testActor);
 
   info("Reload the page");
-  yield testActor.eval("content.location.reload();");
+  yield testActor.reload();
   yield inspector.once("markuploaded");
 
   info("Test that the layout-view works on the reloaded page");
   yield assertLayoutView(inspector, view, testActor);
 });
 
 function* assertLayoutView(inspector, view, testActor) {
   info("Selecting the test node");
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -9,16 +9,17 @@ support-files =
   doc_markup_edit.html
   doc_markup_events.html
   doc_markup_events_form.html
   doc_markup_events_jquery.html
   doc_markup_events-overflow.html
   doc_markup_flashing.html
   doc_markup_html_mixed_case.html
   doc_markup_image_and_canvas.html
+  doc_markup_image_and_canvas_2.html
   doc_markup_links.html
   doc_markup_mutation.html
   doc_markup_navigation.html
   doc_markup_not_displayed.html
   doc_markup_pagesize_01.html
   doc_markup_pagesize_02.html
   doc_markup_search.html
   doc_markup_svg_attributes.html
--- a/devtools/client/inspector/markup/test/browser_markup_html_edit_01.js
+++ b/devtools/client/inspector/markup/test/browser_markup_html_edit_01.js
@@ -3,69 +3,74 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 /* import-globals-from helper_outerhtml_test_runner.js */
 "use strict";
 
 // Test outerHTML edition via the markup-view
 
 loadHelperScript("helper_outerhtml_test_runner.js");
 
-const TEST_DATA = [
-  {
-    selector: "#one",
-    oldHTML: '<div id="one">First <em>Div</em></div>',
-    newHTML: '<div id="one">First Div</div>',
-    validate: function*(pageNode, pageNodeFront, selectedNodeFront) {
-      is(pageNode.textContent, "First Div", "New div has expected text content");
-      ok(!getNode("#one em", {expectNoMatch: true}), "No em remaining")
-    }
-  },
-  {
-    selector: "#removedChildren",
-    oldHTML: '<div id="removedChildren">removedChild <i>Italic <b>Bold <u>Underline</u></b></i> Normal</div>',
-    newHTML: '<div id="removedChildren">removedChild</div>'
-  },
-  {
-    selector: "#addedChildren",
-    oldHTML: '<div id="addedChildren">addedChildren</div>',
-    newHTML: '<div id="addedChildren">addedChildren <i>Italic <b>Bold <u>Underline</u></b></i> Normal</div>'
-  },
-  {
-    selector: "#addedAttribute",
-    oldHTML: '<div id="addedAttribute">addedAttribute</div>',
-    newHTML: '<div id="addedAttribute" class="important" disabled checked>addedAttribute</div>',
-    validate: function*(pageNode, pageNodeFront, selectedNodeFront) {
-      is(pageNodeFront, selectedNodeFront, "Original element is selected");
-      is(pageNode.outerHTML, '<div id="addedAttribute" class="important" disabled="" checked="">addedAttribute</div>',
-            "Attributes have been added");
-    }
-  },
-  {
-    selector: "#changedTag",
-    oldHTML: '<div id="changedTag">changedTag</div>',
-    newHTML: '<p id="changedTag" class="important">changedTag</p>'
-  },
-  {
-    selector: "#siblings",
-    oldHTML: '<div id="siblings">siblings</div>',
-    newHTML: '<div id="siblings-before-sibling">before sibling</div>' +
-             '<div id="siblings">siblings (updated)</div>' +
-             '<div id="siblings-after-sibling">after sibling</div>',
-    validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
-      let beforeSibling = getNode("#siblings-before-sibling");
-      let beforeSiblingFront = yield getNodeFront("#siblings-before-sibling", inspector);
-      let afterSibling = getNode("#siblings-after-sibling");
+const TEST_DATA = [{
+  selector: "#one",
+  oldHTML: '<div id="one">First <em>Div</em></div>',
+  newHTML: '<div id="one">First Div</div>',
+  validate: function*({pageNodeFront, selectedNodeFront, testActor}) {
+    let text = yield testActor.getProperty("#one", "textContent");
+    is(text, "First Div", "New div has expected text content");
+    let num = yield testActor.getNumberOfElementMatches("#one em");
+    is(num, 0, "No em remaining");
+  }
+}, {
+  selector: "#removedChildren",
+  oldHTML: "<div id=\"removedChildren\">removedChild " +
+           "<i>Italic <b>Bold <u>Underline</u></b></i> Normal</div>",
+  newHTML: "<div id=\"removedChildren\">removedChild</div>"
+}, {
+  selector: "#addedChildren",
+  oldHTML: '<div id="addedChildren">addedChildren</div>',
+  newHTML: "<div id=\"addedChildren\">addedChildren " +
+           "<i>Italic <b>Bold <u>Underline</u></b></i> Normal</div>"
+}, {
+  selector: "#addedAttribute",
+  oldHTML: '<div id="addedAttribute">addedAttribute</div>',
+  newHTML: "<div id=\"addedAttribute\" class=\"important\" disabled checked>" +
+           "addedAttribute</div>",
+  validate: function*({pageNodeFront, selectedNodeFront, testActor}) {
+    is(pageNodeFront, selectedNodeFront, "Original element is selected");
+    let html = yield testActor.getProperty("#addedAttribute", "outerHTML");
+    is(html, "<div id=\"addedAttribute\" class=\"important\" disabled=\"\" " +
+       "checked=\"\">addedAttribute</div>", "Attributes have been added");
+  }
+}, {
+  selector: "#changedTag",
+  oldHTML: '<div id="changedTag">changedTag</div>',
+  newHTML: '<p id="changedTag" class="important">changedTag</p>'
+}, {
+  selector: "#siblings",
+  oldHTML: '<div id="siblings">siblings</div>',
+  newHTML: '<div id="siblings-before-sibling">before sibling</div>' +
+           '<div id="siblings">siblings (updated)</div>' +
+           '<div id="siblings-after-sibling">after sibling</div>',
+  validate: function*({selectedNodeFront, inspector, testActor}) {
+    let beforeSiblingFront = yield getNodeFront("#siblings-before-sibling",
+                                                inspector);
+    is(beforeSiblingFront, selectedNodeFront, "Sibling has been selected");
 
-      is(beforeSiblingFront, selectedNodeFront, "Sibling has been selected");
-      is(pageNode.textContent, "siblings (updated)", "New div has expected text content");
-      is(beforeSibling.textContent, "before sibling", "Sibling has been inserted");
-      is(afterSibling.textContent, "after sibling", "Sibling has been inserted");
-    }
+    let text = yield testActor.getProperty("#siblings", "textContent");
+    is(text, "siblings (updated)", "New div has expected text content");
+
+    let beforeText = yield testActor.getProperty("#siblings-before-sibling",
+                                                 "textContent");
+    is(beforeText, "before sibling", "Sibling has been inserted");
+
+    let afterText = yield testActor.getProperty("#siblings-after-sibling",
+                                                "textContent");
+    is(afterText, "after sibling", "Sibling has been inserted");
   }
-];
+}];
 
 const TEST_URL = "data:text/html," +
   "<!DOCTYPE html>" +
   "<head><meta charset='utf-8' /></head>" +
   "<body>" +
   TEST_DATA.map(outer => outer.oldHTML).join("\n") +
   "</body>" +
   "</html>";
--- a/devtools/client/inspector/markup/test/browser_markup_html_edit_02.js
+++ b/devtools/client/inspector/markup/test/browser_markup_html_edit_02.js
@@ -7,86 +7,104 @@
 // Test outerHTML edition via the markup-view
 
 loadHelperScript("helper_outerhtml_test_runner.js");
 requestLongerTimeout(2);
 
 const TEST_DATA = [
   {
     selector: "#badMarkup1",
-    oldHTML: '<div id="badMarkup1">badMarkup1</div>',
-    newHTML: '<div id="badMarkup1">badMarkup1</div> hanging</div>',
-    validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
+    oldHTML: "<div id=\"badMarkup1\">badMarkup1</div>",
+    newHTML: "<div id=\"badMarkup1\">badMarkup1</div> hanging</div>",
+    validate: function*({pageNodeFront, selectedNodeFront, testActor}) {
       is(pageNodeFront, selectedNodeFront, "Original element is selected");
 
-      let textNode = pageNode.nextSibling;
-
-      is(textNode.nodeName, "#text", "Sibling is a text element");
-      is(textNode.data, " hanging", "New text node has expected text content");
+      let textNodeName = yield testActor.eval(`
+        content.document.querySelector("#badMarkup1").nextSibling.nodeName
+      `);
+      let textNodeData = yield testActor.eval(`
+        content.document.querySelector("#badMarkup1").nextSibling.data
+      `);
+      is(textNodeName, "#text", "Sibling is a text element");
+      is(textNodeData, " hanging", "New text node has expected text content");
     }
   },
   {
     selector: "#badMarkup2",
-    oldHTML: '<div id="badMarkup2">badMarkup2</div>',
-    newHTML: '<div id="badMarkup2">badMarkup2</div> hanging<div></div></div></div></body>',
-    validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
+    oldHTML: "<div id=\"badMarkup2\">badMarkup2</div>",
+    newHTML: "<div id=\"badMarkup2\">badMarkup2</div> hanging<div></div>" +
+             "</div></div></body>",
+    validate: function*({pageNodeFront, selectedNodeFront, testActor}) {
       is(pageNodeFront, selectedNodeFront, "Original element is selected");
 
-      let textNode = pageNode.nextSibling;
-
-      is(textNode.nodeName, "#text", "Sibling is a text element");
-      is(textNode.data, " hanging", "New text node has expected text content");
+      let textNodeName = yield testActor.eval(`
+        content.document.querySelector("#badMarkup2").nextSibling.nodeName
+      `);
+      let textNodeData = yield testActor.eval(`
+        content.document.querySelector("#badMarkup2").nextSibling.data
+      `);
+      is(textNodeName, "#text", "Sibling is a text element");
+      is(textNodeData, " hanging", "New text node has expected text content");
     }
   },
   {
     selector: "#badMarkup3",
-    oldHTML: '<div id="badMarkup3">badMarkup3</div>',
-    newHTML: '<div id="badMarkup3">badMarkup3 <em>Emphasized <strong> and strong</div>',
-    validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
+    oldHTML: "<div id=\"badMarkup3\">badMarkup3</div>",
+    newHTML: "<div id=\"badMarkup3\">badMarkup3 <em>Emphasized <strong> " +
+             "and strong</div>",
+    validate: function*({pageNodeFront, selectedNodeFront, testActor}) {
       is(pageNodeFront, selectedNodeFront, "Original element is selected");
 
-      let em = getNode("#badMarkup3 em");
-      let strong = getNode("#badMarkup3 strong");
-
-      is(em.textContent, "Emphasized  and strong", "<em> was auto created");
-      is(strong.textContent, " and strong", "<strong> was auto created");
+      let emText = yield testActor.getProperty("#badMarkup3 em", "textContent");
+      let strongText = yield testActor.getProperty("#badMarkup3 strong",
+                                                   "textContent");
+      is(emText, "Emphasized  and strong", "<em> was auto created");
+      is(strongText, " and strong", "<strong> was auto created");
     }
   },
   {
     selector: "#badMarkup4",
-    oldHTML: '<div id="badMarkup4">badMarkup4</div>',
-    newHTML: '<div id="badMarkup4">badMarkup4</p>',
-    validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
+    oldHTML: "<div id=\"badMarkup4\">badMarkup4</div>",
+    newHTML: "<div id=\"badMarkup4\">badMarkup4</p>",
+    validate: function*({pageNodeFront, selectedNodeFront, testActor}) {
       is(pageNodeFront, selectedNodeFront, "Original element is selected");
 
-      let div = getNode("#badMarkup4");
-      let p = getNode("#badMarkup4 p");
+      let divText = yield testActor.getProperty("#badMarkup4", "textContent");
+      let divTag = yield testActor.getProperty("#badMarkup4", "tagName");
 
-      is(div.textContent, "badMarkup4", "textContent is correct");
-      is(div.tagName, "DIV", "did not change to <p> tag");
-      is(p.textContent, "", "The <p> tag has no children");
-      is(p.tagName, "P", "Created an empty <p> tag");
+      let pText = yield testActor.getProperty("#badMarkup4 p", "textContent");
+      let pTag = yield testActor.getProperty("#badMarkup4 p", "tagName");
+
+      is(divText, "badMarkup4", "textContent is correct");
+      is(divTag, "DIV", "did not change to <p> tag");
+      is(pText, "", "The <p> tag has no children");
+      is(pTag, "P", "Created an empty <p> tag");
     }
   },
   {
     selector: "#badMarkup5",
-    oldHTML: '<p id="badMarkup5">badMarkup5</p>',
-    newHTML: '<p id="badMarkup5">badMarkup5 <div>with a nested div</div></p>',
-    validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) {
+    oldHTML: "<p id=\"badMarkup5\">badMarkup5</p>",
+    newHTML: "<p id=\"badMarkup5\">badMarkup5 <div>with a nested div</div></p>",
+    validate: function*({pageNodeFront, selectedNodeFront, testActor}) {
       is(pageNodeFront, selectedNodeFront, "Original element is selected");
 
-      let p = getNode("#badMarkup5");
-      let nodiv = getNode("#badMarkup5 div", {expectNoMatch: true});
-      let div = getNode("#badMarkup5 ~ div");
+      let num = yield testActor.getNumberOfElementMatches("#badMarkup5 div");
+
+      let pText = yield testActor.getProperty("#badMarkup5", "textContent");
+      let pTag = yield testActor.getProperty("#badMarkup5", "tagName");
 
-      ok(!nodiv, "The invalid markup got created as a sibling");
-      is(p.textContent, "badMarkup5 ", "The <p> tag does not take in the <div> content");
-      is(p.tagName, "P", "Did not change to a <div> tag");
-      is(div.textContent, "with a nested div", "textContent is correct");
-      is(div.tagName, "DIV", "Did not change to <p> tag");
+      let divText = yield testActor.getProperty("#badMarkup5 ~ div",
+                                                "textContent");
+      let divTag = yield testActor.getProperty("#badMarkup5 ~ div", "tagName");
+
+      is(num, 0, "The invalid markup got created as a sibling");
+      is(pText, "badMarkup5 ", "The p tag does not take in the div content");
+      is(pTag, "P", "Did not change to a <div> tag");
+      is(divText, "with a nested div", "textContent is correct");
+      is(divTag, "DIV", "Did not change to <p> tag");
     }
   }
 ];
 
 const TEST_URL = "data:text/html," +
   "<!DOCTYPE html>" +
   "<head><meta charset='utf-8' /></head>" +
   "<body>" +
--- a/devtools/client/inspector/markup/test/browser_markup_html_edit_03.js
+++ b/devtools/client/inspector/markup/test/browser_markup_html_edit_03.js
@@ -16,167 +16,185 @@ const TEST_URL = "data:text/html," +
   "</html>";
 const SELECTOR = "#keyboard";
 const OLD_HTML = '<div id="keyboard"></div>';
 const NEW_HTML = '<div id="keyboard">Edited</div>';
 
 requestLongerTimeout(2);
 
 add_task(function*() {
-  let {inspector} = yield openInspectorForURL(TEST_URL);
+  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   inspector.markup._frame.focus();
 
-  info("Checking that pressing escape cancels edits");
-  yield testEscapeCancels(inspector);
+  info("Check that pressing escape cancels edits");
+  yield testEscapeCancels(inspector, testActor);
 
-  info("Checking that pressing F2 commits edits");
-  yield testF2Commits(inspector);
+  info("Check that pressing F2 commits edits");
+  yield testF2Commits(inspector, testActor);
 
-  info("Checking that editing the <body> element works like other nodes");
-  yield testBody(inspector);
+  info("Check that editing the <body> element works like other nodes");
+  yield testBody(inspector, testActor);
 
-  info("Checking that editing the <head> element works like other nodes");
-  yield testHead(inspector);
+  info("Check that editing the <head> element works like other nodes");
+  yield testHead(inspector, testActor);
 
-  info("Checking that editing the <html> element works like other nodes");
-  yield testDocumentElement(inspector);
+  info("Check that editing the <html> element works like other nodes");
+  yield testDocumentElement(inspector, testActor);
 
-  info("Checking (again) that editing the <html> element works like other nodes");
-  yield testDocumentElement2(inspector);
+  info("Check (again) that editing the <html> element works like other nodes");
+  yield testDocumentElement2(inspector, testActor);
 });
 
-function testEscapeCancels(inspector) {
-  let def = promise.defer();
-  let node = getNode(SELECTOR);
+function* testEscapeCancels(inspector, testActor) {
+  yield selectNode(SELECTOR, inspector);
 
-  selectNode(SELECTOR, inspector).then(() => {
-    inspector.markup.htmlEditor.on("popupshown", function onPopupShown() {
-      inspector.markup.htmlEditor.off("popupshown", onPopupShown);
-
-      ok(inspector.markup.htmlEditor._visible, "HTML Editor is visible");
-      is(node.outerHTML, OLD_HTML, "The node is starting with old HTML.");
-
-      inspector.markup.htmlEditor.on("popuphidden", function onPopupHidden() {
-        inspector.markup.htmlEditor.off("popuphidden", onPopupHidden);
-        ok(!inspector.markup.htmlEditor._visible, "HTML Editor is not visible");
+  let onEditorShown = once(inspector.markup.htmlEditor, "popupshown");
+  EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
+  yield onEditorShown;
+  ok(inspector.markup.htmlEditor._visible, "HTML Editor is visible");
 
-        let node = getNode(SELECTOR);
-        is(node.outerHTML, OLD_HTML, "Escape cancels edits");
-        def.resolve();
-      });
+  is((yield testActor.getProperty(SELECTOR, "outerHTML")), OLD_HTML,
+     "The node is starting with old HTML.");
 
-      inspector.markup.htmlEditor.editor.setText(NEW_HTML);
+  inspector.markup.htmlEditor.editor.setText(NEW_HTML);
 
-      EventUtils.sendKey("ESCAPE", inspector.markup.htmlEditor.doc.defaultView);
-    });
+  let onEditorHiddem = once(inspector.markup.htmlEditor, "popuphidden");
+  EventUtils.sendKey("ESCAPE", inspector.markup.htmlEditor.doc.defaultView);
+  yield onEditorHiddem;
+  ok(!inspector.markup.htmlEditor._visible, "HTML Editor is not visible");
 
-    EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
-  });
-
-  return def.promise;
+  is((yield testActor.getProperty(SELECTOR, "outerHTML")), OLD_HTML,
+     "Escape cancels edits");
 }
 
-function testF2Commits(inspector) {
-  let def = promise.defer();
-  let node = getNode(SELECTOR);
-
-  inspector.markup.htmlEditor.on("popupshown", function onPopupShown() {
-    inspector.markup.htmlEditor.off("popupshown", onPopupShown);
-
-    ok(inspector.markup.htmlEditor._visible, "HTML Editor is visible");
-    is(node.outerHTML, OLD_HTML, "The node is starting with old HTML.");
-
-    inspector.once("markupmutation", (e, aMutations) => {
-      ok(!inspector.markup.htmlEditor._visible, "HTML Editor is not visible");
-
-      let node = getNode(SELECTOR);
-      is(node.outerHTML, NEW_HTML, "F2 commits edits - the node has new HTML.");
-      def.resolve();
-    });
-
-    inspector.markup.htmlEditor.editor.setText(NEW_HTML);
-    EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
-  });
-
+function* testF2Commits(inspector, testActor) {
+  let onEditorShown = once(inspector.markup.htmlEditor, "popupshown");
   inspector.markup._frame.contentDocument.documentElement.focus();
   EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
+  yield onEditorShown;
+  ok(inspector.markup.htmlEditor._visible, "HTML Editor is visible");
 
-  return def.promise;
+  is((yield testActor.getProperty(SELECTOR, "outerHTML")), OLD_HTML,
+     "The node is starting with old HTML.");
+
+  let onMutations = inspector.once("markupmutation");
+  inspector.markup.htmlEditor.editor.setText(NEW_HTML);
+  EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
+  yield onMutations;
+
+  ok(!inspector.markup.htmlEditor._visible, "HTML Editor is not visible");
+
+  is((yield testActor.getProperty(SELECTOR, "outerHTML")), NEW_HTML,
+     "F2 commits edits - the node has new HTML.");
 }
 
-function* testBody(inspector) {
-  let body = getNode("body");
+function* testBody(inspector, testActor) {
+  let currentBodyHTML = yield testActor.getProperty("body", "outerHTML");
   let bodyHTML = '<body id="updated"><p></p></body>';
   let bodyFront = yield getNodeFront("body", inspector);
-  let doc = content.document;
 
   let onReselected = inspector.markup.once("reselectedonremoved");
-  yield inspector.markup.updateNodeOuterHTML(bodyFront, bodyHTML, body.outerHTML);
+  yield inspector.markup.updateNodeOuterHTML(bodyFront, bodyHTML,
+                                             currentBodyHTML);
   yield onReselected;
 
-  is(getNode("body").outerHTML, bodyHTML, "<body> HTML has been updated");
-  is(doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
+  let newBodyHTML = yield testActor.getProperty("body", "outerHTML");
+  is(newBodyHTML, bodyHTML, "<body> HTML has been updated");
+
+  let headsNum = yield testActor.getNumberOfElementMatches("head");
+  is(headsNum, 1, "no extra <head>s have been added");
 
   yield inspector.once("inspector-updated");
 }
 
-function* testHead(inspector) {
-  let head = getNode("head");
+function* testHead(inspector, testActor) {
   yield selectNode("head", inspector);
 
-  let headHTML = '<head id="updated"><title>New Title</title><script>window.foo="bar";</script></head>';
+  let currentHeadHTML = yield testActor.getProperty("head", "outerHTML");
+  let headHTML = "<head id=\"updated\"><title>New Title</title>" +
+                 "<script>window.foo=\"bar\";</script></head>";
   let headFront = yield getNodeFront("head", inspector);
-  let doc = content.document;
 
   let onReselected = inspector.markup.once("reselectedonremoved");
-  yield inspector.markup.updateNodeOuterHTML(headFront, headHTML, head.outerHTML);
+  yield inspector.markup.updateNodeOuterHTML(headFront, headHTML,
+                                             currentHeadHTML);
   yield onReselected;
 
-  is(doc.title, "New Title", "New title has been added");
-  is(doc.defaultView.foo, undefined, "Script has not been executed");
-  is(doc.querySelector("head").outerHTML, headHTML, "<head> HTML has been updated");
-  is(doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
+  is((yield testActor.eval("content.document.title")), "New Title",
+     "New title has been added");
+  is((yield testActor.eval("content.foo")), undefined,
+     "Script has not been executed");
+  is((yield testActor.getProperty("head", "outerHTML")), headHTML,
+     "<head> HTML has been updated");
+  is((yield testActor.getNumberOfElementMatches("body")), 1,
+     "no extra <body>s have been added");
 
   yield inspector.once("inspector-updated");
 }
 
-function* testDocumentElement(inspector) {
-  let doc = content.document;
-  let docElement = doc.documentElement;
-  let docElementHTML = '<html id="updated" foo="bar"><head><title>Updated from document element</title><script>window.foo="bar";</script></head><body><p>Hello</p></body></html>';
+function* testDocumentElement(inspector, testActor) {
+  let currentDocElementOuterHMTL = yield testActor.eval(
+    "content.document.documentElement.outerHMTL");
+  let docElementHTML = "<html id=\"updated\" foo=\"bar\"><head>" +
+                       "<title>Updated from document element</title>" +
+                       "<script>window.foo=\"bar\";</script></head><body>" +
+                       "<p>Hello</p></body></html>";
   let docElementFront = yield inspector.markup.walker.documentElement();
 
   let onReselected = inspector.markup.once("reselectedonremoved");
-  yield inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML, docElement.outerHTML);
+  yield inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML,
+    currentDocElementOuterHMTL);
   yield onReselected;
 
-  is(doc.title, "Updated from document element", "New title has been added");
-  is(doc.defaultView.foo, undefined, "Script has not been executed");
-  is(doc.documentElement.id, "updated", "<html> ID has been updated");
-  is(doc.documentElement.className, "", "<html> class has been updated");
-  is(doc.documentElement.getAttribute("foo"), "bar", "<html> attribute has been updated");
-  is(doc.documentElement.outerHTML, docElementHTML, "<html> HTML has been updated");
-  is(doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
-  is(doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
-  is(doc.body.textContent, "Hello", "document.body.textContent has been updated");
+  is((yield testActor.eval("content.document.title")),
+     "Updated from document element", "New title has been added");
+  is((yield testActor.eval("content.foo")),
+     undefined, "Script has not been executed");
+  is((yield testActor.getAttribute("html", "id")),
+     "updated", "<html> ID has been updated");
+  is((yield testActor.getAttribute("html", "class")),
+     null, "<html> class has been updated");
+  is((yield testActor.getAttribute("html", "foo")),
+     "bar", "<html> attribute has been updated");
+  is((yield testActor.getProperty("html", "outerHTML")),
+     docElementHTML, "<html> HTML has been updated");
+  is((yield testActor.getNumberOfElementMatches("head")),
+     1, "no extra <head>s have been added");
+  is((yield testActor.getNumberOfElementMatches("body")),
+     1, "no extra <body>s have been added");
+  is((yield testActor.getProperty("body", "textContent")),
+     "Hello", "document.body.textContent has been updated");
 }
 
-function* testDocumentElement2(inspector) {
-  let doc = content.document;
-  let docElement = doc.documentElement;
-  let docElementHTML = '<html class="updated" id="somethingelse"><head><title>Updated again from document element</title><script>window.foo="bar";</script></head><body><p>Hello again</p></body></html>';
+function* testDocumentElement2(inspector, testActor) {
+  let currentDocElementOuterHMTL = yield testActor.eval(
+    "content.document.documentElement.outerHMTL");
+  let docElementHTML = "<html class=\"updated\" id=\"somethingelse\"><head>" +
+                       "<title>Updated again from document element</title>" +
+                       "<script>window.foo=\"bar\";</script></head><body>" +
+                       "<p>Hello again</p></body></html>";
   let docElementFront = yield inspector.markup.walker.documentElement();
 
   let onReselected = inspector.markup.once("reselectedonremoved");
-  inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML, docElement.outerHTML);
+  inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML,
+    currentDocElementOuterHMTL);
   yield onReselected;
 
-  is(doc.title, "Updated again from document element", "New title has been added");
-  is(doc.defaultView.foo, undefined, "Script has not been executed");
-  is(doc.documentElement.id, "somethingelse", "<html> ID has been updated");
-  is(doc.documentElement.className, "updated", "<html> class has been updated");
-  is(doc.documentElement.getAttribute("foo"), null, "<html> attribute has been removed");
-  is(doc.documentElement.outerHTML, docElementHTML, "<html> HTML has been updated");
-  is(doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
-  is(doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
-  is(doc.body.textContent, "Hello again", "document.body.textContent has been updated");
+  is((yield testActor.eval("content.document.title")),
+     "Updated again from document element", "New title has been added");
+  is((yield testActor.eval("content.foo")),
+     undefined, "Script has not been executed");
+  is((yield testActor.getAttribute("html", "id")),
+     "somethingelse", "<html> ID has been updated");
+  is((yield testActor.getAttribute("html", "class")),
+     "updated", "<html> class has been updated");
+  is((yield testActor.getAttribute("html", "foo")),
+     null, "<html> attribute has been removed");
+  is((yield testActor.getProperty("html", "outerHTML")),
+     docElementHTML, "<html> HTML has been updated");
+  is((yield testActor.getNumberOfElementMatches("head")),
+     1, "no extra <head>s have been added");
+  is((yield testActor.getNumberOfElementMatches("body")),
+     1, "no extra <body>s have been added");
+  is((yield testActor.getProperty("body", "textContent")),
+     "Hello again", "document.body.textContent has been updated");
 }
--- a/devtools/client/inspector/markup/test/browser_markup_image_tooltip.js
+++ b/devtools/client/inspector/markup/test/browser_markup_image_tooltip.js
@@ -1,65 +1,38 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
-
 "use strict";
 
 // Test that image preview tooltips are shown on img and canvas tags in the
 // markup-view and that the tooltip actually contains an image and shows the
 // right dimension label
 
-const PAGE_CONTENT = [
-  '<img class="local" src="chrome://branding/content/about-logo.png" />',
-  '<img class="data" src="data:image/png;base64,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" />',
-  '<img class="remote" src="' + URL_ROOT + 'doc_markup_tooltip.png" />',
-  '<canvas class="canvas" width="600" height="600"></canvas>'
-].join("\n");
-
 const TEST_NODES = [
   {selector: "img.local", size: "192" + " \u00D7 " + "192"},
   {selector: "img.data", size: "64" + " \u00D7 " + "64"},
   {selector: "img.remote", size: "22" + " \u00D7 " + "23"},
   {selector: ".canvas", size: "600" + " \u00D7 " + "600"}
 ];
 
 add_task(function*() {
-  yield addTab("data:text/html,markup view tooltip test");
-  createPage();
-
+  yield addTab(URL_ROOT + "doc_markup_image_and_canvas_2.html");
   let {inspector} = yield openInspector();
 
   info("Selecting the first <img> tag");
   yield selectNode("img", inspector);
 
   for (let testNode of TEST_NODES) {
     let target = yield getImageTooltipTarget(testNode, inspector);
     yield assertTooltipShownOn(target, inspector);
     checkImageTooltip(testNode, inspector);
   }
 });
 
-function createPage() {
-  info("Fill the page with the test content");
-  content.document.body.innerHTML = PAGE_CONTENT;
-
-  info("Fill the canvas");
-  let doc = content.document;
-  let context = doc.querySelector(".canvas").getContext("2d");
-
-  context.beginPath();
-  context.moveTo(300, 0);
-  context.lineTo(600, 600);
-  context.lineTo(0, 600);
-  context.closePath();
-  context.fillStyle = "#ffc821";
-  context.fill();
-}
-
 function* getImageTooltipTarget({selector}, inspector) {
   let nodeFront = yield getNodeFront(selector, inspector);
   let isImg = nodeFront.tagName.toLowerCase() === "img";
 
   let container = getContainerForNodeFront(nodeFront, inspector);
 
   let target = container.editor.tag;
   if (isImg) {
@@ -74,12 +47,13 @@ function* assertTooltipShownOn(element, 
   ok(isValid, "The element is a valid hover target for the image tooltip");
 }
 
 function checkImageTooltip({selector, size}, {markup}) {
   let images = markup.tooltip.panel.getElementsByTagName("image");
   is(images.length, 1, "Tooltip for [" + selector + "] contains an image");
 
   let label = markup.tooltip.panel.querySelector(".devtools-tooltip-caption");
-  is(label.textContent, size, "Tooltip label for [" + selector + "] displays the right image size");
+  is(label.textContent, size,
+     "Tooltip label for [" + selector + "] displays the right image size");
 
   markup.tooltip.hide();
 }
--- a/devtools/client/inspector/markup/test/browser_markup_links_03.js
+++ b/devtools/client/inspector/markup/test/browser_markup_links_03.js
@@ -8,30 +8,30 @@
 
 const TEST_URL = URL_ROOT + "doc_markup_links.html";
 
 add_task(function*() {
   let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   info("Adding a contextmenu attribute to the body node via the content");
   let onMutated = inspector.once("markupmutation");
-  yield setNodeAttribute("body", "contextmenu", "menu1", testActor);
+  yield testActor.setAttribute("body", "contextmenu", "menu1");
   yield onMutated;
 
   info("Checking for links in the new attribute");
   let {editor} = yield getContainerForSelector("body", inspector);
   let linkEls = editor.attrElements.get("contextmenu")
                                    .querySelectorAll(".link");
   is(linkEls.length, 1, "There is one link in the contextmenu attribute");
   is(linkEls[0].dataset.type, "idref", "The link has the right type");
   is(linkEls[0].textContent, "menu1", "The link has the right value");
 
   info("Editing the contextmenu attribute on the body node");
   onMutated = inspector.once("markupmutation");
-  yield setNodeAttribute("body", "contextmenu", "menu2", testActor);
+  yield testActor.setAttribute("body", "contextmenu", "menu2");
   yield onMutated;
 
   info("Checking for links in the updated attribute");
   ({editor} = yield getContainerForSelector("body", inspector));
   linkEls = editor.attrElements.get("contextmenu").querySelectorAll(".link");
   is(linkEls.length, 1, "There is one link in the contextmenu attribute");
   is(linkEls[0].dataset.type, "idref", "The link has the right type");
   is(linkEls[0].textContent, "menu2", "The link has the right value");
--- a/devtools/client/inspector/markup/test/browser_markup_load_01.js
+++ b/devtools/client/inspector/markup/test/browser_markup_load_01.js
@@ -35,17 +35,17 @@ const TEST_URL = "data:text/html," +
 add_task(function*() {
   let {inspector, testActor, tab} = yield openInspectorForURL(TEST_URL);
   let domContentLoaded = waitForLinkedBrowserEvent(tab, "DOMContentLoaded");
   let pageLoaded = waitForLinkedBrowserEvent(tab, "load");
 
   ok(inspector.markup, "There is a markup view");
 
   // Select an element while the tab is in the middle of a slow reload.
-  reloadTab(testActor);
+  testActor.eval("location.reload()");
   yield domContentLoaded;
   yield chooseWithInspectElementContextMenu("img", testActor);
   yield pageLoaded;
 
   yield inspector.once("markuploaded");
   yield waitForMultipleChildrenUpdates(inspector);
 
   ok(inspector.markup, "There is a markup view");
--- a/devtools/client/inspector/markup/test/browser_markup_mutation_01.js
+++ b/devtools/client/inspector/markup/test/browser_markup_mutation_01.js
@@ -12,203 +12,205 @@ const TEST_URL = URL_ROOT + "doc_markup_
 // - desc: for logging only
 // - numMutations: how many mutations are expected to come happen due to the
 //   test case.  Defaults to 1 if not set.
 // - test: a function supposed to mutate the DOM
 // - check: a function supposed to test that the mutation was handled
 const TEST_DATA = [
   {
     desc: "Adding an attribute",
-    test: () => {
-      let node1 = getNode("#node1");
-      node1.setAttribute("newattr", "newattrval");
+    test: function*(testActor) {
+      yield testActor.setAttribute("#node1", "newattr", "newattrval");
     },
     check: function*(inspector) {
       let {editor} = yield getContainerForSelector("#node1", inspector);
       ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
         return attr.textContent.trim() === "newattr=\"newattrval\"";
       }), "newattr attribute found");
     }
   },
   {
     desc: "Removing an attribute",
-    test: () => {
-      let node1 = getNode("#node1");
-      node1.removeAttribute("newattr");
+    test: function*(testActor) {
+      yield testActor.removeAttribute("#node1", "newattr");
     },
     check: function*(inspector) {
       let {editor} = yield getContainerForSelector("#node1", inspector);
       ok(![...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
         return attr.textContent.trim() === "newattr=\"newattrval\"";
       }), "newattr attribute removed");
     }
   },
   {
     desc: "Re-adding an attribute",
-    test: () => {
-      let node1 = getNode("#node1");
-      node1.setAttribute("newattr", "newattrval");
+    test: function*(testActor) {
+      yield testActor.setAttribute("#node1", "newattr", "newattrval");
     },
     check: function*(inspector) {
       let {editor} = yield getContainerForSelector("#node1", inspector);
       ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
         return attr.textContent.trim() === "newattr=\"newattrval\"";
       }), "newattr attribute found");
     }
   },
   {
     desc: "Changing an attribute",
-    test: () => {
-      let node1 = getNode("#node1");
-      node1.setAttribute("newattr", "newattrchanged");
+    test: function*(testActor) {
+      yield testActor.setAttribute("#node1", "newattr", "newattrchanged");
     },
     check: function*(inspector) {
       let {editor} = yield getContainerForSelector("#node1", inspector);
       ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
         return attr.textContent.trim() === "newattr=\"newattrchanged\"";
       }), "newattr attribute found");
     }
   },
   {
     desc: "Adding ::after element",
     numMutations: 2,
-    test: () => {
-      let node1 = getNode("#node1");
-      node1.classList.add("pseudo");
+    test: function*(testActor) {
+      yield testActor.eval(`
+        let node1 = content.document.querySelector("#node1");
+        node1.classList.add("pseudo");
+      `)
     },
     check: function*(inspector) {
       let {children} = yield getContainerForSelector("#node1", inspector);
       is(children.childNodes.length, 2,
         "Node1 now has 2 children (text child and ::after");
     }
   },
   {
     desc: "Removing ::after element",
     numMutations: 2,
-    test: () => {
-      let node1 = getNode("#node1");
-      node1.classList.remove("pseudo");
+    test: function*(testActor) {
+      yield testActor.eval(`
+        let node1 = content.document.querySelector("#node1");
+        node1.classList.remove("pseudo");
+      `);
     },
     check: function*(inspector) {
       let container = yield getContainerForSelector("#node1", inspector);
       ok(container.singleTextChild, "Has single text child.");
     }
   },
   {
     desc: "Updating the text-content",
-    test: () => {
-      let node1 = getNode("#node1");
-      node1.textContent = "newtext";
+    test: function*(testActor) {
+      yield testActor.setProperty("#node1", "textContent", "newtext");
     },
     check: function*(inspector) {
       let container = yield getContainerForSelector("#node1", inspector);
       ok(container.singleTextChild, "Has single text child.");
       ok(!container.canExpand, "Can't expand container with singleTextChild.");
       ok(!container.singleTextChild.canExpand, "Can't expand singleTextChild.");
       is(container.editor.elt.querySelector(".text").textContent.trim(),
          "newtext", "Single text child editor updated.");
     }
   },
   {
     desc: "Adding a second text child",
-    test: () => {
-      let node1 = getNode("#node1");
-      let newText = node1.ownerDocument.createTextNode("more");
-      node1.appendChild(newText);
+    test: function*(testActor) {
+      yield testActor.eval(`
+        let node1 = content.document.querySelector("#node1");
+        let newText = node1.ownerDocument.createTextNode("more");
+        node1.appendChild(newText);
+      `);
     },
     check: function*(inspector) {
       let container = yield getContainerForSelector("#node1", inspector);
       ok(!container.singleTextChild, "Does not have single text child.");
       ok(container.canExpand, "Can expand container with child nodes.");
       ok(container.editor.elt.querySelector(".text") == null,
         "Single text child editor removed.");
     },
   },
   {
     desc: "Go from 2 to 1 text child",
-    test: () => {
-      let node1 = getNode("#node1");
-      node1.textContent = "newtext";
+    test: function*(testActor) {
+      yield testActor.setProperty("#node1", "textContent", "newtext");
     },
     check: function*(inspector) {
       let container = yield getContainerForSelector("#node1", inspector);
       ok(container.singleTextChild, "Has single text child.");
       ok(!container.canExpand, "Can't expand container with singleTextChild.");
       ok(!container.singleTextChild.canExpand, "Can't expand singleTextChild.");
       ok(container.editor.elt.querySelector(".text").textContent.trim(),
          "newtext", "Single text child editor updated.");
     },
   },
   {
     desc: "Removing an only text child",
-    test: () => {
-      let node1 = getNode("#node1");
-      node1.innerHTML = "";
+    test: function*(testActor) {
+      yield testActor.setProperty("#node1", "innerHTML", "");
     },
     check: function*(inspector) {
       let container = yield getContainerForSelector("#node1", inspector);
       ok(!container.singleTextChild, "Does not have single text child.");
       ok(!container.canExpand, "Can't expand empty container.");
       ok(container.editor.elt.querySelector(".text") == null,
         "Single text child editor removed.");
     },
   },
   {
     desc: "Go from 0 to 1 text child",
-    test: () => {
-      let node1 = getNode("#node1");
-      node1.textContent = "newtext";
+    test: function*(testActor) {
+      yield testActor.setProperty("#node1", "textContent", "newtext");
     },
     check: function*(inspector) {
       let container = yield getContainerForSelector("#node1", inspector);
       ok(container.singleTextChild, "Has single text child.");
       ok(!container.canExpand, "Can't expand container with singleTextChild.");
       ok(!container.singleTextChild.canExpand, "Can't expand singleTextChild.");
       ok(container.editor.elt.querySelector(".text").textContent.trim(),
          "newtext", "Single text child editor updated.");
     },
   },
 
   {
     desc: "Updating the innerHTML",
-    test: () => {
-      let node2 = getNode("#node2");
-      node2.innerHTML = "<div><span>foo</span></div>";
+    test: function*(testActor) {
+      yield testActor.setProperty("#node2", "innerHTML",
+                                  "<div><span>foo</span></div>");
     },
     check: function*(inspector) {
       let container = yield getContainerForSelector("#node2", inspector);
 
       let openTags = container.children.querySelectorAll(".open .tag");
       is(openTags.length, 2, "There are 2 tags in node2");
       is(openTags[0].textContent.trim(), "div", "The first tag is a div");
       is(openTags[1].textContent.trim(), "span", "The second tag is a span");
 
       is(container.children.querySelector(".text").textContent.trim(), "foo",
         "The span's textcontent is correct");
     }
   },
   {
     desc: "Removing child nodes",
-    test: () => {
-      let node4 = getNode("#node4");
-      while (node4.firstChild) {
-        node4.removeChild(node4.firstChild);
-      }
+    test: function*(testActor) {
+      yield testActor.eval(`
+        let node4 = content.document.querySelector("#node4");
+        while (node4.firstChild) {
+          node4.removeChild(node4.firstChild);
+        }
+      `);
     },
     check: function*(inspector) {
       let {children} = yield getContainerForSelector("#node4", inspector);
       is(children.innerHTML, "", "Children have been removed");
     }
   },
   {
     desc: "Appending a child to a different parent",
-    test: () => {
-      let node17 = getNode("#node17");
-      let node2 = getNode("#node2");
-      node2.appendChild(node17);
+    test: function*(testActor) {
+      yield testActor.eval(`
+        let node17 = content.document.querySelector("#node17");
+        let node2 = content.document.querySelector("#node2");
+        node2.appendChild(node17);
+      `);
     },
     check: function*(inspector) {
       let {children} = yield getContainerForSelector("#node16", inspector);
       is(children.innerHTML, "",
          "Node17 has been removed from its node16 parent");
 
       let container = yield getContainerForSelector("#node2", inspector);
       let openTags = container.children.querySelectorAll(".open .tag");
@@ -226,24 +228,24 @@ const TEST_DATA = [
     //        node21
     // will become:
     // body
     //   node1
     //     node20
     //      node21
     //      node18
     //        node19
-    test: () => {
-      let node18 = getNode("#node18");
-      let node20 = getNode("#node20");
-
-      let node1 = getNode("#node1");
-
-      node1.appendChild(node20);
-      node20.appendChild(node18);
+    test: function*(testActor) {
+      yield testActor.eval(`
+        let node18 = content.document.querySelector("#node18");
+        let node20 = content.document.querySelector("#node20");
+        let node1 = content.document.querySelector("#node1");
+        node1.appendChild(node20);
+        node20.appendChild(node18);
+      `);
     },
     check: function*(inspector) {
       yield inspector.markup.expandAll();
 
       let {children} = yield getContainerForSelector("#node1", inspector);
       is(children.childNodes.length, 2,
         "Node1 now has 2 children (textnode and node20)");
 
@@ -260,43 +262,43 @@ const TEST_DATA = [
       is(node18.querySelector(".open .attreditor .attr-value")
                .textContent.trim(),
          "node18", "Node20's second child is indeed node18");
     }
   }
 ];
 
 add_task(function*() {
-  let {inspector} = yield openInspectorForURL(TEST_URL);
+  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   info("Expanding all markup-view nodes");
   yield inspector.markup.expandAll();
 
   for (let {desc, test, check, numMutations} of TEST_DATA) {
     info("Starting test: " + desc);
 
     numMutations = numMutations || 1;
 
     info("Executing the test markup mutation");
-    yield new Promise((resolve) => {
-      // If a test expects more than one mutation it may come through in a
-      // single event or possibly in multiples.
-      let seenMutations = 0;
-      inspector.on("markupmutation", function onmutation(e, mutations) {
-        seenMutations += mutations.length;
-        info("Receieved " + seenMutations +
-             " mutations, expecting at least " + numMutations);
-        if (seenMutations >= numMutations) {
-          inspector.off("markupmutation", onmutation);
-          resolve();
-        }
-      });
 
-      test();
+    // If a test expects more than one mutation it may come through in a single
+    // event or possibly in multiples.
+    let def = promise.defer();
+    let seenMutations = 0;
+    inspector.on("markupmutation", function onmutation(e, mutations) {
+      seenMutations += mutations.length;
+      info("Receieved " + seenMutations +
+           " mutations, expecting at least " + numMutations);
+      if (seenMutations >= numMutations) {
+        inspector.off("markupmutation", onmutation);
+        def.resolve();
+      }
     });
+    yield test(testActor);
+    yield def.promise;
 
     info("Expanding all markup-view nodes to make sure new nodes are imported");
     yield inspector.markup.expandAll();
 
     info("Checking the markup-view content");
     yield check(inspector);
   }
 });
--- a/devtools/client/inspector/markup/test/browser_markup_mutation_02.js
+++ b/devtools/client/inspector/markup/test/browser_markup_mutation_02.js
@@ -8,99 +8,117 @@
 // corresponding DOM nodes mutate
 
 const {clearTimeout} = require("sdk/timers");
 const TEST_URL = URL_ROOT + "doc_markup_flashing.html";
 
 // The test data contains a list of mutations to test.
 // Each item is an object:
 // - desc: a description of the test step, for better logging
-// - mutate: a function that should make changes to the content DOM
+// - mutate: a generator function that should make changes to the content DOM
 // - attribute: if set, the test will expect the corresponding attribute to
 //   flash instead of the whole node
 // - flashedNode: [optional] the css selector of the node that is expected to
 //   flash in the markup-view as a result of the mutation.
 //   If missing, the rootNode (".list") will be expected to flash
 const TEST_DATA = [{
   desc: "Adding a new node should flash the new node",
-  mutate: (doc, rootNode) => {
-    let newLi = doc.createElement("LI");
-    newLi.textContent = "new list item";
-    rootNode.appendChild(newLi);
+  mutate: function*(testActor) {
+    yield testActor.eval(`
+      let newLi = content.document.createElement("LI");
+      newLi.textContent = "new list item";
+      content.document.querySelector(".list").appendChild(newLi);
+    `);
   },
   flashedNode: ".list li:nth-child(3)"
 }, {
   desc: "Removing a node should flash its parent",
-  mutate: (doc, rootNode) => {
-    rootNode.removeChild(rootNode.lastElementChild);
+  mutate: function*(testActor) {
+    yield testActor.eval(`
+      let root = content.document.querySelector(".list");
+      root.removeChild(root.lastElementChild);
+    `);
   }
 }, {
   desc: "Re-appending an existing node should only flash this node",
-  mutate: (doc, rootNode) => {
-    rootNode.appendChild(rootNode.firstElementChild);
+  mutate: function*(testActor) {
+    yield testActor.eval(`
+      let root = content.document.querySelector(".list");
+      root.appendChild(root.firstElementChild);
+    `);
   },
   flashedNode: ".list .item:last-child"
 }, {
   desc: "Adding an attribute should flash the attribute",
   attribute: "test-name",
-  mutate: (doc, rootNode) => {
-    rootNode.setAttribute("test-name", "value-" + Date.now());
+  mutate: function*(testActor) {
+    yield testActor.setAttribute(".list", "test-name", "value-" + Date.now());
   }
 }, {
   desc: "Adding an attribute with css reserved characters should flash the " +
         "attribute",
   attribute: "one:two",
-  mutate: (doc, rootNode) => {
-    rootNode.setAttribute("one:two", "value-" + Date.now());
+  mutate: function*(testActor) {
+    yield testActor.setAttribute(".list", "one:two", "value-" + Date.now());
   }
 }, {
   desc: "Editing an attribute should flash the attribute",
   attribute: "class",
-  mutate: (doc, rootNode) => {
-    rootNode.setAttribute("class", "list value-" + Date.now());
+  mutate: function*(testActor) {
+    yield testActor.setAttribute(".list", "class", "list value-" + Date.now());
   }
 }, {
   desc: "Multiple changes to an attribute should flash the attribute",
   attribute: "class",
-  mutate: (doc, rootNode) => {
-    rootNode.removeAttribute("class");
-    rootNode.setAttribute("class", "list value-" + Date.now());
-    rootNode.setAttribute("class", "list value-" + Date.now());
-    rootNode.removeAttribute("class");
-    rootNode.setAttribute("class", "list value-" + Date.now());
-    rootNode.setAttribute("class", "list value-" + Date.now());
+  mutate: function*(testActor) {
+    yield testActor.eval(`
+      let root = content.document.querySelector(".list");
+      root.removeAttribute("class");
+      root.setAttribute("class", "list value-" + Date.now());
+      root.setAttribute("class", "list value-" + Date.now());
+      root.removeAttribute("class");
+      root.setAttribute("class", "list value-" + Date.now());
+      root.setAttribute("class", "list value-" + Date.now());
+    `);
   }
 }, {
   desc: "Removing an attribute should flash the node",
-  mutate: (doc, rootNode) => {
-    rootNode.removeAttribute("class");
+  mutate: function*(testActor) {
+    yield testActor.eval(`
+      let root = content.document.querySelector(".list");
+      root.removeAttribute("class");
+    `);
   }
 }];
 
 add_task(function*() {
-  let {inspector} = yield openInspectorForURL(TEST_URL);
+  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   // Make sure mutated nodes flash for a very long time so we can more easily
   // assert they do
   inspector.markup.CONTAINER_FLASHING_DURATION = 1000 * 60 * 60;
 
   info("Getting the <ul.list> root node to test mutations on");
-  let rootNode = getNode(".list");
   let rootNodeFront = yield getNodeFront(".list", inspector);
 
   info("Selecting the last element of the root node before starting");
   yield selectNode(".list .item:nth-child(2)", inspector);
 
   for (let {mutate, flashedNode, desc, attribute} of TEST_DATA) {
     info("Starting test: " + desc);
 
     info("Mutating the DOM and listening for markupmutation event");
-    let mutated = inspector.once("markupmutation");
-    mutate(content.document, rootNode);
-    yield mutated;
+    let onMutation = inspector.once("markupmutation");
+    yield mutate(testActor);
+    let mutations = yield onMutation;
+
+    info("Wait for the breadcrumbs widget to update if it needs to");
+    if (inspector.breadcrumbs._hasInterestingMutations(mutations)) {
+      yield inspector.once("breadcrumbs-updated");
+    }
 
     info("Asserting that the correct markup-container is flashing");
     let flashingNodeFront = rootNodeFront;
     if (flashedNode) {
       flashingNodeFront = yield getNodeFront(flashedNode, inspector);
     }
 
     if (attribute) {
--- a/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_02.js
+++ b/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_02.js
@@ -8,114 +8,134 @@
 // their display changes
 
 const TEST_URL = URL_ROOT + "doc_markup_not_displayed.html";
 const TEST_DATA = [
   {
     desc: "Hiding a node by creating a new stylesheet",
     selector: "#normal-div",
     before: true,
-    changeStyle: (doc, node) => {
-      let div = doc.createElement("div");
-      div.id = "new-style";
-      div.innerHTML = "<style>#normal-div {display:none;}</style>";
-      doc.body.appendChild(div);
+    changeStyle: function*(testActor) {
+      yield testActor.eval(`
+        let div = content.document.createElement("div");
+        div.id = "new-style";
+        div.innerHTML = "<style>#normal-div {display:none;}</style>";
+        content.document.body.appendChild(div);
+      `);
     },
     after: false
   },
   {
     desc: "Showing a node by deleting an existing stylesheet",
     selector: "#normal-div",
     before: false,
-    changeStyle: (doc, node) => {
-      doc.getElementById("new-style").remove();
+    changeStyle: function*(testActor) {
+      yield testActor.eval(`
+        content.document.getElementById("new-style").remove();
+      `);
     },
     after: true
   },
   {
     desc: "Hiding a node by changing its style property",
     selector: "#display-none",
     before: false,
-    changeStyle: (doc, node) => {
-      node.style.display = "block";
+    changeStyle: function*(testActor) {
+      yield testActor.eval(`
+        let node = content.document.querySelector("#display-none");
+        node.style.display = "block";
+      `);
     },
     after: true
   },
   {
     desc: "Showing a node by removing its hidden attribute",
     selector: "#hidden-true",
     before: false,
-    changeStyle: (doc, node) => {
-      node.removeAttribute("hidden");
+    changeStyle: function*(testActor) {
+      yield testActor.eval(`
+        content.document.querySelector("#hidden-true")
+                        .removeAttribute("hidden");
+      `);
     },
     after: true
   },
   {
     desc: "Hiding a node by adding a hidden attribute",
     selector: "#hidden-true",
     before: true,
-    changeStyle: (doc, node) => {
-      node.setAttribute("hidden", "true");
+    changeStyle: function*(testActor) {
+      yield testActor.setAttribute("#hidden-true", "hidden", "true");
     },
     after: false
   },
   {
     desc: "Showing a node by changin a stylesheet's rule",
     selector: "#hidden-via-stylesheet",
     before: false,
-    changeStyle: (doc, node) => {
-      doc.styleSheets[0].cssRules[0].style.setProperty("display", "inline");
+    changeStyle: function*(testActor) {
+      yield testActor.eval(`
+        content.document.styleSheets[0]
+                        .cssRules[0].style
+                        .setProperty("display", "inline");
+      `);
     },
     after: true
   },
   {
     desc: "Hiding a node by adding a new rule to a stylesheet",
     selector: "#hidden-via-stylesheet",
     before: true,
-    changeStyle: (doc, node) => {
-      doc.styleSheets[0].insertRule(
-        "#hidden-via-stylesheet {display: none;}", 1);
+    changeStyle: function*(testActor) {
+      yield testActor.eval(`
+        content.document.styleSheets[0].insertRule(
+          "#hidden-via-stylesheet {display: none;}", 1);
+      `);
     },
     after: false
   },
   {
     desc: "Hiding a node by adding a class that matches an existing rule",
     selector: "#normal-div",
     before: true,
-    changeStyle: (doc, node) => {
-      doc.styleSheets[0].insertRule(
-        ".a-new-class {display: none;}", 2);
-      node.classList.add("a-new-class");
+    changeStyle: function*(testActor) {
+      yield testActor.eval(`
+        content.document.styleSheets[0].insertRule(
+          ".a-new-class {display: none;}", 2);
+        content.document.querySelector("#normal-div")
+                        .classList.add("a-new-class");
+      `);
     },
     after: false
   }
 ];
 
 add_task(function*() {
-  let {inspector} = yield openInspectorForURL(TEST_URL);
+  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   for (let data of TEST_DATA) {
     info("Running test case: " + data.desc);
-    yield runTestData(inspector, data);
+    yield runTestData(inspector, testActor, data);
   }
 });
 
-function* runTestData(inspector, {selector, before, changeStyle, after}) {
+function* runTestData(inspector, testActor,
+                      {selector, before, changeStyle, after}) {
   info("Getting the " + selector + " test node");
   let nodeFront = yield getNodeFront(selector, inspector);
   let container = getContainerForNodeFront(nodeFront, inspector);
   is(!container.elt.classList.contains("not-displayed"), before,
     "The container is marked as " + (before ? "shown" : "hidden"));
 
   info("Listening for the display-change event");
   let onDisplayChanged = promise.defer();
   inspector.markup.walker.once("display-change", onDisplayChanged.resolve);
 
   info("Making style changes");
-  changeStyle(content.document, getNode(selector));
+  yield changeStyle(testActor);
   let nodes = yield onDisplayChanged.promise;
 
   info("Verifying that the list of changed nodes include our container");
 
   ok(nodes.length, "The display-change event was received with a nodes");
   let foundContainer = false;
   for (let node of nodes) {
     if (getContainerForNodeFront(node, inspector) === container) {
--- a/devtools/client/inspector/markup/test/browser_markup_pagesize_02.js
+++ b/devtools/client/inspector/markup/test/browser_markup_pagesize_02.js
@@ -9,38 +9,39 @@
 // nodes" actually shows the nodes
 
 const TEST_URL = URL_ROOT + "doc_markup_pagesize_02.html";
 
 // Make sure nodes are hidden when there are more than 5 in a row
 Services.prefs.setIntPref("devtools.markup.pagesize", 5);
 
 add_task(function*() {
-  let {inspector} = yield openInspectorForURL(TEST_URL);
+  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   info("Selecting the UL node");
   yield clickContainer("ul", inspector);
   info("Reloading the page with the UL node selected will expand its children");
-  yield reloadPage(inspector);
+  yield reloadPage(inspector, testActor);
   yield inspector.markup._waitForChildren();
 
   info("Click on the 'show all nodes' button in the UL's list of children");
   yield showAllNodes(inspector);
 
-  yield assertAllNodesAreVisible(inspector);
+  yield assertAllNodesAreVisible(inspector, testActor);
 });
 
 function* showAllNodes(inspector) {
   let container = yield getContainerForSelector("ul", inspector);
   let button = container.elt.querySelector("button");
   ok(button, "All nodes button is here");
   let win = button.ownerDocument.defaultView;
 
   EventUtils.sendMouseEvent({type: "click"}, button, win);
   yield inspector.markup._waitForChildren();
 }
 
-function* assertAllNodesAreVisible(inspector) {
+function* assertAllNodesAreVisible(inspector, testActor) {
   let container = yield getContainerForSelector("ul", inspector);
   ok(!container.elt.querySelector("button"),
      "All nodes button isn't here anymore");
-  is(container.children.childNodes.length, getNode("ul").children.length);
+  let numItems = yield testActor.getNumberOfElementMatches("ul > *");
+  is(container.children.childNodes.length, numItems);
 }
--- a/devtools/client/inspector/markup/test/browser_markup_remove_xul_attributes.js
+++ b/devtools/client/inspector/markup/test/browser_markup_remove_xul_attributes.js
@@ -5,25 +5,26 @@
 "use strict";
 
 // Test confirms that XUL attributes don't show up as empty
 // attributes after being deleted
 
 const TEST_URL = URL_ROOT + "doc_markup_xul.xul";
 
 add_task(function*() {
-  let {inspector} = yield openInspectorForURL(TEST_URL);
+  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
-  let panel = yield getNode("#test", inspector);
   let panelFront = yield getNodeFront("#test", inspector);
-
   ok(panelFront.hasAttribute("id"),
      "panelFront has id attribute in the beginning");
 
   info("Removing panel's id attribute");
-  panel.removeAttribute("id");
+  let onMutation = inspector.once("markupmutation");
+  let onInspectorUpdated = inspector.once("inspector-updated");
+  yield testActor.removeAttribute("#test", "id");
 
-  info("Waiting for markupmutation");
-  yield inspector.once("markupmutation");
+  info("Waiting for markupmutation and inspector-updated");
+  yield onMutation;
+  yield onInspectorUpdated;
 
   is(panelFront.hasAttribute("id"), false,
      "panelFront doesn't have id attribute anymore");
 });
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_03.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_03.js
@@ -16,36 +16,36 @@ add_task(function*() {
 
   info("Selecting the test node");
   yield selectNode("#retag-me", inspector);
 
   info("Getting the markup-container for the test node");
   let container = yield getContainerForSelector("#retag-me", inspector);
   ok(container.expanded, "The container is expanded");
 
-  let parentInfo = yield getNodeInfo("#retag-me", testActor);
+  let parentInfo = yield testActor.getNodeInfo("#retag-me");
   is(parentInfo.tagName.toLowerCase(), "div",
      "We've got #retag-me element, it's a DIV");
   is(parentInfo.numChildren, 1, "#retag-me has one child");
-  let childInfo = yield getNodeInfo("#retag-me > *", testActor);
+  let childInfo = yield testActor.getNodeInfo("#retag-me > *");
   is(childInfo.attributes[0].value, "retag-me-2",
      "#retag-me's only child is #retag-me-2");
 
   info("Changing #retag-me's tagname in the markup-view");
   let mutated = inspector.once("markupmutation");
   let tagEditor = container.editor.tag;
   setEditableFieldValue(tagEditor, "p", inspector);
   yield mutated;
 
   info("Checking that the markup-container exists and is correct");
   container = yield getContainerForSelector("#retag-me", inspector);
   ok(container.expanded, "The container is still expanded");
   ok(container.selected, "The container is still selected");
 
   info("Checking that the tagname change was done");
-  parentInfo = yield getNodeInfo("#retag-me", testActor);
+  parentInfo = yield testActor.getNodeInfo("#retag-me");
   is(parentInfo.tagName.toLowerCase(), "p",
      "The #retag-me element is now a P");
   is(parentInfo.numChildren, 1, "#retag-me still has one child");
-  childInfo = yield getNodeInfo("#retag-me > *", testActor);
+  childInfo = yield testActor.getNodeInfo("#retag-me > *");
   is(childInfo.attributes[0].value, "retag-me-2",
      "#retag-me's only child is #retag-me-2");
 });
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_04.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_04.js
@@ -43,39 +43,41 @@ const TEST_DATA = [{
   selector: "#second",
   key: "back_space",
   focusedSelector: "#first"
 }, {
   selector: "#third",
   key: "back_space",
   focusedSelector: "#second"
 }, {
-  setup: function*(inspector) {
+  setup: function*(inspector, testActor) {
     // Removing the siblings of #first in order to test with an only child.
     let mutated = inspector.once("markupmutation");
-    for (let node of content.document.querySelectorAll("#second, #third")) {
-      node.remove();
-    }
+    yield testActor.eval(`
+      for (let node of content.document.querySelectorAll("#second, #third")) {
+        node.remove();
+      }
+    `);
     yield mutated;
   },
   selector: "#first",
   key: "delete",
   focusedSelector: "#parent"
 }, {
   selector: "#first",
   key: "back_space",
   focusedSelector: "#parent"
 }];
 
 add_task(function*() {
-  let {inspector} = yield openInspectorForURL(TEST_URL);
+  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   for (let {setup, selector, key, focusedSelector} of TEST_DATA) {
     if (setup) {
-      yield setup(inspector);
+      yield setup(inspector, testActor);
     }
 
     yield checkDeleteAndSelection(inspector, key, selector, focusedSelector);
   }
 });
 
 function* checkDeleteAndSelection(inspector, key, selector, focusedSelector) {
   info("Test deleting node " + selector + " with " + key + ", " +
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_07.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_07.js
@@ -40,59 +40,59 @@ var TEST_DATA = [{
     style: ""
   }
 }, {
   desc: "Try to add long data URL to make sure it is collapsed in attribute editor.",
   text: `style='${DATA_URL_INLINE_STYLE}'`,
   expectedAttributes: {
     "style": DATA_URL_INLINE_STYLE
   },
-  validate: (element, container, inspector) => {
+  validate: (container, inspector) => {
     let editor = container.editor;
     let visibleAttrText = editor.attrElements.get("style")
                                              .querySelector(".attr-value")
                                              .textContent;
     is(visibleAttrText, DATA_URL_INLINE_STYLE_COLLAPSED);
   }
 }, {
   desc: "Try to add long attribute to make sure it is collapsed in attribute editor.",
   text: `data-long="${LONG_ATTRIBUTE}"`,
   expectedAttributes: {
     "data-long": LONG_ATTRIBUTE
   },
-  validate: (element, container, inspector) => {
+  validate: (container, inspector) => {
     let editor = container.editor;
     let visibleAttrText = editor.attrElements.get("data-long")
                                              .querySelector(".attr-value")
                                              .textContent;
     is(visibleAttrText, LONG_ATTRIBUTE_COLLAPSED);
   }
 }, {
   desc: "Try to add long data URL to make sure it is collapsed in attribute editor.",
   text: `src="${DATA_URL_ATTRIBUTE}"`,
   expectedAttributes: {
     "src": DATA_URL_ATTRIBUTE
   },
-  validate: (element, container, inspector) => {
+  validate: (container, inspector) => {
     let editor = container.editor;
     let visibleAttrText = editor.attrElements.get("src")
                                 .querySelector(".attr-value").textContent;
     is(visibleAttrText, DATA_URL_ATTRIBUTE_COLLAPSED);
   }
 }, {
   desc: "Try to add long attribute with collapseAttributes == false" +
   "to make sure it isn't collapsed in attribute editor.",
   text: `data-long="${LONG_ATTRIBUTE}"`,
   expectedAttributes: {
     "data-long": LONG_ATTRIBUTE
   },
   setUp: function(inspector) {
     Services.prefs.setBoolPref("devtools.markup.collapseAttributes", false);
   },
-  validate: (element, container, inspector) => {
+  validate: (container, inspector) => {
     let editor = container.editor;
     let visibleAttrText = editor.attrElements
       .get("data-long")
       .querySelector(".attr-value")
       .textContent;
     is(visibleAttrText, LONG_ATTRIBUTE);
   },
   tearDown: function(inspector) {
@@ -102,17 +102,17 @@ var TEST_DATA = [{
   desc: "Try to collapse attributes with collapseAttributeLength == 5",
   text: `data-long="${LONG_ATTRIBUTE}"`,
   expectedAttributes: {
     "data-long": LONG_ATTRIBUTE
   },
   setUp: function(inspector) {
     Services.prefs.setIntPref("devtools.markup.collapseAttributeLength", 2);
   },
-  validate: (element, container, inspector) => {
+  validate: (container, inspector) => {
     let firstChar = LONG_ATTRIBUTE[0];
     let lastChar = LONG_ATTRIBUTE[LONG_ATTRIBUTE.length - 1];
     let collapsed = firstChar + "\u2026" + lastChar;
     let editor = container.editor;
     let visibleAttrText = editor.attrElements
       .get("data-long")
       .querySelector(".attr-value")
       .textContent;
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_08.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_08.js
@@ -20,18 +20,18 @@ add_task(function*() {
   yield testEditingAttributeWithMixedQuotes(inspector, testActor);
 });
 
 function* testCollapsedLongAttribute(inspector, testActor) {
   info("Try to modify the collapsed long attribute, making sure it expands.");
 
   info("Adding test attributes to the node");
   let onMutated = inspector.once("markupmutation");
-  yield setNodeAttribute("#node24", "class", "", testActor);
-  yield setNodeAttribute("#node24", "data-long", LONG_ATTRIBUTE, testActor);
+  yield testActor.setAttribute("#node24", "class", "");
+  yield testActor.setAttribute("#node24", "data-long", LONG_ATTRIBUTE);
   yield onMutated;
 
   yield assertAttributes("#node24", {
     id: "node24",
     "class": "",
     "data-long": LONG_ATTRIBUTE
   }, testActor);
 
--- a/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_01.js
+++ b/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_01.js
@@ -4,54 +4,67 @@
 
 "use strict";
 
 // Test editing a node's text content
 
 const TEST_URL = URL_ROOT + "doc_markup_edit.html";
 
 add_task(function*() {
-  let {inspector} = yield openInspectorForURL(TEST_URL);
+  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   info("Expanding all nodes");
   yield inspector.markup.expandAll();
   yield waitForMultipleChildrenUpdates(inspector);
 
-  yield editContainer(inspector, {
+  yield editContainer(inspector, testActor, {
     selector: ".node6",
     newValue: "New text",
     oldValue: "line6"
   });
 
-  yield editContainer(inspector, {
+  yield editContainer(inspector, testActor, {
     selector: "#node17",
-    newValue: "LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. DONEC POSUERE PLACERAT MAGNA ET IMPERDIET.",
-    oldValue: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec posuere placerat magna et imperdiet.",
+    newValue: "LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. " +
+              "DONEC POSUERE PLACERAT MAGNA ET IMPERDIET.",
+    oldValue: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
+              "Donec posuere placerat magna et imperdiet.",
     shortValue: true
   });
 
-  yield editContainer(inspector, {
+  yield editContainer(inspector, testActor, {
     selector: "#node17",
     newValue: "New value",
-    oldValue: "LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. DONEC POSUERE PLACERAT MAGNA ET IMPERDIET.",
+    oldValue: "LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. " +
+              "DONEC POSUERE PLACERAT MAGNA ET IMPERDIET.",
     shortValue: true
   });
 });
 
-function* editContainer(inspector, {selector, newValue, oldValue, shortValue}) {
-  let node = getNode(selector).firstChild;
-  is(node.nodeValue, oldValue, "The test node's text content is correct");
+function* getNodeValue(selector, testActor) {
+  let nodeValue = yield testActor.eval(`
+    content.document.querySelector("${selector}").firstChild.nodeValue;
+  `);
+  return nodeValue;
+}
+
+function* editContainer(inspector, testActor,
+                        {selector, newValue, oldValue, shortValue}) {
+  let nodeValue = yield getNodeValue(selector, testActor);
+  is(nodeValue, oldValue, "The test node's text content is correct");
 
   info("Changing the text content");
   let onMutated = inspector.once("markupmutation");
   let container = yield getContainerForSelector(selector, inspector);
   let field = container.elt.querySelector("pre");
 
   if (shortValue) {
-    is(oldValue.indexOf(field.textContent.substring(0, field.textContent.length - 1)), 0,
+    is(oldValue.indexOf(
+       field.textContent.substring(0, field.textContent.length - 1)),
+       0,
        "The shortened value starts with the full value " + field.textContent);
     ok(oldValue.length > field.textContent.length,
        "The shortened value is short");
   } else {
     is(field.textContent, oldValue,
        "The text node has the correct original value");
   }
 
@@ -64,14 +77,15 @@ function* editContainer(inspector, {sele
 
   is(field.textContent, oldValue,
      "The text node has the correct original value after selecting");
   setEditableFieldValue(field, newValue, inspector);
 
   info("Listening to the markupmutation event");
   yield onMutated;
 
-  is(node.nodeValue, newValue, "The test node's text content has changed");
+  nodeValue = yield getNodeValue(selector, testActor);
+  is(nodeValue, newValue, "The test node's text content has changed");
 
   info("Selecting the <body> to reset the selection");
   let bodyContainer = yield getContainerForSelector("body", inspector);
   inspector.markup.markNodeAsSelected(bodyContainer.node);
 }
--- a/devtools/client/inspector/markup/test/browser_markup_toggle_01.js
+++ b/devtools/client/inspector/markup/test/browser_markup_toggle_01.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 // Test toggling (expand/collapse) elements by clicking on twisties
 
 const TEST_URL = URL_ROOT + "doc_markup_toggle.html";
 
 add_task(function*() {
-  let {inspector} = yield openInspectorForURL(TEST_URL);
+  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   info("Getting the container for the html element");
   let container = yield getContainerForSelector("html", inspector);
   ok(container.mustExpand, "HTML element mustExpand");
   ok(container.canExpand, "HTML element canExpand");
   is(container.expander.style.visibility, "hidden", "HTML twisty is hidden");
 
   info("Getting the container for the UL parent element");
@@ -27,30 +27,32 @@ add_task(function*() {
   let onChildren = waitForChildrenUpdated(inspector);
   let onUpdated = inspector.once("inspector-updated");
   EventUtils.synthesizeMouseAtCenter(container.expander, {},
     inspector.markup.doc.defaultView);
   yield onChildren;
   yield onUpdated;
 
   info("Checking that child LI elements have been created");
-  for (let i = 0; i < content.document.querySelectorAll("li").length; i++) {
+  let numLi = yield testActor.getNumberOfElementMatches("li");
+  for (let i = 0; i < numLi; i++) {
     let liContainer = yield getContainerForSelector(
       `li:nth-child(${i + 1})`, inspector);
     ok(liContainer, "A container for the child LI element was created");
   }
   ok(container.expanded, "Parent UL container is expanded");
 
   info("Clicking again on the UL expander");
   // No need to wait, this is a local, synchronous operation where nodes are
   // only hidden from the view, not destroyed
   EventUtils.synthesizeMouseAtCenter(container.expander, {},
     inspector.markup.doc.defaultView);
 
   info("Checking that child LI elements have been hidden");
-  for (let i = 0; i < content.document.querySelectorAll("li").length; i++) {
+  numLi = yield testActor.getNumberOfElementMatches("li");
+  for (let i = 0; i < numLi; i++) {
     let liContainer = yield getContainerForSelector(
       `li:nth-child(${i + 1})`, inspector);
     is(liContainer.elt.getClientRects().length, 0,
       "The container for the child LI element was hidden");
   }
   ok(!container.expanded, "Parent UL container is collapsed");
 });
--- a/devtools/client/inspector/markup/test/browser_markup_toggle_02.js
+++ b/devtools/client/inspector/markup/test/browser_markup_toggle_02.js
@@ -4,44 +4,46 @@
 
 "use strict";
 
 // Test toggling (expand/collapse) elements by dbl-clicking on tag lines
 
 const TEST_URL = URL_ROOT + "doc_markup_toggle.html";
 
 add_task(function*() {
-  let {inspector} = yield openInspectorForURL(TEST_URL);
+  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
 
   info("Getting the container for the UL parent element");
   let container = yield getContainerForSelector("ul", inspector);
 
   info("Dbl-clicking on the UL parent expander, and waiting for children");
   let onChildren = waitForChildrenUpdated(inspector);
   let onUpdated = inspector.once("inspector-updated");
   EventUtils.synthesizeMouseAtCenter(container.tagLine, {clickCount: 2},
     inspector.markup.doc.defaultView);
   yield onChildren;
   yield onUpdated;
 
   info("Checking that child LI elements have been created");
-  for (let i = 0; i < content.document.querySelectorAll("li").length; i++) {
+  let numLi = yield testActor.getNumberOfElementMatches("li");
+  for (let i = 0; i < numLi; i++) {
     let liContainer = yield getContainerForSelector(
       "li:nth-child(" + (i + 1) + ")", inspector);
     ok(liContainer, "A container for the child LI element was created");
   }
   ok(container.expanded, "Parent UL container is expanded");
 
   info("Dbl-clicking again on the UL expander");
   // No need to wait, this is a local, synchronous operation where nodes are
   // only hidden from the view, not destroyed
   EventUtils.synthesizeMouseAtCenter(container.tagLine, {clickCount: 2},
     inspector.markup.doc.defaultView);
 
   info("Checking that child LI elements have been hidden");
-  for (let i = 0; i < content.document.querySelectorAll("li").length; i++) {
+  numLi = yield testActor.getNumberOfElementMatches("li");
+  for (let i = 0; i < numLi; i++) {
     let liContainer = yield getContainerForSelector(
       "li:nth-child(" + (i + 1) + ")", inspector);
     is(liContainer.elt.getClientRects().length, 0,
       "The container for the child LI element was hidden");
   }
   ok(!container.expanded, "Parent UL container is collapsed");
 });
--- a/devtools/client/inspector/markup/test/browser_markup_update-on-navigtion.js
+++ b/devtools/client/inspector/markup/test/browser_markup_update-on-navigtion.js
@@ -5,23 +5,23 @@
 
 // Test that markup view handles page navigation correctly.
 
 const SCHEMA = "data:text/html;charset=UTF-8,";
 const URL_1 = SCHEMA + "<div id='one' style='color:red;'>ONE</div>";
 const URL_2 = SCHEMA + "<div id='two' style='color:green;'>TWO</div>";
 
 add_task(function* () {
-  let { inspector, toolbox } = yield openInspectorForURL(URL_1);
+  let {inspector, testActor} = yield openInspectorForURL(URL_1);
 
   assertMarkupViewIsLoaded();
   yield selectNode("#one", inspector);
 
-  let willNavigate = toolbox.target.once("will-navigate");
-  content.location = URL_2;
+  let willNavigate = inspector.toolbox.target.once("will-navigate");
+  yield testActor.eval(`content.location = "${URL_2}"`);
 
   info("Waiting for will-navigate");
   yield willNavigate;
 
   info("Navigation to page 2 has started, the inspector should be empty");
   assertMarkupViewIsEmpty();
 
   info("Waiting for new-root");
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/doc_markup_image_and_canvas_2.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html class="html">
+  <head class="head">
+    <meta charset=utf-8 />
+    <title>Image and Canvas markup-view test</title>
+  </head>
+  <body>
+    <img class="local" src="chrome://branding/content/about-logo.png" />
+    <img class="data" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAADI5JREFUeNrsWwuQFNUVPf1m5z87szv7HWSWj8CigBFMEFZKiQsB1PgJwUAZg1HBpIQsKmokEhNjWUnFVPnDWBT+KolJYbRMoqUVq0yCClpqiX8sCchPWFwVlt2db7+X93pez7zu6Vn2NxsVWh8987p7pu+9555z7+tZjTGGY3kjOMa34w447oBjfKsY7i/UNM3Y8eFSAkD50Plgw03K5P9gvGv7U5ieeR3PszeREiPNX3/0DL4hjslzhm8THh+OITfXk3dhiv4GDtGPVzCaeJmPLYzuu5qJuWfuw2QTlcN1X9pwQU7LhdZ/ZAseD45cOh9hHvDkc/yAF/DNhdb5Mrr3PvBMaAYW8fMSIi2G497IMEK/YutGtAYr6+ej+nxu/NN8Ks3N7AR6HgcLz0Eg1Ljg1UcxZzi5qewIkMYLRweTr2Kzp+nmyXAd5pS3XQDd+N/4h4zgu9FI7brlXf90nMEnuwQxlvv+hosE3TuexmWeysmT4W+WxkMaLzf9Y8ATgjcUn7T9H1gqrpFq8eV1gMn6t16NhngjfoX6q4DUP032Rd4LJgpSLwJ1yzFqBG69eRkah0MVyo0Acfe+yy9AG4nMiYCkeM53KKFXncBLAXqEm+wCqZwaueq7WCmuLTcKSJmj737ol2hurA9eq9VdyiO8yWa3NNyog+SB5CZodSsQq/dfu34tJpYbBaTMzvVddDZu16q5smXf4G8zEvqm4cyaAmJPuTJk3oJWdS4WzcVtfMZbThSQckb/pYfRGgo3zNOqZnEHbJPGK4abaDCQIIsT8V/qTaBqHkLh6LzXH8XZQhbLhYKyyCC/WeHYcNdmvOgfe8skzbWL270/T3wf7tSx/lGCbTu8xlzzmCSWLc5iwmgikcCHi3Mga0Ry913vBFvQwg90l6M4ImWKfsWOp7DSWxmfpPlCFuPFfsNfKrCnPYpQKIRgqBK7D0SxYaNHwkEiJMtl0ReDp3Lc5D3PGoTo/sKngCl7a5chFqvBatKwjBd7WwqIlzB/78NcoUcp5VSgGxm+7b8eqQRGnHMO634epO4S1EZww09/iFg5UmGoESDuznP1xVhTUX1WWHPzjpd25wyH0hRxI3LGM75nxmuNEEUVpAN0XgxmPoKralakbQnWlIMQyVBD/w+3orkq4lvualjKyWwzt4MaxqspQHVhPOWG64bxYuhZXSFGWhipbSDVragOu5Y9eAsmDDUKyBA703vemVhHoueD6e9wAzJK1WfmN0Umk5GGM4kEMZcuIECqgjm0nldAqmbjwtm4VxZH5AvlADP6mx9Eqy9Q0+KqW8Ch+47FaMMYmnNGfY1iPMshoC6qFxme4wQ+0p+ARE6H3+9veWEDWgUhDhUKyFARn4jM5BNxT0XsMg7bfymGK1ov3wtjDfhL4w0HVGUVBEjDaaE+QNdrcNWch1PG4W6xrjBUXECGivg++Cva3JUT4iQUz3V2RsSVaKLwOuDT89A3HdBQoxhNC+fnVm74ual2EG893P6G+PuP4SfiO4cCBWQooL9qCWKNXPbcI37Aa/lnlZxXRt4RFONGwSDCPAHqOuqjWct1QiEMw5mChM5X4K47FyNqcd3aK9AwFH0CGYLoe1ctxk2eWi57rg5JfGp9rzC6ggCdFlAgHBDw5Yxlcg6G8SyHCjMlsgmDD9zhSeHlF+JnAgWDTQUy2NxfdwOao1UVV3pi3+bE97YSbWpLAbn6zefHNQkp1PMpIBwwvslKgIYTKM2nEpNzrGcH3FXTEal0L38kJ4uDQgEZbO4vnI173LXf5NHZaiUxtaCxyZuo/rK6LpUg54yg3zTWRAArvDcRIPZ6BqzrQ1REpmL+DNw32OKIDCb3X1qPVn8wNNMT4w2bvs+q4bAZrqBh2skaL3yyhhIIZ4i6oHkUK0RckcB8GigEyRIH4A6Mgc8fatl0/+BkkQxC9gIT4ljna1rIZW9rEdNbjJcNjsnoYj7LHWCUwpITzEgzRQKZ3XAFHbTzA3hrz8TEUUZxFBhoKpABQt/97p+w0hMZG68I8R6FtlsJT3FELndZntjM+VMnylKYq8GJI3UZaRMpquGSGFVOEfv0YZBMNzz+uvjbfzS6xQERIhlI9FcvQWNdFVb7x1zCb+QNK8vb9NsiifmI5hBgVoOCBC1sb0ab5RomqENxLO3eA1/0NDRU47q2RQNbRCUDIb7lF2CNL3ZGxEV4n08TVvZWYG4pZyV0zUdS45tyCBByOHWiyvZmxFXDCyRo1ge5+Sy0TA+8lWMiP/6O0S32exGV9Jf4fr8azdUR3zL/CZz4MtvzdX5uOYs6NDOmpkuj5Huh+7qUQSYl0ThHzw0YQzcGo6bhzEqoYq5rN3yRiYiG3Vfe2Ybm/qKA9NNZ3nNm4F7/yDkg9AN+U1mHiBcXP8zuDN76jj8hg1QyiWQigalj02BJPhK8I0zxijAjhp5zhlpLUDvS+BCy2HMAvvB4XDgL9/SXC0g/ou/5+6/xLX8w0uJrOIkXfPvyhY0F6gr7M8H0KWFYikcqAXakB+xwD9CdREBLoau7Gz3cAdSIdLFxFtJTCqRChSjnutvhDcREtzjz2Tswtz+yeNRFUeXZXtWux7C1fuoVcbd3J//ipDX3uZZDLGrwweS+UBLL5TDliVBnF8P7H+XI8aRRGsIBJg/Zlslt1+W+D1JWoSyi+kD9jfhs78t7mhZhSl+fLfY1Bdyv3I8V/qpY3B1McgN7ZFT5/vNO0I5DPLLdPBIJA8qc4h2I0QplYfDpJwHT+aj0246r5S8rToG8OjCle8wk4OLvvYGa+Ovr84uo2qBSwJS9G5egoZFLTfiEqWDtbwGfHgKOdPHcS+ai7XDzMPW/FJRLGGcxnBbK4YJC2K+h+T6Bdu5CqHqCWERd3bawb7JI+iJ735+LNaHaprBLLHBm08U3XxShEsdt+f3eTh3v7aC95Dct4RCWL5OZWh/oXBZThxAIxyOXLzBk8aiEWJID8rK3CpPOmeHaGpvCS+7EHv5FujVHUSJPLXvIFeHcNc+9xrB2gws9KZdxuLFax/WLM5gzzSm/lTXF/OdAcapyvjxPqxqHjr2v4ckX2bS2dRBrc5lSdpKjEJ9/9tdwX2WMd53ZQ2IVo3RES+UwVSpCPvYepNx4gmTGDUKIMQ4eduPnD7mx9xOn/KZKOlFbStjONxHTtR+BYAPmnoZ1Zp8wkBRwP/EL3u0F/C2hGl7vpz7vW37T3vP7if8wroKuoh8ribknX9BK5rcF+mo1qKaKyRPJTgTDjbzY8szcuLb3bpH00u35T47j7prRpwDJTxzyG0dHgxPp5bPG8VdkpfPbUg3SgoOo2mwVukb98D5EqpswZTTulCggTk4gpYhv0++wIhCJxr0+Hq1sondis0SE2oxQe3qWXwWyO4DSQg9gJ8Iiw1VFcGqXxet0N9xE4ygIxv/9W6wo9WyROEX/R+eiobYSq2vHTOR631Eiv2lRfh9dvxkumkXh92Qsx8XrAJ+7YGbWuhxOi/U+31NQmzyqNYG8N/3wfo6CRtRHcN01FzkvojohwLu0VVvDa56IS/xcj2b7nN+O+m0jqpE1wMPXZxAN9iCVThtDvH7gmiRGRpU8Lspv1Uhq4wIVdQoyuGSLNYPKUCS8+CzNURbzMmjK3i8u0U793lmuV0ef9nWQ5MGC/DiUqEUSaCtXna9RJEspZS1lrXINK/pcq+SpT50t98QKMq1FRmDfx3vxty102k0PM4ssEnvuz5+G26Ij4yDpz6z9fV8bkyIkqBFkhej0Ib+ZQ34XJK9AfozaiimqIoX3Jp3tiISrcfYpuN2+iFph/02P36PNC9fVcCnp6H9jYouKyfaWufz5Tp9tVxcUniw7IohZv4dZz81/ns67z3AYPrc2n0+Ix2q8k0PWjgBy88XaibnfK9A+5LdDY2Ivhy36fbT8Zv3Lb1U1qLqUxorXEEXIs0mjjrtxoTZWtdvigNs2sgPiujTv6DIZLld6b/V5742JZV3fUsUVFy5gdsNtKWFzUCEVbNepD1MkSMVbsb6SZm7jI3/zODtQKgUMsOw8wDZ63t5xcV1TnaEAxoc6wrqY+Fj+N4DsqOnhOIdicrQSm1MPYCPlIqHn5bbHg8/bj2D3QfZnCX3mpAICDZV8jH5kpbZqTD0W+DxaA74CWzLN2nd14OlL72J38Lf7+TjC7dadZFDoZJQPrtaIKL/G0L6ktptPZVJ8fMqHYPZOKYPMyQGadIJfDvdXwAFiZOTvDBPydf5vk4rWA+RfdhBlaF/yDDBRoMu9pfnSjv/p7DG+HXfAcQcc49v/BBgAcFAO4DmB2GQAAAAASUVORK5CYII=" />
+    <img class="remote" src="http://example.com/browser/devtools/client/inspector/markup/test/doc_markup_tooltip.png" />
+    <canvas class="canvas" width="600" height="600"></canvas>
+    <script type="text/javascript">
+      "use strict";
+
+      let context = document.querySelector(".canvas").getContext("2d");
+      context.beginPath();
+      context.moveTo(300, 0);
+      context.lineTo(600, 600);
+      context.lineTo(0, 600);
+      context.closePath();
+      context.fillStyle = "#ffc821";
+      context.fill();
+    </script>
+  </body>
+</html>
--- a/devtools/client/inspector/markup/test/head.js
+++ b/devtools/client/inspector/markup/test/head.js
@@ -47,86 +47,24 @@ function loadHelperScript(filePath) {
   Services.scriptloader.loadSubScript(testDir + "/" + filePath, this);
 }
 
 /**
  * Reload the current page
  * @return a promise that resolves when the inspector has emitted the event
  * new-root
  */
-function reloadPage(inspector) {
+function reloadPage(inspector, testActor) {
   info("Reloading the page");
   let newRoot = inspector.once("new-root");
-  content.location.reload();
+  testActor.reload();
   return newRoot;
 }
 
 /**
- * Reload the current tab location.
- * @param {TestActorFront} testActor An instance of the current TestActorFront
- * instantiated when the test started.
- */
-function reloadTab(testActor) {
-  return testActor.eval("location.reload()");
-}
-
-/**
- * Simple DOM node accesor function that takes either a node or a string css
- * selector as argument and returns the corresponding node
- * @param {String|DOMNode} nodeOrSelector
- * @return {DOMNode|CPOW} Note that in e10s mode a CPOW object is returned which
- * doesn't implement *all* of the DOMNode's properties
- */
-function getNode(nodeOrSelector) {
-  info("Getting the node for '" + nodeOrSelector + "'");
-  return typeof nodeOrSelector === "string" ?
-    content.document.querySelector(nodeOrSelector) :
-    nodeOrSelector;
-}
-
-/**
- * Get information about a DOM element, identified by its selector.
- * @param {String} selector.
- * @return {Promise} a promise that resolves to the element's information.
- */
-function getNodeInfo(selector, testActor) {
-  return testActor.getNodeInfo(selector);
-}
-
-/**
- * Set the value of an attribute of a DOM element, identified by its selector.
- * @param {String} selector.
- * @param {String} attributeName.
- * @param {String} attributeValue.
- * @param {TestActorFront} testActor The current TestActorFront instance.
- * @return {Promise} resolves when done.
- */
-function setNodeAttribute(selector, attributeName, attributeValue, testActor) {
-  return testActor.setAttribute(selector, attributeName, attributeValue);
-}
-
-/**
- * Highlight a node and set the inspector's current selection to the node or
- * the first match of the given css selector.
- * @param {String|DOMNode} nodeOrSelector
- * @param {InspectorPanel} inspector
- *        The instance of InspectorPanel currently loaded in the toolbox
- * @return a promise that resolves when the inspector is updated with the new
- * node
- */
-function selectAndHighlightNode(nodeOrSelector, inspector) {
-  info("Highlighting and selecting the node " + nodeOrSelector);
-
-  let node = getNode(nodeOrSelector);
-  let updated = inspector.toolbox.once("highlighter-ready");
-  inspector.selection.setNode(node, "test-highlight");
-  return updated;
-}
-
-/**
  * Get the MarkupContainer object instance that corresponds to the given
  * NodeFront
  * @param {NodeFront} nodeFront
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently
  * loaded in the toolbox
  * @return {MarkupContainer}
  */
 function getContainerForNodeFront(nodeFront, {markup}) {
@@ -236,17 +174,17 @@ var addNewAttributes = Task.async(functi
  * @param {Object} expected An object containing the attributes to check.
  *        e.g. {id: "id1", class: "someclass"}
  * @param {TestActorFront} testActor The current TestActorFront instance.
  *
  * Note that node.getAttribute() returns attribute values provided by the HTML
  * parser. The parser only provides unescaped entities so &amp; will return &.
  */
 var assertAttributes = Task.async(function*(selector, expected, testActor) {
-  let {attributes: actual} = yield getNodeInfo(selector, testActor);
+  let {attributes: actual} = yield testActor.getNodeInfo(selector);
 
   is(actual.length, Object.keys(expected).length,
     "The node " + selector + " has the expected number of attributes.");
   for (let attr in expected) {
     let foundAttr = actual.find(({name}) => name === attr);
     let foundValue = foundAttr ? foundAttr.value : undefined;
     ok(foundAttr, "The node " + selector + " has the attribute " + attr);
     is(foundValue, expected[attr],
@@ -320,17 +258,17 @@ function searchUsingSelectorSearch(selec
 /**
  * This shouldn't be used in the tests, but is useful when writing new tests or
  * debugging existing tests in order to introduce delays in the test steps
  * @param {Number} ms The time to wait
  * @return A promise that resolves when the time is passed
  */
 function wait(ms) {
   let def = promise.defer();
-  content.setTimeout(def.resolve, ms);
+  setTimeout(def.resolve, ms);
   return def.promise;
 }
 
 /**
  * Check to see if the inspector menu items for editing are disabled.
  * Things like Edit As HTML, Delete Node, etc.
  * @param {NodeFront} nodeFront
  * @param {InspectorPanel} inspector
--- a/devtools/client/inspector/markup/test/helper_attributes_test_runner.js
+++ b/devtools/client/inspector/markup/test/helper_attributes_test_runner.js
@@ -53,27 +53,26 @@ function runAddAttributesTests(tests, no
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently
  * @param {TestActorFront} testActor The current TestActorFront instance.
  * opened
  */
 function* runAddAttributesTest(test, selector, inspector, testActor) {
   if (test.setUp) {
     test.setUp(inspector);
   }
-  let element = getNode(selector);
 
   info("Starting add-attribute test: " + test.desc);
   yield addNewAttributes(selector, test.text, inspector);
 
   info("Assert that the attribute(s) has/have been applied correctly");
   yield assertAttributes(selector, test.expectedAttributes, testActor);
 
   if (test.validate) {
     let container = yield getContainerForSelector(selector, inspector);
-    test.validate(element, container, inspector);
+    test.validate(container, inspector);
   }
 
   info("Undo the change");
   yield undoChange(inspector);
 
   info("Assert that the attribute(s) has/have been removed correctly");
   yield assertAttributes(selector, {}, testActor);
   if (test.tearDown) {
--- a/devtools/client/inspector/markup/test/helper_events_test_runner.js
+++ b/devtools/client/inspector/markup/test/helper_events_test_runner.js
@@ -65,18 +65,17 @@ function* checkEventsForNode(test, inspe
   // Click button to show tooltip
   info("Clicking evHolder");
   EventUtils.synthesizeMouseAtCenter(evHolder, {},
     inspector.markup.doc.defaultView);
   yield tooltip.once("shown");
   info("tooltip shown");
 
   // Check values
-  let content = tooltip.content;
-  let headers = content.querySelectorAll(".event-header");
+  let headers = tooltip.content.querySelectorAll(".event-header");
   let nodeFront = container.node;
   let cssSelector = nodeFront.nodeName + "#" + nodeFront.id;
 
   for (let i = 0; i < headers.length; i++) {
     info("Processing header[" + i + "] for " + cssSelector);
 
     let header = headers[i];
     let type = header.querySelector(".event-tooltip-event-type");
--- a/devtools/client/inspector/markup/test/helper_outerhtml_test_runner.js
+++ b/devtools/client/inspector/markup/test/helper_outerhtml_test_runner.js
@@ -17,17 +17,17 @@
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently
  * opened
  * @param {TestActorFront} testActor The current TestActorFront instance
  * @return a promise that resolves when the tests have run
  */
 function runEditOuterHTMLTests(tests, inspector, testActor) {
   info("Running " + tests.length + " edit-outer-html tests");
   return Task.spawn(function* () {
-    for (let step of TEST_DATA) {
+    for (let step of tests) {
       yield runEditOuterHTMLTest(step, inspector, testActor);
     }
   });
 }
 
 /**
  * Run a single edit-outer-html test.
  * See runEditOuterHTMLTests for a description.
@@ -54,24 +54,24 @@ function* runEditOuterHTMLTest(test, ins
                                              test.newHTML, test.oldHTML);
   yield onReselected;
 
   // Typically selectedNode will === pageNode, but if a new element has been
   // injected in front of it, this will not be the case. If this happens.
   let selectedNodeFront = inspector.selection.nodeFront;
   let pageNodeFront = yield inspector.walker.querySelector(
     inspector.walker.rootNode, test.selector);
-  let pageNode = getNode(test.selector);
 
   if (test.validate) {
-    yield test.validate(pageNode, pageNodeFront, selectedNodeFront, inspector);
+    yield test.validate({pageNodeFront, selectedNodeFront,
+                         inspector, testActor});
   } else {
     is(pageNodeFront, selectedNodeFront,
        "Original node (grabbed by selector) is selected");
-    let {outerHTML} = yield getNodeInfo(test.selector, testActor);
+    let {outerHTML} = yield testActor.getNodeInfo(test.selector);
     is(outerHTML, test.newHTML, "Outer HTML has been updated");
   }
 
   // Wait for the inspector to be fully updated to avoid causing errors by
   // abruptly closing hanging requests when the test ends
   yield onUpdated;
 
   let closeTagLine = inspector.markup.getContainer(pageNodeFront).closeTagLine;
--- a/devtools/client/inspector/rules/test/head.js
+++ b/devtools/client/inspector/rules/test/head.js
@@ -851,17 +851,17 @@ var setSearchFilter = Task.async(functio
  *
  * @param {InspectorPanel} inspector
  *        The instance of InspectorPanel currently loaded in the toolbox
  * @param {TestActor} testActor
  *        The current instance of the TestActor
  */
 function* reloadPage(inspector, testActor) {
   let onNewRoot = inspector.once("new-root");
-  yield testActor.eval("content.location.reload();");
+  yield testActor.reload();
   yield onNewRoot;
   yield inspector.markup._waitForChildren();
 }
 
 /**
  * Create a new rule by clicking on the "add rule" button.
  *
  * @param {InspectorPanel} inspector
--- a/devtools/client/shared/test/test-actor.js
+++ b/devtools/client/shared/test/test-actor.js
@@ -488,16 +488,42 @@ var TestActor = exports.TestActor = prot
       selector: Arg(0, "string"),
       property: Arg(1, "string"),
       value: Arg(2, "string")
     },
     response: {}
   }),
 
   /**
+   * Remove an attribute from a DOM Node.
+   * @param {String} selector The node selector
+   * @param {String} attribute The attribute name
+   */
+  removeAttribute: protocol.method(function (selector, attribute) {
+    let node = this._querySelector(selector);
+    node.removeAttribute(attribute);
+  }, {
+    request: {
+      selector: Arg(0, "string"),
+      property: Arg(1, "string")
+    },
+    response: {}
+  }),
+
+  /**
+   * Reload the content window.
+   */
+  reload: protocol.method(function () {
+    this.content.location.reload();
+  }, {
+    request: {},
+    response: {}
+  }),
+
+  /**
    * Reload an iframe and wait for its load event.
    * @param {String} selector The node selector
    */
   reloadFrame: protocol.method(function (selector) {
     let node = this._querySelector(selector);
 
     let deferred = promise.defer();