Backed out changeset 85d33b74434a (bug 1327675) for asan dt10 failures in browser_rules_content_02.js a=backout
authorWes Kocher <wkocher@mozilla.com>
Tue, 31 Jan 2017 10:24:33 -0800
changeset 468866 895ddf282ead4d4533313c43b7cfa0aa218981e3
parent 468865 8d2a9160dcafe13d28099a643212f784b5124e8c
child 468867 1d025ac534a6333a8170a59a95a8a3673d4028ee
child 468993 bb5ca84bd66091749a4a81a3eb82a5afd78ca0d8
push id43551
push userbmo:kgilbert@mozilla.com
push dateTue, 31 Jan 2017 23:27:06 +0000
reviewersbackout
bugs1327675
milestone54.0a1
backs out85d33b74434a76f5d49c5c88482cc94014c6e6c2
Backed out changeset 85d33b74434a (bug 1327675) for asan dt10 failures in browser_rules_content_02.js a=backout MozReview-Commit-ID: GxWdtGX5Lor
devtools/client/inspector/rules/test/browser.ini
devtools/client/inspector/rules/test/browser_rules_edit-selector_04.js
devtools/client/inspector/rules/test/browser_rules_inherited-properties_03.js
devtools/client/inspector/rules/test/browser_rules_inherited-properties_04.js
devtools/client/inspector/rules/test/browser_rules_selector-highlighter-on-navigate.js
devtools/client/inspector/rules/test/browser_rules_selector-highlighter_01.js
devtools/client/inspector/rules/test/browser_rules_selector-highlighter_02.js
devtools/client/inspector/rules/test/browser_rules_selector-highlighter_03.js
devtools/client/inspector/rules/test/browser_rules_selector-highlighter_04.js
devtools/client/inspector/rules/test/browser_rules_selector-highlighter_05.js
devtools/client/inspector/rules/test/head.js
devtools/client/inspector/rules/views/rule-editor.js
devtools/client/inspector/shared/test/head.js
devtools/client/inspector/test/shared-head.js
--- a/devtools/client/inspector/rules/test/browser.ini
+++ b/devtools/client/inspector/rules/test/browser.ini
@@ -207,17 +207,16 @@ skip-if = (os == 'linux' && bits == 32 &
 [browser_rules_select-and-copy-styles.js]
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_rules_selector-highlighter-on-navigate.js]
 [browser_rules_selector-highlighter_01.js]
 [browser_rules_selector-highlighter_02.js]
 [browser_rules_selector-highlighter_03.js]
 [browser_rules_selector-highlighter_04.js]
-[browser_rules_selector-highlighter_05.js]
 [browser_rules_selector_highlight.js]
 [browser_rules_strict-search-filter-computed-list_01.js]
 [browser_rules_strict-search-filter_01.js]
 [browser_rules_strict-search-filter_02.js]
 [browser_rules_strict-search-filter_03.js]
 [browser_rules_style-editor-link.js]
 [browser_rules_urls-clickable.js]
 [browser_rules_user-agent-styles.js]
--- a/devtools/client/inspector/rules/test/browser_rules_edit-selector_04.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector_04.js
@@ -28,17 +28,17 @@ add_task(function* () {
   yield testEditSelector(view, "body");
   yield testSelectorHighlight(view, "body");
 });
 
 function* testSelectorHighlight(view, name) {
   info("Test creating selector highlighter");
 
   info("Clicking on a selector icon");
-  let icon = yield getRuleViewSelectorHighlighterIcon(view, name);
+  let icon = getRuleViewSelectorHighlighterIcon(view, name);
 
   let onToggled = view.once("ruleview-selectorhighlighter-toggled");
   EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);
   let isVisible = yield onToggled;
 
   ok(view.selectorHighlighter, "The selectorhighlighter instance was created");
   ok(isVisible, "The toggle event says the highlighter is visible");
 }
--- a/devtools/client/inspector/rules/test/browser_rules_inherited-properties_03.js
+++ b/devtools/client/inspector/rules/test/browser_rules_inherited-properties_03.js
@@ -13,17 +13,16 @@ const TEST_URI = `
     <div id="test1">Styled Node</div>
   </div>
 `;
 
 add_task(function* () {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#test1", inspector);
-  yield getRuleViewSelectorHighlighterIcon(view, "element", 1);
   yield elementStyleInherit(inspector, view);
 });
 
 function* elementStyleInherit(inspector, view) {
   let elementStyle = view._elementStyle;
   is(elementStyle.rules.length, 2, "Should have 2 rules.");
 
   let elementRule = elementStyle.rules[0];
--- a/devtools/client/inspector/rules/test/browser_rules_inherited-properties_04.js
+++ b/devtools/client/inspector/rules/test/browser_rules_inherited-properties_04.js
@@ -15,17 +15,16 @@ const TEST_URI = `
     </div>
   </div>
 `;
 
 add_task(function* () {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("a", inspector);
-  yield getRuleViewSelectorHighlighterIcon(view, "element", 2);
   yield elementStyleInherit(inspector, view);
 });
 
 function* elementStyleInherit(inspector, view) {
   let gutters = view.element.querySelectorAll(".theme-gutter");
   is(gutters.length, 2,
     "Gutters should contains 2 sections");
   ok(gutters[0].textContent, "Inherited from div");
--- a/devtools/client/inspector/rules/test/browser_rules_selector-highlighter-on-navigate.js
+++ b/devtools/client/inspector/rules/test/browser_rules_selector-highlighter-on-navigate.js
@@ -18,17 +18,17 @@ const TEST_URI = `
 const TEST_URI_2 = "data:text/html,<html><body>test</body></html>";
 
 add_task(function* () {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   let highlighters = view.highlighters;
 
   info("Clicking on a selector icon");
-  let icon = yield getRuleViewSelectorHighlighterIcon(view, "body, p, td");
+  let icon = getRuleViewSelectorHighlighterIcon(view, "body, p, td");
 
   let onToggled = view.once("ruleview-selectorhighlighter-toggled");
   EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);
   let isVisible = yield onToggled;
 
   ok(highlighters.selectorHighlighterShown, "The selectorHighlighterShown is set.");
   ok(view.selectorHighlighter, "The selectorhighlighter instance was created");
   ok(isVisible, "The toggle event says the highlighter is visible");
--- a/devtools/client/inspector/rules/test/browser_rules_selector-highlighter_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_selector-highlighter_01.js
@@ -19,17 +19,17 @@ const TEST_URI = `
 add_task(function* () {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {view} = yield openRuleView();
 
   ok(!view.selectorHighlighter,
     "No selectorhighlighter exist in the rule-view");
 
   info("Clicking on a selector icon");
-  let icon = yield getRuleViewSelectorHighlighterIcon(view, "body, p, td");
+  let icon = getRuleViewSelectorHighlighterIcon(view, "body, p, td");
 
   let onToggled = view.once("ruleview-selectorhighlighter-toggled");
   EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);
   let isVisible = yield onToggled;
 
   ok(view.selectorHighlighter, "The selectorhighlighter instance was created");
   ok(isVisible, "The toggle event says the highlighter is visible");
 });
--- a/devtools/client/inspector/rules/test/browser_rules_selector-highlighter_02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_selector-highlighter_02.js
@@ -41,38 +41,38 @@ add_task(function* () {
       this.options = null;
       this.isShown = false;
     }
   };
 
   // Inject the mock highlighter in the rule-view
   view.selectorHighlighter = HighlighterFront;
 
-  let icon = yield getRuleViewSelectorHighlighterIcon(view, "body");
+  let icon = getRuleViewSelectorHighlighterIcon(view, "body");
 
   info("Checking that the HighlighterFront's show/hide methods are called");
 
   info("Clicking once on the body selector highlighter icon");
   yield clickSelectorIcon(icon, view);
   ok(HighlighterFront.isShown, "The highlighter is shown");
 
   info("Clicking once again on the body selector highlighter icon");
   yield clickSelectorIcon(icon, view);
   ok(!HighlighterFront.isShown, "The highlighter is hidden");
 
   info("Checking that the right NodeFront reference and options are passed");
   yield selectNode("p", inspector);
-  icon = yield getRuleViewSelectorHighlighterIcon(view, "p");
+  icon = getRuleViewSelectorHighlighterIcon(view, "p");
 
   yield clickSelectorIcon(icon, view);
   is(HighlighterFront.nodeFront.tagName, "P",
     "The right NodeFront is passed to the highlighter (1)");
   is(HighlighterFront.options.selector, "p",
     "The right selector option is passed to the highlighter (1)");
 
   yield selectNode("body", inspector);
-  icon = yield getRuleViewSelectorHighlighterIcon(view, "body");
+  icon = getRuleViewSelectorHighlighterIcon(view, "body");
   yield clickSelectorIcon(icon, view);
   is(HighlighterFront.nodeFront.tagName, "BODY",
     "The right NodeFront is passed to the highlighter (2)");
   is(HighlighterFront.options.selector, "body",
     "The right selector option is passed to the highlighter (2)");
 });
