Bug 1139187 - Unit Test for Geometry Editor; r=pbro draft
authorMatteo Ferretti <mferretti@mozilla.com>
Thu, 17 Mar 2016 10:59:39 -0400
changeset 345858 ee5329e825e4d37763e6e351f383d381574b33cb
parent 345857 f2b398dac98c9735bb228b40667884df6558c3ea
child 346180 852fc6f5d8bb5c05343a7d0211bace9da4ca73d7
push id14186
push userbmo:zer0@mozilla.com
push dateWed, 30 Mar 2016 14:42:09 +0000
reviewerspbro
bugs1139187
milestone48.0a1
Bug 1139187 - Unit Test for Geometry Editor; r=pbro MozReview-Commit-ID: 9smoBjNt1St
devtools/client/inspector/test/browser_inspector_highlighter-geometry_01.js
devtools/client/inspector/test/browser_inspector_highlighter-geometry_02.js
devtools/client/inspector/test/browser_inspector_highlighter-geometry_03.js
devtools/client/inspector/test/browser_inspector_highlighter-geometry_04.js
devtools/client/inspector/test/browser_inspector_highlighter-geometry_05.js
devtools/client/inspector/test/doc_inspector_highlighter-geometry_01.html
devtools/client/inspector/test/head.js
devtools/client/shared/test/test-actor.js
--- a/devtools/client/inspector/test/browser_inspector_highlighter-geometry_01.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-geometry_01.js
@@ -1,95 +1,89 @@
 /* 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";
 
 // Test the creation of the geometry highlighter elements.
 
-const TEST_URL = "data:text/html;charset=utf-8," +
-                 "<span id='inline'></span>" +
-                 "<div id='positioned' style='background:yellow;position:absolute;left:5rem;top:30px;right:300px;bottom:10em;'></div>" +
-                 "<div id='sized' style='background:red;width:5em;height:50%;'></div>";
+const TEST_URL = `data:text/html;charset=utf-8,
+                  <span id='inline'></span>
+                  <div id='positioned' style='
+                    background:yellow;
+                    position:absolute;
+                    left:5rem;
+                    top:30px;
+                    right:300px;
+                    bottom:10em;'></div>
+                  <div id='sized' style='
+                    background:red;
+                    width:5em;
+                    height:50%;'></div>`;
+
+const HIGHLIGHTER_TYPE = "GeometryEditorHighlighter";
+
 const ID = "geometry-editor-";
 const SIDES = ["left", "right", "top", "bottom"];
-const SIZES = ["width", "height"];
 
-add_task(function*() {
-  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
-  let front = inspector.inspector;
+add_task(function* () {
+  let helper = yield openInspectorForURL(TEST_URL)
+                       .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
+
+  let { finalize } = helper;
 
-  let highlighter = yield front.getHighlighterByType("GeometryEditorHighlighter");
+  helper.prefix = ID;
 
-  yield hasArrowsAndLabels(highlighter, inspector, testActor);
-  yield isHiddenForNonPositionedNonSizedElement(highlighter, inspector, testActor);
-  yield sideArrowsAreDisplayedForPositionedNode(highlighter, inspector, testActor);
-  yield sizeLabelIsDisplayedForSizedNode(highlighter, inspector, testActor);
+  yield hasArrowsAndLabelsAndHandlers(helper);
+  yield isHiddenForNonPositionedNonSizedElement(helper);
+  yield sideArrowsAreDisplayedForPositionedNode(helper);
 
-  yield highlighter.finalize();
+  finalize();
 });
 
-function* hasArrowsAndLabels(highlighterFront, inspector, testActor) {
+function* hasArrowsAndLabelsAndHandlers({getElementAttribute}) {
   info("Checking that the highlighter has the expected arrows and labels");
 
   for (let name of [...SIDES]) {
-    let value = yield testActor.getHighlighterNodeAttribute(ID + "arrow-" + name, "class", highlighterFront);
+    let value = yield getElementAttribute("arrow-" + name, "class");
     is(value, ID + "arrow " + name, "The " + name + " arrow exists");
 
-    value = yield testActor.getHighlighterNodeAttribute(ID + "label-text-" + name, "class", highlighterFront);
+    value = yield getElementAttribute("label-text-" + name, "class");
     is(value, ID + "label-text", "The " + name + " label exists");
-  }
-
-  let value = yield testActor.getHighlighterNodeAttribute(ID + "label-text-size", "class", highlighterFront);
-  is(value, ID + "label-text", "The size label exists");
-}
-
-function* isHiddenForNonPositionedNonSizedElement(highlighterFront, inspector, testActor) {
-  info("Asking to show the highlighter on an inline, non positioned element");
 
-  let node = yield getNodeFront("#inline", inspector);
-  yield highlighterFront.show(node);
-
-  for (let name of [...SIDES]) {
-    let hidden = yield testActor.getHighlighterNodeAttribute(ID + "arrow-" + name, "hidden", highlighterFront);
-    is(hidden, "true", "The " + name + " arrow is hidden");
+    value = yield getElementAttribute("handler-" + name, "class");
+    is(value, ID + "handler-" + name, "The " + name + " handler exists");
   }
-
-  let hidden = yield testActor.getHighlighterNodeAttribute(ID + "label-size", "hidden", highlighterFront);
-  is(hidden, "true", "The size label is hidden");
 }
 
-function* sideArrowsAreDisplayedForPositionedNode(highlighterFront, inspector, testActor) {
+function* isHiddenForNonPositionedNonSizedElement(
+  {show, hide, isElementHidden}) {
+  info("Asking to show the highlighter on an inline, non p  ositioned element");
+
+  yield show("#inline");
+
+  for (let name of [...SIDES]) {
+    let hidden = yield isElementHidden("arrow-" + name);
+    ok(hidden, "The " + name + " arrow is hidden");
+
+    hidden = yield isElementHidden("handler-" + name);
+    ok(hidden, "The " + name + " handler is hidden");
+  }
+}
+
+function* sideArrowsAreDisplayedForPositionedNode(
+  {show, hide, isElementHidden}) {
   info("Asking to show the highlighter on the positioned node");
 
-  let node = yield getNodeFront("#positioned", inspector);
-  yield highlighterFront.show(node);
+  yield show("#positioned");
 
   for (let name of SIDES) {
-    let hidden = yield testActor.getHighlighterNodeAttribute(ID + "arrow-" + name, "hidden", highlighterFront);
+    let hidden = yield isElementHidden("arrow-" + name);
     ok(!hidden, "The " + name + " arrow is visible for the positioned node");
-  }
-
-  let hidden = yield testActor.getHighlighterNodeAttribute(ID + "label-size", "hidden", highlighterFront);
-  is(hidden, "true", "The size label is hidden");
-
-  info("Hiding the highlighter");
-  yield highlighterFront.hide();
-}
 
-function* sizeLabelIsDisplayedForSizedNode(highlighterFront, inspector, testActor) {
-  info("Asking to show the highlighter on the sized node");
-
-  let node = yield getNodeFront("#sized", inspector);
-  yield highlighterFront.show(node);
-
-  let hidden = yield testActor.getHighlighterNodeAttribute(ID + "label-size", "hidden", highlighterFront);
-  ok(!hidden, "The size label is visible");
-
-  for (let name of SIDES) {
-    let hidden = yield testActor.getHighlighterNodeAttribute(ID + "arrow-" + name, "hidden", highlighterFront);
-    is(hidden, "true", "The " + name + " arrow is hidden for the sized node");
+    hidden = yield isElementHidden("handler-" + name);
+    ok(!hidden, "The " + name + " handler is visible for the positioned node");
   }
 
   info("Hiding the highlighter");
-  yield highlighterFront.hide();
+  yield hide();
 }
--- a/devtools/client/inspector/test/browser_inspector_highlighter-geometry_02.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-geometry_02.js
@@ -1,24 +1,48 @@
 /* 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/. */
 
