Bug 1435373 - Shapes editor: update tests for new implementation. draft
authorRazvan Caliman <rcaliman@mozilla.com>
Thu, 05 Apr 2018 12:21:59 +0200
changeset 779202 03b412c9e45e0b293af9050543b3f1e69df88e7c
parent 779201 86bec3760b5ed86c42e4f3a1c77597ce64be0120
push id105693
push userbmo:rcaliman@mozilla.com
push dateMon, 09 Apr 2018 13:16:25 +0000
bugs1435373
milestone61.0a1
Bug 1435373 - Shapes editor: update tests for new implementation. MozReview-Commit-ID: KUVacaWD5lv
devtools/client/inspector/rules/test/browser_rules_shapes-toggle_01.js
devtools/client/inspector/rules/test/browser_rules_shapes-toggle_03.js
devtools/client/inspector/rules/test/browser_rules_shapes-toggle_04.js
devtools/client/inspector/rules/test/browser_rules_shapes-toggle_05.js
devtools/client/inspector/rules/test/browser_rules_shapes-toggle_06.js
devtools/client/inspector/rules/test/browser_rules_shapes-toggle_07.js
devtools/client/inspector/test/browser_inspector_highlighter-cssshape_04.js
devtools/client/inspector/test/browser_inspector_highlighter-cssshape_05.js
devtools/client/inspector/test/browser_inspector_highlighter-cssshape_06.js
devtools/client/inspector/test/browser_inspector_highlighter-cssshape_07.js
devtools/client/inspector/test/browser_inspector_highlighter-cssshape_iframe_01.js
devtools/client/inspector/test/head.js
--- a/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_01.js
@@ -20,28 +20,28 @@ const TEST_URI = `
 
 const HIGHLIGHTER_TYPE = "ShapesHighlighter";
 
 add_task(async function() {
   await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = await openRuleView();
   let highlighters = view.highlighters;
 
+  info("Select a node with a shape value");
   await selectNode("#shape", inspector);
   let container = getRuleViewProperty(view, "#shape", "clip-path").valueSpan;
   let shapesToggle = container.querySelector(".ruleview-shapeswatch");
 
   info("Checking the initial state of the CSS shape toggle in the rule-view.");
   ok(shapesToggle, "Shapes highlighter toggle is visible.");
   ok(!shapesToggle.classList.contains("active"),
     "Shapes highlighter toggle button is not active.");
   ok(!highlighters.highlighters[HIGHLIGHTER_TYPE],
     "No CSS shapes highlighter exists in the rule-view.");
   ok(!highlighters.shapesHighlighterShown, "No CSS shapes highlighter is shown.");
-
   info("Toggling ON the CSS shapes highlighter from the rule-view.");
   let onHighlighterShown = highlighters.once("shapes-highlighter-shown");
   shapesToggle.click();
   await onHighlighterShown;
 
   info("Checking the CSS shapes highlighter is created and toggle button is active in " +
     "the rule-view.");
   ok(shapesToggle.classList.contains("active"),
--- a/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_03.js
+++ b/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_03.js
@@ -59,17 +59,18 @@ add_task(async function() {
   container = getRuleViewProperty(view, ".shape", "clip-path").valueSpan;
   shapeToggle = container.querySelector(".ruleview-shapeswatch");
 
   info("Checking the state of the CSS shapes toggle for the second shapes container " +
     "in the rule-view.");
   ok(shapeToggle, "shapes highlighter toggle is visible.");
   ok(!shapeToggle.classList.contains("active"),
     "shapes highlighter toggle button is not active.");
-  ok(highlighters.shapesHighlighterShown, "CSS shapes highlighter is still shown.");
+  ok(!highlighters.shapesHighlighterShown, "CSS shapes highlighter is still no longer" +
+    "shown due to selecting another node.");
 
   info("Toggling ON the CSS shapes highlighter for the second shapes container " +
     "from the rule-view.");
   onHighlighterShown = highlighters.once("shapes-highlighter-shown");
   shapeToggle.click();
   await onHighlighterShown;
 
   info("Checking the CSS shapes highlighter is created for the second shapes container " +
--- a/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_04.js
+++ b/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_04.js
@@ -18,16 +18,17 @@ const TEST_URI = `
   <div id="shape"></div>
 `;
 
 add_task(async function() {
   await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = await openRuleView();
   let highlighters = view.highlighters;
 
+  info("Select a node with a shape value");
   await selectNode("#shape", inspector);
   let container = getRuleViewProperty(view, "#shape", "clip-path").valueSpan;
   let shapeToggle = container.querySelector(".ruleview-shapeswatch");
 
   info("Toggling ON the CSS shape highlighter from the rule-view.");
   let onHighlighterShown = highlighters.once("shapes-highlighter-shown");
   shapeToggle.click();
   await onHighlighterShown;
--- a/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_05.js
+++ b/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_05.js
@@ -18,16 +18,17 @@ const TEST_URI = `
   <div id="shape"></div>
 `;
 
 add_task(async function() {
   await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view, testActor} = await openRuleView();
   let highlighters = view.highlighters;
 
+  info("Select a node with a shape value");
   await selectNode("#shape", inspector);
   let container = getRuleViewProperty(view, "#shape", "clip-path").valueSpan;
   let shapeToggle = container.querySelector(".ruleview-shapeswatch");
 
   info("Toggling ON the CSS shapes highlighter from the rule-view.");
   let onHighlighterShown = highlighters.once("shapes-highlighter-shown");
   shapeToggle.click();
   await onHighlighterShown;
--- a/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_06.js
+++ b/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_06.js
@@ -20,16 +20,17 @@ const TEST_URI = `
   <div class="shape" id="shape2"></div>
 `;
 
 add_task(async function() {
   await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = await openRuleView();
   let highlighters = view.highlighters;
 
+  info("Selecting the first shapes container.");
   await selectNode("#shape1", inspector);
   let clipPathContainer = getRuleViewProperty(view, ".shape", "clip-path").valueSpan;
   let clipPathShapeToggle = clipPathContainer.querySelector(".ruleview-shapeswatch");
   let shapeOutsideContainer = getRuleViewProperty(view, ".shape",
     "shape-outside").valueSpan;
   let shapeOutsideToggle = shapeOutsideContainer.querySelector(".ruleview-shapeswatch");
 
   info("Toggling ON the CSS shapes highlighter for clip-path from the rule-view.");
@@ -58,21 +59,9 @@ add_task(async function() {
   clipPathShapeToggle = clipPathContainer.querySelector(".ruleview-shapeswatch");
   shapeOutsideContainer = getRuleViewProperty(view, ".shape",
     "shape-outside").valueSpan;
   shapeOutsideToggle = shapeOutsideContainer.querySelector(".ruleview-shapeswatch");
   ok(!clipPathShapeToggle.classList.contains("active"),
      "clip-path toggle button is not active.");
   ok(!shapeOutsideToggle.classList.contains("active"),
      "shape-outside toggle button is not active.");
-
-  info("Selecting the first shapes container.");
-  await selectNode("#shape1", inspector);
-  clipPathContainer = getRuleViewProperty(view, ".shape", "clip-path").valueSpan;
-  clipPathShapeToggle = clipPathContainer.querySelector(".ruleview-shapeswatch");
-  shapeOutsideContainer = getRuleViewProperty(view, ".shape",
-    "shape-outside").valueSpan;
-  shapeOutsideToggle = shapeOutsideContainer.querySelector(".ruleview-shapeswatch");
-  ok(!clipPathShapeToggle.classList.contains("active"),
-     "clip-path toggle button is not active.");
-  ok(shapeOutsideToggle.classList.contains("active"),
-     "shape-outside toggle button is active.");
 });
--- a/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_07.js
+++ b/devtools/client/inspector/rules/test/browser_rules_shapes-toggle_07.js
@@ -19,25 +19,21 @@ const TEST_URI = `
 
 const HIGHLIGHTER_TYPE = "ShapesHighlighter";
 
 add_task(async function() {
   await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = await openRuleView();
   let highlighters = view.highlighters;
 
+  info("Select a node with a shape value");
   await selectNode("#shape", inspector);
   let container = getRuleViewProperty(view, "#shape", "clip-path").valueSpan;
   let shapesToggle = container.querySelector(".ruleview-shapeswatch");
 
-  info("Checking the initial state of the CSS shape toggle in the rule-view.");
-  ok(!highlighters.highlighters[HIGHLIGHTER_TYPE],
-    "No CSS shapes highlighter exists in the rule-view.");
-  ok(!highlighters.shapesHighlighterShown, "No CSS shapes highlighter is shown.");
-
   info("Toggling ON the CSS shapes highlighter with transform mode on.");
   let onHighlighterShown = highlighters.once("shapes-highlighter-shown");
   EventUtils.sendMouseEvent({type: "click", metaKey: true, ctrlKey: true},
     shapesToggle, view.styleWindow);
   await onHighlighterShown;
 
   info("Checking the CSS shapes highlighter is created and transform mode is on");
   ok(highlighters.highlighters[HIGHLIGHTER_TYPE],
--- a/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_04.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_04.js
@@ -5,233 +5,320 @@
 "use strict";
 
 // Test that shapes are updated correctly on mouse events.
 
 const TEST_URL = URL_ROOT + "doc_inspector_highlighter_cssshapes.html";
 const HIGHLIGHTER_TYPE = "ShapesHighlighter";
 
 add_task(async function() {
-  let inspector = await openInspectorForURL(TEST_URL);
-  let helper = await getHighlighterHelperFor(HIGHLIGHTER_TYPE)(inspector);
-  let {testActor} = inspector;
+  let env = await openInspectorForURL(TEST_URL);
+  let helper = await getHighlighterHelperFor(HIGHLIGHTER_TYPE)(env);
+  let {testActor, inspector} = env;
+  let view = selectRuleView(inspector);
+  let highlighters = view.highlighters;
 
-  await testPolygonMovePoint(testActor, helper);
-  await testPolygonAddPoint(testActor, helper);
-  await testPolygonRemovePoint(testActor, helper);
-  await testCircleMoveCenter(testActor, helper);
-  await testEllipseMoveRadius(testActor, helper);
-  await testInsetMoveEdges(testActor, helper);
+  let config = {inspector, view, highlighters, testActor, helper};
+
+  await testPolygonMovePoint(config);
+  await testPolygonAddPoint(config);
+  await testPolygonRemovePoint(config);
+  await testCircleMoveCenter(config);
+  await testEllipseMoveRadius(config);
+  await testInsetMoveEdges(config);
 
   helper.finalize();
 });
 
-async function testPolygonMovePoint(testActor, helper) {
-  info("Displaying polygon");
-  await helper.show("#polygon", {mode: "cssClipPath"});
-  let { mouse, highlightedNode } = helper;
+async function getComputedPropertyValue(selector, property, inspector) {
+  let highlightedNode = await getNodeFront(selector, inspector);
+  let computedStyle = await inspector.pageStyle.getComputed(highlightedNode);
+  return computedStyle[property].value;
+}
+
+async function setup(config) {
+  const { view, selector, property, inspector } = config;
+  info(`Turn on shapes highlighter for ${selector}`);
+  await selectNode(selector, inspector);
+  await toggleShapesHighlighter(view, selector, property, true);
+}
 
-  let points = await helper.getElementAttribute("shapes-polygon", "points");
+async function teardown(config) {
+  const { view, selector, property } = config;
+  info(`Turn off shapes highlighter for ${selector}`);
+  await toggleShapesHighlighter(view, selector, property, false);
+}
+
+async function testPolygonMovePoint(config) {
+  const {inspector, view, highlighters, testActor, helper} = config;
+  const selector = "#polygon";
+  const property = "clip-path";
+
+  await setup({selector, property, ...config});
+
+  let points = await testActor.getHighlighterNodeAttribute(
+    "shapes-polygon", "points", highlighters.highlighters[HIGHLIGHTER_TYPE]);
   let [x, y] = points.split(" ")[0].split(",");
-  let quads = await testActor.getAllAdjustedQuads("#polygon");
+  let quads = await testActor.getAllAdjustedQuads(selector);
   let { top, left, width, height } = quads.border[0].bounds;
   x = left + width * x / 100;
   y = top + height * y / 100;
   let dx = width / 10;
   let dy = height / 10;
 
+  let onRuleViewChanged = view.once("ruleview-changed");
   info("Moving first polygon point");
+  let { mouse } = helper;
   await mouse.down(x, y);
   await mouse.move(x + dx, y + dy);
   await mouse.up();
   await testActor.reflow();
+  info("Waiting for rule view changed from shape change");
+  await onRuleViewChanged;
 
-  let computedStyle = await highlightedNode.getComputedStyle();
-  let definition = computedStyle["clip-path"].value;
+  let definition = await getComputedPropertyValue(selector, property, inspector);
   ok(definition.includes(`${dx}px ${dy}px`), `Point moved to ${dx}px ${dy}px`);
+
+  await teardown({selector, property, ...config});
 }
 
-async function testPolygonAddPoint(testActor, helper) {
-  await helper.show("#polygon", {mode: "cssClipPath"});
-  let { mouse, highlightedNode } = helper;
+async function testPolygonAddPoint(config) {
+  const {inspector, view, highlighters, testActor, helper} = config;
+  const selector = "#polygon";
+  const property = "clip-path";
+
+  await setup({selector, property, ...config});
 
   // Move first point to have same x as second point, then double click between
   // the two points to add a new one.
-  let points = await helper.getElementAttribute("shapes-polygon", "points");
+  let points = await testActor.getHighlighterNodeAttribute(
+    "shapes-polygon", "points", highlighters.highlighters[HIGHLIGHTER_TYPE]);
   let pointsArray = points.split(" ");
-  let quads = await testActor.getAllAdjustedQuads("#polygon");
+  let quads = await testActor.getAllAdjustedQuads(selector);
   let { top, left, width, height } = quads.border[0].bounds;
   let [x1, y1] = pointsArray[0].split(",");
   let [x2, y2] = pointsArray[1].split(",");
   x1 = left + width * x1 / 100;
   x2 = left + width * x2 / 100;
   y1 = top + height * y1 / 100;
   y2 = top + height * y2 / 100;
 
+  let { mouse } = helper;
   await mouse.down(x1, y1);
   await mouse.move(x2, y1);
   await mouse.up();
   await testActor.reflow();
 
   let newPointX = x2;
   let newPointY = (y1 + y2) / 2;
   let options = {
     selector: ":root",
     x: newPointX,
     y: newPointY,
     center: false,
     options: {clickCount: 2}
   };
 
+  let onRuleViewChanged = view.once("ruleview-changed");
   info("Adding new polygon point");
   await testActor.synthesizeMouse(options);
   await testActor.reflow();
+  info("Waiting for rule view changed from shape change");
+  await onRuleViewChanged;
 
-  let computedStyle = await highlightedNode.getComputedStyle();
-  let definition = computedStyle["clip-path"].value;
   // Decimal precision for coordinates with percentage units is 2
   let precision = 2;
   // Round to the desired decimal precision and cast to Number to remove trailing zeroes.
   newPointX = Number((newPointX * 100 / width).toFixed(precision));
   newPointY = Number((newPointY * 100 / height).toFixed(precision));
+  let definition = await getComputedPropertyValue(selector, property, inspector);
   ok(definition.includes(`${newPointX}% ${newPointY}%`),
      "Point successfuly added");
+
+  await teardown({selector, property, ...config});
 }
 
-async function testPolygonRemovePoint(testActor, helper) {
-  await helper.show("#polygon", {mode: "cssClipPath"});
-  let { highlightedNode } = helper;
+async function testPolygonRemovePoint(config) {
+  const {inspector, highlighters, testActor, helper} = config;
+  const selector = "#polygon";
+  const property = "clip-path";
 
-  let points = await helper.getElementAttribute("shapes-polygon", "points");
+  await setup({selector, property, ...config});
+
+  let points = await testActor.getHighlighterNodeAttribute(
+    "shapes-polygon", "points", highlighters.highlighters[HIGHLIGHTER_TYPE]);
   let [x, y] = points.split(" ")[0].split(",");
-  let quads = await testActor.getAllAdjustedQuads("#polygon");
+  let quads = await testActor.getAllAdjustedQuads(selector);
   let { top, left, width, height } = quads.border[0].bounds;
 
   let options = {
     selector: ":root",
     x: left + width * x / 100,
     y: top + height * y / 100,
     center: false,
     options: {clickCount: 2}
   };
 
-  info("Removing first polygon point");
-  await testActor.synthesizeMouse(options);
-  await testActor.reflow();
+  info("Move mouse over first point in highlighter");
+  let onEventHandled = highlighters.once("highlighter-event-handled");
+  let { mouse } = helper;
+  await mouse.move(options.x, options.y);
+  await onEventHandled;
+  let markerHidden = await testActor.getHighlighterNodeAttribute(
+    "shapes-marker-hover", "hidden", highlighters.highlighters[HIGHLIGHTER_TYPE]);
+  ok(!markerHidden, "Marker on highlighter is visible");
 
-  let computedStyle = await highlightedNode.getComputedStyle();
-  let definition = computedStyle["clip-path"].value;
+  info("Double click on first point in highlighter");
+  let onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+  await testActor.synthesizeMouse(options);
+  info("Waiting for shape changes to apply");
+  await onShapeChangeApplied;
+  let definition = await getComputedPropertyValue(selector, property, inspector);
   ok(!definition.includes(`${x}% ${y}%`), "Point successfully removed");
+
+  await teardown({selector, property, ...config});
 }
 
-async function testCircleMoveCenter(testActor, helper) {
-  await helper.show("#circle", {mode: "cssClipPath"});
-  let { mouse, highlightedNode } = helper;
+async function testCircleMoveCenter(config) {
+  const {inspector, highlighters, testActor, helper} = config;
+  const selector = "#circle";
+  const property = "clip-path";
 
-  let cx = parseFloat(await helper.getElementAttribute("shapes-ellipse", "cx"));
-  let cy = parseFloat(await helper.getElementAttribute("shapes-ellipse", "cy"));
-  let quads = await testActor.getAllAdjustedQuads("#circle");
+  await setup({selector, property, ...config});
+
+  let cx = parseFloat(await testActor.getHighlighterNodeAttribute(
+    "shapes-ellipse", "cx", highlighters.highlighters[HIGHLIGHTER_TYPE]));
+  let cy = parseFloat(await testActor.getHighlighterNodeAttribute(
+    "shapes-ellipse", "cy", highlighters.highlighters[HIGHLIGHTER_TYPE]));
+  let quads = await testActor.getAllAdjustedQuads(selector);
   let { width, height } = quads.border[0].bounds;
   let cxPixel = width * cx / 100;
   let cyPixel = height * cy / 100;
   let dx = width / 10;
   let dy = height / 10;
 
+  let onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
   info("Moving circle center");
-  await mouse.down(cxPixel, cyPixel, "#circle");
-  await mouse.move(cxPixel + dx, cyPixel + dy, "#circle");
-  await mouse.up(cxPixel + dx, cyPixel + dy, "#circle");
+  let { mouse } = helper;
+  await mouse.down(cxPixel, cyPixel, selector);
+  await mouse.move(cxPixel + dx, cyPixel + dy, selector);
+  await mouse.up(cxPixel + dx, cyPixel + dy, selector);
   await testActor.reflow();
+  await onShapeChangeApplied;
 
-  let computedStyle = await highlightedNode.getComputedStyle();
-  let definition = computedStyle["clip-path"].value;
+  let definition = await getComputedPropertyValue(selector, property, inspector);
   ok(definition.includes(`at ${cx + 10}% ${cy + 10}%`),
      "Circle center successfully moved");
+
+  await teardown({selector, property, ...config});
 }
 
-async function testEllipseMoveRadius(testActor, helper) {
-  await helper.show("#ellipse", {mode: "cssClipPath"});
-  let { mouse, highlightedNode } = helper;
+async function testEllipseMoveRadius(config) {
+  const {inspector, highlighters, testActor, helper} = config;
+  const selector = "#ellipse";
+  const property = "clip-path";
+
+  await setup({selector, property, ...config});
 
-  let rx = parseFloat(await helper.getElementAttribute("shapes-ellipse", "rx"));
-  let ry = parseFloat(await helper.getElementAttribute("shapes-ellipse", "ry"));
-  let cx = parseFloat(await helper.getElementAttribute("shapes-ellipse", "cx"));
-  let cy = parseFloat(await helper.getElementAttribute("shapes-ellipse", "cy"));
+  let rx = parseFloat(await testActor.getHighlighterNodeAttribute(
+    "shapes-ellipse", "rx", highlighters.highlighters[HIGHLIGHTER_TYPE]));
+  let ry = parseFloat(await testActor.getHighlighterNodeAttribute(
+    "shapes-ellipse", "ry", highlighters.highlighters[HIGHLIGHTER_TYPE]));
+  let cx = parseFloat(await testActor.getHighlighterNodeAttribute(
+    "shapes-ellipse", "cx", highlighters.highlighters[HIGHLIGHTER_TYPE]));
+  let cy = parseFloat(await testActor.getHighlighterNodeAttribute(
+    "shapes-ellipse", "cy", highlighters.highlighters[HIGHLIGHTER_TYPE]));
   let quads = await testActor.getAllAdjustedQuads("#ellipse");
   let { width, height } = quads.content[0].bounds;
-  let computedStyle = await highlightedNode.getComputedStyle();
+  let highlightedNode = await getNodeFront(selector, inspector);
+  let computedStyle = await inspector.pageStyle.getComputed(highlightedNode);
   let paddingTop = parseFloat(computedStyle["padding-top"].value);
   let paddingLeft = parseFloat(computedStyle["padding-left"].value);
   let cxPixel = paddingLeft + width * cx / 100;
   let cyPixel = paddingTop + height * cy / 100;
   let rxPixel = cxPixel + width * rx / 100;
   let ryPixel = cyPixel + height * ry / 100;
   let dx = width / 10;
   let dy = height / 10;
 
+  let { mouse } = helper;
   info("Moving ellipse rx");
-  await mouse.down(rxPixel, cyPixel, "#ellipse");
-  await mouse.move(rxPixel + dx, cyPixel, "#ellipse");
-  await mouse.up(rxPixel + dx, cyPixel, "#ellipse");
+  await mouse.down(rxPixel, cyPixel, selector);
+  await mouse.move(rxPixel + dx, cyPixel, selector);
+  await mouse.up(rxPixel + dx, cyPixel, selector);
   await testActor.reflow();
 
   info("Moving ellipse ry");
-  await mouse.down(cxPixel, ryPixel, "#ellipse");
-  await mouse.move(cxPixel, ryPixel - dy, "#ellipse");
-  await mouse.up(cxPixel, ryPixel - dy, "#ellipse");
+  let onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+  await mouse.down(cxPixel, ryPixel, selector);
+  await mouse.move(cxPixel, ryPixel - dy, selector);
+  await mouse.up(cxPixel, ryPixel - dy, selector);
   await testActor.reflow();
+  await onShapeChangeApplied;
 
-  computedStyle = await highlightedNode.getComputedStyle();
-  let definition = computedStyle["clip-path"].value;
+  let definition = await getComputedPropertyValue(selector, property, inspector);
   ok(definition.includes(`${rx + 10}% ${ry - 10}%`),
      "Ellipse radiuses successfully moved");
+
+  await teardown({selector, property, ...config});
 }
 
-async function testInsetMoveEdges(testActor, helper) {
-  await helper.show("#inset", {mode: "cssClipPath"});
-  let { mouse, highlightedNode } = helper;
+async function testInsetMoveEdges(config) {
+  const {inspector, highlighters, testActor, helper} = config;
+  const selector = "#inset";
+  const property = "clip-path";
+
+  await setup({selector, property, ...config});
 
-  let x = parseFloat(await helper.getElementAttribute("shapes-rect", "x"));
-  let y = parseFloat(await helper.getElementAttribute("shapes-rect", "y"));
-  let width = parseFloat(await helper.getElementAttribute("shapes-rect", "width"));
-  let height = parseFloat(await helper.getElementAttribute("shapes-rect", "height"));
-  let quads = await testActor.getAllAdjustedQuads("#inset");
+  let x = parseFloat(await testActor.getHighlighterNodeAttribute(
+    "shapes-rect", "x", highlighters.highlighters[HIGHLIGHTER_TYPE]));
+  let y = parseFloat(await testActor.getHighlighterNodeAttribute(
+    "shapes-rect", "y", highlighters.highlighters[HIGHLIGHTER_TYPE]));
+  let width = parseFloat(await testActor.getHighlighterNodeAttribute(
+    "shapes-rect", "width", highlighters.highlighters[HIGHLIGHTER_TYPE]));
+  let height = parseFloat(await testActor.getHighlighterNodeAttribute(
+    "shapes-rect", "height", highlighters.highlighters[HIGHLIGHTER_TYPE]));
+  let quads = await testActor.getAllAdjustedQuads(selector);
   let { width: elemWidth, height: elemHeight } = quads.content[0].bounds;
 
   let left = elemWidth * x / 100;
   let top = elemHeight * y / 100;
   let right = left + elemWidth * width / 100;
   let bottom = top + elemHeight * height / 100;
   let xCenter = (left + right) / 2;
   let yCenter = (top + bottom) / 2;
   let dx = elemWidth / 10;
   let dy = elemHeight / 10;
+  let { mouse } = helper;
 
   info("Moving inset top");
-  await mouse.down(xCenter, top, "#inset");
-  await mouse.move(xCenter, top + dy, "#inset");
-  await mouse.up(xCenter, top + dy, "#inset");
+  await mouse.down(xCenter, top, selector);
+  await mouse.move(xCenter, top + dy, selector);
+  await mouse.up(xCenter, top + dy, selector);
   await testActor.reflow();
 
   info("Moving inset bottom");
-  await mouse.down(xCenter, bottom, "#inset");
-  await mouse.move(xCenter, bottom + dy, "#inset");
-  await mouse.up(xCenter, bottom + dy, "#inset");
+  await mouse.down(xCenter, bottom, selector);
+  await mouse.move(xCenter, bottom + dy, selector);
+  await mouse.up(xCenter, bottom + dy, selector);
   await testActor.reflow();
 
   info("Moving inset left");
-  await mouse.down(left, yCenter, "#inset");
-  await mouse.move(left + dx, yCenter, "#inset");
-  await mouse.up(left + dx, yCenter, "#inset");
+  await mouse.down(left, yCenter, selector);
+  await mouse.move(left + dx, yCenter, selector);
+  await mouse.up(left + dx, yCenter, selector);
   await testActor.reflow();
 
   info("Moving inset right");
-  await mouse.down(right, yCenter, "#inset");
-  await mouse.move(right + dx, yCenter, "#inset");
-  await mouse.up(right + dx, yCenter, "#inset");
+  let onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+  await mouse.down(right, yCenter, selector);
+  await mouse.move(right + dx, yCenter, selector);
+  await mouse.up(right + dx, yCenter, selector);
   await testActor.reflow();
+  await onShapeChangeApplied;
 
-  let computedStyle = await highlightedNode.getComputedStyle();
-  let definition = computedStyle["clip-path"].value;
+  let definition = await getComputedPropertyValue(selector, property, inspector);
   ok(definition.includes(
     `${top + dy}px ${elemWidth - right - dx}px ${100 - y - height - 10}% ${x + 10}%`),
      "Inset edges successfully moved");
+
+  await teardown({selector, property, ...config});
 }
--- a/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_05.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_05.js
@@ -2,109 +2,114 @@
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test hovering over shape points in the rule-view and shapes highlighter.
 
 const TEST_URL = URL_ROOT + "doc_inspector_highlighter_cssshapes.html";
-
 const HIGHLIGHTER_TYPE = "ShapesHighlighter";
-const CSS_SHAPES_ENABLED_PREF = "devtools.inspector.shapesHighlighter.enabled";
 
 add_task(async function() {
-  await pushPref(CSS_SHAPES_ENABLED_PREF, true);
   let env = await openInspectorForURL(TEST_URL);
   let helper = await getHighlighterHelperFor(HIGHLIGHTER_TYPE)(env);
   let { testActor, inspector } = env;
   let view = selectRuleView(inspector);
   let highlighters = view.highlighters;
+  let config = { inspector, view, highlighters, testActor, helper };
 
-  await highlightFromRuleView(inspector, view, highlighters, testActor);
-  await highlightFromHighlighter(view, highlighters, testActor, helper);
+  await highlightFromRuleView(config);
+  await highlightFromHighlighter(config);
 });
 
-async function highlightFromRuleView(inspector, view, highlighters, testActor) {
-  await selectNode("#polygon", inspector);
-  await toggleShapesHighlighter(view, highlighters, "#polygon", "clip-path", true);
-  let container = getRuleViewProperty(view, "#polygon", "clip-path").valueSpan;
+async function setup(config) {
+  const { view, selector, property, inspector } = config;
+  info(`Turn on shapes highlighter for ${selector}`);
+  await selectNode(selector, inspector);
+  await toggleShapesHighlighter(view, selector, property, true);
+}
+
+async function teardown(config) {
+  const { view, selector, property } = config;
+  info(`Turn off shapes highlighter for ${selector}`);
+  await toggleShapesHighlighter(view, selector, property, false);
+}
+/*
+* Test that points hovered in the rule view will highlight corresponding points
+* in the shapes highlighter on the page.
+*/
+async function highlightFromRuleView(config) {
+  const { view, highlighters, testActor } = config;
+  const selector = "#polygon";
+  const property = "clip-path";
+
+  await setup({ selector, property, ...config });
+
+  let container = getRuleViewProperty(view, selector, property).valueSpan;
   let shapesToggle = container.querySelector(".ruleview-shapeswatch");
 
   let highlighterFront = highlighters.highlighters[HIGHLIGHTER_TYPE];
   let markerHidden = await testActor.getHighlighterNodeAttribute(
     "shapes-marker-hover", "hidden", highlighterFront);
   ok(markerHidden, "Hover marker on highlighter is not visible");
 
   info("Hover over point 0 in rule view");
   let pointSpan = container.querySelector(".ruleview-shape-point[data-point='0']");
   let onHighlighterShown = highlighters.once("shapes-highlighter-shown");
   EventUtils.synthesizeMouseAtCenter(pointSpan, {type: "mousemove"}, view.styleWindow);
   await onHighlighterShown;
 
-  ok(pointSpan.classList.contains("active"), "Hovered span is active");
-  is(highlighters.state.shapes.options.hoverPoint, "0",
-     "Hovered point is saved to state");
-
+  info("Point in shapes highlighter is marked when same point in rule view is hovered");
   markerHidden = await testActor.getHighlighterNodeAttribute(
     "shapes-marker-hover", "hidden", highlighterFront);
   ok(!markerHidden, "Marker on highlighter is visible");
 
   info("Move mouse off point");
   onHighlighterShown = highlighters.once("shapes-highlighter-shown");
   EventUtils.synthesizeMouseAtCenter(shapesToggle, {type: "mousemove"}, view.styleWindow);
   await onHighlighterShown;
 
-  ok(!pointSpan.classList.contains("active"), "Hovered span is no longer active");
-  is(highlighters.state.shapes.options.hoverPoint, null, "Hovered point is null");
-
   markerHidden = await testActor.getHighlighterNodeAttribute(
     "shapes-marker-hover", "hidden", highlighterFront);
   ok(markerHidden, "Marker on highlighter is not visible");
 
-  info("Hide shapes highlighter");
-  await toggleShapesHighlighter(view, highlighters, "#polygon", "clip-path", false);
+  await teardown({selector, property, ...config});
 }
 
-async function highlightFromHighlighter(view, highlighters, testActor, helper) {
+/*
+* Test that points hovered in the shapes highlighter on the page will highlight
+* corresponding points in the rule view.
+*/
+async function highlightFromHighlighter(config) {
+  const { view, highlighters, testActor, helper } = config;
+  const selector = "#polygon";
+  const property = "clip-path";
+
+  await setup({ selector, property, ...config });
+
   let highlighterFront = highlighters.highlighters[HIGHLIGHTER_TYPE];
   let { mouse } = helper;
-
-  await toggleShapesHighlighter(view, highlighters, "#polygon", "clip-path", true);
-  let container = getRuleViewProperty(view, "#polygon", "clip-path").valueSpan;
+  let container = getRuleViewProperty(view, selector, property).valueSpan;
 
   info("Hover over first point in highlighter");
   let onEventHandled = highlighters.once("highlighter-event-handled");
   await mouse.move(0, 0);
   await onEventHandled;
   let markerHidden = await testActor.getHighlighterNodeAttribute(
     "shapes-marker-hover", "hidden", highlighterFront);
   ok(!markerHidden, "Marker on highlighter is visible");
 
+  info("Point in rule view is marked when same point in shapes highlighter is hovered");
   let pointSpan = container.querySelector(".ruleview-shape-point[data-point='0']");
   ok(pointSpan.classList.contains("active"), "Span for point 0 is active");
-  is(highlighters.state.shapes.hoverPoint, "0", "Hovered point is saved to state");
-
-  info("Check that point is still highlighted after moving it");
-  await mouse.down(0, 0);
-  await mouse.move(10, 10);
-  await mouse.up(10, 10);
-  markerHidden = await testActor.getHighlighterNodeAttribute(
-    "shapes-marker-hover", "hidden", highlighterFront);
-  ok(!markerHidden, "Marker on highlighter is visible after moving point");
-
-  container = getRuleViewProperty(view, "element", "clip-path").valueSpan;
-  pointSpan = container.querySelector(".ruleview-shape-point[data-point='0']");
-  ok(pointSpan.classList.contains("active"),
-     "Span for point 0 is active after moving point");
-  is(highlighters.state.shapes.hoverPoint, "0",
-     "Hovered point is saved to state after moving point");
 
   info("Move mouse off point");
   onEventHandled = highlighters.once("highlighter-event-handled");
   await mouse.move(100, 100);
   await onEventHandled;
   markerHidden = await testActor.getHighlighterNodeAttribute(
     "shapes-marker-hover", "hidden", highlighterFront);
   ok(markerHidden, "Marker on highlighter is no longer visible");
   ok(!pointSpan.classList.contains("active"), "Span for point 0 is no longer active");
-  is(highlighters.state.shapes.hoverPoint, null, "Hovered point is null");
+
+  await teardown({ selector, property, ...config });
 }
--- a/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_06.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_06.js
@@ -3,145 +3,183 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Test that shapes are updated correctly on mouse events in transform mode.
 
 const TEST_URL = URL_ROOT + "doc_inspector_highlighter_cssshapes.html";
 const HIGHLIGHTER_TYPE = "ShapesHighlighter";
-const SHAPE_IDS = ["#polygon-transform", "#circle", "#ellipse", "#inset"];
+const SHAPE_SELECTORS = ["#polygon-transform", "#circle", "#ellipse", "#inset"];
 
 add_task(async function() {
-  let inspector = await openInspectorForURL(TEST_URL);
-  let helper = await getHighlighterHelperFor(HIGHLIGHTER_TYPE)(inspector);
-  let {testActor} = inspector;
+  let env = await openInspectorForURL(TEST_URL);
+  let helper = await getHighlighterHelperFor(HIGHLIGHTER_TYPE)(env);
+  let {testActor, inspector} = env;
+  let view = selectRuleView(inspector);
+  let highlighters = view.highlighters;
+  let config = { inspector, view, highlighters, testActor, helper };
 
-  await testTranslate(testActor, helper);
-  await testScale(testActor, helper);
-
-  helper.finalize();
+  await testTranslate(config);
+  await testScale(config);
 });
 
-async function testTranslate(testActor, helper) {
-  for (let shape of SHAPE_IDS) {
-    info(`Displaying ${shape}`);
-    await helper.show(shape, {mode: "cssClipPath", transformMode: true});
+async function setup(config) {
+  const { inspector, view, selector, property, options } = config;
+  await selectNode(selector, inspector);
+  await toggleShapesHighlighter(view, selector, property, true, options);
+}
+
+async function teardown(config) {
+  const { view, selector, property } = config;
+  info(`Turn off shapes highlighter for ${selector}`);
+  await toggleShapesHighlighter(view, selector, property, false);
+}
+
+async function testTranslate(config) {
+  const { testActor, helper, highlighters } = config;
+  const options = { transformMode: true };
+  const property = "clip-path";
+
+  for (let selector of SHAPE_SELECTORS) {
+    await setup({selector, property, options, ...config});
     let { mouse } = helper;
 
-    let { center, width, height } = await getBoundingBoxInPx(testActor, helper, shape);
+    let { center, width, height } = await getBoundingBoxInPx({selector, ...config});
     let [x, y] = center;
     let dx = width / 10;
     let dy = height / 10;
+    let onShapeChangeApplied;
 
-    info(`Translating ${shape}`);
-    await mouse.down(x, y, shape);
-    await mouse.move(x + dx, y + dy, shape);
-    await mouse.up(x + dx, y + dy, shape);
-    await testActor.reflow();
+    info(`Translating ${selector}`);
+    onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+    await mouse.down(x, y, selector);
+    await mouse.move(x + dx, y + dy, selector);
+    await mouse.up(x + dx, y + dy, selector);
+    await onShapeChangeApplied;
+
+    let newBB = await getBoundingBoxInPx({selector, ...config});
+    isnot(newBB.center[0], x, `${selector} translated on y axis`);
+    isnot(newBB.center[1], y, `${selector} translated on x axis`);
 
-    let newBB = await getBoundingBoxInPx(testActor, helper);
-    isnot(newBB.center[0], x, `${shape} translated on y axis`);
-    isnot(newBB.center[1], y, `${shape} translated on x axis`);
+    info(`Translating ${selector} back`);
+    onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+    await mouse.down(x + dx, y + dy, selector);
+    await mouse.move(x, y, selector);
+    await mouse.up(x, y, selector);
+    await testActor.reflow();
+    await onShapeChangeApplied;
 
-    info(`Translating ${shape} back`);
-    await mouse.down(x + dx, y + dy, shape);
-    await mouse.move(x, y, shape);
-    await mouse.up(x, y, shape);
-    await testActor.reflow();
+    newBB = await getBoundingBoxInPx({selector, ...config});
+    is(newBB.center[0], x, `${selector} translated back on x axis`);
+    is(newBB.center[1], y, `${selector} translated back on y axis`);
 
-    newBB = await getBoundingBoxInPx(testActor, helper, shape);
-    is(newBB.center[0], x, `${shape} translated back on x axis`);
-    is(newBB.center[1], y, `${shape} translated back on y axis`);
+    await teardown({selector, property, ...config});
   }
 }
 
-async function testScale(testActor, helper) {
-  for (let shape of SHAPE_IDS) {
-    info(`Displaying ${shape}`);
-    await helper.show(shape, {mode: "cssClipPath", transformMode: true});
+async function testScale(config) {
+  const { testActor, helper, highlighters } = config;
+  const options = { transformMode: true };
+  const property = "clip-path";
+
+  for (let selector of SHAPE_SELECTORS) {
+    await setup({selector, property, options, ...config});
     let { mouse } = helper;
 
     let { nw, width,
-          height, center } = await getBoundingBoxInPx(testActor, helper, shape);
+          height, center } = await getBoundingBoxInPx({selector, ...config});
 
     // if the top or left edges are not visible, move the shape so it is.
     if (nw[0] < 0 || nw[1] < 0) {
       let [x, y] = center;
       let dx = Math.max(0, -nw[0]);
       let dy = Math.max(0, -nw[1]);
-      await mouse.down(x, y, shape);
-      await mouse.move(x + dx, y + dy, shape);
-      await mouse.up(x + dx, y + dy, shape);
+      await mouse.down(x, y, selector);
+      await mouse.move(x + dx, y + dy, selector);
+      await mouse.up(x + dx, y + dy, selector);
       await testActor.reflow();
       nw[0] += dx;
       nw[1] += dy;
     }
     let dx = width / 10;
     let dy = height / 10;
+    let onShapeChangeApplied;
 
     info("Scaling from nw");
-    await mouse.down(nw[0], nw[1], shape);
-    await mouse.move(nw[0] + dx, nw[1] + dy, shape);
-    await mouse.up(nw[0] + dx, nw[1] + dy, shape);
+    onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+    await mouse.down(nw[0], nw[1], selector);
+    await mouse.move(nw[0] + dx, nw[1] + dy, selector);
+    await mouse.up(nw[0] + dx, nw[1] + dy, selector);
     await testActor.reflow();
+    await onShapeChangeApplied;
 
-    let nwBB = await getBoundingBoxInPx(testActor, helper, shape);
-    isnot(nwBB.nw[0], nw[0], `${shape} nw moved right after nw scale`);
-    isnot(nwBB.nw[1], nw[1], `${shape} nw moved down after nw scale`);
-    isnot(nwBB.width, width, `${shape} width reduced after nw scale`);
-    isnot(nwBB.height, height, `${shape} height reduced after nw scale`);
+    let nwBB = await getBoundingBoxInPx({selector, ...config});
+    isnot(nwBB.nw[0], nw[0], `${selector} nw moved right after nw scale`);
+    isnot(nwBB.nw[1], nw[1], `${selector} nw moved down after nw scale`);
+    isnot(nwBB.width, width, `${selector} width reduced after nw scale`);
+    isnot(nwBB.height, height, `${selector} height reduced after nw scale`);
 
     info("Scaling from ne");
-    await mouse.down(nwBB.ne[0], nwBB.ne[1], shape);
-    await mouse.move(nwBB.ne[0] - dx, nwBB.ne[1] + dy, shape);
-    await mouse.up(nwBB.ne[0] - dx, nwBB.ne[1] + dy, shape);
+    onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+    await mouse.down(nwBB.ne[0], nwBB.ne[1], selector);
+    await mouse.move(nwBB.ne[0] - dx, nwBB.ne[1] + dy, selector);
+    await mouse.up(nwBB.ne[0] - dx, nwBB.ne[1] + dy, selector);
     await testActor.reflow();
+    await onShapeChangeApplied;
 
-    let neBB = await getBoundingBoxInPx(testActor, helper, shape);
-    isnot(neBB.ne[0], nwBB.ne[0], `${shape} ne moved right after ne scale`);
-    isnot(neBB.ne[1], nwBB.ne[1], `${shape} ne moved down after ne scale`);
-    isnot(neBB.width, nwBB.width, `${shape} width reduced after ne scale`);
-    isnot(neBB.height, nwBB.height, `${shape} height reduced after ne scale`);
+    let neBB = await getBoundingBoxInPx({selector, ...config});
+    isnot(neBB.ne[0], nwBB.ne[0], `${selector} ne moved right after ne scale`);
+    isnot(neBB.ne[1], nwBB.ne[1], `${selector} ne moved down after ne scale`);
+    isnot(neBB.width, nwBB.width, `${selector} width reduced after ne scale`);
+    isnot(neBB.height, nwBB.height, `${selector} height reduced after ne scale`);
 
     info("Scaling from sw");
-    await mouse.down(neBB.sw[0], neBB.sw[1], shape);
-    await mouse.move(neBB.sw[0] + dx, neBB.sw[1] - dy, shape);
-    await mouse.up(neBB.sw[0] + dx, neBB.sw[1] - dy, shape);
+    onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+    await mouse.down(neBB.sw[0], neBB.sw[1], selector);
+    await mouse.move(neBB.sw[0] + dx, neBB.sw[1] - dy, selector);
+    await mouse.up(neBB.sw[0] + dx, neBB.sw[1] - dy, selector);
     await testActor.reflow();
+    await onShapeChangeApplied;
 
-    let swBB = await getBoundingBoxInPx(testActor, helper, shape);
-    isnot(swBB.sw[0], neBB.sw[0], `${shape} sw moved right after sw scale`);
-    isnot(swBB.sw[1], neBB.sw[1], `${shape} sw moved down after sw scale`);
-    isnot(swBB.width, neBB.width, `${shape} width reduced after sw scale`);
-    isnot(swBB.height, neBB.height, `${shape} height reduced after sw scale`);
+    let swBB = await getBoundingBoxInPx({selector, ...config});
+    isnot(swBB.sw[0], neBB.sw[0], `${selector} sw moved right after sw scale`);
+    isnot(swBB.sw[1], neBB.sw[1], `${selector} sw moved down after sw scale`);
+    isnot(swBB.width, neBB.width, `${selector} width reduced after sw scale`);
+    isnot(swBB.height, neBB.height, `${selector} height reduced after sw scale`);
 
     info("Scaling from se");
-    await mouse.down(swBB.se[0], swBB.se[1], shape);
-    await mouse.move(swBB.se[0] - dx, swBB.se[1] - dy, shape);
-    await mouse.up(swBB.se[0] - dx, swBB.se[1] - dy, shape);
+    onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+    await mouse.down(swBB.se[0], swBB.se[1], selector);
+    await mouse.move(swBB.se[0] - dx, swBB.se[1] - dy, selector);
+    await mouse.up(swBB.se[0] - dx, swBB.se[1] - dy, selector);
     await testActor.reflow();
+    await onShapeChangeApplied;
 
-    let seBB = await getBoundingBoxInPx(testActor, helper, shape);
-    isnot(seBB.se[0], swBB.se[0], `${shape} se moved right after se scale`);
-    isnot(seBB.se[1], swBB.se[1], `${shape} se moved down after se scale`);
-    isnot(seBB.width, swBB.width, `${shape} width reduced after se scale`);
-    isnot(seBB.height, swBB.height, `${shape} height reduced after se scale`);
+    let seBB = await getBoundingBoxInPx({selector, ...config});
+    isnot(seBB.se[0], swBB.se[0], `${selector} se moved right after se scale`);
+    isnot(seBB.se[1], swBB.se[1], `${selector} se moved down after se scale`);
+    isnot(seBB.width, swBB.width, `${selector} width reduced after se scale`);
+    isnot(seBB.height, swBB.height, `${selector} height reduced after se scale`);
+
+    await teardown({selector, property, ...config});
   }
 }
 
-async function getBoundingBoxInPx(testActor, helper, shape = "#polygon") {
-  let quads = await testActor.getAllAdjustedQuads(shape);
+async function getBoundingBoxInPx(config) {
+  const { testActor, selector, inspector, highlighters } = config;
+  let quads = await testActor.getAllAdjustedQuads(selector);
   let { width, height } = quads.content[0].bounds;
-  let computedStyle = await helper.highlightedNode.getComputedStyle();
+  let highlightedNode = await getNodeFront(selector, inspector);
+  let computedStyle = await inspector.pageStyle.getComputed(highlightedNode);
   let paddingTop = parseFloat(computedStyle["padding-top"].value);
   let paddingLeft = parseFloat(computedStyle["padding-left"].value);
-
   // path is always of form "Mx y Lx y Lx y Lx y Z", where x/y are numbers
-  let path = await helper.getElementAttribute("shapes-bounding-box", "d");
+  let path = await testActor.getHighlighterNodeAttribute(
+    "shapes-bounding-box", "d", highlighters.highlighters[HIGHLIGHTER_TYPE]);
   let coords = path.replace(/[MLZ]/g, "").split(" ").map((n, i) => {
     return i % 2 === 0 ? paddingLeft + width * n / 100 : paddingTop + height * n / 100;
   });
 
   let nw = [coords[0], coords[1]];
   let ne = [coords[2], coords[3]];
   let se = [coords[4], coords[5]];
   let sw = [coords[6], coords[7]];
--- a/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_07.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_07.js
@@ -3,111 +3,140 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Test that shapes are updated correctly for scaling on one axis in transform mode.
 
 const TEST_URL = URL_ROOT + "doc_inspector_highlighter_cssshapes.html";
 const HIGHLIGHTER_TYPE = "ShapesHighlighter";
-const SHAPE_IDS = ["#polygon-transform", "#ellipse"];
+const SHAPE_SELECTORS = ["#polygon-transform", "#ellipse"];
 
 add_task(async function() {
-  let inspector = await openInspectorForURL(TEST_URL);
-  let helper = await getHighlighterHelperFor(HIGHLIGHTER_TYPE)(inspector);
-  let {testActor} = inspector;
+  let env = await openInspectorForURL(TEST_URL);
+  let helper = await getHighlighterHelperFor(HIGHLIGHTER_TYPE)(env);
+  let {testActor, inspector} = env;
+  let view = selectRuleView(inspector);
+  let highlighters = view.highlighters;
+  let config = { inspector, view, highlighters, testActor, helper };
 
-  await testOneDimScale(testActor, helper);
-
-  helper.finalize();
+  await testOneDimScale(config);
 });
 
-async function testOneDimScale(testActor, helper) {
-  for (let shape of SHAPE_IDS) {
-    info(`Displaying ${shape}`);
-    await helper.show(shape, {mode: "cssClipPath", transformMode: true});
+async function setup(config) {
+  const { inspector, view, selector, property, options } = config;
+  await selectNode(selector, inspector);
+  await toggleShapesHighlighter(view, selector, property, true, options);
+}
+
+async function teardown(config) {
+  const { view, selector, property } = config;
+  info(`Turn off shapes highlighter for ${selector}`);
+  await toggleShapesHighlighter(view, selector, property, false);
+}
+
+async function testOneDimScale(config) {
+  const { testActor, helper, highlighters } = config;
+  const options = { transformMode: true };
+  const property = "clip-path";
+
+  for (let selector of SHAPE_SELECTORS) {
+    await setup({selector, property, options, ...config});
     let { mouse } = helper;
 
     let { nw, width,
-          height, center } = await getBoundingBoxInPx(testActor, helper, shape);
+          height, center } = await getBoundingBoxInPx({selector, ...config});
 
     // if the top or left edges are not visible, move the shape so it is.
     if (nw[0] < 0 || nw[1] < 0) {
       let [x, y] = center;
       let dx = Math.max(0, -nw[0]);
       let dy = Math.max(0, -nw[1]);
-      await mouse.down(x, y, shape);
-      await mouse.move(x + dx, y + dy, shape);
-      await mouse.up(x + dx, y + dy, shape);
+      await mouse.down(x, y, selector);
+      await mouse.move(x + dx, y + dy, selector);
+      await mouse.up(x + dx, y + dy, selector);
       await testActor.reflow();
       nw[0] += dx;
       nw[1] += dy;
     }
     let dx = width / 10;
     let dy = height / 10;
+    let onShapeChangeApplied;
 
     info("Scaling from w");
-    await mouse.down(nw[0], center[1], shape);
-    await mouse.move(nw[0] + dx, center[1], shape);
-    await mouse.up(nw[0] + dx, center[1], shape);
+    onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+    await mouse.down(nw[0], center[1], selector);
+    await mouse.move(nw[0] + dx, center[1], selector);
+    await mouse.up(nw[0] + dx, center[1], selector);
     await testActor.reflow();
+    await onShapeChangeApplied;
 
-    let wBB = await getBoundingBoxInPx(testActor, helper, shape);
-    isnot(wBB.nw[0], nw[0], `${shape} nw moved right after w scale`);
-    is(wBB.nw[1], nw[1], `${shape} nw not moved down after w scale`);
-    isnot(wBB.width, width, `${shape} width reduced after w scale`);
-    is(wBB.height, height, `${shape} height not reduced after w scale`);
+    let wBB = await getBoundingBoxInPx({selector, ...config});
+    isnot(wBB.nw[0], nw[0], `${selector} nw moved right after w scale`);
+    is(wBB.nw[1], nw[1], `${selector} nw not moved down after w scale`);
+    isnot(wBB.width, width, `${selector} width reduced after w scale`);
+    is(wBB.height, height, `${selector} height not reduced after w scale`);
 
     info("Scaling from e");
-    await mouse.down(wBB.ne[0], center[1], shape);
-    await mouse.move(wBB.ne[0] - dx, center[1], shape);
-    await mouse.up(wBB.ne[0] - dx, center[1], shape);
+    onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+    await mouse.down(wBB.ne[0], center[1], selector);
+    await mouse.move(wBB.ne[0] - dx, center[1], selector);
+    await mouse.up(wBB.ne[0] - dx, center[1], selector);
     await testActor.reflow();
+    await onShapeChangeApplied;
 
-    let eBB = await getBoundingBoxInPx(testActor, helper, shape);
-    isnot(eBB.ne[0], wBB.ne[0], `${shape} ne moved left after e scale`);
-    is(eBB.ne[1], wBB.ne[1], `${shape} ne not moved down after e scale`);
-    isnot(eBB.width, wBB.width, `${shape} width reduced after e scale`);
-    is(eBB.height, wBB.height, `${shape} height not reduced after e scale`);
+    let eBB = await getBoundingBoxInPx({selector, ...config});
+    isnot(eBB.ne[0], wBB.ne[0], `${selector} ne moved left after e scale`);
+    is(eBB.ne[1], wBB.ne[1], `${selector} ne not moved down after e scale`);
+    isnot(eBB.width, wBB.width, `${selector} width reduced after e scale`);
+    is(eBB.height, wBB.height, `${selector} height not reduced after e scale`);
 
     info("Scaling from s");
-    await mouse.down(eBB.center[0], eBB.sw[1], shape);
-    await mouse.move(eBB.center[0], eBB.sw[1] - dy, shape);
-    await mouse.up(eBB.center[0], eBB.sw[1] - dy, shape);
+    onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+    await mouse.down(eBB.center[0], eBB.sw[1], selector);
+    await mouse.move(eBB.center[0], eBB.sw[1] - dy, selector);
+    await mouse.up(eBB.center[0], eBB.sw[1] - dy, selector);
     await testActor.reflow();
+    await onShapeChangeApplied;
 
-    let sBB = await getBoundingBoxInPx(testActor, helper, shape);
-    is(sBB.sw[0], eBB.sw[0], `${shape} sw not moved right after w scale`);
-    isnot(sBB.sw[1], eBB.sw[1], `${shape} sw moved down after w scale`);
-    is(sBB.width, eBB.width, `${shape} width not reduced after w scale`);
-    isnot(sBB.height, eBB.height, `${shape} height reduced after w scale`);
+    let sBB = await getBoundingBoxInPx({selector, ...config});
+    is(sBB.sw[0], eBB.sw[0], `${selector} sw not moved right after w scale`);
+    isnot(sBB.sw[1], eBB.sw[1], `${selector} sw moved down after w scale`);
+    is(sBB.width, eBB.width, `${selector} width not reduced after w scale`);
+    isnot(sBB.height, eBB.height, `${selector} height reduced after w scale`);
 
     info("Scaling from n");
-    await mouse.down(sBB.center[0], sBB.nw[1], shape);
-    await mouse.move(sBB.center[0], sBB.nw[1] + dy, shape);
-    await mouse.up(sBB.center[0], sBB.nw[1] + dy, shape);
+    onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
+    await mouse.down(sBB.center[0], sBB.nw[1], selector);
+    await mouse.move(sBB.center[0], sBB.nw[1] + dy, selector);
+    await mouse.up(sBB.center[0], sBB.nw[1] + dy, selector);
     await testActor.reflow();
+    await onShapeChangeApplied;
 
-    let nBB = await getBoundingBoxInPx(testActor, helper, shape);
-    is(nBB.nw[0], sBB.nw[0], `${shape} nw not moved right after n scale`);
-    isnot(nBB.nw[1], sBB.nw[1], `${shape} nw moved down after n scale`);
-    is(nBB.width, sBB.width, `${shape} width reduced after n scale`);
-    isnot(nBB.height, sBB.height, `${shape} height not reduced after n scale`);
+    let nBB = await getBoundingBoxInPx({selector, ...config});
+    is(nBB.nw[0], sBB.nw[0], `${selector} nw not moved right after n scale`);
+    isnot(nBB.nw[1], sBB.nw[1], `${selector} nw moved down after n scale`);
+    is(nBB.width, sBB.width, `${selector} width reduced after n scale`);
+    isnot(nBB.height, sBB.height, `${selector} height not reduced after n scale`);
+
+    await teardown({selector, property, ...config});
   }
 }
 
-async function getBoundingBoxInPx(testActor, helper, shape = "#polygon") {
-  let quads = await testActor.getAllAdjustedQuads(shape);
+async function getBoundingBoxInPx(config) {
+  const { testActor, selector, inspector, highlighters } = config;
+  let quads = await testActor.getAllAdjustedQuads(selector);
   let { width, height } = quads.content[0].bounds;
-  let computedStyle = await helper.highlightedNode.getComputedStyle();
+  let highlightedNode = await getNodeFront(selector, inspector);
+  let computedStyle = await inspector.pageStyle.getComputed(highlightedNode);
   let paddingTop = parseFloat(computedStyle["padding-top"].value);
   let paddingLeft = parseFloat(computedStyle["padding-left"].value);
-
   // path is always of form "Mx y Lx y Lx y Lx y Z", where x/y are numbers
-  let path = await helper.getElementAttribute("shapes-bounding-box", "d");
+  let path = await testActor.getHighlighterNodeAttribute(
+    "shapes-bounding-box", "d", highlighters.highlighters[HIGHLIGHTER_TYPE]);
   let coords = path.replace(/[MLZ]/g, "").split(" ").map((n, i) => {
     return i % 2 === 0 ? paddingLeft + width * n / 100 : paddingTop + height * n / 100;
   });
 
   let nw = [coords[0], coords[1]];
   let ne = [coords[2], coords[3]];
   let se = [coords[4], coords[5]];
   let sw = [coords[6], coords[7]];
--- a/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_iframe_01.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_iframe_01.js
@@ -5,42 +5,55 @@
 "use strict";
 
 // Test that shapes in iframes are updated correctly on mouse events.
 
 const TEST_URL = URL_ROOT + "doc_inspector_highlighter_cssshapes_iframe.html";
 const HIGHLIGHTER_TYPE = "ShapesHighlighter";
 
 add_task(async function() {
-  let inspector = await openInspectorForURL(TEST_URL);
-  let helper = await getHighlighterHelperFor(HIGHLIGHTER_TYPE)(inspector);
-  let {testActor} = inspector;
+  let env = await openInspectorForURL(TEST_URL);
+  let helper = await getHighlighterHelperFor(HIGHLIGHTER_TYPE)(env);
+  let {testActor, inspector} = env;
+  let view = selectRuleView(inspector);
+  let highlighters = view.highlighters;
+  let config = {inspector, view, highlighters, testActor, helper};
 
-  await testPolygonIframeMovePoint(testActor, helper);
-
-  await helper.finalize();
+  await testPolygonIframeMovePoint(config);
 });
 
-async function testPolygonIframeMovePoint(testActor, helper) {
-  info("Displaying polygon");
-  await helper.show("#polygon", {mode: "cssClipPath"}, "#frame");
-  let { mouse, highlightedNode } = helper;
+async function testPolygonIframeMovePoint(config) {
+  const { inspector, view, testActor, helper } = config;
+  const selector = "#polygon";
+  const property = "clip-path";
 
+  info(`Turn on shapes highlighter for ${selector}`);
+  // Get a reference to the highlighter's target node inside the iframe.
+  let highlightedNode = await getNodeFrontInFrame(selector, "#frame", inspector);
+  // Select the nested node so toggling of the shapes highlighter works from the rule view
+  await selectNode(highlightedNode, inspector);
+  await toggleShapesHighlighter(view, selector, property, true);
+  let { mouse } = helper;
+
+  let onRuleViewChanged = view.once("ruleview-changed");
   info("Moving polygon point visible in iframe");
   await mouse.down(10, 10);
   await mouse.move(20, 20);
   await mouse.up();
   await testActor.reflow();
+  await onRuleViewChanged;
 
-  let computedStyle = await highlightedNode.getComputedStyle();
+  let computedStyle = await inspector.pageStyle.getComputed(highlightedNode);
   let definition = computedStyle["clip-path"].value;
   ok(definition.includes("10px 10px"), "Point moved to 10px 10px");
 
+  onRuleViewChanged = view.once("ruleview-changed");
   info("Moving polygon point not visible in iframe");
   await mouse.down(110, 410);
   await mouse.move(120, 420);
   await mouse.up();
   await testActor.reflow();
+  await onRuleViewChanged;
 
-  computedStyle = await highlightedNode.getComputedStyle();
+  computedStyle = await inspector.pageStyle.getComputed(highlightedNode);
   definition = computedStyle["clip-path"].value;
   ok(definition.includes("110px 51.25%"), "Point moved to 110px 51.25%");
 }
--- a/devtools/client/inspector/test/head.js
+++ b/devtools/client/inspector/test/head.js
@@ -810,36 +810,44 @@ async function getDisplayedNodeTextConte
 }
 
 /**
  * Toggle the shapes highlighter by simulating a click on the toggle
  * in the rules view with the given selector and property
  *
  * @param {CssRuleView} view
  *        The instance of the rule-view panel
- * @param {Object} highlighters
- *        The highlighters instance of the rule-view panel
  * @param {String} selector
  *        The selector in the rule-view to look for the property in
  * @param {String} property
  *        The name of the property
  * @param {Boolean} show
  *        If true, the shapes highlighter is being shown. If false, it is being hidden
+ * @param {Options} options
+ *        Config option for the shapes highlighter. Contains:
+ *        - {Boolean} transformMode: wether to show the highlighter in transforms mode
  */
-async function toggleShapesHighlighter(view, highlighters, selector, property, show) {
-  info("Toggle shapes highlighter");
-  let container = getRuleViewProperty(view, selector, property).valueSpan;
-  let shapesToggle = container.querySelector(".ruleview-shapeswatch");
+async function toggleShapesHighlighter(view, selector, property, show, options = {}) {
+  info(`Toggle shapes highlighter ${show ? "on" : "off"} for ${property} on ${selector}`);
+  const highlighters = view.highlighters;
+  const container = getRuleViewProperty(view, selector, property).valueSpan;
+  const shapesToggle = container.querySelector(".ruleview-shapeswatch");
+
+  let metaKey = options.transformMode;
+  let ctrlKey = options.transformMode;
+
   if (show) {
     let onHighlighterShown = highlighters.once("shapes-highlighter-shown");
-    shapesToggle.click();
+    EventUtils.sendMouseEvent({type: "click", metaKey, ctrlKey },
+      shapesToggle, view.styleWindow);
     await onHighlighterShown;
   } else {
     let onHighlighterHidden = highlighters.once("shapes-highlighter-hidden");
-    shapesToggle.click();
+    EventUtils.sendMouseEvent({type: "click", metaKey, ctrlKey },
+      shapesToggle, view.styleWindow);
     await onHighlighterHidden;
   }
 }
 
 /**
  * Expand the provided markup container programatically and  wait for all children to
  * update.
  */