--- a/devtools/client/inspector/rules/test/browser_rules_selector-highlighter_03.js
+++ b/devtools/client/inspector/rules/test/browser_rules_selector-highlighter_03.js
@@ -34,45 +34,45 @@ add_task(function* () {
     }
   };
 
   // Inject the mock highlighter in the rule-view
   view.selectorHighlighter = HighlighterFront;
 
   info("Select .node-1 and click on the .node-1 selector icon");
   yield selectNode(".node-1", inspector);
-  let icon = yield getRuleViewSelectorHighlighterIcon(view, ".node-1");
+  let icon = getRuleViewSelectorHighlighterIcon(view, ".node-1");
   yield clickSelectorIcon(icon, view);
   ok(HighlighterFront.isShown, "The highlighter is shown");
 
   info("With .node-1 still selected, click again on the .node-1 selector icon");
   yield clickSelectorIcon(icon, view);
   ok(!HighlighterFront.isShown, "The highlighter is now hidden");
 
   info("With .node-1 still selected, click on the div selector icon");
-  icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
+  icon = getRuleViewSelectorHighlighterIcon(view, "div");
   yield clickSelectorIcon(icon, view);
   ok(HighlighterFront.isShown, "The highlighter is shown again");
 
   info("With .node-1 still selected, click again on the .node-1 selector icon");
-  icon = yield getRuleViewSelectorHighlighterIcon(view, ".node-1");
+  icon = getRuleViewSelectorHighlighterIcon(view, ".node-1");
   yield clickSelectorIcon(icon, view);
   ok(HighlighterFront.isShown,
     "The highlighter is shown again since the clicked selector was different");
 
   info("Selecting .node-2");
   yield selectNode(".node-2", inspector);
   ok(HighlighterFront.isShown,
     "The highlighter is still shown after selection");
 
   info("With .node-2 selected, click on the div selector icon");
-  icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
+  icon = getRuleViewSelectorHighlighterIcon(view, "div");
   yield clickSelectorIcon(icon, view);
   ok(HighlighterFront.isShown,
     "The highlighter is shown still since the selected was different");
 
   info("Switching back to .node-1 and clicking on the div selector");
   yield selectNode(".node-1", inspector);
-  icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
+  icon = getRuleViewSelectorHighlighterIcon(view, "div");
   yield clickSelectorIcon(icon, view);
   ok(!HighlighterFront.isShown,
     "The highlighter is hidden now that the same selector was clicked");
 });
--- a/devtools/client/inspector/rules/test/browser_rules_selector-highlighter_04.js
+++ b/devtools/client/inspector/rules/test/browser_rules_selector-highlighter_04.js
@@ -34,17 +34,17 @@ add_task(function* () {
       this.isShown = false;
     }
   };
   // Inject the mock highlighter in the rule-view
   view.selectorHighlighter = HighlighterFront;
 
   info("Checking that the right NodeFront reference and options are passed");
   yield selectNode("p", inspector);
-  let icon = yield getRuleViewSelectorHighlighterIcon(view, "element");
+  let icon = getRuleViewSelectorHighlighterIcon(view, "element");
 
   yield clickSelectorIcon(icon, view);
   is(HighlighterFront.nodeFront.tagName, "P",
      "The right NodeFront is passed to the highlighter (1)");
   is(HighlighterFront.options.selector, "body > p:nth-child(1)",
      "The right selector option is passed to the highlighter (1)");
   ok(HighlighterFront.isShown, "The toggle event says the highlighter is visible");
 