+/* Globals defined in: devtools/client/inspector/test/head.js */
+
 "use strict";
 
 // Test that the geometry highlighter labels are correct.
 
-const TEST_URL = "data:text/html;charset=utf-8," +
-                 "<div id='positioned' style='background:yellow;position:absolute;left:5rem;top:30px;right:300px;bottom:10em;'></div>" +
-                 "<div id='positioned2' style='background:blue;position:absolute;right:10%;top:5vmin;'>test element</div>" +
-                 "<div id='relative' style='background:green;position:relative;top:10px;left:20px;bottom:30px;right:40px;width:100px;height:100px;'></div>" +
-                 "<div id='relative2' style='background:grey;position:relative;top:0;bottom:-50px;height:3em;'>relative</div>" +
-                 "<div id='sized' style='background:red;width:5em;height:50%;'></div>" +
-                 "<div id='sized2' style='background:orange;width:40px;position:absolute;right:0;bottom:0'>wow</div>";
+const TEST_URL = `data:text/html;charset=utf-8,
+                  <div id='positioned' style='
+                    background:yellow;
+                    position:absolute;
+                    left:5rem;
+                    top:30px;
+                    right:300px;
+                    bottom:10em;'></div>
+                  <div id='positioned2' style='
+                    background:blue;
+                    position:absolute;
+                    right:10%;
+                    top:5vmin;'>test element</div>
+                 <div id='relative' style='
+                    background:green;
+                    position:relative;
+                    top:10px;
+                    left:20px;
+                    bottom:30px;
+                    right:40px;
+                    width:100px;
+                    height:100px;'></div>
+                 <div id='relative2' style='
+                    background:grey;
+                    position:relative;
+                    top:0;bottom:-50px;
+                    height:3em;'>relative</div>`;
+
 const ID = "geometry-editor-";
