Bug 1273323 - Add integration tests for namespaced elements. r=jdescottes draft
authorNicolas Chevobbe <chevobbe.nicolas@gmail.com>
Sun, 22 May 2016 00:03:42 +0200
changeset 370806 8f9cb5e50453bc5bc9e851568fe869c7e89a08a6
parent 370805 2a2ce43bcafb42f0f5fcf4dd0f135eefdfe085b7
child 521836 1e9989e78b53afc10267668c0c75f26202075253
push id19154
push userchevobbe.nicolas@gmail.com
push dateWed, 25 May 2016 11:43:15 +0000
reviewersjdescottes
bugs1273323
milestone49.0a1
Bug 1273323 - Add integration tests for namespaced elements. r=jdescottes Add tests for : - markup display - add rule - breadcrumb - highlighter info bar - markup search - webconsole element output Move webconsole dom output test to head.js as similar things are done in several tests. MozReview-Commit-ID: 6gclZhzd7sD
devtools/client/inspector/markup/test/browser.ini
devtools/client/inspector/markup/test/browser_markup_node_names_namespaced.js
devtools/client/inspector/rules/test/browser.ini
devtools/client/inspector/rules/test/browser_rules_add-rule_06.js
devtools/client/inspector/test/browser.ini
devtools/client/inspector/test/browser_inspector_breadcrumbs_namespaced.js
devtools/client/inspector/test/browser_inspector_infobar_02.js
devtools/client/inspector/test/browser_inspector_search-08.js
devtools/client/webconsole/test/browser.ini
devtools/client/webconsole/test/browser_webconsole_output_dom_elements_02.js
devtools/client/webconsole/test/browser_webconsole_output_dom_elements_05.js
devtools/client/webconsole/test/head.js
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -102,18 +102,19 @@ skip-if = true # Bug 1177550
 [browser_markup_keybindings_01.js]
 [browser_markup_keybindings_02.js]
 [browser_markup_keybindings_03.js]
 [browser_markup_keybindings_04.js]
 [browser_markup_keybindings_delete_attributes.js]
 [browser_markup_keybindings_scrolltonode.js]
 [browser_markup_mutation_01.js]
 [browser_markup_mutation_02.js]
+[browser_markup_navigation.js]
 [browser_markup_node_names.js]
