Bug 1435373 - Shapes editor: update tests for new implementation.r=pbro
authorRazvan Caliman <rcaliman@mozilla.com>
Tue, 10 Apr 2018 13:59:13 +0200
changeset 412561 b9f53df7f400
parent 412560 bc52ed730824
child 412562 efe7d9c93434
push id101945
push userjdescottes@mozilla.com
push dateTue, 10 Apr 2018 12:00:45 +0000
treeherdermozilla-inbound@b9f53df7f400 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspbro
bugs1435373
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1435373 - Shapes editor: update tests for new implementation.r=pbro 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
@@ -790,36 +790,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.
  */