+const HIGHLIGHTER_TYPE = "GeometryEditorHighlighter";
 
 const POSITIONED_ELEMENT_TESTS = [{
   selector: "#positioned",
   expectedLabels: [
     {side: "left", visible: true, label: "5rem"},
     {side: "top", visible: true, label: "30px"},
     {side: "right", visible: true, label: "300px"},
     {side: "bottom", visible: true, label: "10em"}
@@ -27,24 +51,16 @@ const POSITIONED_ELEMENT_TESTS = [{
   selector: "#positioned2",
   expectedLabels: [
     {side: "left", visible: false},
     {side: "top", visible: true, label: "5vmin"},
     {side: "right", visible: true, label: "10%"},
     {side: "bottom", visible: false}
   ]
 }, {
-  selector: "#sized",
-  expectedLabels: [
-    {side: "left", visible: false},
-    {side: "top", visible: false},
-    {side: "right", visible: false},
-    {side: "bottom", visible: false}
-  ]
-}, {
   selector: "#relative",
   expectedLabels: [
     {side: "left", visible: true, label: "20px"},
     {side: "top", visible: true, label: "10px"},
     {side: "right", visible: false},
     {side: "bottom", visible: false}
   ]
 }, {
@@ -52,91 +68,49 @@ const POSITIONED_ELEMENT_TESTS = [{
   expectedLabels: [
     {side: "left", visible: false},
     {side: "top", visible: true, label: "0px"},
     {side: "right", visible: false},
     {side: "bottom", visible: false}
   ]
 }];
 
-const SIZED_ELEMENT_TESTS = [{
-  selector: "#positioned",
-  visible: false
-}, {
-  selector: "#sized",
-  visible: true,
-  expected: "\u2194 5em \u2195 50%"
-}, {
-  selector: "#relative",
-  visible: true,
-  expected: "\u2194 100px \u2195 100px"
-}, {
-  selector: "#relative2",
-  visible: true,
-  expected: "\u2195 3em"
-}, {
-  selector: "#sized2",
-  visible: true,
-  expected: "\u2194 40px"
-}];
+add_task(function* () {
+  let helper = yield openInspectorForURL(TEST_URL)
+                       .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
+
+  helper.prefix = ID;
 
-add_task(function*() {
-  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
-  let front = inspector.inspector;
+  let { finalize } = helper;
 
-  let highlighter = yield front.getHighlighterByType("GeometryEditorHighlighter");
+  yield positionLabelsAreCorrect(helper);
 
-  yield positionLabelsAreCorrect(highlighter, inspector, testActor);
-  yield sizeLabelIsCorrect(highlighter, inspector, testActor);
-
-  yield highlighter.finalize();
+  yield finalize();
 });
 
-function* positionLabelsAreCorrect(highlighterFront, inspector, testActor) {
+function* positionLabelsAreCorrect(
+  {show, hide, isElementHidden, getElementTextContent}
+) {
   info("Highlight nodes and check position labels");
 
   for (let {selector, expectedLabels} of POSITIONED_ELEMENT_TESTS) {
     info("Testing node " + selector);
-    let node = yield getNodeFront(selector, inspector);
-    yield highlighterFront.show(node);
+
+    yield show(selector);
 
     for (let {side, visible, label} of expectedLabels) {
-      let id = ID + "label-" + side;
+      let id = "label-" + side;
 
-      let hidden = yield testActor.getHighlighterNodeAttribute(id, "hidden", highlighterFront);
+      let hidden = yield isElementHidden(id);
       if (visible) {
         ok(!hidden, "The " + side + " label is visible");
 
-        let value = yield testActor.getHighlighterNodeTextContent(id, highlighterFront);
+        let value = yield getElementTextContent(id);
         is(value, label, "The " + side + " label textcontent is correct");
       } else {
-        is(hidden, "true", "The " + side + " label is hidden");
+        ok(hidden, "The " + side + " label is hidden");
       }
     }
 
     info("Hiding the highlighter");
-    yield highlighterFront.hide();
+    yield hide();
   }
 }
-
-function* sizeLabelIsCorrect(highlighterFront, inspector, testActor) {
-  info("Highlight nodes and check size labels");
-
-  let id = ID + "label-size";
-  for (let {selector, visible, expected} of SIZED_ELEMENT_TESTS) {
-    info("Testing node " + selector);
-    let node = yield getNodeFront(selector, inspector);
-    yield highlighterFront.show(node);
-
-    let hidden = yield testActor.getHighlighterNodeAttribute(id, "hidden", highlighterFront);
-    if (!visible) {
-      is(hidden, "true", "The size label is hidden");
-    } else {
-      ok(!hidden, "The size label is visible");
-
-      let label = yield testActor.getHighlighterNodeTextContent(id, highlighterFront);
-      is(label, expected, "The size label textcontent is correct");
-    }
-
-    info("Hiding the highlighter");
-    yield highlighterFront.hide();
-  }
-}
--- a/devtools/client/inspector/test/browser_inspector_highlighter-geometry_03.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-geometry_03.js
@@ -1,60 +1,61 @@
 /* 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/. */
 
+/* Globals defined in: devtools/client/inspector/test/head.js */
+
 "use strict";
 
 // Test that the right arrows/labels are shown even when the css properties are
 // in several different css rules.
 
 const TEST_URL = URL_ROOT + "doc_inspector_highlighter-geometry_01.html";
 const ID = "geometry-editor-";
+const HIGHLIGHTER_TYPE = "GeometryEditorHighlighter";
 const PROPS = ["left", "right", "top", "bottom"];
 
-add_task(function*() {
-  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
-  let front = inspector.inspector;
+add_task(function* () {
+  let helper = yield openInspectorForURL(TEST_URL)
+                       .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
 
-  let highlighter = yield front.getHighlighterByType("GeometryEditorHighlighter");
+  helper.prefix = ID;
+
+  let { finalize } = helper;
 
-  yield checkArrowsLabels("#node1", ["size"],
-                          highlighter, inspector, testActor);
+  yield checkArrowsLabelsAndHandlers(
+    "#node2", ["top", "left", "bottom", "right"],
+     helper);
 
-  yield checkArrowsLabels("#node2", ["top", "left", "bottom", "right"],
-                          highlighter, inspector, testActor);
+  yield checkArrowsLabelsAndHandlers("#node3", ["top", "left"], helper);
 
-  yield checkArrowsLabels("#node3", ["top", "left", "size"],
-                          highlighter, inspector, testActor);
-
-  yield highlighter.finalize();
+  yield finalize();
 });
 
-function* checkArrowsLabels(selector, expectedProperties, highlighterFront, inspector, testActor) {
+function* checkArrowsLabelsAndHandlers(selector, expectedProperties,
+  {show, hide, isElementHidden}
+) {
   info("Getting node " + selector + " from the page");
-  let node = yield getNodeFront(selector, inspector);
 
-  info("Highlighting the node");
-  yield highlighterFront.show(node);
+  yield show(selector);
 
   for (let name of expectedProperties) {
-    let hidden;
-    if (name === "size") {
-      hidden = yield testActor.getHighlighterNodeAttribute(ID + "label-size", "hidden", highlighterFront);
-    } else {
-      hidden = yield testActor.getHighlighterNodeAttribute(ID + "arrow-" + name, "hidden", highlighterFront);
-    }
-    ok(!hidden, "The " + name + " arrow/label is visible for node " + selector);
+    let hidden = (yield isElementHidden("arrow-" + name)) &&
+                 (yield isElementHidden("handler-" + name));
+    ok(!hidden,
+      "The " + name + " label/arrow & handler is visible for node " + selector);
   }
 
   // Testing that the other arrows are hidden
   for (let name of PROPS) {
     if (expectedProperties.indexOf(name) !== -1) {
       continue;
     }
-    let hidden = yield testActor.getHighlighterNodeAttribute(ID + "arrow-" + name, "hidden", highlighterFront);
-    is(hidden, "true", "The " + name + " arrow is hidden for node " + selector);
+    let hidden = (yield isElementHidden("arrow-" + name)) &&
+                 (yield isElementHidden("handler-" + name));
+    ok(hidden,
+      "The " + name + " arrow & handler is hidden for node " + selector);
   }
 
   info("Hiding the highlighter");
-  yield highlighterFront.hide();
+  yield hide();
 }
--- a/devtools/client/inspector/test/browser_inspector_highlighter-geometry_04.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-geometry_04.js
@@ -1,56 +1,85 @@
 /* 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/. */
 
+ /* Globals defined in: devtools/client/inspector/test/head.js */
+
 "use strict";
 
-// Test that the arrows are positioned correctly and have the right size.
+// Test that the arrows and handlers are positioned correctly and have the right
+// size.
 
 const TEST_URL = URL_ROOT + "doc_inspector_highlighter-geometry_01.html";
 const ID = "geometry-editor-";
+const HIGHLIGHTER_TYPE = "GeometryEditorHighlighter";
 
-add_task(function*() {
-  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
-  let front = inspector.inspector;
+const handlerMap = {
+  "top": {"cx": "x2", "cy": "y2"},
+  "bottom": {"cx": "x2", "cy": "y2"},
+  "left": {"cx": "x2", "cy": "y2"},
+  "right": {"cx": "x2", "cy": "y2"}
+};
 
-  let highlighter = yield front.getHighlighterByType("GeometryEditorHighlighter");
+add_task(function* () {
+  let helper = yield openInspectorForURL(TEST_URL)
+                       .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
+
+  helper.prefix = ID;
 
-  yield checkArrows(highlighter, inspector, testActor, ".absolute-all-4", {
-   "top": {x1: 506, y1: 51, x2: 506, y2: 61},
-   "bottom": {x1: 506, y1: 451, x2: 506, y2: 251},
-   "left": {x1: 401, y1: 156, x2: 411, y2: 156},
-   "right": {x1: 901, y1: 156, x2: 601, y2: 156}
+  let { hide, finalize } = helper;
+
+  yield checkArrowsAndHandlers(helper, ".absolute-all-4", {
+    "top": {x1: 506, y1: 51, x2: 506, y2: 61},
+    "bottom": {x1: 506, y1: 451, x2: 506, y2: 251},
+    "left": {x1: 401, y1: 156, x2: 411, y2: 156},
+    "right": {x1: 901, y1: 156, x2: 601, y2: 156}
   });
 
-  yield checkArrows(highlighter, inspector, testActor, ".relative", {
-   "top": {x1: 901, y1: 51, x2: 901, y2: 91},
-   "left": {x1: 401, y1: 97, x2: 651, y2: 97}
+  yield checkArrowsAndHandlers(helper, ".relative", {
+    "top": {x1: 901, y1: 51, x2: 901, y2: 91},
+    "left": {x1: 401, y1: 97, x2: 651, y2: 97}
   });
 
-  yield checkArrows(highlighter, inspector, testActor, ".fixed", {
-   "top": {x1: 25, y1: 0, x2: 25, y2: 400},
-   "left": {x1: 0, y1: 425, x2: 0, y2: 425}
+  yield checkArrowsAndHandlers(helper, ".fixed", {
+    "top": {x1: 25, y1: 0, x2: 25, y2: 400},
+    "left": {x1: 0, y1: 425, x2: 0, y2: 425}
   });
 
   info("Hiding the highlighter");
-  yield highlighter.hide();
-  yield highlighter.finalize();
+  yield hide();
+  yield finalize();
 });
 
-function* checkArrows(highlighter, inspector, testActor, selector, arrows) {
+function* checkArrowsAndHandlers(helper, selector, arrows) {
   info("Highlighting the test node " + selector);
-  let node = yield getNodeFront(selector, inspector);
-  yield highlighter.show(node);
+
+  yield helper.show(selector);
 
   for (let side in arrows) {
-    yield checkArrow(highlighter, testActor, side, arrows[side]);
+    yield checkArrowAndHandler(helper, side, arrows[side]);
   }
 }
 
-function* checkArrow(highlighter, testActor, name, expectedCoordinates) {
-  for (let coordinate in expectedCoordinates) {
-    let value = yield testActor.getHighlighterNodeAttribute(ID + "arrow-" + name, coordinate, highlighter);
-    is(Math.floor(value), expectedCoordinates[coordinate],
+function* checkArrowAndHandler({getElementAttribute}, name, expectedCoords) {
+  info("Checking " + name + "arrow and handler coordinates are correct");
+
+  let handlerX = yield getElementAttribute("handler-" + name, "cx");
+  let handlerY = yield getElementAttribute("handler-" + name, "cy");
+
+  let expectedHandlerX = yield getElementAttribute("arrow-" + name,
+                                handlerMap[name].cx);
+  let expectedHandlerY = yield getElementAttribute("arrow-" + name,
+                                handlerMap[name].cy);
+
+  is(handlerX, expectedHandlerX,
+    "coordinate X for handler " + name + " is correct.");
+  is(handlerY, expectedHandlerY,
+    "coordinate Y for handler " + name + " is correct.");
+
+  for (let coordinate in expectedCoords) {
+    let value = yield getElementAttribute("arrow-" + name, coordinate);
+
+    is(Math.floor(value), expectedCoords[coordinate],
       coordinate + " coordinate for arrow " + name + " is correct");
   }
 }
--- a/devtools/client/inspector/test/browser_inspector_highlighter-geometry_05.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-geometry_05.js
@@ -1,134 +1,119 @@
 /* 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/. */
 
+ /* Globals defined in: devtools/client/inspector/test/head.js */
+
 "use strict";
 
-// Test that the arrows and offsetparent and currentnode elements of the
-// geometry highlighter only appear when needed.
+// Test that the arrows/handlers and offsetparent and currentnode elements of
+// the geometry highlighter only appear when needed.
 
 const TEST_URL = URL_ROOT + "doc_inspector_highlighter-geometry_02.html";
 const ID = "geometry-editor-";
+const HIGHLIGHTER_TYPE = "GeometryEditorHighlighter";
 
 const TEST_DATA = [{
   selector: "body",
   isOffsetParentVisible: false,
   isCurrentNodeVisible: false,
-  hasVisibleArrows: false,
-  isSizeVisible: false
+  hasVisibleArrowsAndHandlers: false
 }, {
   selector: "h1",
   isOffsetParentVisible: false,
   isCurrentNodeVisible: false,
-  hasVisibleArrows: false,
-  isSizeVisible: false
+  hasVisibleArrowsAndHandlers: false
 }, {
   selector: ".absolute",
   isOffsetParentVisible: false,
   isCurrentNodeVisible: true,
-  hasVisibleArrows: true,
-  isSizeVisible: false
+  hasVisibleArrowsAndHandlers: true
 }, {
   selector: "#absolute-container",
   isOffsetParentVisible: false,
   isCurrentNodeVisible: true,
-  hasVisibleArrows: false,
-  isSizeVisible: true
+  hasVisibleArrowsAndHandlers: false
 }, {
   selector: ".absolute-bottom-right",
   isOffsetParentVisible: true,
   isCurrentNodeVisible: true,
-  hasVisibleArrows: true,
-  isSizeVisible: false
+  hasVisibleArrowsAndHandlers: true
 }, {
   selector: ".absolute-width-margin",
   isOffsetParentVisible: true,
   isCurrentNodeVisible: true,
-  hasVisibleArrows: true,
-  isSizeVisible: true
+  hasVisibleArrowsAndHandlers: true
 }, {
   selector: ".absolute-all-4",
   isOffsetParentVisible: true,
   isCurrentNodeVisible: true,
-  hasVisibleArrows: true,
-  isSizeVisible: false
+  hasVisibleArrowsAndHandlers: true
 }, {
   selector: ".relative",
   isOffsetParentVisible: true,
   isCurrentNodeVisible: true,
-  hasVisibleArrows: true,
-  isSizeVisible: false
+  hasVisibleArrowsAndHandlers: true
 }, {
   selector: ".static",
   isOffsetParentVisible: false,
   isCurrentNodeVisible: false,
-  hasVisibleArrows: false,
-  isSizeVisible: false
+  hasVisibleArrowsAndHandlers: false
 }, {
   selector: ".static-size",
   isOffsetParentVisible: false,
   isCurrentNodeVisible: true,
-  hasVisibleArrows: false,
-  isSizeVisible: true
+  hasVisibleArrowsAndHandlers: false
 }, {
   selector: ".fixed",
   isOffsetParentVisible: false,
   isCurrentNodeVisible: true,
-  hasVisibleArrows: true,
-  isSizeVisible: false
+  hasVisibleArrowsAndHandlers: true
 }];
 
-add_task(function*() {
-  let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
-  let front = inspector.inspector;
+add_task(function* () {
+  let helper = yield openInspectorForURL(TEST_URL)
+                       .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
 
-  let highlighter = yield front.getHighlighterByType("GeometryEditorHighlighter");
+  helper.prefix = ID;
+
+  let { hide, finalize } = helper;
 
   for (let data of TEST_DATA) {
-    yield testNode(inspector, highlighter, testActor, data);
+    yield testNode(helper, data);
   }
 
   info("Hiding the highlighter");
-  yield highlighter.hide();
-  yield highlighter.finalize();
+  yield hide();
+  yield finalize();
 });
 
-function* testNode(inspector, highlighter, testActor, data) {
-  info("Highlighting the test node " + data.selector);
-  let node = yield getNodeFront(data.selector, inspector);
-  yield highlighter.show(node);
+function* testNode(helper, data) {
+  let { selector } = data;
+  yield helper.show(data.selector);
 
-  is((yield isOffsetParentVisible(highlighter, testActor)), data.isOffsetParentVisible,
-    "The offset-parent highlighter visibility is correct for node " + data.selector);
-  is((yield isCurrentNodeVisible(highlighter, testActor)), data.isCurrentNodeVisible,
-    "The current-node highlighter visibility is correct for node " + data.selector);
-  is((yield hasVisibleArrows(highlighter, testActor)), data.hasVisibleArrows,
-    "The arrows visibility is correct for node " + data.selector);
-  is((yield isSizeVisible(highlighter, testActor)), data.isSizeVisible,
-    "The size label visibility is correct for node " + data.selector);
+  is((yield isOffsetParentVisible(helper)), data.isOffsetParentVisible,
+    "The offset-parent highlighter visibility is correct for node " + selector);
+  is((yield isCurrentNodeVisible(helper)), data.isCurrentNodeVisible,
+    "The current-node highlighter visibility is correct for node " + selector);
+  is((yield hasVisibleArrowsAndHandlers(helper)),
+    data.hasVisibleArrowsAndHandlers,
+    "The arrows visibility is correct for node " + selector);
 }
 
-function* isOffsetParentVisible(highlighter, testActor) {
-  let hidden = yield testActor.getHighlighterNodeAttribute(ID + "offset-parent", "hidden", highlighter);
-  return !hidden;
+function* isOffsetParentVisible({isElementHidden}) {
+  return !(yield isElementHidden("offset-parent"));
 }
 
-function* isCurrentNodeVisible(highlighter, testActor) {
-  let hidden = yield testActor.getHighlighterNodeAttribute(ID + "current-node", "hidden", highlighter);
-  return !hidden;
+function* isCurrentNodeVisible({isElementHidden}) {
+  return !(yield isElementHidden("current-node"));
 }
 
-function* hasVisibleArrows(highlighter, testActor) {
+function* hasVisibleArrowsAndHandlers({isElementHidden}) {
   for (let side of ["top", "left", "bottom", "right"]) {
-    let hidden = yield testActor.getHighlighterNodeAttribute(ID + "arrow-" + side, "hidden", highlighter);
+    let hidden = yield isElementHidden("arrow-" + side);
     if (!hidden) {
-      return true;
+      return !(yield isElementHidden("handler-" + side));
     }
   }
   return false;
 }
-
-function* isSizeVisible(highlighter, testActor) {
-  let hidden = yield testActor.getHighlighterNodeAttribute(ID + "label-size", "hidden", highlighter);
-  return !hidden;
-}
--- a/devtools/client/inspector/test/doc_inspector_highlighter-geometry_01.html
+++ b/devtools/client/inspector/test/doc_inspector_highlighter-geometry_01.html
@@ -23,17 +23,17 @@
       position: absolute;
       background: #f06;
     }
     .pos-top-left {
       top: 30px;
       left: 25%;
     }
     .pos-bottom-right {
-      bottom: 5em;
+      bottom: 10em;
       right: -10px;
     }
 
     .inline-positioned {
       background: yellow;
     }
 
     #absolute-container {
--- a/devtools/client/inspector/test/head.js
+++ b/devtools/client/inspector/test/head.js
@@ -470,24 +470,46 @@ function* getNodeFrontForSelector(select
  */
 const getHighlighterHelperFor = (type) => Task.async(
   function*({inspector, testActor}) {
     let front = inspector.inspector;
     let highlighter = yield front.getHighlighterByType(type);
 
     let prefix = "";
 
+    // Internals for mouse events
+    let prevX, prevY;
+
+    // Highlighted node
+    let  highlightedNode = null;
+
     return {
       set prefix(value) {
         prefix = value;
       },
+      get highlightedNode() {
+        if (!highlightedNode) {
+          return null;
+        }
+
+        return {
+          getComputedStyle: function*(options = {}) {
+            return yield inspector.pageStyle.getComputed(
+              highlightedNode, options);
+          }
+        };
+      },
 
       show: function*(selector = ":root") {
-        let node = yield getNodeFront(selector, inspector);
-        yield highlighter.show(node);
+        highlightedNode = yield getNodeFront(selector, inspector);
+        return yield highlighter.show(highlightedNode);
+      },
+
+      hide: function*() {
+        yield highlighter.hide();
       },
 
       isElementHidden: function*(id) {
         return (yield testActor.getHighlighterNodeAttribute(
           prefix + id, "hidden", highlighter)) === "true";
       },
 
       getElementTextContent: function*(id) {
@@ -496,20 +518,45 @@ const getHighlighterHelperFor = (type) =
       },
 
       getElementAttribute: function*(id, name) {
         return yield testActor.getHighlighterNodeAttribute(
           prefix + id, name, highlighter);
       },
 
       synthesizeMouse: function*(options) {
+        options = Object.assign({selector: ":root"}, options);
         yield testActor.synthesizeMouse(options);
       },
 
+      // This object will synthesize any "mouse" prefixed event to the
+      // `testActor`, using the name of method called as suffix for the
+      // event's name.
+      // If no x, y coords are given, the previous ones are used.
+      //
+      // For example:
+      //   mouse.down(10, 20); // synthesize "mousedown" at 10,20
+      //   mouse.move(20, 30); // synthesize "mousemove" at 20,30
+      //   mouse.up();         // synthesize "mouseup" at 20,30
+      mouse: new Proxy({}, {
+        get: (target, name) =>
+          function*(x = prevX, y = prevY) {
+            prevX = x;
+            prevY = y;
+            yield testActor.synthesizeMouse({
+              selector: ":root", x, y, options: {type: "mouse" + name}});
+          }
+      }),
+
+      reflow: function*() {
+        yield testActor.reflow();
+      },
+
       finalize: function*() {
+        highlightedNode = null;
         yield highlighter.finalize();
       }
     };
   }
 );
 
 // The expand all operation of the markup-view calls itself recursively and
 // there's not one event we can wait for to know when it's done
--- a/devtools/client/shared/test/test-actor.js
+++ b/devtools/client/shared/test/test-actor.js
@@ -615,16 +615,27 @@ var TestActor = exports.TestActor = prot
       y: Arg(1, "number"),
       relative: Arg(2, "nullable:boolean"),
     },
     response: {
       value: RetVal("json")
     }
   }),
 
+  /**
+   * Forces the reflow and waits for the next repaint.
+   */
+  reflow: protocol.method(function () {
+    let deferred = promise.defer();
+    this.content.document.documentElement.offsetWidth;
+    this.content.requestAnimationFrame(deferred.resolve);
+
+    return deferred.promise;
+  }),
+
   getNodeRect: protocol.method(Task.async(function* (selector) {
     let node = this._querySelector(selector);
     return getRect(this.content, node, this.content);
   }), {
     request: {
       selector: Arg(0, "string")
     },
     response: {