deleted file mode 100644
--- a/devtools/client/inspector/rules/test/browser_rules_selector-highlighter_05.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
-http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that the selector highlighter is correctly shown when clicking on a
-// inherited element
-
-// Note that in this test, we mock the highlighter front, merely testing the
-// behavior of the style-inspector UI for now
-
-const TEST_URI = `
-<div style="cursor:pointer">
-  A
-  <div style="cursor:pointer">
-    B<a>Cursor</a>
-  </div>
-</div>
-`;
-
-add_task(function* () {
-  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
-  let {inspector, view} = yield openRuleView();
-
-  // Mock the highlighter front to get the reference of the NodeFront
-  let HighlighterFront = {
-    isShown: false,
-    nodeFront: null,
-    options: null,
-    show: function (nodeFront, options) {
-      this.nodeFront = nodeFront;
-      this.options = options;
-      this.isShown = true;
-    },
-    hide: function () {
-      this.nodeFront = null;
-      this.options = null;
-      this.isShown = false;
-    }
-  };
-  // Inject the mock highlighter in the rule-view
-  view.selectorHighlighter = HighlighterFront;
-
-  info("Checking that the right NodeFront reference and options are passed");
-  yield selectNode("a", inspector);
-
-  let icon = yield getRuleViewSelectorHighlighterIcon(view, "element");
-  yield clickSelectorIcon(icon, view);
-  is(HighlighterFront.options.selector,
-     "body > div:nth-child(1) > div:nth-child(1) > a:nth-child(1)",
-     "The right selector option is passed to the highlighter (1)");
-
-  icon = yield getRuleViewSelectorHighlighterIcon(view, "element", 1);
-  yield clickSelectorIcon(icon, view);
-  is(HighlighterFront.options.selector, "body > div:nth-child(1) > div:nth-child(1)",
-     "The right selector option is passed to the highlighter (1)");
-
-  icon = yield getRuleViewSelectorHighlighterIcon(view, "element", 2);
-  yield clickSelectorIcon(icon, view);
-  is(HighlighterFront.options.selector, "body > div:nth-child(1)",
-     "The right selector option is passed to the highlighter (1)");
-});
--- a/devtools/client/inspector/rules/test/head.js
+++ b/devtools/client/inspector/rules/test/head.js
@@ -40,31 +40,144 @@ addTab = function (url) {
     info("Loading the helper frame script " + FRAME_SCRIPT_URL);
     let browser = tab.linkedBrowser;
     browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
     return tab;
   });
 };
 
 /**
+ * Wait for a content -> chrome message on the message manager (the window
+ * messagemanager is used).
+ *
+ * @param {String} name
+ *        The message name
+ * @return {Promise} A promise that resolves to the response data when the
+ * message has been received
+ */
+function waitForContentMessage(name) {
+  info("Expecting message " + name + " from content");
+
+  let mm = gBrowser.selectedBrowser.messageManager;
+
+  let def = defer();
+  mm.addMessageListener(name, function onMessage(msg) {
+    mm.removeMessageListener(name, onMessage);
+    def.resolve(msg.data);
+  });
+  return def.promise;
+}
+
+/**
+ * Send an async message to the frame script (chrome -> content) and wait for a
+ * response message with the same name (content -> chrome).
+ *
+ * @param {String} name
+ *        The message name. Should be one of the messages defined
+ *        in doc_frame_script.js
+ * @param {Object} data
+ *        Optional data to send along
+ * @param {Object} objects
+ *        Optional CPOW objects to send along
+ * @param {Boolean} expectResponse
+ *        If set to false, don't wait for a response with the same name
+ *        from the content script. Defaults to true.
+ * @return {Promise} Resolves to the response data if a response is expected,
+ * immediately resolves otherwise
+ */
+function executeInContent(name, data = {}, objects = {},
+                          expectResponse = true) {
+  info("Sending message " + name + " to content");
+  let mm = gBrowser.selectedBrowser.messageManager;
+
+  mm.sendAsyncMessage(name, data, objects);
+  if (expectResponse) {
+    return waitForContentMessage(name);
+  }
+
+  return promise.resolve();
+}
+
+/**
+ * Send an async message to the frame script and get back the requested
+ * computed style property.
+ *
+ * @param {String} selector
+ *        The selector used to obtain the element.
+ * @param {String} pseudo
+ *        pseudo id to query, or null.
+ * @param {String} name
+ *        name of the property.
+ */
+function* getComputedStyleProperty(selector, pseudo, propName) {
+  return yield executeInContent("Test:GetComputedStylePropertyValue",
+    {selector,
+     pseudo,
+     name: propName});
+}
+
+/**
  * Get an element's inline style property value.
  * @param {TestActor} testActor
  * @param {String} selector
  *        The selector used to obtain the element.
  * @param {String} name
  *        name of the property.
  */
 function getStyle(testActor, selector, propName) {
   return testActor.eval(`
     content.document.querySelector("${selector}")
                     .style.getPropertyValue("${propName}");
   `);
 }
 
 /**
+ * Send an async message to the frame script and wait until the requested
+ * computed style property has the expected value.
+ *
+ * @param {String} selector
+ *        The selector used to obtain the element.
+ * @param {String} pseudo
+ *        pseudo id to query, or null.
+ * @param {String} prop
+ *        name of the property.
+ * @param {String} expected
+ *        expected value of property
+ * @param {String} name
+ *        the name used in test message
+ */
+function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
+  return yield executeInContent("Test:WaitForComputedStylePropertyValue",
+    {selector,
+     pseudo,
+     expected,
+     name});
+}
+
+/**
+ * Given an inplace editable element, click to switch it to edit mode, wait for
+ * focus
+ *
+ * @return a promise that resolves to the inplace-editor element when ready
+ */
+var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
+    yOffset = 1, options = {}) {
+  let onFocus = once(editable.parentNode, "focus", true);
+  info("Clicking on editable field to turn to edit mode");
+  EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
+    editable.ownerDocument.defaultView);
+  yield onFocus;
+
+  info("Editable field gained focus, returning the input field now");
+  let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
+
+  return onEdit;
+});
+
+/**
  * When a tooltip is closed, this ends up "commiting" the value changed within
  * the tooltip (e.g. the color in case of a colorpicker) which, in turn, ends up
  * setting the value of the corresponding css property in the rule-view.
  * Use this function to close the tooltip and make sure the test waits for the
  * ruleview-changed event.
  * @param {SwatchBasedEditorTooltip} editorTooltip
  * @param {CSSRuleView} view
  */
