Bug 1246677 - 9 - Get rid of all remaining _applyingModifications usage in tests; r=ochameau
authorPatrick Brosset <pbrosset@mozilla.com>
Tue, 23 Feb 2016 16:50:08 +0100
changeset 323967 fab1d65e405ada5fc969a22fb8ef9bd7e405170b
parent 323966 ce103dd1d95b3f3d4ed9fb121453a86e61122312
child 323968 825cd61d323da7ec9bdd516a2fc01e937ff1611b
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau
bugs1246677
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1246677 - 9 - Get rid of all remaining _applyingModifications usage in tests; r=ochameau 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/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
@@ -17,32 +17,27 @@ 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 testCancelNew(view);
-});
 
-function* testCancelNew(view) {
   let elementRuleEditor = getRuleViewRuleEditor(view, 0);
   let editor = yield focusNewRuleViewProperty(elementRuleEditor);
   is(inplaceEditor(elementRuleEditor.newPropSpan), editor,
     "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
@@ -53,69 +53,70 @@ function* testTopLeft(inspector, view) {
 
   info("Make sure that dblclicking on the header container also toggles " +
        "the pseudo elements");
   EventUtils.synthesizeMouseAtCenter(gutters[0], {clickCount: 2},
                                      view.styleWindow);
   ok(!view.element.firstChild.classList.contains("show-expandable-container"),
      "Pseudo Elements are collapsed by dblclicking");
 
-  let elementRule = rules.elementRules[0];
   let elementRuleView = getRuleViewRuleEditor(view, 3);
 
   let elementFirstLineRule = rules.firstLineRules[0];
   let elementFirstLineRuleView =
     [...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(id, ":first-line", "background-color")),
      "rgb(0, 255, 0)", "Added property should have been used.");
   is((yield getComputedStyleProperty(id, ":first-line", "font-style")),
      "italic", "Added property should have been used.");
   is((yield getComputedStyleProperty(id, null, "text-decoration")),
      "none", "Added property should not apply to element");
 
-  firstProp.setEnabled(false);
-  yield elementFirstLineRule._applyingModifications;
+  yield togglePropStatus(view, firstProp);
 
   is((yield getComputedStyleProperty(id, ":first-line", "background-color")),
      "rgb(255, 0, 0)", "Disabled property should now have been used.");
   is((yield getComputedStyleProperty(id, 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(id, ":first-line", "background-color")),
      "rgb(0, 255, 0)", "Added property should have been used.");
   is((yield getComputedStyleProperty(id, 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(id, null, "background-color")),
      "rgb(0, 0, 255)", "Added property should have been used.");
   is((yield getComputedStyleProperty(id, ":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/head.js
+++ b/devtools/client/inspector/rules/test/head.js
@@ -480,17 +480,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:
@@ -510,24 +512,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
  */
@@ -578,17 +665,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",
@@ -636,48 +723,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