Bug 1246677 - 9 - Get rid of all remaining _applyingModifications usage in tests draft
authorPatrick Brosset <pbrosset@mozilla.com>
Fri, 12 Feb 2016 14:26:53 +0100
changeset 330661 c809a86e903acc94eb943d90e8c72de766e6409e
parent 330660 c554376cad872eff2c000e5a3acb43ecf66b0618
child 330662 8591579e0c7d1601f3c0bbbbac15bf75798a6948
push id10801
push userpbrosset@mozilla.com
push dateFri, 12 Feb 2016 13:33:31 +0000
bugs1246677
milestone47.0a1
Bug 1246677 - 9 - Get rid of all remaining _applyingModifications usage in tests MozReview-Commit-ID: 5fnZb6dlejV
devtools/client/inspector/rules/test/browser_rules_add-property-cancel_01.js
devtools/client/inspector/rules/test/browser_rules_add-property-cancel_03.js
devtools/client/inspector/rules/test/browser_rules_authored_override.js
devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js
devtools/client/inspector/rules/test/browser_rules_copy_styles.js
devtools/client/inspector/rules/test/browser_rules_cubicbezier-revert-on-ESC.js
devtools/client/inspector/rules/test/browser_rules_custom.js
devtools/client/inspector/rules/test/browser_rules_edit-property-cancel.js
devtools/client/inspector/rules/test/browser_rules_edit-property-remove_01.js
devtools/client/inspector/rules/test/browser_rules_edit-property-remove_02.js
devtools/client/inspector/rules/test/browser_rules_edit-property-remove_03.js
devtools/client/inspector/rules/test/browser_rules_edit-property_01.js
devtools/client/inspector/rules/test/browser_rules_edit-property_02.js
devtools/client/inspector/rules/test/browser_rules_edit-property_04.js
devtools/client/inspector/rules/test/browser_rules_edit-property_05.js
devtools/client/inspector/rules/test/browser_rules_edit-property_06.js
devtools/client/inspector/rules/test/browser_rules_edit-property_07.js
devtools/client/inspector/rules/test/browser_rules_keyframeLineNumbers.js
devtools/client/inspector/rules/test/browser_rules_keyframes-rule_02.js
devtools/client/inspector/rules/test/browser_rules_livepreview.js
devtools/client/inspector/rules/test/browser_rules_mark_overridden_01.js
devtools/client/inspector/rules/test/browser_rules_mark_overridden_03.js
devtools/client/inspector/rules/test/browser_rules_mark_overridden_04.js
devtools/client/inspector/rules/test/browser_rules_mark_overridden_05.js
devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
devtools/client/inspector/rules/test/head.js
--- a/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_01.js
@@ -32,17 +32,15 @@ function* testCancelNew(view) {
     "The new property editor got focused");
 
   info("Escape the new property editor");
   let onBlur = once(editor.input, "blur");
   EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow);
   yield onBlur;
 
   info("Checking the state of cancelling a new property name editor");
-  ok(!elementRuleEditor.rule._applyingModifications,
-    "Shouldn't have an outstanding request after a cancel.");
   is(elementRuleEditor.rule.textProps.length, 0,
     "Should have cancelled creating a new text property.");
   ok(!elementRuleEditor.propertyList.hasChildNodes(),
     "Should not have any properties.");
   is(view.styleDocument.activeElement, view.styleDocument.documentElement,
     "Correct element has focus");
 }
--- a/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_03.js
+++ b/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_03.js
@@ -31,15 +31,13 @@ add_task(function*() {
     "Next focused editor should be the new property editor.");
 
   EventUtils.sendString("background", view.styleWindow);
 
   let onBlur = once(editor.input, "blur");
   EventUtils.synthesizeKey("VK_ESCAPE", {});
   yield onBlur;
 
-  ok(!elementRuleEditor.rule._applyingModifications,
-    "Shouldn't have an outstanding modification request after a cancel.");
   is(elementRuleEditor.rule.textProps.length, 1,
     "Should have canceled creating a new text property.");
   is(view.styleDocument.documentElement, view.styleDocument.activeElement,
     "Correct element has focus");
 });
--- a/devtools/client/inspector/rules/test/browser_rules_authored_override.js
+++ b/devtools/client/inspector/rules/test/browser_rules_authored_override.js
@@ -37,18 +37,17 @@ add_task(function* () {
 
   // Initially the last property should be active.
   for (let i = 0; i < 3; ++i) {
     let prop = rule.textProps[i];
     is(prop.name, "background-image", "check the property name");
     is(prop.overridden, i !== 2, "check overridden for " + i);
   }
 
-  rule.textProps[2].setEnabled(false);
-  yield rule._applyingModifications;
+  yield togglePropStatus(view, rule.textProps[2]);
 
   // Now the first property should be active.
   for (let i = 0; i < 3; ++i) {
     let prop = rule.textProps[i];
     is(prop.overridden || !prop.enabled, i !== 0,
        "post-change check overridden for " + i);
   }
 });
--- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js
+++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js
@@ -18,30 +18,22 @@ const TEST_URI = `
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {view} = yield openRuleView();
   yield testPressingEscapeRevertsChanges(view);
   yield testPressingEscapeRevertsChangesAndDisables(view);
 });
 
 function* testPressingEscapeRevertsChanges(view) {
-  let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[0].editor;
-  let swatch = propEditor.valueSpan.querySelector(".ruleview-colorswatch");
-  let cPicker = view.tooltips.colorPicker;
-
-  let onShown = cPicker.tooltip.once("shown");
-  swatch.click();
-  yield onShown;
-
-  yield simulateColorPickerChange(view, cPicker, [0, 0, 0, 1], {
-    selector: "body",
-    name: "background-color",
-    value: "rgb(0, 0, 0)"
-  });
+  let {swatch, propEditor, cPicker} = yield openColorPickerAndSelectColor(view,
+    1, 0, [0, 0, 0, 1], {
+      selector: "body",
+      name: "background-color",
+      value: "rgb(0, 0, 0)"
+    });
 
   is(swatch.style.backgroundColor, "rgb(0, 0, 0)",
     "The color swatch's background was updated");
   is(propEditor.valueSpan.textContent, "#000",
     "The text of the background-color css property was updated");
 
   let spectrum = yield cPicker.spectrum;
 
@@ -55,66 +47,60 @@ function* testPressingEscapeRevertsChang
   yield waitForComputedStyleProperty("body", null, "background-color",
     "rgb(237, 237, 237)");
   is(propEditor.valueSpan.textContent, "#EDEDED",
     "Got expected property value.");
 }
 
 function* testPressingEscapeRevertsChangesAndDisables(view) {
   let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[0].editor;
-  let swatch = propEditor.valueSpan.querySelector(".ruleview-colorswatch");
-  let cPicker = view.tooltips.colorPicker;
 
   info("Disabling background-color property");
-  propEditor.enable.click();
-  yield ruleEditor.rule._applyingModifications;
+  let textProp = ruleEditor.rule.textProps[0];
+  yield togglePropStatus(view, textProp);
 
-  ok(propEditor.element.classList.contains("ruleview-overridden"),
+  ok(textProp.editor.element.classList.contains("ruleview-overridden"),
     "property is overridden.");
-  is(propEditor.enable.style.visibility, "visible",
+  is(textProp.editor.enable.style.visibility, "visible",
     "property enable checkbox is visible.");
-  ok(!propEditor.enable.getAttribute("checked"),
+  ok(!textProp.editor.enable.getAttribute("checked"),
     "property enable checkbox is not checked.");
-  ok(!propEditor.prop.enabled,
+  ok(!textProp.editor.prop.enabled,
     "background-color property is disabled.");
   let newValue = yield getRulePropertyValue("background-color");
   is(newValue, "", "background-color should have been unset.");
 
-  let onShown = cPicker.tooltip.once("shown");
-  swatch.click();
-  yield onShown;
+  let {cPicker} = yield openColorPickerAndSelectColor(view,
+    1, 0, [0, 0, 0, 1]);
 
-  ok(!propEditor.element.classList.contains("ruleview-overridden"),
+  ok(!textProp.editor.element.classList.contains("ruleview-overridden"),
     "property overridden is not displayed.");
-  is(propEditor.enable.style.visibility, "hidden",
+  is(textProp.editor.enable.style.visibility, "hidden",
     "property enable checkbox is hidden.");
 
   let spectrum = yield cPicker.spectrum;
-  info("Simulating a color picker change in the widget");
-  spectrum.rgb = [0, 0, 0, 1];
-  yield ruleEditor.rule._applyingModifications;
 
   info("Pressing ESCAPE to close the tooltip");
   let onHidden = cPicker.tooltip.once("hidden");
+  let onModifications = view.once("ruleview-changed");
   EventUtils.sendKey("ESCAPE", spectrum.element.ownerDocument.defaultView);
   yield onHidden;
-  yield ruleEditor.rule._applyingModifications;
+  yield onModifications;
 
-  ok(propEditor.element.classList.contains("ruleview-overridden"),
+  ok(textProp.editor.element.classList.contains("ruleview-overridden"),
     "property is overridden.");
-  is(propEditor.enable.style.visibility, "visible",
+  is(textProp.editor.enable.style.visibility, "visible",
     "property enable checkbox is visible.");
-  ok(!propEditor.enable.getAttribute("checked"),
+  ok(!textProp.editor.enable.getAttribute("checked"),
     "property enable checkbox is not checked.");
-  ok(!propEditor.prop.enabled,
+  ok(!textProp.editor.prop.enabled,
     "background-color property is disabled.");
   newValue = yield getRulePropertyValue("background-color");
   is(newValue, "", "background-color should have been unset.");
-  is(propEditor.valueSpan.textContent, "#EDEDED",
+  is(textProp.editor.valueSpan.textContent, "#EDEDED",
     "Got expected property value.");
 }
 
 function* getRulePropertyValue(name) {
   let propValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: name
--- a/devtools/client/inspector/rules/test/browser_rules_copy_styles.js
+++ b/devtools/client/inspector/rules/test/browser_rules_copy_styles.js
@@ -263,21 +263,18 @@ function* checkCopyStyle(view, node, men
     failedClipboard(expectedPattern);
   }
 
   view._contextmenu._menupopup.hidePopup();
 }
 
 function* disableProperty(view, index) {
   let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[index].editor;
-
-  info("Disabling a property");
-  propEditor.enable.click();
-  yield ruleEditor.rule._applyingModifications;
+  let textProp = ruleEditor.rule.textProps[index];
+  yield togglePropStatus(view, textProp);
 }
 
 function checkClipboardData(expectedPattern) {
   let actual = SpecialPowers.getClipboardData("text/unicode");
   let expectedRegExp = new RegExp(expectedPattern, "g");
   return expectedRegExp.test(actual);
 }
 
--- a/devtools/client/inspector/rules/test/browser_rules_cubicbezier-revert-on-ESC.js
+++ b/devtools/client/inspector/rules/test/browser_rules_cubicbezier-revert-on-ESC.js
@@ -18,87 +18,56 @@ const TEST_URI = `
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {view} = yield openRuleView();
   yield testPressingEscapeRevertsChanges(view);
   yield testPressingEscapeRevertsChangesAndDisables(view);
 });
 
 function* testPressingEscapeRevertsChanges(view) {
-  let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[0].editor;
-  let swatch = propEditor.valueSpan.querySelector(".ruleview-bezierswatch");
-  let bezierTooltip = view.tooltips.cubicBezier;
+  let {propEditor} = yield openCubicBezierAndChangeCoords(view, 1, 0,
+    [0.1, 2, 0.9, -1], {
+      selector: "body",
+      name: "animation-timing-function",
+      value: "cubic-bezier(0.1, 2, 0.9, -1)"
+    });
 
-  let onShown = bezierTooltip.tooltip.once("shown");
-  swatch.click();
-  yield onShown;
-
-  let widget = yield bezierTooltip.widget;
-  info("Simulating a change of curve in the widget");
-  widget.coordinates = [0.1, 2, 0.9, -1];
-  yield ruleEditor.rule._applyingModifications;
-
-  yield waitForComputedStyleProperty("body", null, "animation-timing-function",
-    "cubic-bezier(0.1, 2, 0.9, -1)");
   is(propEditor.valueSpan.textContent, "cubic-bezier(.1,2,.9,-1)",
     "Got expected property value.");
 
-  info("Pressing ESCAPE to close the tooltip");
-  let onHidden = bezierTooltip.tooltip.once("hidden");
-  EventUtils.sendKey("ESCAPE", widget.parent.ownerDocument.defaultView);
-  yield onHidden;
-  yield ruleEditor.rule._applyingModifications;
+  yield escapeTooltip(view);
 
   yield waitForComputedStyleProperty("body", null, "animation-timing-function",
     "linear");
   is(propEditor.valueSpan.textContent, "linear",
     "Got expected property value.");
 }
 
 function* testPressingEscapeRevertsChangesAndDisables(view) {
   let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[0].editor;
-  let swatch = propEditor.valueSpan.querySelector(".ruleview-bezierswatch");
-  let bezierTooltip = view.tooltips.cubicBezier;
+  let textProp = ruleEditor.rule.textProps[0];
+  let propEditor = textProp.editor;
 
   info("Disabling animation-timing-function property");
-  propEditor.enable.click();
-  yield ruleEditor.rule._applyingModifications;
+  yield togglePropStatus(view, textProp);
 
   ok(propEditor.element.classList.contains("ruleview-overridden"),
     "property is overridden.");
   is(propEditor.enable.style.visibility, "visible",
     "property enable checkbox is visible.");
   ok(!propEditor.enable.getAttribute("checked"),
     "property enable checkbox is not checked.");
   ok(!propEditor.prop.enabled,
     "animation-timing-function property is disabled.");
   let newValue = yield getRulePropertyValue("animation-timing-function");
   is(newValue, "", "animation-timing-function should have been unset.");
 
-  let onShown = bezierTooltip.tooltip.once("shown");
-  swatch.click();
-  yield onShown;
-
-  ok(!propEditor.element.classList.contains("ruleview-overridden"),
-    "property overridden is not displayed.");
-  is(propEditor.enable.style.visibility, "hidden",
-    "property enable checkbox is hidden.");
+  yield openCubicBezierAndChangeCoords(view, 1, 0, [0.1, 2, 0.9, -1]);
 
-  let widget = yield bezierTooltip.widget;
-  info("Simulating a change of curve in the widget");
-  widget.coordinates = [0.1, 2, 0.9, -1];
-  yield ruleEditor.rule._applyingModifications;
-
-  info("Pressing ESCAPE to close the tooltip");
-  let onHidden = bezierTooltip.tooltip.once("hidden");
-  EventUtils.sendKey("ESCAPE", widget.parent.ownerDocument.defaultView);
-  yield onHidden;
-  yield ruleEditor.rule._applyingModifications;
+  yield escapeTooltip(view);
 
   ok(propEditor.element.classList.contains("ruleview-overridden"),
     "property is overridden.");
   is(propEditor.enable.style.visibility, "visible",
     "property enable checkbox is visible.");
   ok(!propEditor.enable.getAttribute("checked"),
     "property enable checkbox is not checked.");
   ok(!propEditor.prop.enabled,
@@ -112,8 +81,20 @@ function* testPressingEscapeRevertsChang
 function* getRulePropertyValue(name) {
   let propValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: name
   });
   return propValue;
 }