-[browser_markup_navigation.js]
+[browser_markup_node_names_namespaced.js]
 [browser_markup_node_not_displayed_01.js]
 [browser_markup_node_not_displayed_02.js]
 [browser_markup_pagesize_01.js]
 [browser_markup_pagesize_02.js]
 [browser_markup_remove_xul_attributes.js]
 skip-if = e10s # Bug 1036409 - The last selected node isn't reselected
 [browser_markup_search_01.js]
 [browser_markup_tag_edit_01.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_node_names_namespaced.js
@@ -0,0 +1,43 @@
+/* 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 namespaced element node names in the markupview.
+
+const XHTML = `
+  <!DOCTYPE html>
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:svg="http://www.w3.org/2000/svg">
+    <body>
+      <svg:svg width="100" height="100">
+        <svg:clipPath id="clip">
+          <svg:rect id="rectangle" x="0" y="0" width="10" height="5"></svg:rect>
+        </svg:clipPath>
+        <svg:circle cx="0" cy="0" r="5"></svg:circle>
+      </svg:svg>
+    </body>
+  </html>
+`;
+
+const TEST_URI = "data:application/xhtml+xml;charset=utf-8," + encodeURI(XHTML);
+
+add_task(function* () {
+  let {inspector} = yield openInspectorForURL(TEST_URI);
+
+  // Get and open the svg element to show its children.
+  let svgNodeFront = yield getNodeFront("svg", inspector);
+  yield inspector.markup.expandNode(svgNodeFront);
+  yield waitForMultipleChildrenUpdates(inspector);
+
+  let clipPathContainer = yield getContainerForSelector("clipPath", inspector);
+  info("Checking the clipPath element");
+  ok(clipPathContainer.editor.tag.textContent === "svg:clipPath",
+     "svg:clipPath node is correctly displayed");
+
+  let circlePathContainer = yield getContainerForSelector("circle", inspector);
+  info("Checking the circle element");
+  ok(circlePathContainer.editor.tag.textContent === "svg:circle",
+     "svg:circle node is correctly displayed");
+});
--- a/devtools/client/inspector/rules/test/browser.ini
+++ b/devtools/client/inspector/rules/test/browser.ini
@@ -47,16 +47,17 @@ support-files =
 [browser_rules_add-property_01.js]
 [browser_rules_add-property_02.js]
 [browser_rules_add-property-svg.js]
 [browser_rules_add-rule_01.js]
 [browser_rules_add-rule_02.js]
 [browser_rules_add-rule_03.js]
 [browser_rules_add-rule_04.js]
 [browser_rules_add-rule_05.js]
+[browser_rules_add-rule_06.js]
 [browser_rules_add-rule_pseudo_class.js]
 [browser_rules_add-rule_iframes.js]
 [browser_rules_authored.js]
 [browser_rules_authored_color.js]
 [browser_rules_authored_override.js]
 [browser_rules_blob_stylesheet.js]
 [browser_rules_colorpicker-and-image-tooltip_01.js]
 [browser_rules_colorpicker-and-image-tooltip_02.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/browser_rules_add-rule_06.js
@@ -0,0 +1,49 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests the behaviour of adding a new rule using the add rule button
+// on namespaced elements.
+
+const XHTML = `
+  <!DOCTYPE html>
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:svg="http://www.w3.org/2000/svg">
+    <body>
+      <svg:svg width="100" height="100">
+        <svg:clipPath>
+          <svg:rect x="0" y="0" width="10" height="5"></svg:rect>
+        </svg:clipPath>
+        <svg:circle cx="0" cy="0" r="5"></svg:circle>
+      </svg:svg>
+    </body>
+  </html>
+`;
+const TEST_URI = "data:application/xhtml+xml;charset=utf-8," + encodeURI(XHTML);
+
+const TEST_DATA = [
+  { node: "clipPath", expected: "clipPath" },
+  { node: "rect", expected: "rect" },
+  { node: "circle", expected: "circle" }
+];
+
+add_task(function* () {
+  yield addTab(TEST_URI);
+  let {inspector, view} = yield openRuleView();
+
+  for (let data of TEST_DATA) {
+    let {node, expected} = data;
+    yield selectNode(node, inspector);
+    yield addNewRule(inspector, view);
+    yield testNewRule(view, expected, 1);
+  }
+});
+
+function* testNewRule(view, expected, index) {
+  let idRuleEditor = getRuleViewRuleEditor(view, index);
+  let editor = idRuleEditor.selectorText.ownerDocument.activeElement;
+  is(editor.value, expected,
+      "Selector editor value is as expected: " + expected);
+}
--- a/devtools/client/inspector/test/browser.ini
+++ b/devtools/client/inspector/test/browser.ini
@@ -41,16 +41,17 @@ support-files =
 [browser_inspector_addNode_02.js]
 [browser_inspector_addNode_03.js]
 [browser_inspector_breadcrumbs.js]
 [browser_inspector_breadcrumbs_highlight_hover.js]
 [browser_inspector_breadcrumbs_keybinding.js]
 [browser_inspector_breadcrumbs_keyboard_trap.js]
 skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
 [browser_inspector_breadcrumbs_mutations.js]
+[browser_inspector_breadcrumbs_namespaced.js]
 [browser_inspector_delete-selected-node-01.js]
 [browser_inspector_delete-selected-node-02.js]
 [browser_inspector_delete-selected-node-03.js]
 [browser_inspector_destroy-after-navigation.js]
 [browser_inspector_destroy-before-ready.js]
 [browser_inspector_expand-collapse.js]
 [browser_inspector_gcli-inspect-command.js]
 [browser_inspector_highlighter-01.js]
@@ -86,16 +87,17 @@ skip-if = os == "mac" # Full keyboard na
 [browser_inspector_highlighter-rulers_01.js]
 [browser_inspector_highlighter-rulers_02.js]
 [browser_inspector_highlighter-selector_01.js]
 [browser_inspector_highlighter-selector_02.js]
 [browser_inspector_highlighter-xbl.js]
 [browser_inspector_highlighter-zoom.js]
 [browser_inspector_iframe-navigation.js]
 [browser_inspector_infobar_01.js]
+[browser_inspector_infobar_02.js]
 [browser_inspector_initialization.js]
 skip-if = (e10s && debug) # Bug 1250058 - Docshell leak on debug e10s
 [browser_inspector_inspect-object-element.js]
 [browser_inspector_invalidate.js]
 [browser_inspector_keyboard-shortcuts-copy-outerhtml.js]
 [browser_inspector_keyboard-shortcuts.js]
 [browser_inspector_menu-01-sensitivity.js]
 [browser_inspector_menu-02-copy-items.js]
@@ -117,16 +119,17 @@ skip-if = (e10s && debug) # Bug 1250058 
 [browser_inspector_remove-iframe-during-load.js]
 [browser_inspector_search-01.js]
 [browser_inspector_search-02.js]
 [browser_inspector_search-03.js]
 [browser_inspector_search-04.js]
 [browser_inspector_search-05.js]
 [browser_inspector_search-06.js]
 [browser_inspector_search-07.js]
+[browser_inspector_search-08.js]
 [browser_inspector_search_keyboard_trap.js]
 [browser_inspector_search-reserved.js]
 [browser_inspector_search-selection.js]
 [browser_inspector_select-docshell.js]
 [browser_inspector_select-last-selected.js]
 [browser_inspector_search-navigation.js]
 [browser_inspector_sidebarstate.js]
 [browser_inspector_switch-to-inspector-on-pick.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/test/browser_inspector_breadcrumbs_namespaced.js
@@ -0,0 +1,55 @@
+/* vim: set ft=javascript 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 the breadcrumbs widget content for namespaced elements is correct.
+
+const XHTML = `
+  <!DOCTYPE html>
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:svg="http://www.w3.org/2000/svg">
+    <body>
+      <svg:svg width="100" height="100">
+        <svg:clipPath id="clip">
+          <svg:rect id="rectangle" x="0" y="0" width="10" height="5"></svg:rect>
+        </svg:clipPath>
+        <svg:circle cx="0" cy="0" r="5"></svg:circle>
+      </svg:svg>
+    </body>
+  </html>
+`;
+
+const TEST_URI = "data:application/xhtml+xml;charset=utf-8," + encodeURI(XHTML);
+
+const NODES = [
+  {selector: "clipPath", nodes: ["svg:svg", "svg:clipPath"],
+    nodeName: "svg:clipPath", title: "svg:clipPath#clip"},
+  {selector: "circle", nodes: ["svg:svg", "svg:circle"],
+    nodeName: "svg:circle", title: "svg:circle"},
+];
+
+add_task(function* () {
+  let { inspector } = yield openInspectorForURL(TEST_URI);
+  let container = inspector.panelDoc.getElementById("inspector-breadcrumbs");
+
+  for (let node of NODES) {
+    info("Testing node " + node.selector);
+
+    info("Selecting node and waiting for breadcrumbs to update");
+    let breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
+    yield selectNode(node.selector, inspector);
+    yield breadcrumbsUpdated;
+
+    info("Performing checks for node " + node.selector);
+
+    let checkedButton = container.querySelector("button[checked]");
+
+    let labelTag = checkedButton.querySelector(".breadcrumbs-widget-item-tag");
+    is(labelTag.textContent, node.nodeName,
+      "Node " + node.selector + " has the expected tag name");
+
+    is(checkedButton.getAttribute("tooltiptext"), node.title,
+      "Node " + node.selector + " has the expected tooltip");
+  }
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/test/browser_inspector_infobar_02.js
@@ -0,0 +1,50 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Check the text content of the highlighter info bar for namespaced elements.
+
+const XHTML = `
+  <!DOCTYPE html>
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:svg="http://www.w3.org/2000/svg">
+    <body>
+      <svg:svg width="100" height="100">
+        <svg:circle cx="0" cy="0" r="5"></svg:circle>
+      </svg:svg>
+    </body>
+  </html>
+`;
+
+const TEST_URI = "data:application/xhtml+xml;charset=utf-8," + encodeURI(XHTML);
+
+add_task(function* () {
+  let {inspector, testActor} = yield openInspectorForURL(TEST_URI);
+
+  let testData = [
+    {
+      selector: "svg",
+      tag: "svg:svg"
+    },
+    {
+      selector: "circle",
+      tag: "svg:circle"
+    },
+  ];
+
+  for (let currTest of testData) {
+    yield testNode(currTest, inspector, testActor);
+  }
+});
+
+function* testNode(test, inspector, testActor) {
+  info("Testing " + test.selector);
+
+  yield selectAndHighlightNode(test.selector, inspector);
+
+  let tag = yield testActor.getHighlighterNodeTextContent(
+    "box-model-nodeinfobar-tagname");
+  is(tag, test.tag, "node " + test.selector + ": tagName matches.");
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/test/browser_inspector_search-08.js
@@ -0,0 +1,64 @@
+/* vim: set ft=javascript 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 searching for namespaced elements does work.
+
+const XHTML = `
+  <!DOCTYPE html>
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:svg="http://www.w3.org/2000/svg">
+    <body>
+      <svg:svg width="100" height="100">
+        <svg:clipPath>
+          <svg:rect x="0" y="0" width="10" height="5"></svg:rect>
+        </svg:clipPath>
+        <svg:circle cx="0" cy="0" r="5"></svg:circle>
+      </svg:svg>
+    </body>
+  </html>
+`;
+
+const TEST_URI = "data:application/xhtml+xml;charset=utf-8," + encodeURI(XHTML);
+
+// An array of (key, suggestions) pairs where key is a key to press and
+// suggestions is an array of suggestions that should be shown in the popup.
+const TEST_DATA = [{
+  key: "c",
+  suggestions: ["circle", "clipPath"]
+}, {
+  key: "VK_BACK_SPACE",
+  suggestions: []
+}, {
+  key: "s",
+  suggestions: ["svg"]
+}];
+
+add_task(function* () {
+  let {inspector} = yield openInspectorForURL(TEST_URI);
+  let {searchBox} = inspector;
+  let popup = inspector.searchSuggestions.searchPopup;
+
+  yield focusSearchBoxUsingShortcut(inspector.panelWin);
+
+  for (let {key, suggestions} of TEST_DATA) {
+    info("Pressing " + key + " to get " + suggestions.join(", "));
+
+    let command = once(searchBox, "command");
+    EventUtils.synthesizeKey(key, {}, inspector.panelWin);
+    yield command;
+
+    info("Waiting for search query to complete and getting the suggestions");
+    yield inspector.searchSuggestions._lastQuery;
+    let actualSuggestions = popup.getItems().reverse();
+
+    is(popup.isOpen ? actualSuggestions.length : 0, suggestions.length,
+       "There are expected number of suggestions.");
+
+    for (let i = 0; i < suggestions.length; i++) {
+      is(actualSuggestions[i].label, suggestions[i],
+         "The suggestion at " + i + "th index is correct.");
+    }
+  }
+});
--- a/devtools/client/webconsole/test/browser.ini
+++ b/devtools/client/webconsole/test/browser.ini
@@ -354,16 +354,17 @@ tags = trackingprotection
 [browser_webconsole_output_05.js]
 [browser_webconsole_output_06.js]
 [browser_webconsole_output_dom_elements_01.js]
 [browser_webconsole_output_dom_elements_02.js]
 skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
 [browser_webconsole_output_dom_elements_03.js]
 [browser_webconsole_output_dom_elements_04.js]
 skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
+[browser_webconsole_output_dom_elements_05.js]
 [browser_webconsole_output_events.js]
 [browser_webconsole_output_regexp.js]
 [browser_webconsole_output_table.js]
 [browser_console_variables_view_highlighter.js]
 [browser_webconsole_start_netmon_first.js]
 [browser_webconsole_console_trace_duplicates.js]
 [browser_webconsole_cd_iframe.js]
 [browser_webconsole_autocomplete_crossdomain_iframe.js]
--- a/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_02.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_02.js
@@ -1,54 +1,54 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test the inspector links in the webconsole output for DOM Nodes actually
-// open the inspector and select the right node
+// open the inspector and select the right node.
 
 "use strict";
 
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
                  "test/test-console-output-dom-elements.html";
 
 const TEST_DATA = [
   {
     // The first test shouldn't be returning the body element as this is the
     // default selected node, so re-selecting it won't fire the
     // inspector-updated event
     input: "testNode()",
     output: '<p some-attribute="some-value">',
-    tagName: "P",
+    displayName: "p",
     attrs: [{name: "some-attribute", value: "some-value"}]
   },
   {
     input: "testBodyNode()",
     output: '<body class="body-class" id="body-id">',
-    tagName: "BODY",
+    displayName: "body",
     attrs: [
       {
         name: "class", value: "body-class"
       },
       {
         name: "id", value: "body-id"
       }
     ]
   },
   {
     input: "testNodeInIframe()",
     output: "<p>",
-    tagName: "P",
+    displayName: "p",
     attrs: []
   },
   {
     input: "testDocumentElement()",
     output: '<html dir="ltr" lang="en-US">',
-    tagName: "HTML",
+    displayName: "html",
     attrs: [
       {
         name: "dir",
         value: "ltr"
       },
       {
         name: "lang",
         value: "en-US"
@@ -56,87 +56,11 @@ const TEST_DATA = [
     ]
   }
 ];
 
 function test() {
   Task.spawn(function* () {
     let {tab} = yield loadTab(TEST_URI);
     let hud = yield openConsole(tab);
-    let toolbox = gDevTools.getToolbox(hud.target);
-
-    // Loading the inspector panel at first, to make it possible to listen for
-    // new node selections
-    yield toolbox.selectTool("inspector");
-    let inspector = toolbox.getCurrentPanel();
-    yield toolbox.selectTool("webconsole");
-
-    info("Iterating over the test data");
-    for (let data of TEST_DATA) {
-      let [result] = yield jsEval(data.input, hud, {text: data.output});
-      let {msg} = yield getWidgetAndMessage(result);
-
-      let inspectorIcon = msg.querySelector(".open-inspector");
-      ok(inspectorIcon, "Inspector icon found in the ElementNode widget");
-
-      info("Clicking on the inspector icon and waiting for the " +
-           "inspector to be selected");
-      let onInspectorSelected = toolbox.once("inspector-selected");
-      let onInspectorUpdated = inspector.once("inspector-updated");
-      let onNewNode = toolbox.selection.once("new-node-front");
-      let onNodeHighlight = toolbox.once("node-highlight");
-
-      EventUtils.synthesizeMouseAtCenter(inspectorIcon, {},
-        inspectorIcon.ownerDocument.defaultView);
-      yield onInspectorSelected;
-      yield onInspectorUpdated;
-      yield onNodeHighlight;
-      let nodeFront = yield onNewNode;
-
-      ok(true, "Inspector selected and new node got selected");
-
-      is(nodeFront.tagName, data.tagName, "The correct node was highlighted");
-
-      let attrs = nodeFront.attributes;
-      for (let i in data.attrs) {
-        is(attrs[i].name, data.attrs[i].name,
-           "The correct node was highlighted");
-        is(attrs[i].value, data.attrs[i].value,
-           "The correct node was highlighted");
-      }
-
-      info("Unhighlight the node by moving away from the markup view");
-      let onNodeUnhighlight = toolbox.once("node-unhighlight");
-      let btn = inspector.toolbox.doc.querySelector(".toolbox-dock-button");
-      EventUtils.synthesizeMouseAtCenter(btn, {type: "mousemove"},
-        inspector.toolbox.win);
-      yield onNodeUnhighlight;
-
-      info("Switching back to the console");
-      yield toolbox.selectTool("webconsole");
-    }
+    yield checkDomElementHighlightingForInputs(hud, TEST_DATA);
   }).then(finishTest);
 }
-
-function jsEval(input, hud, message) {
-  info("Executing '" + input + "' in the web console");
-
-  hud.jsterm.clearOutput();
-  hud.jsterm.execute(input);
-
-  return waitForMessages({
-    webconsole: hud,
-    messages: [message]
-  });
-}
-
-function* getWidgetAndMessage(result) {
-  info("Getting the output ElementNode widget");
-
-  let msg = [...result.matched][0];
-  let widget = [...msg._messageObject.widgets][0];
-  ok(widget, "ElementNode widget found in the output");
-
-  info("Waiting for the ElementNode widget to be linked to the inspector");
-  yield widget.linkToInspector();
-
-  return {widget: widget, msg: msg};
-}
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_05.js
@@ -0,0 +1,47 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript 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 the inspector links in the webconsole output for namespaced elements
+// actually open the inspector and select the right node.
+
+const XHTML = `
+  <!DOCTYPE html>
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:svg="http://www.w3.org/2000/svg">
+    <body>
+      <svg:svg width="100" height="100">
+        <svg:clipPath id="clip">
+          <svg:rect id="rectangle" x="0" y="0" width="10" height="5"></svg:rect>
+        </svg:clipPath>
+        <svg:circle cx="0" cy="0" r="5"></svg:circle>
+      </svg:svg>
+    </body>
+  </html>
+`;
+
+const TEST_URI = "data:application/xhtml+xml;charset=utf-8," + encodeURI(XHTML);
+
+const TEST_DATA = [
+  {
+    input: 'document.querySelector("clipPath")',
+    output: '<svg:clipPath id="clip">',
+    displayName: "svg:clipPath"
+  },
+  {
+    input: 'document.querySelector("circle")',
+    output: '<svg:circle cx="0" cy="0" r="5">',
+    displayName: "svg:circle"
+  },
+];
+
+function test() {
+  Task.spawn(function* () {
+    let {tab} = yield loadTab(TEST_URI);
+    let hud = yield openConsole(tab);
+    yield checkDomElementHighlightingForInputs(hud, TEST_DATA);
+  }).then(finishTest);
+}
--- a/devtools/client/webconsole/test/head.js
+++ b/devtools/client/webconsole/test/head.js
@@ -1579,16 +1579,124 @@ function checkOutputForInputs(hud, input
          "opened tab '" + uri + "', expected tab '" + entry.expectedTab + "'");
       yield closeTab(tab);
     }).then(resolve, reject);
   }
 
   return Task.spawn(runner);
 }
 
+/**
+ * Check the web console DOM element output for the given inputs.
+ * Each input is checked for the expected JS eval result. The JS eval result is
+ * also checked if it opens the inspector with the correct node selected on
+ * inspector icon click
+ *
+ * @param object hud
+ *        The web console instance to work with.
+ * @param array inputTests
+ *        An array of input tests. An input test element is an object. Each
+ *        object has the following properties:
+ *        - input: string, JS input value to execute.
+ *
+ *        - output: string, expected JS eval result.
+ *
+ *        - displayName: string, expected NodeFront's displayName.
+ *
+ *        - attr: Array, expected NodeFront's attributes
+ */
+function checkDomElementHighlightingForInputs(hud, inputs) {
+  function* runner() {
+    let toolbox = gDevTools.getToolbox(hud.target);
+
+    // Loading the inspector panel at first, to make it possible to listen for
+    // new node selections
+    yield toolbox.selectTool("inspector");
+    let inspector = toolbox.getCurrentPanel();
+    yield toolbox.selectTool("webconsole");
+
+    info("Iterating over the test data");
+    for (let data of inputs) {
+      let [result] = yield jsEval(data.input, {text: data.output});
+      let {msg} = yield checkWidgetAndMessage(result);
+      yield checkNodeHighlight(toolbox, inspector, msg, data);
+    }
+  }
+
+  function jsEval(input, message) {
+    info("Executing '" + input + "' in the web console");
+
+    hud.jsterm.clearOutput();
+    hud.jsterm.execute(input);
+
+    return waitForMessages({
+      webconsole: hud,
+      messages: [message]
+    });
+  }
+
+  function* checkWidgetAndMessage(result) {
+    info("Getting the output ElementNode widget");
+
+    let msg = [...result.matched][0];
+    let widget = [...msg._messageObject.widgets][0];
+    ok(widget, "ElementNode widget found in the output");
+
+    info("Waiting for the ElementNode widget to be linked to the inspector");
+    yield widget.linkToInspector();
+
+    return {widget, msg};
+  }
+
+  function* checkNodeHighlight(toolbox, inspector, msg, testData) {
+    let inspectorIcon = msg.querySelector(".open-inspector");
+    ok(inspectorIcon, "Inspector icon found in the ElementNode widget");
+
+    info("Clicking on the inspector icon and waiting for the " +
+         "inspector to be selected");
+    let onInspectorSelected = toolbox.once("inspector-selected");
+    let onInspectorUpdated = inspector.once("inspector-updated");
+    let onNewNode = toolbox.selection.once("new-node-front");
+    let onNodeHighlight = toolbox.once("node-highlight");
+
+    EventUtils.synthesizeMouseAtCenter(inspectorIcon, {},
+      inspectorIcon.ownerDocument.defaultView);
+    yield onInspectorSelected;
+    yield onInspectorUpdated;
+    yield onNodeHighlight;
+    let nodeFront = yield onNewNode;
+
+    ok(true, "Inspector selected and new node got selected");
+
+    is(nodeFront.displayName, testData.displayName,
+      "The correct node was highlighted");
+
+    if (testData.attrs) {
+      let attrs = nodeFront.attributes;
+      for (let i in testData.attrs) {
+        is(attrs[i].name, testData.attrs[i].name,
+           "Expected attribute's name is present");
+        is(attrs[i].value, testData.attrs[i].value,
+           "Expected attribute's value is present");
+      }
+    }
+
+    info("Unhighlight the node by moving away from the markup view");
+    let onNodeUnhighlight = toolbox.once("node-unhighlight");
+    let btn = inspector.toolbox.doc.querySelector(".toolbox-dock-button");
+    EventUtils.synthesizeMouseAtCenter(btn, {type: "mousemove"},
+      inspector.toolbox.win);
+    yield onNodeUnhighlight;
+
+    info("Switching back to the console");
+    yield toolbox.selectTool("webconsole");
+  }
+
+  return Task.spawn(runner);
+}
 
 /**
  * Finish the request and resolve with the request object.
  *
  * @param {Function} predicate A predicate function that takes the request
  * object as an argument and returns true if the request was the expected one,
  * false otherwise. The returned promise is resolved ONLY if the predicate
  * matches a request. Defaults to accepting any request.