@@ -102,16 +215,119 @@ var waitForSuccess = Task.async(function
       ok(false, "Failure: " + desc);
       break;
     }
     yield new Promise(r => setTimeout(r, 200));
   }
 });
 
 /**
+ * Get the DOMNode for a css rule in the rule-view that corresponds to the given
+ * selector
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view for which the rule
+ *        object is wanted
+ * @return {DOMNode}
+ */
+function getRuleViewRule(view, selectorText) {
+  let rule;
+  for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
+    let selector = r.querySelector(".ruleview-selectorcontainer, " +
+                                   ".ruleview-selector-matched");
+    if (selector && selector.textContent === selectorText) {
+      rule = r;
+      break;
+    }
+  }
+
+  return rule;
+}
+
+/**
+ * Get references to the name and value span nodes corresponding to a given
+ * selector and property name in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for the property in
+ * @param {String} propertyName
+ *        The name of the property
+ * @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
+ */
+function getRuleViewProperty(view, selectorText, propertyName) {
+  let prop;
+
+  let rule = getRuleViewRule(view, selectorText);
+  if (rule) {
+    // Look for the propertyName in that rule element
+    for (let p of rule.querySelectorAll(".ruleview-property")) {
+      let nameSpan = p.querySelector(".ruleview-propertyname");
+      let valueSpan = p.querySelector(".ruleview-propertyvalue");
+
+      if (nameSpan.textContent === propertyName) {
+        prop = {nameSpan: nameSpan, valueSpan: valueSpan};
+        break;
+      }
+    }
+  }
+  return prop;
+}
+
+/**
+ * Get the text value of the property corresponding to a given selector and name
+ * in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for the property in
+ * @param {String} propertyName
+ *        The name of the property
+ * @return {String} The property value
+ */
+function getRuleViewPropertyValue(view, selectorText, propertyName) {
+  return getRuleViewProperty(view, selectorText, propertyName)
+    .valueSpan.textContent;
+}
+
+/**
+ * Get a reference to the selector DOM element corresponding to a given selector
+ * in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for
+ * @return {DOMNode} The selector DOM element
+ */
+function getRuleViewSelector(view, selectorText) {
+  let rule = getRuleViewRule(view, selectorText);
+  return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
+}
+
+/**
+ * Get a reference to the selectorhighlighter icon DOM element corresponding to
+ * a given selector in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for
+ * @return {DOMNode} The selectorhighlighter icon DOM element
+ */
+function getRuleViewSelectorHighlighterIcon(view, selectorText) {
+  let rule = getRuleViewRule(view, selectorText);
+  return rule.querySelector(".ruleview-selectorhighlighter");
+}
+
+/**
  * Simulate a color change in a given color picker tooltip, and optionally wait
  * for a given element in the page to have its style changed as a result.
  * Note that this function assumes that the colorpicker popup is already open
  * and it won't close it after having selected the new color.
  *
  * @param {RuleView} ruleView
  *        The related rule view instance
  * @param {SwatchColorPickerTooltip} colorPicker
@@ -232,16 +448,44 @@ var openCubicBezierAndChangeCoords = Tas
     let {selector, name, value} = expectedChange;
     yield waitForComputedStyleProperty(selector, null, name, value);
   }
 
   return {propEditor, swatch, bezierTooltip};
 });
 
 /**
+ * Get a rule-link from the rule-view given its index
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {Number} index
+ *        The index of the link to get
+ * @return {DOMNode} The link if any at this index
+ */
+function getRuleViewLinkByIndex(view, index) {
+  let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
+  return links[index];
+}
+
+/**
+ * Get rule-link text from the rule-view given its index
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {Number} index
+ *        The index of the link to get
+ * @return {String} The string at this index
+ */
+function getRuleViewLinkTextByIndex(view, index) {
+  let link = getRuleViewLinkByIndex(view, index);
+  return link.querySelector(".ruleview-rule-source-label").textContent;
+}
+
+/**
  * Simulate adding a new property in an existing rule in the rule-view.
  *
  * @param {CssRuleView} view
  *        The instance of the rule-view panel
  * @param {Number} ruleIndex
  *        The index of the rule to use. Note that if ruleIndex is 0, you might
  *        want to also listen to markupmutation events in your test since
  *        that's going to change the style attribute of the selected node.
@@ -377,16 +621,84 @@ var removeProperty = Task.async(function
  */
 var togglePropStatus = Task.async(function* (view, textProp) {
   let onRuleViewRefreshed = view.once("ruleview-changed");
   textProp.editor.enable.click();
   yield onRuleViewRefreshed;
 });
 
 /**
+ * Click on a rule-view's close brace to focus a new property name editor
+ *
+ * @param {RuleEditor} ruleEditor
+ *        An instance of RuleEditor that will receive the new property
+ * @return a promise that resolves to the newly created editor when ready and
+ * focused
+ */
+var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
+  info("Clicking on a close ruleEditor brace to start editing a new property");
+
+  // Use bottom alignment to avoid scrolling out of the parent element area.
+  ruleEditor.closeBrace.scrollIntoView(false);
+  let editor = yield focusEditableField(ruleEditor.ruleView,
+    ruleEditor.closeBrace);
+
+  is(inplaceEditor(ruleEditor.newPropSpan), editor,
+    "Focused editor is the new property editor.");
+
+  return editor;
+});
+
+/**
+ * Create a new property name in the rule-view, focusing a new property editor
+ * by clicking on the close brace, and then entering the given text.
+ * Keep in mind that the rule-view knows how to handle strings with multiple
+ * properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
+ *
+ * @param {RuleEditor} ruleEditor
+ *        The instance of RuleEditor that will receive the new property(ies)
+ * @param {String} inputValue
+ *        The text to be entered in the new property name field
+ * @return a promise that resolves when the new property name has been entered
+ * and once the value field is focused
+ */
+var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
+  info("Creating a new property editor");
+  let editor = yield focusNewRuleViewProperty(ruleEditor);
+
+  info("Entering the value " + inputValue);
+  editor.input.value = inputValue;
+
+  info("Submitting the new value and waiting for value field focus");
+  let onFocus = once(ruleEditor.element, "focus", true);
+  EventUtils.synthesizeKey("VK_RETURN", {},
+    ruleEditor.element.ownerDocument.defaultView);
+  yield onFocus;
+});
+
+/**
+ * Set the search value for the rule-view filter styles search box.
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} searchValue
+ *        The filter search value
+ * @return a promise that resolves when the rule-view is filtered for the
+ * search term
+ */
+var setSearchFilter = Task.async(function* (view, searchValue) {
+  info("Setting filter text to \"" + searchValue + "\"");
+  let win = view.styleWindow;
+  let searchField = view.searchField;
+  searchField.focus();
+  synthesizeKeys(searchValue, win);
+  yield view.inspector.once("ruleview-filtered");
+});
+
+/**
  * Reload the current page and wait for the inspector to be initialized after
  * the navigation
  *
  * @param {InspectorPanel} inspector
  *        The instance of InspectorPanel currently loaded in the toolbox
  * @param {TestActor} testActor
  *        The current instance of the TestActor
  */