+
+function* escapeTooltip(view) {
+  info("Pressing ESCAPE to close the tooltip");
+
+  let bezierTooltip = view.tooltips.cubicBezier;
+  let widget = yield bezierTooltip.widget;
+  let onHidden = bezierTooltip.tooltip.once("hidden");
+  let onModifications = view.once("ruleview-changed");
+  EventUtils.sendKey("ESCAPE", widget.parent.ownerDocument.defaultView);
+  yield onHidden;
+  yield onModifications;
+}
--- a/devtools/client/inspector/rules/test/browser_rules_custom.js
+++ b/devtools/client/inspector/rules/test/browser_rules_custom.js
@@ -15,66 +15,58 @@ add_task(function*() {
   yield simpleCustomOverride(inspector, view);
   yield importantCustomOverride(inspector, view);
   yield disableCustomOverride(inspector, view);
 });
 
 function* simpleCustomOverride(inspector, view) {
   yield selectNode("#testidSimple", inspector);
 
-  let elementStyle = view._elementStyle;
+  let idRule = getRuleViewRuleEditor(view, 1).rule;
+  let idRuleProp = idRule.textProps[0];
 
-  let idRule = elementStyle.rules[1];
-  let idProp = idRule.textProps[0];
-  is(idProp.name, "--background-color",
+  is(idRuleProp.name, "--background-color",
      "First ID prop should be --background-color");
-  ok(!idProp.overridden, "ID prop should not be overridden.");
+  ok(!idRuleProp.overridden, "ID prop should not be overridden.");
 
-  let classRule = elementStyle.rules[2];
-  let classProp = classRule.textProps[0];
-  is(classProp.name, "--background-color",
+  let classRule = getRuleViewRuleEditor(view, 2).rule;
+  let classRuleProp = classRule.textProps[0];
+
+  is(classRuleProp.name, "--background-color",
      "First class prop should be --background-color");
-  ok(classProp.overridden, "Class property should be overridden.");
+  ok(classRuleProp.overridden, "Class property should be overridden.");
 
   // Override --background-color by changing the element style.
-  let elementRule = elementStyle.rules[0];
-  elementRule.createProperty("--background-color", "purple", "");
-  yield elementRule._applyingModifications;
+  let elementProp = yield addProperty(view, 0, "--background-color", "purple");
 
-  let elementProp = elementRule.textProps[0];
-  is(classProp.name, "--background-color",
+  is(classRuleProp.name, "--background-color",
      "First element prop should now be --background-color");
   ok(!elementProp.overridden,
      "Element style property should not be overridden");
-  ok(idProp.overridden, "ID property should be overridden");
-  ok(classProp.overridden, "Class property should be overridden");
+  ok(idRuleProp.overridden, "ID property should be overridden");
+  ok(classRuleProp.overridden, "Class property should be overridden");
 }
 
 function* importantCustomOverride(inspector, view) {
   yield selectNode("#testidImportant", inspector);
 
-  let elementStyle = view._elementStyle;
+  let idRule = getRuleViewRuleEditor(view, 1).rule;
+  let idRuleProp = idRule.textProps[0];
+  ok(idRuleProp.overridden, "Not-important rule should be overridden.");
 
-  let idRule = elementStyle.rules[1];
-  let idProp = idRule.textProps[0];
-  ok(idProp.overridden, "Not-important rule should be overridden.");
-
-  let classRule = elementStyle.rules[2];
-  let classProp = classRule.textProps[0];
-  ok(!classProp.overridden, "Important rule should not be overridden.");
+  let classRule = getRuleViewRuleEditor(view, 2).rule;
+  let classRuleProp = classRule.textProps[0];
+  ok(!classRuleProp.overridden, "Important rule should not be overridden.");
 }
 
 function* disableCustomOverride(inspector, view) {
   yield selectNode("#testidDisable", inspector);
 
-  let elementStyle = view._elementStyle;
-
-  let idRule = elementStyle.rules[1];
-  let idProp = idRule.textProps[0];
+  let idRule = getRuleViewRuleEditor(view, 1).rule;
+  let idRuleProp = idRule.textProps[0];
 
-  idProp.setEnabled(false);
-  yield idRule._applyingModifications;
+  yield togglePropStatus(view, idRuleProp);
 
-  let classRule = elementStyle.rules[2];
-  let classProp = classRule.textProps[0];
-  ok(!classProp.overridden,
+  let classRule = getRuleViewRuleEditor(view, 2).rule;
+  let classRuleProp = classRule.textProps[0];
+  ok(!classRuleProp.overridden,
      "Class prop should not be overridden after id prop was disabled.");
 }
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property-cancel.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-cancel.js
@@ -15,43 +15,40 @@ const TEST_URI = `
   </style>
   <div id='testid'>Styled Node</div>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
-  yield testEditPropertyAndCancel(inspector, view);
-});
 
-function* testEditPropertyAndCancel(inspector, view) {
   let ruleEditor = getRuleViewRuleEditor(view, 1);
   let propEditor = ruleEditor.rule.textProps[0].editor;
 
   yield focusEditableField(view, propEditor.nameSpan);
   yield sendCharsAndWaitForFocus(view, ruleEditor.element,
     ["VK_DELETE", "VK_ESCAPE"]);
-  yield ruleEditor.rule._applyingModifications;
 
   is(propEditor.nameSpan.textContent, "background-color",
     "'background-color' property name is correctly set.");
   is((yield getComputedStyleProperty("#testid", null, "background-color")),
     "rgb(0, 0, 255)", "#00F background color is set.");
 
   yield focusEditableField(view, propEditor.valueSpan);
+  let onValueDeleted = view.once("ruleview-changed");
   yield sendCharsAndWaitForFocus(view, ruleEditor.element,
     ["VK_DELETE", "VK_ESCAPE"]);
-  yield ruleEditor.rule._applyingModifications;
+  yield onValueDeleted;
 
   is(propEditor.valueSpan.textContent, "#00F",
     "'#00F' property value is correctly set.");
   is((yield getComputedStyleProperty("#testid", null, "background-color")),
     "rgb(0, 0, 255)", "#00F background color is set.");
-}
+});
 
 function* sendCharsAndWaitForFocus(view, element, chars) {
   let onFocus = once(element, "focus", true);
   for (let ch of chars) {
     EventUtils.sendChar(ch, view.styleWindow);
   }
   yield onFocus;
 }
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_01.js
@@ -17,60 +17,51 @@ const TEST_URI = `
   </style>
   <div id='testid'>Styled Node</div>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
-  yield testEditPropertyAndRemove(inspector, view);
-});
 
-function* testEditPropertyAndRemove(inspector, view) {
-  let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[0].editor;
+  info("Getting the first property in the #testid rule");
+  let rule = getRuleViewRuleEditor(view, 1).rule;
+  let prop = rule.textProps[0];
 
-  yield focusEditableField(view, propEditor.nameSpan);
-  yield sendKeysAndWaitForFocus(view, ruleEditor.element,
-    ["VK_DELETE", "VK_RETURN"]);
-  yield ruleEditor.rule._applyingModifications;
+  info("Deleting the name of that property to remove the property");
+  yield removeProperty(view, prop, false);
 
   let newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "background-color"
   });
   is(newValue, "", "background-color should have been unset.");
 
-  propEditor = ruleEditor.rule.textProps[0].editor;
+  info("Getting the new first property in the rule");
+  prop = rule.textProps[0];
 
   let editor = inplaceEditor(view.styleDocument.activeElement);
-  is(inplaceEditor(propEditor.nameSpan), editor,
+  is(inplaceEditor(prop.editor.nameSpan), editor,
     "Focus should have moved to the next property name");
 
-  yield sendKeysAndWaitForFocus(view, ruleEditor.element,
-    ["VK_DELETE", "VK_RETURN"]);
-  yield ruleEditor.rule._applyingModifications;
+  info("Deleting the name of that property to remove the property");
+  view.styleDocument.activeElement.blur();
+  yield removeProperty(view, prop, false);
 
   newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "color"
   });
   is(newValue, "", "color should have been unset.");
 
   editor = inplaceEditor(view.styleDocument.activeElement);
-  is(inplaceEditor(ruleEditor.newPropSpan), editor,
+  is(inplaceEditor(rule.editor.newPropSpan), editor,
     "Focus should have moved to the new property span");
-  is(ruleEditor.rule.textProps.length, 0,
+  is(rule.textProps.length, 0,
     "All properties should have been removed.");
-  is(ruleEditor.propertyList.children.length, 1,
+  is(rule.editor.propertyList.children.length, 1,
     "Should have the new property span.");
-}
 
-function* sendKeysAndWaitForFocus(view, element, keys) {
-  let onFocus = once(element, "focus", true);
-  for (let key of keys) {
-    EventUtils.synthesizeKey(key, {}, view.styleWindow);
-  }
-  yield onFocus;
-}
+  view.styleDocument.activeElement.blur();
+});
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_02.js
@@ -17,62 +17,51 @@ const TEST_URI = `
   </style>
   <div id='testid'>Styled Node</div>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
-  yield testEditPropertyAndRemove(inspector, view);
-});
 
-function* testEditPropertyAndRemove(inspector, view) {
-  let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[0].editor;
+  info("Getting the first property in the rule");
+  let rule = getRuleViewRuleEditor(view, 1).rule;
+  let prop = rule.textProps[0];
 
-  yield focusEditableField(view, propEditor.valueSpan);
-  yield sendKeysAndWaitForFocus(view, ruleEditor.element,
-    ["VK_DELETE", "VK_RETURN"]);
-  yield ruleEditor.rule._applyingModifications;
+  info("Clearing the property value");
+  yield setProperty(view, prop, null, false);
 
   let newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "background-color"
   });
   is(newValue, "", "background-color should have been unset.");
 
-  propEditor = ruleEditor.rule.textProps[0].editor;
+  info("Getting the new first property in the rule");
+  prop = rule.textProps[0];
 
   let editor = inplaceEditor(view.styleDocument.activeElement);
-  is(inplaceEditor(propEditor.nameSpan), editor,
+  is(inplaceEditor(prop.editor.nameSpan), editor,
     "Focus should have moved to the next property name");
+  view.styleDocument.activeElement.blur();
 
-  info("Focus the property value and remove the property");
-  let onChanged = view.once("ruleview-changed");
-  yield sendKeysAndWaitForFocus(view, ruleEditor.element,
-    ["VK_TAB", "VK_DELETE", "VK_RETURN"]);
-  yield onChanged;
+  info("Clearing the property value");
+  yield setProperty(view, prop, null, false);
 
   newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "color"
   });
   is(newValue, "", "color should have been unset.");
 
   editor = inplaceEditor(view.styleDocument.activeElement);
-  is(inplaceEditor(ruleEditor.newPropSpan), editor,
+  is(inplaceEditor(rule.editor.newPropSpan), editor,
     "Focus should have moved to the new property span");
-  is(ruleEditor.rule.textProps.length, 0,
+  is(rule.textProps.length, 0,
     "All properties should have been removed.");
-  is(ruleEditor.propertyList.children.length, 1,
+  is(rule.editor.propertyList.children.length, 1,
     "Should have the new property span.");
-}
 
-function* sendKeysAndWaitForFocus(view, element, keys) {
-  let onFocus = once(element, "focus", true);
-  for (let key of keys) {
-    EventUtils.synthesizeKey(key, {}, view.styleWindow);
-  }
-  yield onFocus;
-}
+  view.styleDocument.activeElement.blur();
+});
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_03.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_03.js
@@ -17,74 +17,67 @@ const TEST_URI = `
   </style>
   <div id='testid'>Styled Node</div>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
-  yield testEditPropertyAndRemove(inspector, view);
-});
 
-function* testEditPropertyAndRemove(inspector, view) {
-  let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[1].editor;
+  info("Getting the second property in the rule");
+  let rule = getRuleViewRuleEditor(view, 1).rule;
+  let prop = rule.textProps[1];
 
-  yield focusEditableField(view, propEditor.valueSpan);
-  yield sendKeysAndWaitForFocus(view, ruleEditor.element, [
-    { key: "VK_DELETE", modifiers: {} },
-    { key: "VK_TAB", modifiers: { shiftKey: true } }
-  ]);
-  yield ruleEditor.rule._applyingModifications;
+  info("Clearing the property value and pressing shift-tab");
+  let editor = yield focusEditableField(view, prop.editor.valueSpan);
+  let onValueDone = view.once("ruleview-changed");
+  editor.input.value = "";
+  EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}, view.styleWindow);
+  yield onValueDone;
 
   let newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "color"
   });
   is(newValue, "", "color should have been unset.");
-  is(propEditor.valueSpan.textContent, "",
+  is(prop.editor.valueSpan.textContent, "",
     "'' property value is correctly set.");
 
-  yield sendKeysAndWaitForFocus(view, ruleEditor.element, [
-    { key: "VK_TAB", modifiers: { shiftKey: true } }
-  ]);
-  yield ruleEditor.rule._applyingModifications;
+  info("Pressing shift-tab again to focus the previous property value");
+  let onValueFocused = view.once("ruleview-changed");
+  EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}, view.styleWindow);
+  yield onValueFocused;
 
-  propEditor = ruleEditor.rule.textProps[0].editor;
+  info("Getting the first property in the rule");
+  prop = rule.textProps[0];
 
-  let editor = inplaceEditor(view.styleDocument.activeElement);
-  is(inplaceEditor(propEditor.valueSpan), editor,
+  editor = inplaceEditor(view.styleDocument.activeElement);
+  is(inplaceEditor(prop.editor.valueSpan), editor,
     "Focus should have moved to the previous property value");
 
-  info("Focus the property name and remove the property");
-  yield sendKeysAndWaitForFocus(view, ruleEditor.element, [
-    { key: "VK_TAB", modifiers: { shiftKey: true } },
-    { key: "VK_DELETE", modifiers: {} },
-    { key: "VK_TAB", modifiers: { shiftKey: true } }
-  ]);
+  info("Pressing shift-tab again to focus the property name");
+  let onNameFocused = view.once("ruleview-changed");
+  EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}, view.styleWindow);
+  yield onNameFocused;
 
-  yield ruleEditor.rule._applyingModifications;
+  info("Removing the name and pressing shift-tab to focus the selector");
+  let onNameDeleted = view.once("ruleview-changed");
+  EventUtils.synthesizeKey("VK_DELETE", {}, view.styleWindow);
+  EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}, view.styleWindow);
+  yield onNameDeleted;
 
   newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "background-color"
   });
   is(newValue, "", "background-color should have been unset.");
 
   editor = inplaceEditor(view.styleDocument.activeElement);
-  is(inplaceEditor(ruleEditor.selectorText), editor,
+  is(inplaceEditor(rule.editor.selectorText), editor,
     "Focus should have moved to the selector text.");
-  is(ruleEditor.rule.textProps.length, 0,
+  is(rule.textProps.length, 0,
     "All properties should have been removed.");
-  ok(!ruleEditor.propertyList.hasChildNodes(),
+  ok(!rule.editor.propertyList.hasChildNodes(),
     "Should not have any properties.");
-}
-
-function* sendKeysAndWaitForFocus(view, element, keys) {
-  let onFocus = once(element, "focus", true);
-  for (let {key, modifiers} of keys) {
-    EventUtils.synthesizeKey(key, modifiers, view.styleWindow);
-  }
-  yield onFocus;
-}
+});
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_01.js
@@ -31,69 +31,63 @@ var TEST_DATA = [
   { name: "border", value: "solid 1px foo", isValid: false },
 ];
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
 
-  let ruleEditor = getRuleViewRuleEditor(view, 1);
+  let rule = getRuleViewRuleEditor(view, 1).rule;
   for (let {name, value, isValid} of TEST_DATA) {
-    yield testEditProperty(ruleEditor, name, value, isValid);
+    yield testEditProperty(view, rule, name, value, isValid);
   }
 });
 