@@ -462,16 +774,36 @@ function* sendKeysAndWaitForFocus(view, 
   let onFocus = once(element, "focus", true);
   for (let key of keys) {
     EventUtils.sendKey(key, view.styleWindow);
   }
   yield onFocus;
 }
 
 /**
+ * Open the style editor context menu and return all of it's items in a flat array
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @return An array of MenuItems
+ */
+function openStyleContextMenuAndGetAllItems(view, target) {
+  let menu = view._contextmenu._openMenu({target: target});
+
+  // Flatten all menu items into a single array to make searching through it easier
+  let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
+    if (item.submenu) {
+      return addItem(item.submenu.items);
+    }
+    return item;
+  }));
+
+  return allItems;
+}
+
+/**
  * Wait for a markupmutation event on the inspector that is for a style modification.
  * @param {InspectorPanel} inspector
  * @return {Promise}
  */
 function waitForStyleModification(inspector) {
   return new Promise(function (resolve) {
     function checkForStyleModification(name, mutations) {
       for (let mutation of mutations) {
--- a/devtools/client/inspector/rules/views/rule-editor.js
+++ b/devtools/client/inspector/rules/views/rule-editor.js
@@ -144,44 +144,29 @@ RuleEditor.prototype = {
         element: this.selectorText,
         done: this._onSelectorDone,
         cssProperties: this.rule.cssProperties,
         contextMenu: this.ruleView.inspector.onTextBoxContextMenu
       });
     }
 
     if (this.rule.domRule.type !== CSSRule.KEYFRAME_RULE) {
-      Task.spawn(function* () {
-        let selector;
+      let selector = this.rule.domRule.selectors
+               ? this.rule.domRule.selectors.join(", ")
+               : this.ruleView.inspector.selectionCssSelector;
 
-        if (this.rule.domRule.selectors) {
-          // This is a "normal" rule with a selector.
-          selector = this.rule.domRule.selectors.join(", ");
-        } else if (this.rule.inherited) {
-          // This is an inline style from an inherited rule. Need to resolve the unique
-          // selector from the node which rule this is inherited from.
-          selector = yield this.rule.inherited.getUniqueSelector();
-        } else {
-          // This is an inline style from the current node.
-          selector = this.ruleView.inspector.selectionCssSelector;
-        }
-
-        let selectorHighlighter = createChild(header, "span", {
-          class: "ruleview-selectorhighlighter" +
-                 (this.ruleView.highlighters.selectorHighlighterShown === selector ?
-                  " highlighted" : ""),
-          title: l10n("rule.selectorHighlighter.tooltip")
-        });
-        selectorHighlighter.addEventListener("click", () => {
-          this.ruleView.toggleSelectorHighlighter(selectorHighlighter, selector);
-        });
-
-        this.uniqueSelector = selector;
-        this.emit("selector-icon-created");
-      }.bind(this));
+      let selectorHighlighter = createChild(header, "span", {
+        class: "ruleview-selectorhighlighter" +
+               (this.ruleView.highlighters.selectorHighlighterShown === selector ?
+                " highlighted" : ""),
+        title: l10n("rule.selectorHighlighter.tooltip")
+      });
+      selectorHighlighter.addEventListener("click", () => {
+        this.ruleView.toggleSelectorHighlighter(selectorHighlighter, selector);
+      });
     }
 
     this.openBrace = createChild(header, "span", {
       class: "ruleview-ruleopen",
       textContent: " {"
     });
 
     this.propertyList = createChild(code, "ul", {
--- a/devtools/client/inspector/shared/test/head.js
+++ b/devtools/client/inspector/shared/test/head.js
@@ -84,16 +84,133 @@ addTab = function (url) {
     info("Loading the helper frame script " + FRAME_SCRIPT_URL);
     let browser = tab.linkedBrowser;
     browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
     return tab;
   });
 };
 
 /**
+ * Wait for a content -> chrome message on the message manager (the window
+ * messagemanager is used).
+ *
+ * @param {String} name
+ *        The message name
+ * @return {Promise} A promise that resolves to the response data when the
+ * message has been received
+ */
+function waitForContentMessage(name) {
+  info("Expecting message " + name + " from content");
+
+  let mm = gBrowser.selectedBrowser.messageManager;
+
+  let def = defer();
+  mm.addMessageListener(name, function onMessage(msg) {
+    mm.removeMessageListener(name, onMessage);
+    def.resolve(msg.data);
+  });
+  return def.promise;
+}
+
+/**
+ * Send an async message to the frame script (chrome -> content) and wait for a
+ * response message with the same name (content -> chrome).
+ *
+ * @param {String} name
+ *        The message name. Should be one of the messages defined
+ *        in doc_frame_script.js
+ * @param {Object} data
+ *        Optional data to send along
+ * @param {Object} objects
+ *        Optional CPOW objects to send along
+ * @param {Boolean} expectResponse
+ *        If set to false, don't wait for a response with the same name
+ *        from the content script. Defaults to true.
+ * @return {Promise} Resolves to the response data if a response is expected,
+ * immediately resolves otherwise
+ */
+function executeInContent(name, data = {}, objects = {},
+                          expectResponse = true) {
+  info("Sending message " + name + " to content");
+  let mm = gBrowser.selectedBrowser.messageManager;
+
+  mm.sendAsyncMessage(name, data, objects);
+  if (expectResponse) {
+    return waitForContentMessage(name);
+  }
+
+  return promise.resolve();
+}
+
+/**
+ * Send an async message to the frame script and get back the requested
+ * computed style property.
+ *
+ * @param {String} selector
+ *        The selector used to obtain the element.
+ * @param {String} pseudo
+ *        pseudo id to query, or null.
+ * @param {String} name
+ *        name of the property.
+ */
+function* getComputedStyleProperty(selector, pseudo, propName) {
+  let data = {
+    selector,
+    pseudo,
+    name: propName
+  };
+  return yield executeInContent("Test:GetComputedStylePropertyValue", data);
+}
+
+/**
+ * Send an async message to the frame script and wait until the requested
+ * computed style property has the expected value.
+ *
+ * @param {String} selector
+ *        The selector used to obtain the element.
+ * @param {String} pseudo
+ *        pseudo id to query, or null.
+ * @param {String} prop
+ *        name of the property.
+ * @param {String} expected
+ *        expected value of property
+ * @param {String} name
+ *        the name used in test message
+ */
+function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
+  let data = {
+    selector,
+    pseudo,
+    expected,
+    name
+  };
+  return yield executeInContent("Test:WaitForComputedStylePropertyValue", data);
+}
+
+/**
+ * Given an inplace editable element, click to switch it to edit mode, wait for
+ * focus
+ *
+ * @return a promise that resolves to the inplace-editor element when ready
+ */
+var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
+                                               yOffset = 1, options = {}) {
+  let onFocus = once(editable.parentNode, "focus", true);
+  info("Clicking on editable field to turn to edit mode");
+  EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
+    editable.ownerDocument.defaultView);
+  yield onFocus;
+
+  info("Editable field gained focus, returning the input field now");
+  let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
+
+  return onEdit;
+});
+
+/**
  * Polls a given function waiting for it to return true.
  *
  * @param {Function} validatorFn
  *        A validator function that returns a boolean.
  *        This is called every few milliseconds to check if the result is true.
  *        When it is true, the promise resolves.
  * @param {String} name
  *        Optional name of the test. This is used to generate
@@ -137,16 +254,119 @@ var getFontFamilyDataURL = Task.async(fu
 /* *********************************************
  * RULE-VIEW
  * *********************************************
  * Rule-view related test utility functions
  * This object contains functions to get rules, get properties, ...
  */
 
 /**
+ * Get the DOMNode for a css rule in the rule-view that corresponds to the given
+ * selector
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view for which the rule
+ *        object is wanted
+ * @return {DOMNode}
+ */
+function getRuleViewRule(view, selectorText) {
+  let rule;
+  for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
+    let selector = r.querySelector(".ruleview-selectorcontainer, " +
+                                   ".ruleview-selector-matched");
+    if (selector && selector.textContent === selectorText) {
+      rule = r;
+      break;
+    }
+  }
+
+  return rule;
+}
+
+/**
+ * Get references to the name and value span nodes corresponding to a given
+ * selector and property name in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for the property in
+ * @param {String} propertyName
+ *        The name of the property
+ * @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
+ */
+function getRuleViewProperty(view, selectorText, propertyName) {
+  let prop;
+
+  let rule = getRuleViewRule(view, selectorText);
+  if (rule) {
+    // Look for the propertyName in that rule element
+    for (let p of rule.querySelectorAll(".ruleview-property")) {
+      let nameSpan = p.querySelector(".ruleview-propertyname");
+      let valueSpan = p.querySelector(".ruleview-propertyvalue");
+
+      if (nameSpan.textContent === propertyName) {
+        prop = {nameSpan: nameSpan, valueSpan: valueSpan};
+        break;
+      }
+    }
+  }
+  return prop;
+}
+
+/**
+ * Get the text value of the property corresponding to a given selector and name
+ * in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for the property in
+ * @param {String} propertyName
+ *        The name of the property
+ * @return {String} The property value
+ */
+function getRuleViewPropertyValue(view, selectorText, propertyName) {
+  return getRuleViewProperty(view, selectorText, propertyName)
+    .valueSpan.textContent;
+}
+
+/**
+ * Get a reference to the selector DOM element corresponding to a given selector
+ * in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for
+ * @return {DOMNode} The selector DOM element
+ */
+function getRuleViewSelector(view, selectorText) {
+  let rule = getRuleViewRule(view, selectorText);
+  return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
+}
+
+/**
+ * Get a reference to the selectorhighlighter icon DOM element corresponding to
+ * a given selector in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for
+ * @return {DOMNode} The selectorhighlighter icon DOM element
+ */
+function getRuleViewSelectorHighlighterIcon(view, selectorText) {
+  let rule = getRuleViewRule(view, selectorText);
+  return rule.querySelector(".ruleview-selectorhighlighter");
+}
+
+/**
  * Simulate a color change in a given color picker tooltip, and optionally wait
  * for a given element in the page to have its style changed as a result
  *
  * @param {RuleView} ruleView
  *        The related rule view instance
  * @param {SwatchColorPickerTooltip} colorPicker
  * @param {Array} newRgba
  *        The new color to be set [r, g, b, a]
@@ -175,16 +395,110 @@ var simulateColorPickerChange = Task.asy
     info("Waiting for the style to be applied on the page");
     yield waitForSuccess(() => {
       let {element, name, value} = expectedChange;
       return content.getComputedStyle(element)[name] === value;
     }, "Color picker change applied on the page");
   }
 });
 
+/**
+ * Get a rule-link from the rule-view given its index
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {Number} index
+ *        The index of the link to get
+ * @return {DOMNode} The link if any at this index
+ */
+function getRuleViewLinkByIndex(view, index) {
+  let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
+  return links[index];
+}
+
+/**
+ * Get rule-link text from the rule-view given its index
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {Number} index
+ *        The index of the link to get
+ * @return {String} The string at this index
+ */
+function getRuleViewLinkTextByIndex(view, index) {
+  let link = getRuleViewLinkByIndex(view, index);
+  return link.querySelector(".ruleview-rule-source-label").textContent;
+}
+
+/**
+ * Click on a rule-view's close brace to focus a new property name editor
+ *
+ * @param {RuleEditor} ruleEditor
+ *        An instance of RuleEditor that will receive the new property
+ * @return a promise that resolves to the newly created editor when ready and
+ * focused
+ */
+var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
+  info("Clicking on a close ruleEditor brace to start editing a new property");
+  ruleEditor.closeBrace.scrollIntoView();
+  let editor = yield focusEditableField(ruleEditor.ruleView,
+    ruleEditor.closeBrace);
+
+  is(inplaceEditor(ruleEditor.newPropSpan), editor,
+    "Focused editor is the new property editor.");
+
+  return editor;
+});
+
+/**
+ * Create a new property name in the rule-view, focusing a new property editor
+ * by clicking on the close brace, and then entering the given text.
+ * Keep in mind that the rule-view knows how to handle strings with multiple
+ * properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
+ *
+ * @param {RuleEditor} ruleEditor
+ *        The instance of RuleEditor that will receive the new property(ies)
+ * @param {String} inputValue
+ *        The text to be entered in the new property name field
+ * @return a promise that resolves when the new property name has been entered
+ * and once the value field is focused
+ */
+var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
+  info("Creating a new property editor");
+  let editor = yield focusNewRuleViewProperty(ruleEditor);
+
+  info("Entering the value " + inputValue);
+  editor.input.value = inputValue;
+
+  info("Submitting the new value and waiting for value field focus");
+  let onFocus = once(ruleEditor.element, "focus", true);
+  EventUtils.synthesizeKey("VK_RETURN", {},
+    ruleEditor.element.ownerDocument.defaultView);
+  yield onFocus;
+});
+
+/**
+ * Set the search value for the rule-view filter styles search box.
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} searchValue
+ *        The filter search value
+ * @return a promise that resolves when the rule-view is filtered for the
+ * search term
+ */
+var setSearchFilter = Task.async(function* (view, searchValue) {
+  info("Setting filter text to \"" + searchValue + "\"");
+  let win = view.styleWindow;
+  let searchField = view.searchField;
+  searchField.focus();
+  synthesizeKeys(searchValue, win);
+  yield view.inspector.once("ruleview-filtered");
+});
+
 /* *********************************************
  * COMPUTED-VIEW
  * *********************************************
  * Computed-view related utility functions.
  * Allows to get properties, links, expand properties, ...
  */
 
 /**
@@ -220,8 +534,28 @@ function getComputedViewProperty(view, n
  * @param {String} name
  *        The name of the property to retrieve
  * @return {String} The property value
  */
 function getComputedViewPropertyValue(view, name, propertyName) {
   return getComputedViewProperty(view, name, propertyName)
     .valueSpan.textContent;
 }