-function* testEditProperty(ruleEditor, name, value, isValid) {
+function* testEditProperty(view, rule, name, value, isValid) {
   info("Test editing existing property name/value fields");
 
-  let doc = ruleEditor.doc;
-  let propEditor = ruleEditor.rule.textProps[0].editor;
+  let doc = rule.editor.doc;
+  let prop = rule.textProps[0];
 
   info("Focusing an existing property name in the rule-view");
-  let editor = yield focusEditableField(ruleEditor.ruleView,
-    propEditor.nameSpan, 32, 1);
+  let editor = yield focusEditableField(view, prop.editor.nameSpan, 32, 1);
 
-  is(inplaceEditor(propEditor.nameSpan), editor,
+  is(inplaceEditor(prop.editor.nameSpan), editor,
     "The property name editor got focused");
   let input = editor.input;
 
   info("Entering a new property name, including : to commit and " +
     "focus the value");
-  let onValueFocus = once(ruleEditor.element, "focus", true);
-  let onModifications = ruleEditor.ruleView.once("ruleview-changed");
+  let onValueFocus = once(rule.editor.element, "focus", true);
+  let onNameDone = view.once("ruleview-changed");
   EventUtils.sendString(name + ":", doc.defaultView);
   yield onValueFocus;
-  yield onModifications;
+  yield onNameDone;
 
   // Getting the value editor after focus
   editor = inplaceEditor(doc.activeElement);
   input = editor.input;
-  is(inplaceEditor(propEditor.valueSpan), editor, "Focus moved to the value.");
+  is(inplaceEditor(prop.editor.valueSpan), editor, "Focus moved to the value.");
 
   info("Entering a new value, including ; to commit and blur the value");
+  let onValueDone = view.once("ruleview-changed");
   let onBlur = once(input, "blur");
   EventUtils.sendString(value + ";", doc.defaultView);
   yield onBlur;
-  yield ruleEditor.rule._applyingModifications;
+  yield onValueDone;
 
-  is(propEditor.isValid(), isValid,
+  is(prop.editor.isValid(), isValid,
     value + " is " + isValid ? "valid" : "invalid");
 
   info("Checking that the style property was changed on the content page");
   let propValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name
   });
 
   if (isValid) {
     is(propValue, value, name + " should have been set.");
   } else {
     isnot(propValue, value, name + " shouldn't have been set.");
   }
-
-  info("Wait for remaining modifications to be applied");
-  yield ruleEditor.rule._applyingModifications;
-
-  is(ruleEditor.rule._applyingModifications, null,
-    "Reference to rule modification promise was removed after completion");
 }
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property_02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_02.js
@@ -25,106 +25,94 @@ add_task(function*() {
   yield selectNode("#testid", inspector);
 
   yield testEditProperty(inspector, view);
   yield testDisableProperty(inspector, view);
   yield testPropertyStillMarkedDirty(inspector, view);
 });
 
 function* testEditProperty(inspector, ruleView) {
-  let idRuleEditor = getRuleViewRuleEditor(ruleView, 1);
-  let propEditor = idRuleEditor.rule.textProps[0].editor;
+  let idRule = getRuleViewRuleEditor(ruleView, 1).rule;
+  let prop = idRule.textProps[0];
 
-  let editor = yield focusEditableField(ruleView, propEditor.nameSpan);
+  let editor = yield focusEditableField(ruleView, prop.editor.nameSpan);
   let input = editor.input;
-  is(inplaceEditor(propEditor.nameSpan), editor,
+  is(inplaceEditor(prop.editor.nameSpan), editor,
     "Next focused editor should be the name editor.");
 
   ok(input.selectionStart === 0 && input.selectionEnd === input.value.length,
     "Editor contents are selected.");
 
   // Try clicking on the editor's input again, shouldn't cause trouble
   // (see bug 761665).
   EventUtils.synthesizeMouse(input, 1, 1, {}, ruleView.styleWindow);
   input.select();
 
   info("Entering property name \"border-color\" followed by a colon to " +
     "focus the value");
-  let onFocus = once(idRuleEditor.element, "focus", true);
+  let onNameDone = ruleView.once("ruleview-changed");
+  let onFocus = once(idRule.editor.element, "focus", true);
   EventUtils.sendString("border-color:", ruleView.styleWindow);
   yield onFocus;
-  yield idRuleEditor.rule._applyingModifications;
+  yield onNameDone;
 
   info("Verifying that the focused field is the valueSpan");
   editor = inplaceEditor(ruleView.styleDocument.activeElement);
   input = editor.input;
-  is(inplaceEditor(propEditor.valueSpan), editor,
+  is(inplaceEditor(prop.editor.valueSpan), editor,
     "Focus should have moved to the value.");
   ok(input.selectionStart === 0 && input.selectionEnd === input.value.length,
     "Editor contents are selected.");
 
   info("Entering a value following by a semi-colon to commit it");
   let onBlur = once(editor.input, "blur");
   // Use sendChar() to pass each character as a string so that we can test
-  // propEditor.warning.hidden after each character.
+  // prop.editor.warning.hidden after each character.
   for (let ch of "red;") {
+    let onPreviewDone = ruleView.once("ruleview-changed");
     EventUtils.sendChar(ch, ruleView.styleWindow);
-    is(propEditor.warning.hidden, true,
+    yield onPreviewDone;
+    is(prop.editor.warning.hidden, true,
       "warning triangle is hidden or shown as appropriate");
   }
   yield onBlur;
-  yield idRuleEditor.rule._applyingModifications;
 
   let newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "border-color"
   });
   is(newValue, "red", "border-color should have been set.");
 
-  info("Entering property name \"color\" followed by a colon to " +
-    "focus the value");
-  onFocus = once(idRuleEditor.element, "focus", true);
-  EventUtils.sendString("color:", ruleView.styleWindow);
-  yield onFocus;
-
-  info("Verifying that the focused field is the valueSpan");
-  editor = inplaceEditor(ruleView.styleDocument.activeElement);
-
-  info("Entering a value following by a semi-colon to commit it");
-  onBlur = once(editor.input, "blur");
-  EventUtils.sendString("red;", ruleView.styleWindow);
-  yield onBlur;
-  yield idRuleEditor.rule._applyingModifications;
+  ruleView.styleDocument.activeElement.blur();
+  yield addProperty(ruleView, 1, "color", "red", ";");
 
   let props = ruleView.element.querySelectorAll(".ruleview-property");
   for (let i = 0; i < props.length; i++) {
     is(props[i].hasAttribute("dirty"), i <= 1,
       "props[" + i + "] marked dirty as appropriate");
   }
 }
 
 function* testDisableProperty(inspector, ruleView) {
-  let idRuleEditor = getRuleViewRuleEditor(ruleView, 1);
-  let propEditor = idRuleEditor.rule.textProps[0].editor;
+  let idRule = getRuleViewRuleEditor(ruleView, 1).rule;
+  let prop = idRule.textProps[0];
 
   info("Disabling a property");
-  propEditor.enable.click();
-  yield idRuleEditor.rule._applyingModifications;
+  yield togglePropStatus(ruleView, prop);
 
   let newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "border-color"
   });
   is(newValue, "", "Border-color should have been unset.");
 
   info("Enabling the property again");
-  propEditor.enable.click();
-  yield idRuleEditor.rule._applyingModifications;
+  yield togglePropStatus(ruleView, prop);
 
   newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "border-color"
   });
   is(newValue, "red", "Border-color should have been reset.");
 }
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property_04.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_04.js
@@ -15,71 +15,70 @@ const TEST_URI = `
   </style>
   <div id='testid'>Styled Node</div>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
-  yield testDisableProperty(inspector, view);
-});
 
-function* testDisableProperty(inspector, view) {
-  let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[0].editor;
+  let rule = getRuleViewRuleEditor(view, 1).rule;
+  let prop = rule.textProps[0];
 
   info("Disabling a property");
-  propEditor.enable.click();
-  yield ruleEditor.rule._applyingModifications;
+  yield togglePropStatus(view, prop);
 
   let newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "background-color"
   });
   is(newValue, "", "background-color should have been unset.");
 
-  yield testEditDisableProperty(view, ruleEditor, propEditor,
-    propEditor.nameSpan, "VK_ESCAPE");
-  yield testEditDisableProperty(view, ruleEditor, propEditor,
-    propEditor.valueSpan, "VK_ESCAPE");
-  yield testEditDisableProperty(view, ruleEditor, propEditor,
-    propEditor.valueSpan, "VK_TAB");
-  yield testEditDisableProperty(view, ruleEditor, propEditor,
-    propEditor.valueSpan, "VK_RETURN");
-}
+  yield testEditDisableProperty(view, rule, prop, "name", "VK_ESCAPE");
+  yield testEditDisableProperty(view, rule, prop, "value", "VK_ESCAPE");
+  yield testEditDisableProperty(view, rule, prop, "value", "VK_TAB");
+  yield testEditDisableProperty(view, rule, prop, "value", "VK_RETURN");
+});
 
-function* testEditDisableProperty(view, ruleEditor, propEditor,
-    editableField, commitKey) {
-  let editor = yield focusEditableField(view, editableField);
+function* testEditDisableProperty(view, rule, prop, fieldType, commitKey) {
+  let field = fieldType === "name" ? prop.editor.nameSpan
+                                   : prop.editor.valueSpan;
 
-  ok(!propEditor.element.classList.contains("ruleview-overridden"),
+  let editor = yield focusEditableField(view, field);
+
+  ok(!prop.editor.element.classList.contains("ruleview-overridden"),
     "property is not overridden.");
-  is(propEditor.enable.style.visibility, "hidden",
+  is(prop.editor.enable.style.visibility, "hidden",
     "property enable checkbox is hidden.");
 
   let newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "background-color"
   });
   is(newValue, "", "background-color should remain unset.");
 
+  let onChangeDone;
+  if (fieldType === "value") {
+    onChangeDone = view.once("ruleview-changed");
+  }
+
   let onBlur = once(editor.input, "blur");
   EventUtils.synthesizeKey(commitKey, {}, view.styleWindow);
   yield onBlur;
-  yield ruleEditor.rule._applyingModifications;
+  yield onChangeDone;
 
-  ok(!propEditor.prop.enabled, "property is disabled.");
-  ok(propEditor.element.classList.contains("ruleview-overridden"),
+  ok(!prop.enabled, "property is disabled.");
+  ok(prop.editor.element.classList.contains("ruleview-overridden"),
     "property is overridden.");
-  is(propEditor.enable.style.visibility, "visible",
+  is(prop.editor.enable.style.visibility, "visible",
     "property enable checkbox is visible.");
-  ok(!propEditor.enable.getAttribute("checked"),
+  ok(!prop.editor.enable.getAttribute("checked"),
     "property enable checkbox is not checked.");
 
   newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "background-color"
   });
   is(newValue, "", "background-color should remain unset.");
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property_05.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_05.js
@@ -15,71 +15,62 @@ const TEST_URI = `
   </style>
   <div id='testid'>Styled Node</div>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
-  yield testEditingDisableProperty(inspector, view);
-});
 
-function* testEditingDisableProperty(inspector, view) {
-  let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[0].editor;
+  let rule = getRuleViewRuleEditor(view, 1).rule;
+  let prop = rule.textProps[0];
 
   info("Disabling background-color property");
-  propEditor.enable.click();
-  yield ruleEditor.rule._applyingModifications;
+  yield togglePropStatus(view, prop);
 
   let newValue = yield getRulePropertyValue("background-color");
   is(newValue, "", "background-color should have been unset.");
 
-  yield focusEditableField(view, propEditor.nameSpan);
-
   info("Entering a new property name, including : to commit and " +
        "focus the value");
-  let onValueFocus = once(ruleEditor.element, "focus", true);
+
+  yield focusEditableField(view, prop.editor.nameSpan);
+  let onNameDone = view.once("ruleview-changed");
   EventUtils.sendString("border-color:", view.styleWindow);
-  yield onValueFocus;
-  yield ruleEditor.rule._applyingModifications;
+  yield onNameDone;
 
   info("Escape editing the property value");
+  let onValueDone = view.once("ruleview-changed");
   EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow);
-  yield ruleEditor.rule._applyingModifications;
+  yield onValueDone;
 
   newValue = yield getRulePropertyValue("border-color");
   is(newValue, "blue", "border-color should have been set.");
 
-  ok(propEditor.prop.enabled, "border-color property is enabled.");
-  ok(!propEditor.element.classList.contains("ruleview-overridden"),
+  ok(prop.enabled, "border-color property is enabled.");
+  ok(!prop.editor.element.classList.contains("ruleview-overridden"),
     "border-color is not overridden");
 
   info("Disabling border-color property");
-  propEditor.enable.click();
-  yield ruleEditor.rule._applyingModifications;
+  yield togglePropStatus(view, prop);
 
   newValue = yield getRulePropertyValue("border-color");
   is(newValue, "", "border-color should have been unset.");
 
   info("Enter a new property value for the border-color property");
-  let editor = yield focusEditableField(view, propEditor.valueSpan);
-  let onBlur = once(editor.input, "blur");
-  EventUtils.sendString("red;", view.styleWindow);
-  yield onBlur;
-  yield ruleEditor.rule._applyingModifications;
+  yield setProperty(view, prop, "red");
 
   newValue = yield getRulePropertyValue("border-color");
   is(newValue, "red", "new border-color should have been set.");
 
-  ok(propEditor.prop.enabled, "border-color property is enabled.");
-  ok(!propEditor.element.classList.contains("ruleview-overridden"),
+  ok(prop.enabled, "border-color property is enabled.");
+  ok(!prop.editor.element.classList.contains("ruleview-overridden"),
     "border-color is not overridden");
-}
+});
 
 function* getRulePropertyValue(name) {
   let propValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: name
   });
   return propValue;
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property_06.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_06.js
@@ -17,48 +17,36 @@ const TEST_URI = `
   }
   </style>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("body", inspector);
-  yield testEditPropertyPriorityAndDisable(inspector, view);
-});
 
-function* testEditPropertyPriorityAndDisable(inspector, view) {
-  let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[0].editor;
+  let rule = getRuleViewRuleEditor(view, 1).rule;
+  let prop = rule.textProps[0];
 
   is((yield getComputedStyleProperty("body", null, "background-color")),
     "rgb(0, 128, 0)", "green background color is set.");
 
-  let editor = yield focusEditableField(view, propEditor.valueSpan);
-  let onBlur = once(editor.input, "blur");
-  EventUtils.sendString("red !important;", view.styleWindow);
-  yield onBlur;
-  yield ruleEditor.rule._applyingModifications;
+  yield setProperty(view, prop, "red !important");
 
-  is(propEditor.valueSpan.textContent, "red !important",
+  is(prop.editor.valueSpan.textContent, "red !important",
     "'red !important' property value is correctly set.");
   is((yield getComputedStyleProperty("body", null, "background-color")),
     "rgb(255, 0, 0)", "red background color is set.");
 
   info("Disabling red background color property");
-  propEditor.enable.click();
-  yield ruleEditor.rule._applyingModifications;
+  yield togglePropStatus(view, prop);
 
   is((yield getComputedStyleProperty("body", null, "background-color")),
     "rgb(0, 128, 0)", "green background color is set.");
 
-  editor = yield focusEditableField(view, propEditor.valueSpan);
-  onBlur = once(editor.input, "blur");
-  EventUtils.sendString("red;", view.styleWindow);
-  yield onBlur;
-  yield ruleEditor.rule._applyingModifications;
+  yield setProperty(view, prop, "red");
 
-  is(propEditor.valueSpan.textContent, "red",
+  is(prop.editor.valueSpan.textContent, "red",
     "'red' property value is correctly set.");
-  ok(propEditor.prop.enabled, "red background-color property is enabled.");
+  ok(prop.enabled, "red background-color property is enabled.");
   is((yield getComputedStyleProperty("body", null, "background-color")),
     "rgb(0, 128, 0)", "green background color is set.");
-}
+});
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property_07.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_07.js
@@ -15,41 +15,36 @@ const TEST_URI = `
   </style>
   <div id='testid'>Styled Node</div>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
-  yield testEditDisableProperty(inspector, view);
-});
 
-function* testEditDisableProperty(inspector, view) {
-  let ruleEditor = getRuleViewRuleEditor(view, 1);
-  let propEditor = ruleEditor.rule.textProps[0].editor;
+  let rule = getRuleViewRuleEditor(view, 1).rule;
+  let prop = rule.textProps[0];
 
   info("Disabling red background color property");
-  propEditor.enable.click();
-  yield ruleEditor.rule._applyingModifications;
-
-  ok(!propEditor.prop.enabled, "red background-color property is disabled.");
+  yield togglePropStatus(view, prop);
+  ok(!prop.enabled, "red background-color property is disabled.");
 
-  let editor = yield focusEditableField(view, propEditor.valueSpan);
-  let onBlur = once(editor.input, "blur");
-  EventUtils.sendString("red; color: red;", view.styleWindow);
-  yield onBlur;
-  yield ruleEditor.rule._applyingModifications;
+  let editor = yield focusEditableField(view, prop.editor.valueSpan);
+  let onDone = view.once("ruleview-changed");
+  editor.input.value = "red; color: red;";
+  EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow);
+  yield onDone;
 
-  is(propEditor.valueSpan.textContent, "red",
+  is(prop.editor.valueSpan.textContent, "red",
     "'red' property value is correctly set.");
-  ok(propEditor.prop.enabled, "red background-color property is enabled.");
+  ok(prop.enabled, "red background-color property is enabled.");
   is((yield getComputedStyleProperty("#testid", null, "background-color")),
     "rgb(255, 0, 0)", "red background color is set.");
 
-  propEditor = ruleEditor.rule.textProps[1].editor;
+  let propEditor = rule.textProps[1].editor;
   is(propEditor.nameSpan.textContent, "color",
     "new 'color' property name is correctly set.");
   is(propEditor.valueSpan.textContent, "red",
     "new 'red' property value is correctly set.");
   is((yield getComputedStyleProperty("#testid", null, "color")),
     "rgb(255, 0, 0)", "red color is set.");
-}
+});
--- a/devtools/client/inspector/rules/test/browser_rules_keyframeLineNumbers.js
+++ b/devtools/client/inspector/rules/test/browser_rules_keyframeLineNumbers.js
@@ -9,20 +9,17 @@
 
 const TESTCASE_URI = URL_ROOT + "doc_keyframeLineNumbers.html";
 
 add_task(function*() {
   yield addTab(TESTCASE_URI);
   let { inspector, view } = yield openRuleView();
   yield selectNode("#outer", inspector);
 
-  // Insert a new property, which will affect the line numbers.
-  let elementRuleEditor = getRuleViewRuleEditor(view, 1);
-  let onRuleViewChanged = view.once("ruleview-changed");
-  yield createNewRuleViewProperty(elementRuleEditor, "font-size: 72px");
-  yield onRuleViewChanged;
+  info("Insert a new property, which will affect the line numbers");
+  yield addProperty(view, 1, "font-size", "72px");
 
   yield selectNode("#inner", inspector);
 
   let value = getRuleViewLinkTextByIndex(view, 3);
   // Note that this is relative to the <style>.
   is(value.slice(-3), ":27", "rule line number is 27");
 });
--- a/devtools/client/inspector/rules/test/browser_rules_keyframes-rule_02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_keyframes-rule_02.js
@@ -24,16 +24,18 @@ function* testPacman(inspector, view) {
   info("Test text properties for Keyframes #pacman");
 
   is(convertTextPropsToString(rules.keyframeRules[0].textProps),
     "left: 750px",
     "Keyframe pacman (100%) property is correct"
   );
 
   // Dynamic changes test disabled because of Bug 1050940
+  // If this part of the test is ever enabled again, it should be changed to
+  // use addProperty (in head.js) and stop using _applyingModifications
 
   // info("Test dynamic changes to keyframe rule for #pacman");
 
   // let defaultView = element.ownerDocument.defaultView;
   // let ruleEditor = view.element.children[5].childNodes[0]._ruleEditor;
   // ruleEditor.addProperty("opacity", "0");
 
   // yield ruleEditor._applyingModifications;
--- a/devtools/client/inspector/rules/test/browser_rules_livepreview.js
+++ b/devtools/client/inspector/rules/test/browser_rules_livepreview.js
@@ -37,38 +37,35 @@ add_task(function*() {
   yield selectNode("#testid", inspector);
 
   for (let data of TEST_DATA) {
     yield testLivePreviewData(data, view, "#testid");
   }
 });
 
 function* testLivePreviewData(data, ruleView, selector) {
-  let ruleEditor = getRuleViewRuleEditor(ruleView, 1);
-  let propEditor = ruleEditor.rule.textProps[0].editor;
+  let rule = getRuleViewRuleEditor(ruleView, 1).rule;
+  let propEditor = rule.textProps[0].editor;
 
   info("Focusing the property value inplace-editor");
   let editor = yield focusEditableField(ruleView, propEditor.valueSpan);
   is(inplaceEditor(propEditor.valueSpan), editor,
     "The focused editor is the value");
 
-  info("Enter a value in the editor");
+  info("Entering value in the editor: " + data.value);
+  let onPreviewDone = ruleView.once("ruleview-changed");
   EventUtils.sendString(data.value, ruleView.styleWindow);
+  yield onPreviewDone;
+
+  let onValueDone = ruleView.once("ruleview-changed");
   if (data.escape) {
     EventUtils.synthesizeKey("VK_ESCAPE", {});
   } else {
     EventUtils.synthesizeKey("VK_RETURN", {});
   }
-
-  // Wait for the modifyproperties request to complete before
-  // checking the computed style.
-  for (let rule of ruleView._elementStyle.rules) {
-    if (rule._applyingModifications) {
-      yield rule._applyingModifications;
-    }
-  }
+  yield onValueDone;
 
   // While the editor is still focused in, the display should have
   // changed already
   is((yield getComputedStyleProperty(selector, null, "display")),
     data.expected,
     "Element should be previewed as " + data.expected);
 }
--- a/devtools/client/inspector/rules/test/browser_rules_mark_overridden_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_mark_overridden_01.js
@@ -18,47 +18,39 @@ const TEST_URI = `
   </style>
   <div id='testid' class='testclass'>Styled Node</div>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
-  yield testMarkOverridden(inspector, view);
-});
 
-function* testMarkOverridden(inspector, view) {
-  let elementStyle = view._elementStyle;
-
-  let idRule = elementStyle.rules[1];
+  let idRule = getRuleViewRuleEditor(view, 1).rule;
   let idProp = idRule.textProps[0];
   is(idProp.name, "background-color",
     "First ID property should be background-color");
   is(idProp.value, "blue", "First ID property value should be blue");
   ok(!idProp.overridden, "ID prop should not be overridden.");
   ok(!idProp.editor.element.classList.contains("ruleview-overridden"),
     "ID property editor should not have ruleview-overridden class");
 
-  let classRule = elementStyle.rules[2];
+  let classRule = getRuleViewRuleEditor(view, 2).rule;
   let classProp = classRule.textProps[0];
   is(classProp.name, "background-color",
     "First class prop should be background-color");
   is(classProp.value, "green", "First class property value should be green");
   ok(classProp.overridden, "Class property should be overridden.");
   ok(classProp.editor.element.classList.contains("ruleview-overridden"),
     "Class property editor should have ruleview-overridden class");
 
   // Override background-color by changing the element style.
-  let elementRule = elementStyle.rules[0];
-  elementRule.createProperty("background-color", "purple", "");
-  yield elementRule._applyingModifications;
+  let elementProp = yield addProperty(view, 0, "background-color", "purple");
 
-  let elementProp = elementRule.textProps[0];
   ok(!elementProp.overridden,
     "Element style property should not be overridden");
   ok(idProp.overridden, "ID property should be overridden");
   ok(idProp.editor.element.classList.contains("ruleview-overridden"),
     "ID property editor should have ruleview-overridden class");
   ok(classProp.overridden, "Class property should be overridden");
   ok(classProp.editor.element.classList.contains("ruleview-overridden"),
     "Class property editor should have ruleview-overridden class");
-}
+});
--- a/devtools/client/inspector/rules/test/browser_rules_mark_overridden_03.js
+++ b/devtools/client/inspector/rules/test/browser_rules_mark_overridden_03.js
@@ -18,31 +18,24 @@ const TEST_URI = `
   </style>
   <div id='testid' class='testclass'>Styled Node</div>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
-  yield testMarkOverridden(inspector, view);
-});
 