+
+/**
+ * Open the style editor context menu and return all of it's items in a flat array
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @return An array of MenuItems
+ */
+function openStyleContextMenuAndGetAllItems(view, target) {
+  let menu = view._contextmenu._openMenu({target: target});
+
+  // Flatten all menu items into a single array to make searching through it easier
+  let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
+    if (item.submenu) {
+      return addItem(item.submenu.items);
+    }
+    return item;
+  }));
+
+  return allItems;
+}
--- a/devtools/client/inspector/test/shared-head.js
+++ b/devtools/client/inspector/test/shared-head.js
@@ -1,19 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 /* eslint no-unused-vars: [2, {"vars": "local"}] */
 /* globals registerTestActor, getTestActor, Task, openToolboxForTab, gBrowser */
-/* import-globals-from ../../framework/test/shared-head.js */
-
-var {getInplaceEditorForSpan: inplaceEditor} = require("devtools/client/shared/inplace-editor");
 
 // This file contains functions related to the inspector that are also of interest to
 // other test directores as well.
 
 /**
  * Open the toolbox, with the inspector tool visible.
  * @param {String} hostType Optional hostType, as defined in Toolbox.HostType
  * @return a promise that resolves when the inspector is ready
@@ -182,361 +179,8 @@ function manualThrottle() {
 
   throttle.flush = function () {
     calls.forEach(({func, scope, args}) => func.apply(scope, args));
     calls = [];
   };
 
   return throttle;
 }
-
-/**
- * Wait for a content -> chrome message on the message manager (the window
- * messagemanager is used).
- *
- * @param {String} name
- *        The message name
- * @return {Promise} A promise that resolves to the response data when the
- * message has been received
- */
-function waitForContentMessage(name) {
-  info("Expecting message " + name + " from content");
-
-  let mm = gBrowser.selectedBrowser.messageManager;
-
-  let def = defer();
-  mm.addMessageListener(name, function onMessage(msg) {
-    mm.removeMessageListener(name, onMessage);
-    def.resolve(msg.data);
-  });
-  return def.promise;
-}
-
-/**
- * Send an async message to the frame script (chrome -> content) and wait for a
- * response message with the same name (content -> chrome).
- *
- * @param {String} name
- *        The message name. Should be one of the messages defined
- *        in doc_frame_script.js
- * @param {Object} data
- *        Optional data to send along
- * @param {Object} objects
- *        Optional CPOW objects to send along
- * @param {Boolean} expectResponse
- *        If set to false, don't wait for a response with the same name
- *        from the content script. Defaults to true.
- * @return {Promise} Resolves to the response data if a response is expected,
- * immediately resolves otherwise
- */
-function executeInContent(name, data = {}, objects = {},
-                          expectResponse = true) {
-  info("Sending message " + name + " to content");
-  let mm = gBrowser.selectedBrowser.messageManager;
-
-  mm.sendAsyncMessage(name, data, objects);
-  if (expectResponse) {
-    return waitForContentMessage(name);
-  }
-
-  return promise.resolve();
-}
-
-/**
- * Send an async message to the frame script and get back the requested
- * computed style property.
- *
- * @param {String} selector
- *        The selector used to obtain the element.
- * @param {String} pseudo
- *        pseudo id to query, or null.
- * @param {String} name
- *        name of the property.
- */
-function* getComputedStyleProperty(selector, pseudo, propName) {
-  return yield executeInContent("Test:GetComputedStylePropertyValue",
-    {selector,
-     pseudo,
-     name: propName});
-}
-
-/**
- * Send an async message to the frame script and wait until the requested
- * computed style property has the expected value.
- *
- * @param {String} selector
- *        The selector used to obtain the element.
- * @param {String} pseudo
- *        pseudo id to query, or null.
- * @param {String} prop
- *        name of the property.
- * @param {String} expected
- *        expected value of property
- * @param {String} name
- *        the name used in test message
- */
-function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
-  return yield executeInContent("Test:WaitForComputedStylePropertyValue",
-    {selector,
-     pseudo,
-     expected,
-     name});
-}
-
-/**
- * Given an inplace editable element, click to switch it to edit mode, wait for
- * focus
- *
- * @return a promise that resolves to the inplace-editor element when ready
- */
-var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
-    yOffset = 1, options = {}) {
-  let onFocus = once(editable.parentNode, "focus", true);
-  info("Clicking on editable field to turn to edit mode");
-  EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
-    editable.ownerDocument.defaultView);
-  yield onFocus;
-
-  info("Editable field gained focus, returning the input field now");
-  let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
-
-  return onEdit;
-});
-
-/**
- * Get the DOMNode for a css rule in the rule-view that corresponds to the given
- * selector.
- *
- * @param {CssRuleView} view
- *        The instance of the rule-view panel
- * @param {String} selectorText
- *        The selector in the rule-view for which the rule
- *        object is wanted
- * @param {Number} index
- *        If there are more than 1 rule with the same selector, you may pass a
- *        index to determine which of the rules you want.
- * @return {DOMNode}
- */
-function getRuleViewRule(view, selectorText, index = 0) {
-  let rule;
-  let pos = 0;
-  for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
-    let selector = r.querySelector(".ruleview-selectorcontainer, " +
-                                   ".ruleview-selector-matched");
-    if (selector && selector.textContent === selectorText) {
-      if (index == pos) {
-        rule = r;
-        break;
-      }
-      pos++;
-    }
-  }
-
-  return rule;
-}
-
-/**
- * Get references to the name and value span nodes corresponding to a given
- * selector and property name in the rule-view
- *
- * @param {CssRuleView} view
- *        The instance of the rule-view panel
- * @param {String} selectorText
- *        The selector in the rule-view to look for the property in
- * @param {String} propertyName
- *        The name of the property
- * @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
- */
-function getRuleViewProperty(view, selectorText, propertyName) {
-  let prop;
-
-  let rule = getRuleViewRule(view, selectorText);
-  if (rule) {
-    // Look for the propertyName in that rule element
-    for (let p of rule.querySelectorAll(".ruleview-property")) {
-      let nameSpan = p.querySelector(".ruleview-propertyname");
-      let valueSpan = p.querySelector(".ruleview-propertyvalue");
-
-      if (nameSpan.textContent === propertyName) {
-        prop = {nameSpan: nameSpan, valueSpan: valueSpan};
-        break;
-      }
-    }
-  }
-  return prop;
-}
-
-/**
- * Get the text value of the property corresponding to a given selector and name
- * in the rule-view
- *
- * @param {CssRuleView} view
- *        The instance of the rule-view panel
- * @param {String} selectorText
- *        The selector in the rule-view to look for the property in
- * @param {String} propertyName
- *        The name of the property
- * @return {String} The property value
- */
-function getRuleViewPropertyValue(view, selectorText, propertyName) {
-  return getRuleViewProperty(view, selectorText, propertyName)
-    .valueSpan.textContent;
-}
-
-/**
- * Get a reference to the selector DOM element corresponding to a given selector
- * in the rule-view
- *
- * @param {CssRuleView} view
- *        The instance of the rule-view panel
- * @param {String} selectorText
- *        The selector in the rule-view to look for
- * @return {DOMNode} The selector DOM element
- */
-function getRuleViewSelector(view, selectorText) {
-  let rule = getRuleViewRule(view, selectorText);
-  return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
-}
-
-/**
- * Get a reference to the selectorhighlighter icon DOM element corresponding to
- * a given selector in the rule-view
- *
- * @param {CssRuleView} view
- *        The instance of the rule-view panel
- * @param {String} selectorText
- *        The selector in the rule-view to look for
- * @param {Number} index
- *        If there are more than 1 rule with the same selector, use this index
- *        to determine which one should be retrieved. Defaults to 0
- * @return {DOMNode} The selectorhighlighter icon DOM element
- */
-var getRuleViewSelectorHighlighterIcon = Task.async(function* (view,
-    selectorText, index = 0) {
-  let rule = getRuleViewRule(view, selectorText, index);
-
-  let editor = rule._ruleEditor;
-  if (!editor.uniqueSelector) {
-    yield once(editor, "selector-icon-created");
-  }
-
-  return rule.querySelector(".ruleview-selectorhighlighter");
-});
-
-/**
- * Get a rule-link from the rule-view given its index
- *
- * @param {CssRuleView} view
- *        The instance of the rule-view panel
- * @param {Number} index
- *        The index of the link to get
- * @return {DOMNode} The link if any at this index
- */
-function getRuleViewLinkByIndex(view, index) {
-  let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
-  return links[index];
-}
-
-/**
- * Get rule-link text from the rule-view given its index
- *
- * @param {CssRuleView} view
- *        The instance of the rule-view panel
- * @param {Number} index
- *        The index of the link to get
- * @return {String} The string at this index
- */
-function getRuleViewLinkTextByIndex(view, index) {
-  let link = getRuleViewLinkByIndex(view, index);
-  return link.querySelector(".ruleview-rule-source-label").textContent;
-}
-
-/**
- * Click on a rule-view's close brace to focus a new property name editor
- *
- * @param {RuleEditor} ruleEditor
- *        An instance of RuleEditor that will receive the new property
- * @return a promise that resolves to the newly created editor when ready and
- * focused
- */
-var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
-  info("Clicking on a close ruleEditor brace to start editing a new property");
-
-  // Use bottom alignment to avoid scrolling out of the parent element area.
-  ruleEditor.closeBrace.scrollIntoView(false);
-  let editor = yield focusEditableField(ruleEditor.ruleView,
-    ruleEditor.closeBrace);
-
-  is(inplaceEditor(ruleEditor.newPropSpan), editor,
-    "Focused editor is the new property editor.");
-
-  return editor;
-});
-
-/**
- * Create a new property name in the rule-view, focusing a new property editor
- * by clicking on the close brace, and then entering the given text.
- * Keep in mind that the rule-view knows how to handle strings with multiple
- * properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
- *
- * @param {RuleEditor} ruleEditor
- *        The instance of RuleEditor that will receive the new property(ies)
- * @param {String} inputValue
- *        The text to be entered in the new property name field
- * @return a promise that resolves when the new property name has been entered
- * and once the value field is focused
- */
-var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
-  info("Creating a new property editor");
-  let editor = yield focusNewRuleViewProperty(ruleEditor);
-
-  info("Entering the value " + inputValue);
-  editor.input.value = inputValue;
-
-  info("Submitting the new value and waiting for value field focus");
-  let onFocus = once(ruleEditor.element, "focus", true);
-  EventUtils.synthesizeKey("VK_RETURN", {},
-    ruleEditor.element.ownerDocument.defaultView);
-  yield onFocus;
-});
-
-/**
- * Set the search value for the rule-view filter styles search box.
- *
- * @param {CssRuleView} view
- *        The instance of the rule-view panel
- * @param {String} searchValue
- *        The filter search value
- * @return a promise that resolves when the rule-view is filtered for the
- * search term
- */
-var setSearchFilter = Task.async(function* (view, searchValue) {
-  info("Setting filter text to \"" + searchValue + "\"");
-
-  let searchField = view.searchField;
-  searchField.focus();
-
-  for (let key of searchValue.split("")) {
-    EventUtils.synthesizeKey(key, {}, view.styleWindow);
-  }
-
-  yield view.inspector.once("ruleview-filtered");
-});
-
-/**
- * Open the style editor context menu and return all of it's items in a flat array
- * @param {CssRuleView} view
- *        The instance of the rule-view panel
- * @return An array of MenuItems
- */
-function openStyleContextMenuAndGetAllItems(view, target) {
-  let menu = view._contextmenu._openMenu({target: target});
-
-  // Flatten all menu items into a single array to make searching through it easier
-  let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
-    if (item.submenu) {
-      return addItem(item.submenu.items);
-    }
-    return item;
-  }));
-
-  return allItems;
-}