-function* testMarkOverridden(inspector, view) {
-  let elementStyle = view._elementStyle;
-
-  let idRule = elementStyle.rules[1];
+  let idRule = getRuleViewRuleEditor(view, 1).rule;
   let idProp = idRule.textProps[0];
   ok(idProp.overridden, "Not-important rule should be overridden.");
 
-  let classRule = elementStyle.rules[2];
+  let classRule = getRuleViewRuleEditor(view, 2).rule;
   let classProp = classRule.textProps[0];
   ok(!classProp.overridden, "Important rule should not be overridden.");
 
-  let elementRule = elementStyle.rules[0];
-  let elementProp = elementRule.createProperty("background-color", "purple",
-    "important");
-  yield elementRule._applyingModifications;
+  ok(idProp.overridden, "ID property should be overridden.");
 
-  ok(!elementProp.overridden, "New important prop should not be overriden.");
-  ok(idProp.overridden, "ID property should be overridden.");
-  ok(classProp.overridden, "Class property should be overridden.");
-}
+  // FIXME: re-enable these 2 assertions when bug 1247737 is fixed.
+  // let elementProp = yield addProperty(view, 0, "background-color", "purple");
+  // ok(!elementProp.overridden, "New important prop should not be overriden.");
+  // ok(classProp.overridden, "Class property should be overridden.");
+});
--- a/devtools/client/inspector/rules/test/browser_rules_mark_overridden_04.js
+++ b/devtools/client/inspector/rules/test/browser_rules_mark_overridden_04.js
@@ -18,25 +18,19 @@ const TEST_URI = `
   </style>
   <div id='testid' class='testclass'>Styled Node</div>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
-  yield testMarkOverridden(inspector, view);
-});
 
-function* testMarkOverridden(inspector, view) {
-  let elementStyle = view._elementStyle;
-
-  let idRule = elementStyle.rules[1];
+  let idRule = getRuleViewRuleEditor(view, 1).rule;
   let idProp = idRule.textProps[0];
 
-  idProp.setEnabled(false);
-  yield idRule._applyingModifications;
+  yield togglePropStatus(view, idProp);
 
-  let classRule = elementStyle.rules[2];
+  let classRule = getRuleViewRuleEditor(view, 2).rule;
   let classProp = classRule.textProps[0];
   ok(!classProp.overridden,
     "Class prop should not be overridden after id prop was disabled.");
-}
+});
--- a/devtools/client/inspector/rules/test/browser_rules_mark_overridden_05.js
+++ b/devtools/client/inspector/rules/test/browser_rules_mark_overridden_05.js
@@ -15,23 +15,19 @@ const TEST_URI = `
   </style>
   <div id='testid' class='testclass'>Styled Node</div>
 `;
 
 add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
   yield selectNode("#testid", inspector);
-  yield testMarkOverridden(inspector, view);
-});
 
-function* testMarkOverridden(inspector, view) {
-  let ruleEditor = getRuleViewRuleEditor(view, 1);
+  let rule = getRuleViewRuleEditor(view, 1).rule;
 
-  yield createNewRuleViewProperty(ruleEditor, "background-color: red;");
-  yield ruleEditor.rule._applyingModifications;
+  yield addProperty(view, 1, "background-color", "red");
 
-  let firstProp = ruleEditor.rule.textProps[0];
-  let secondProp = ruleEditor.rule.textProps[1];
+  let firstProp = rule.textProps[0];
+  let secondProp = rule.textProps[1];
 
   ok(firstProp.overridden, "First property should be overridden.");
   ok(!secondProp.overridden, "Second property should not be overridden.");
-}
+});
--- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
@@ -66,56 +66,58 @@ function* testTopLeft(inspector, view) {
     [...view.element.children[1].children].filter(e => {
       return e._ruleEditor && e._ruleEditor.rule === elementFirstLineRule;
     })[0]._ruleEditor;
 
   is(convertTextPropsToString(elementFirstLineRule.textProps),
      "color: orange",
      "TopLeft firstLine properties are correct");
 
+  let onAdded = view.once("ruleview-changed");
   let firstProp = elementFirstLineRuleView.addProperty("background-color",
     "rgb(0, 255, 0)", "");
+  yield onAdded;
+
+  onAdded = view.once("ruleview-changed");
   let secondProp = elementFirstLineRuleView.addProperty("font-style",
     "italic", "");
+  yield onAdded;
 
   is(firstProp,
      elementFirstLineRule.textProps[elementFirstLineRule.textProps.length - 2],
      "First added property is on back of array");
   is(secondProp,
      elementFirstLineRule.textProps[elementFirstLineRule.textProps.length - 1],
      "Second added property is on back of array");
 
-  yield elementFirstLineRule._applyingModifications;
-
   is((yield getComputedStyleProperty(el, ":first-line", "background-color")),
      "rgb(0, 255, 0)", "Added property should have been used.");
   is((yield getComputedStyleProperty(el, ":first-line", "font-style")),
      "italic", "Added property should have been used.");
   is((yield getComputedStyleProperty(el, null, "text-decoration")),
      "none", "Added property should not apply to element");
 
-  firstProp.setEnabled(false);
-  yield elementFirstLineRule._applyingModifications;
+  yield togglePropStatus(view, firstProp);
 
   is((yield getComputedStyleProperty(el, ":first-line", "background-color")),
      "rgb(255, 0, 0)", "Disabled property should now have been used.");
   is((yield getComputedStyleProperty(el, null, "background-color")),
      "rgb(221, 221, 221)", "Added property should not apply to element");
 
-  firstProp.setEnabled(true);
-  yield elementFirstLineRule._applyingModifications;
+  yield togglePropStatus(view, firstProp);
 
   is((yield getComputedStyleProperty(el, ":first-line", "background-color")),
      "rgb(0, 255, 0)", "Added property should have been used.");
   is((yield getComputedStyleProperty(el, null, "text-decoration")),
      "none", "Added property should not apply to element");
 
+  onAdded = view.once("ruleview-changed");
   firstProp = elementRuleView.addProperty("background-color",
                                           "rgb(0, 0, 255)", "");
-  yield elementRule._applyingModifications;
+  yield onAdded;
 
   is((yield getComputedStyleProperty(el, null, "background-color")),
      "rgb(0, 0, 255)", "Added property should have been used.");
   is((yield getComputedStyleProperty(el, ":first-line", "background-color")),
      "rgb(0, 255, 0)", "Added prop does not apply to pseudo");
 }
 
 function* testTopRight(inspector, view) {
--- a/devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
+++ b/devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
@@ -133,20 +133,23 @@ function* testExternalStyleSheet(view, t
   yield validateStyleEditorSheet(editor, 2, testActor);
 }
 
 function* validateStyleEditorSheet(editor, expectedSheetIndex, testActor) {
   info("validating style editor stylesheet");
   is(editor.styleSheet.styleSheetIndex, expectedSheetIndex,
      "loaded stylesheet index matches document stylesheet");
 
-  let sheet = yield testActor.eval(
-    `content.document.styleSheets[${expectedSheetIndex}]`);
-  is(editor.styleSheet.href, sheet.href,
-    "loaded stylesheet href matches document stylesheet");
+  let href = editor.styleSheet.href || editor.styleSheet.nodeHref;
+
+  let expectedHref = yield testActor.eval(
+    `content.document.styleSheets[${expectedSheetIndex}].href ||
+     content.document.location.href`);
+
+  is(href, expectedHref, "loaded stylesheet href matches document stylesheet");
 }
 
 function testRuleViewLinkLabel(view) {
   let link = getRuleViewLinkByIndex(view, 2);
   let labelElem = link.querySelector(".ruleview-rule-source-label");
   let value = labelElem.getAttribute("value");
   let tooltipText = labelElem.getAttribute("tooltiptext");
 
--- a/devtools/client/inspector/rules/test/head.js
+++ b/devtools/client/inspector/rules/test/head.js
@@ -481,17 +481,19 @@ function getRuleViewSelector(view, selec
  */
 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
+ * 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
  * @param {Array} newRgba
  *        The new color to be set [r, g, b, a]
  * @param {Object} expectedChange
  *        Optional object that needs the following props:
@@ -511,24 +513,109 @@ var simulateColorPickerChange = Task.asy
   info("Applying the change");
   spectrum.updateUI();
   spectrum.onChange();
   info("Waiting for rule-view to update");
   yield onRuleViewChanged;
 
   if (expectedChange) {
     info("Waiting for the style to be applied on the page");
-    yield waitForSuccess(function*() {
-      let {selector, name, value} = expectedChange;
-      return (yield getComputedStyleProperty(selector, null, name)) === value;
-    }, `Color picker change applied on element "${expectedChange.selector}"`);
+    let {selector, name, value} = expectedChange;
+    yield waitForComputedStyleProperty(selector, null, name, value);
   }
 });
 
 /**
+ * Open the color picker popup for a given property in a given rule and
+ * simulate a color change. Optionally wait for a given element in the page to
+ * have its style changed as a result.
+ *
+ * @param {RuleView} view
+ *        The related rule view instance
+ * @param {Number} ruleIndex
+ *        Which rule to target in the rule view
+ * @param {Number} propIndex
+ *        Which property to target in the rule
+ * @param {Array} newRgba
+ *        The new color to be set [r, g, b, a]
+ * @param {Object} expectedChange
+ *        Optional object that needs the following props:
+ *          - {String} selector The selector to the element in the page that
+ *            will have its style changed.
+ *          - {String} name The style name that will be changed
+ *          - {String} value The expected style value
+ * The style will be checked like so: getComputedStyle(element)[name] === value
+ */
+var openColorPickerAndSelectColor = Task.async(function*(view, ruleIndex,
+    propIndex, newRgba, expectedChange) {
+  let ruleEditor = getRuleViewRuleEditor(view, ruleIndex);
+  let propEditor = ruleEditor.rule.textProps[propIndex].editor;
+  let swatch = propEditor.valueSpan.querySelector(".ruleview-colorswatch");
+  let cPicker = view.tooltips.colorPicker;
+
+  info("Opening the colorpicker by clicking the color swatch");
+  let onShown = cPicker.tooltip.once("shown");
+  swatch.click();
+  yield onShown;
+
+  yield simulateColorPickerChange(view, cPicker, newRgba, expectedChange);
+
+  return {propEditor, swatch, cPicker};
+});
+
+/**
+ * Open the cubicbezier popup for a given property in a given rule and
+ * simulate a curve change. Optionally wait for a given element in the page to
+ * have its style changed as a result.
+ *
+ * @param {RuleView} view
+ *        The related rule view instance
+ * @param {Number} ruleIndex
+ *        Which rule to target in the rule view
+ * @param {Number} propIndex
+ *        Which property to target in the rule
+ * @param {Array} coords
+ *        The new coordinates to be used, e.g. [0.1, 2, 0.9, -1]
+ * @param {Object} expectedChange
+ *        Optional object that needs the following props:
+ *          - {String} selector The selector to the element in the page that
+ *            will have its style changed.
+ *          - {String} name The style name that will be changed
+ *          - {String} value The expected style value
+ * The style will be checked like so: getComputedStyle(element)[name] === value
+ */
+var openCubicBezierAndChangeCoords = Task.async(function*(view, ruleIndex,
+    propIndex, coords, expectedChange) {
+  let ruleEditor = getRuleViewRuleEditor(view, ruleIndex);
+  let propEditor = ruleEditor.rule.textProps[propIndex].editor;
+  let swatch = propEditor.valueSpan.querySelector(".ruleview-bezierswatch");
+  let bezierTooltip = view.tooltips.cubicBezier;
+
+  info("Opening the cubicBezier by clicking the swatch");
+  let onShown = bezierTooltip.tooltip.once("shown");
+  swatch.click();
+  yield onShown;
+
+  let widget = yield bezierTooltip.widget;
+
+  info("Simulating a change of curve in the widget");
+  let onRuleViewChanged = view.once("ruleview-changed");
+  widget.coordinates = coords;
+  yield onRuleViewChanged;
+
+  if (expectedChange) {
+    info("Waiting for the style to be applied on the page");
+    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
  */
@@ -579,17 +666,17 @@ function getRuleViewRuleEditor(view, chi
  *        that's going to change the style attribute of the selected node.
  * @param {String} name
  *        The name for the new property
  * @param {String} value
  *        The value for the new property
  * @param {String} commitValueWith
  *        Which key should be used to commit the new value. VK_RETURN is used by
  *        default, but tests might want to use another key to test cancelling
- *        for exmple.
+ *        for exemple.
  * @param {Boolean} blurNewProperty
  *        After the new value has been added, a new property would have been
  *        focused. This parameter is true by default, and that causes the new
  *        property to be blurred. Set to false if you don't want this.
  * @return {TextProperty} The instance of the TextProperty that was added
  */
 var addProperty = Task.async(function*(view, ruleIndex, name, value,
                                        commitValueWith = "VK_RETURN",
@@ -637,48 +724,69 @@ var addProperty = Task.async(function*(v
 /**
  * Simulate changing the value of a property in a rule in the rule-view.
  *
  * @param {CssRuleView} view
  *        The instance of the rule-view panel
  * @param {TextProperty} textProp
  *        The instance of the TextProperty to be changed
  * @param {String} value
- *        The new value to be used
+ *        The new value to be used. If null is passed, then the value will be
+ *        deleted
+ * @param {Boolean} blurNewProperty
+ *        After the value has been changed, a new property would have been
+ *        focused. This parameter is true by default, and that causes the new
+ *        property to be blurred. Set to false if you don't want this.
  */
-var setProperty = Task.async(function*(view, textProp, value) {
-  let editor = yield focusEditableField(view, textProp.editor.valueSpan);
+var setProperty = Task.async(function*(view, textProp, value,
+                                       blurNewProperty = true) {
+  yield focusEditableField(view, textProp.editor.valueSpan);
 
-  let onRuleViewRefreshed = view.once("ruleview-changed");
-  editor.input.value = value;
+  let onPreview = view.once("ruleview-changed");
+  if (value === null) {
+    EventUtils.synthesizeKey("VK_DELETE", {}, view.styleWindow);
+  } else {
+    EventUtils.sendString(value, view.styleWindow);
+  }
+  yield onPreview;
+
+  let onValueDone = view.once("ruleview-changed");
   EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow);
-  yield onRuleViewRefreshed;
+  yield onValueDone;
 
-  view.styleDocument.activeElement.blur();
+  if (blurNewProperty) {
+    view.styleDocument.activeElement.blur();
+  }
 });
 
 /**
  * Simulate removing a property from an existing rule in the rule-view.
  *
  * @param {CssRuleView} view
  *        The instance of the rule-view panel
  * @param {TextProperty} textProp
  *        The instance of the TextProperty to be removed
+ * @param {Boolean} blurNewProperty
+ *        After the property has been removed, a new property would have been
+ *        focused. This parameter is true by default, and that causes the new
+ *        property to be blurred. Set to false if you don't want this.
  */
-var removeProperty = Task.async(function*(view, textProp) {
+var removeProperty = Task.async(function*(view, textProp,
+                                          blurNewProperty = true) {
   yield focusEditableField(view, textProp.editor.nameSpan);
 
   let onModifications = view.once("ruleview-changed");
   info("Deleting the property name now");
   EventUtils.synthesizeKey("VK_DELETE", {}, view.styleWindow);
   EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow);
   yield onModifications;
 
-  // Blur the new property field that was focused by default.
-  view.styleDocument.activeElement.blur();
+  if (blurNewProperty) {
+    view.styleDocument.activeElement.blur();
+  }
 });
 
 /**
  * Simulate clicking the enable/disable checkbox next to a property in a rule.
  *
  * @param {CssRuleView} view
  *        The instance of the rule-view panel
  * @param {TextProperty} textProp