summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/components/test
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/inspector/components/test')
-rw-r--r--devtools/client/inspector/components/test/.eslintrc.js6
-rw-r--r--devtools/client/inspector/components/test/browser.ini29
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel.js168
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_editablemodel.js194
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_editablemodel_allproperties.js146
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_editablemodel_bluronclick.js74
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_editablemodel_border.js52
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_editablemodel_stylerules.js113
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_guides.js56
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_rotate-labels-on-sides.js49
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_sync.js44
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_tooltips.js126
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_update-after-navigation.js91
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_update-after-reload.js40
-rw-r--r--devtools/client/inspector/components/test/browser_boxmodel_update-in-iframes.js101
-rw-r--r--devtools/client/inspector/components/test/doc_boxmodel_iframe1.html3
-rw-r--r--devtools/client/inspector/components/test/doc_boxmodel_iframe2.html3
-rw-r--r--devtools/client/inspector/components/test/head.js87
18 files changed, 1382 insertions, 0 deletions
diff --git a/devtools/client/inspector/components/test/.eslintrc.js b/devtools/client/inspector/components/test/.eslintrc.js
new file mode 100644
index 000000000..698ae9181
--- /dev/null
+++ b/devtools/client/inspector/components/test/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+ // Extend from the shared list of defined globals for mochitests.
+ "extends": "../../../../.eslintrc.mochitests.js"
+};
diff --git a/devtools/client/inspector/components/test/browser.ini b/devtools/client/inspector/components/test/browser.ini
new file mode 100644
index 000000000..42eb352d6
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser.ini
@@ -0,0 +1,29 @@
+[DEFAULT]
+tags = devtools
+subsuite = devtools
+support-files =
+ doc_boxmodel_iframe1.html
+ doc_boxmodel_iframe2.html
+ head.js
+ !/devtools/client/commandline/test/helpers.js
+ !/devtools/client/framework/test/shared-head.js
+ !/devtools/client/inspector/test/head.js
+ !/devtools/client/inspector/test/shared-head.js
+ !/devtools/client/shared/test/test-actor.js
+ !/devtools/client/shared/test/test-actor-registry.js
+
+[browser_boxmodel.js]
+[browser_boxmodel_editablemodel.js]
+# [browser_boxmodel_editablemodel_allproperties.js]
+# Disabled for too many intermittent failures (bug 1009322)
+[browser_boxmodel_editablemodel_bluronclick.js]
+[browser_boxmodel_editablemodel_border.js]
+[browser_boxmodel_editablemodel_stylerules.js]
+[browser_boxmodel_guides.js]
+[browser_boxmodel_rotate-labels-on-sides.js]
+[browser_boxmodel_sync.js]
+[browser_boxmodel_tooltips.js]
+[browser_boxmodel_update-after-navigation.js]
+[browser_boxmodel_update-after-reload.js]
+# [browser_boxmodel_update-in-iframes.js]
+# Bug 1020038 boxmodel-view updates for iframe elements changes
diff --git a/devtools/client/inspector/components/test/browser_boxmodel.js b/devtools/client/inspector/components/test/browser_boxmodel.js
new file mode 100644
index 000000000..f8b87f421
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel.js
@@ -0,0 +1,168 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the box model displays the right values and that it updates when
+// the node's style is changed
+
+// Expected values:
+var res1 = [
+ {
+ selector: "#boxmodel-element-size",
+ value: "160" + "\u00D7" + "160.117"
+ },
+ {
+ selector: ".boxmodel-size > span",
+ value: "100" + "\u00D7" + "100.117"
+ },
+ {
+ selector: ".boxmodel-margin.boxmodel-top > span",
+ value: 30
+ },
+ {
+ selector: ".boxmodel-margin.boxmodel-left > span",
+ value: "auto"
+ },
+ {
+ selector: ".boxmodel-margin.boxmodel-bottom > span",
+ value: 30
+ },
+ {
+ selector: ".boxmodel-margin.boxmodel-right > span",
+ value: "auto"
+ },
+ {
+ selector: ".boxmodel-padding.boxmodel-top > span",
+ value: 20
+ },
+ {
+ selector: ".boxmodel-padding.boxmodel-left > span",
+ value: 20
+ },
+ {
+ selector: ".boxmodel-padding.boxmodel-bottom > span",
+ value: 20
+ },
+ {
+ selector: ".boxmodel-padding.boxmodel-right > span",
+ value: 20
+ },
+ {
+ selector: ".boxmodel-border.boxmodel-top > span",
+ value: 10
+ },
+ {
+ selector: ".boxmodel-border.boxmodel-left > span",
+ value: 10
+ },
+ {
+ selector: ".boxmodel-border.boxmodel-bottom > span",
+ value: 10
+ },
+ {
+ selector: ".boxmodel-border.boxmodel-right > span",
+ value: 10
+ },
+];
+
+var res2 = [
+ {
+ selector: "#boxmodel-element-size",
+ value: "190" + "\u00D7" + "210"
+ },
+ {
+ selector: ".boxmodel-size > span",
+ value: "100" + "\u00D7" + "150"
+ },
+ {
+ selector: ".boxmodel-margin.boxmodel-top > span",
+ value: 30
+ },
+ {
+ selector: ".boxmodel-margin.boxmodel-left > span",
+ value: "auto"
+ },
+ {
+ selector: ".boxmodel-margin.boxmodel-bottom > span",
+ value: 30
+ },
+ {
+ selector: ".boxmodel-margin.boxmodel-right > span",
+ value: "auto"
+ },
+ {
+ selector: ".boxmodel-padding.boxmodel-top > span",
+ value: 20
+ },
+ {
+ selector: ".boxmodel-padding.boxmodel-left > span",
+ value: 20
+ },
+ {
+ selector: ".boxmodel-padding.boxmodel-bottom > span",
+ value: 20
+ },
+ {
+ selector: ".boxmodel-padding.boxmodel-right > span",
+ value: 50
+ },
+ {
+ selector: ".boxmodel-border.boxmodel-top > span",
+ value: 10
+ },
+ {
+ selector: ".boxmodel-border.boxmodel-left > span",
+ value: 10
+ },
+ {
+ selector: ".boxmodel-border.boxmodel-bottom > span",
+ value: 10
+ },
+ {
+ selector: ".boxmodel-border.boxmodel-right > span",
+ value: 10
+ },
+];
+
+add_task(function* () {
+ let style = "div { position: absolute; top: 42px; left: 42px; " +
+ "height: 100.111px; width: 100px; border: 10px solid black; " +
+ "padding: 20px; margin: 30px auto;}";
+ let html = "<style>" + style + "</style><div></div>";
+
+ yield addTab("data:text/html," + encodeURIComponent(html));
+ let {inspector, view, testActor} = yield openBoxModelView();
+ yield selectNode("div", inspector);
+
+ yield testInitialValues(inspector, view);
+ yield testChangingValues(inspector, view, testActor);
+});
+
+function* testInitialValues(inspector, view) {
+ info("Test that the initial values of the box model are correct");
+ let viewdoc = view.doc;
+
+ for (let i = 0; i < res1.length; i++) {
+ let elt = viewdoc.querySelector(res1[i].selector);
+ is(elt.textContent, res1[i].value,
+ res1[i].selector + " has the right value.");
+ }
+}
+
+function* testChangingValues(inspector, view, testActor) {
+ info("Test that changing the document updates the box model");
+ let viewdoc = view.doc;
+
+ let onUpdated = waitForUpdate(inspector);
+ yield testActor.setAttribute("div", "style",
+ "height:150px;padding-right:50px;");
+ yield onUpdated;
+
+ for (let i = 0; i < res2.length; i++) {
+ let elt = viewdoc.querySelector(res2[i].selector);
+ is(elt.textContent, res2[i].value,
+ res2[i].selector + " has the right value after style update.");
+ }
+}
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_editablemodel.js b/devtools/client/inspector/components/test/browser_boxmodel_editablemodel.js
new file mode 100644
index 000000000..5c32c2029
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_editablemodel.js
@@ -0,0 +1,194 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that editing the box-model values works as expected and test various
+// key bindings
+
+const TEST_URI = "<style>" +
+ "div { margin: 10px; padding: 3px }" +
+ "#div1 { margin-top: 5px }" +
+ "#div2 { border-bottom: 1em solid black; }" +
+ "#div3 { padding: 2em; }" +
+ "#div4 { margin: 1px; }" +
+ "</style>" +
+ "<div id='div1'></div><div id='div2'></div>" +
+ "<div id='div3'></div><div id='div4'></div>";
+
+add_task(function* () {
+ yield addTab("data:text/html," + encodeURIComponent(TEST_URI));
+ let {inspector, view, testActor} = yield openBoxModelView();
+
+ yield testEditingMargins(inspector, view, testActor);
+ yield testKeyBindings(inspector, view, testActor);
+ yield testEscapeToUndo(inspector, view, testActor);
+ yield testDeletingValue(inspector, view, testActor);
+ yield testRefocusingOnClick(inspector, view, testActor);
+});
+
+function* testEditingMargins(inspector, view, testActor) {
+ info("Test that editing margin dynamically updates the document, pressing " +
+ "escape cancels the changes");
+
+ is((yield getStyle(testActor, "#div1", "margin-top")), "",
+ "Should be no margin-top on the element.");
+ yield selectNode("#div1", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-margin.boxmodel-top > span");
+ is(span.textContent, 5, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "5px", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("3", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is((yield getStyle(testActor, "#div1", "margin-top")), "3px",
+ "Should have updated the margin.");
+
+ EventUtils.synthesizeKey("VK_ESCAPE", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is((yield getStyle(testActor, "#div1", "margin-top")), "",
+ "Should be no margin-top on the element.");
+ is(span.textContent, 5, "Should have the right value in the box model.");
+}
+
+function* testKeyBindings(inspector, view, testActor) {
+ info("Test that arrow keys work correctly and pressing enter commits the " +
+ "changes");
+
+ is((yield getStyle(testActor, "#div1", "margin-left")), "",
+ "Should be no margin-top on the element.");
+ yield selectNode("#div1", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-margin.boxmodel-left > span");
+ is(span.textContent, 10, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "10px", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("VK_UP", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "11px", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div1", "margin-left")), "11px",
+ "Should have updated the margin.");
+
+ EventUtils.synthesizeKey("VK_DOWN", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "10px", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div1", "margin-left")), "10px",
+ "Should have updated the margin.");
+
+ EventUtils.synthesizeKey("VK_UP", { shiftKey: true }, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "20px", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div1", "margin-left")), "20px",
+ "Should have updated the margin.");
+ EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
+
+ is((yield getStyle(testActor, "#div1", "margin-left")), "20px",
+ "Should be the right margin-top on the element.");
+ is(span.textContent, 20, "Should have the right value in the box model.");
+}
+
+function* testEscapeToUndo(inspector, view, testActor) {
+ info("Test that deleting the value removes the property but escape undoes " +
+ "that");
+
+ is((yield getStyle(testActor, "#div1", "margin-left")), "20px",
+ "Should be the right margin-top on the element.");
+ yield selectNode("#div1", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-margin.boxmodel-left > span");
+ is(span.textContent, 20, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "20px", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("VK_DELETE", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div1", "margin-left")), "",
+ "Should have updated the margin.");
+
+ EventUtils.synthesizeKey("VK_ESCAPE", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is((yield getStyle(testActor, "#div1", "margin-left")), "20px",
+ "Should be the right margin-top on the element.");
+ is(span.textContent, 20, "Should have the right value in the box model.");
+}
+
+function* testDeletingValue(inspector, view, testActor) {
+ info("Test that deleting the value removes the property");
+
+ yield setStyle(testActor, "#div1", "marginRight", "15px");
+ yield waitForUpdate(inspector);
+
+ yield selectNode("#div1", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-margin.boxmodel-right > span");
+ is(span.textContent, 15, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "15px", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("VK_DELETE", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div1", "margin-right")), "",
+ "Should have updated the margin.");
+
+ EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
+
+ is((yield getStyle(testActor, "#div1", "margin-right")), "",
+ "Should be the right margin-top on the element.");
+ is(span.textContent, 10, "Should have the right value in the box model.");
+}
+
+function* testRefocusingOnClick(inspector, view, testActor) {
+ info("Test that clicking in the editor input does not remove focus");
+
+ yield selectNode("#div4", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-margin.boxmodel-top > span");
+ is(span.textContent, 1, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+
+ info("Click in the already opened editor input");
+ EventUtils.synthesizeMouseAtCenter(editor, {}, view.doc.defaultView);
+ is(editor, view.doc.activeElement,
+ "Inplace editor input should still have focus.");
+
+ info("Check the input can still be used as expected");
+ EventUtils.synthesizeKey("VK_UP", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "2px", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div4", "margin-top")), "2px",
+ "Should have updated the margin.");
+ EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
+
+ is((yield getStyle(testActor, "#div4", "margin-top")), "2px",
+ "Should be the right margin-top on the element.");
+ is(span.textContent, 2, "Should have the right value in the box model.");
+}
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_allproperties.js b/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_allproperties.js
new file mode 100644
index 000000000..464a7b6c5
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_allproperties.js
@@ -0,0 +1,146 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test editing box model values when all values are set
+
+const TEST_URI = "<style>" +
+ "div { margin: 10px; padding: 3px }" +
+ "#div1 { margin-top: 5px }" +
+ "#div2 { border-bottom: 1em solid black; }" +
+ "#div3 { padding: 2em; }" +
+ "</style>" +
+ "<div id='div1'></div><div id='div2'></div><div id='div3'></div>";
+
+add_task(function* () {
+ yield addTab("data:text/html," + encodeURIComponent(TEST_URI));
+ let {inspector, view, testActor} = yield openBoxModelView();
+
+ yield testEditing(inspector, view, testActor);
+ yield testEditingAndCanceling(inspector, view, testActor);
+ yield testDeleting(inspector, view, testActor);
+ yield testDeletingAndCanceling(inspector, view, testActor);
+});
+
+function* testEditing(inspector, view, testActor) {
+ info("When all properties are set on the node editing one should work");
+
+ yield setStyle(testActor, "#div1", "padding", "5px");
+ yield waitForUpdate(inspector);
+
+ yield selectNode("#div1", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-padding.boxmodel-bottom > span");
+ is(span.textContent, 5, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "5px", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("7", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "7", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div1", "padding-bottom")), "7px",
+ "Should have updated the padding");
+
+ EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
+
+ is((yield getStyle(testActor, "#div1", "padding-bottom")), "7px",
+ "Should be the right padding.");
+ is(span.textContent, 7, "Should have the right value in the box model.");
+}
+
+function* testEditingAndCanceling(inspector, view, testActor) {
+ info("When all properties are set on the node editing one and then " +
+ "cancelling with ESCAPE should work");
+
+ yield setStyle(testActor, "#div1", "padding", "5px");
+ yield waitForUpdate(inspector);
+
+ yield selectNode("#div1", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-padding.boxmodel-left > span");
+ is(span.textContent, 5, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "5px", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("8", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "8", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div1", "padding-left")), "8px",
+ "Should have updated the padding");
+
+ EventUtils.synthesizeKey("VK_ESCAPE", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is((yield getStyle(testActor, "#div1", "padding-left")), "5px",
+ "Should be the right padding.");
+ is(span.textContent, 5, "Should have the right value in the box model.");
+}
+
+function* testDeleting(inspector, view, testActor) {
+ info("When all properties are set on the node deleting one should work");
+
+ yield selectNode("#div1", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-padding.boxmodel-left > span");
+ is(span.textContent, 5, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "5px", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("VK_DELETE", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div1", "padding-left")), "",
+ "Should have updated the padding");
+
+ EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
+
+ is((yield getStyle(testActor, "#div1", "padding-left")), "",
+ "Should be the right padding.");
+ is(span.textContent, 3, "Should have the right value in the box model.");
+}
+
+function* testDeletingAndCanceling(inspector, view, testActor) {
+ info("When all properties are set on the node deleting one then cancelling " +
+ "should work");
+
+ yield setStyle(testActor, "#div1", "padding", "5px");
+ yield waitForUpdate(inspector);
+
+ yield selectNode("#div1", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-padding.boxmodel-left > span");
+ is(span.textContent, 5, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "5px", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("VK_DELETE", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div1", "padding-left")), "",
+ "Should have updated the padding");
+
+ EventUtils.synthesizeKey("VK_ESCAPE", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is((yield getStyle(testActor, "#div1", "padding-left")), "5px",
+ "Should be the right padding.");
+ is(span.textContent, 5, "Should have the right value in the box model.");
+}
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_bluronclick.js b/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_bluronclick.js
new file mode 100644
index 000000000..9e65e4dc7
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_bluronclick.js
@@ -0,0 +1,74 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that inplace editors can be blurred by clicking outside of the editor.
+
+const TEST_URI =
+ `<style>
+ #div1 {
+ margin: 10px;
+ padding: 3px;
+ }
+ </style>
+ <div id="div1"></div>`;
+
+add_task(function* () {
+ // Make sure the toolbox is tall enough to have empty space below the
+ // boxmodel-container.
+ yield pushPref("devtools.toolbox.footer.height", 500);
+
+ yield addTab("data:text/html," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openBoxModelView();
+
+ yield selectNode("#div1", inspector);
+ yield testClickingOutsideEditor(view);
+ yield testClickingBelowContainer(view);
+});
+
+function* testClickingOutsideEditor(view) {
+ info("Test that clicking outside the editor blurs it");
+ let span = view.doc.querySelector(".boxmodel-margin.boxmodel-top > span");
+ is(span.textContent, 10, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+
+ info("Click next to the opened editor input.");
+ let onBlur = once(editor, "blur");
+ let rect = editor.getBoundingClientRect();
+ EventUtils.synthesizeMouse(editor, rect.width + 10, rect.height / 2, {},
+ view.doc.defaultView);
+ yield onBlur;
+
+ is(view.doc.querySelector(".styleinspector-propertyeditor"), null,
+ "Inplace editor has been removed.");
+}
+
+function* testClickingBelowContainer(view) {
+ info("Test that clicking below the box-model container blurs it");
+ let span = view.doc.querySelector(".boxmodel-margin.boxmodel-top > span");
+ is(span.textContent, 10, "Should have the right value in the box model.");
+
+ info("Test that clicking below the boxmodel-container blurs the opened editor");
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+
+ let onBlur = once(editor, "blur");
+ let container = view.doc.querySelector("#boxmodel-container");
+ // Using getBoxQuads here because getBoundingClientRect (and therefore synthesizeMouse)
+ // use an erroneous height of ~50px for the boxmodel-container.
+ let bounds = container.getBoxQuads({relativeTo: view.doc})[0].bounds;
+ EventUtils.synthesizeMouseAtPoint(
+ bounds.left + 10,
+ bounds.top + bounds.height + 10,
+ {}, view.doc.defaultView);
+ yield onBlur;
+
+ is(view.doc.querySelector(".styleinspector-propertyeditor"), null,
+ "Inplace editor has been removed.");
+}
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_border.js b/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_border.js
new file mode 100644
index 000000000..6e9c04b14
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_border.js
@@ -0,0 +1,52 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that editing the border value in the box model applies the border style
+
+const TEST_URI = "<style>" +
+ "div { margin: 10px; padding: 3px }" +
+ "#div1 { margin-top: 5px }" +
+ "#div2 { border-bottom: 1em solid black; }" +
+ "#div3 { padding: 2em; }" +
+ "</style>" +
+ "<div id='div1'></div><div id='div2'></div><div id='div3'></div>";
+
+add_task(function* () {
+ yield addTab("data:text/html," + encodeURIComponent(TEST_URI));
+ let {inspector, view, testActor} = yield openBoxModelView();
+
+ is((yield getStyle(testActor, "#div1", "border-top-width")), "",
+ "Should have the right border");
+ is((yield getStyle(testActor, "#div1", "border-top-style")), "",
+ "Should have the right border");
+ yield selectNode("#div1", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-border.boxmodel-top > span");
+ is(span.textContent, 0, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "0", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("1", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "1", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div1", "border-top-width")), "1px",
+ "Should have the right border");
+ is((yield getStyle(testActor, "#div1", "border-top-style")), "solid",
+ "Should have the right border");
+
+ EventUtils.synthesizeKey("VK_ESCAPE", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is((yield getStyle(testActor, "#div1", "border-top-width")), "",
+ "Should be the right padding.");
+ is((yield getStyle(testActor, "#div1", "border-top-style")), "",
+ "Should have the right border");
+ is(span.textContent, 0, "Should have the right value in the box model.");
+});
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_stylerules.js b/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_stylerules.js
new file mode 100644
index 000000000..43346fa15
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_editablemodel_stylerules.js
@@ -0,0 +1,113 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that units are displayed correctly when editing values in the box model
+// and that values are retrieved and parsed correctly from the back-end
+
+const TEST_URI = "<style>" +
+ "div { margin: 10px; padding: 3px }" +
+ "#div1 { margin-top: 5px }" +
+ "#div2 { border-bottom: 1em solid black; }" +
+ "#div3 { padding: 2em; }" +
+ "</style>" +
+ "<div id='div1'></div><div id='div2'></div><div id='div3'></div>";
+
+add_task(function* () {
+ yield addTab("data:text/html," + encodeURIComponent(TEST_URI));
+ let {inspector, view, testActor} = yield openBoxModelView();
+
+ yield testUnits(inspector, view, testActor);
+ yield testValueComesFromStyleRule(inspector, view, testActor);
+ yield testShorthandsAreParsed(inspector, view, testActor);
+});
+
+function* testUnits(inspector, view, testActor) {
+ info("Test that entering units works");
+
+ is((yield getStyle(testActor, "#div1", "padding-top")), "",
+ "Should have the right padding");
+ yield selectNode("#div1", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-padding.boxmodel-top > span");
+ is(span.textContent, 3, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "3px", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("1", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+ EventUtils.synthesizeKey("e", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is((yield getStyle(testActor, "#div1", "padding-top")), "",
+ "An invalid value is handled cleanly");
+
+ EventUtils.synthesizeKey("m", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "1em", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div1", "padding-top")),
+ "1em", "Should have updated the padding.");
+
+ EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
+
+ is((yield getStyle(testActor, "#div1", "padding-top")), "1em",
+ "Should be the right padding.");
+ is(span.textContent, 16, "Should have the right value in the box model.");
+}
+
+function* testValueComesFromStyleRule(inspector, view, testActor) {
+ info("Test that we pick up the value from a higher style rule");
+
+ is((yield getStyle(testActor, "#div2", "border-bottom-width")), "",
+ "Should have the right border-bottom-width");
+ yield selectNode("#div2", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-border.boxmodel-bottom > span");
+ is(span.textContent, 16, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "1em", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("0", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+
+ is(editor.value, "0", "Should have the right value in the editor.");
+ is((yield getStyle(testActor, "#div2", "border-bottom-width")), "0px",
+ "Should have updated the border.");
+
+ EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
+
+ is((yield getStyle(testActor, "#div2", "border-bottom-width")), "0px",
+ "Should be the right border-bottom-width.");
+ is(span.textContent, 0, "Should have the right value in the box model.");
+}
+
+function* testShorthandsAreParsed(inspector, view, testActor) {
+ info("Test that shorthand properties are parsed correctly");
+
+ is((yield getStyle(testActor, "#div3", "padding-right")), "",
+ "Should have the right padding");
+ yield selectNode("#div3", inspector);
+
+ let span = view.doc.querySelector(".boxmodel-padding.boxmodel-right > span");
+ is(span.textContent, 32, "Should have the right value in the box model.");
+
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+ ok(editor, "Should have opened the editor.");
+ is(editor.value, "2em", "Should have the right value in the editor.");
+
+ EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
+
+ is((yield getStyle(testActor, "#div3", "padding-right")), "",
+ "Should be the right padding.");
+ is(span.textContent, 32, "Should have the right value in the box model.");
+}
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_guides.js b/devtools/client/inspector/components/test/browser_boxmodel_guides.js
new file mode 100644
index 000000000..612d9ace6
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_guides.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that hovering over regions in the box-model shows the highlighter with
+// the right options.
+// Tests that actually check the highlighter is displayed and correct are in the
+// devtools/inspector/test folder. This test only cares about checking that the
+// box model view does call the highlighter, and it does so by mocking it.
+
+const STYLE = "div { position: absolute; top: 50px; left: 50px; " +
+ "height: 10px; width: 10px; border: 10px solid black; " +
+ "padding: 10px; margin: 10px;}";
+const HTML = "<style>" + STYLE + "</style><div></div>";
+const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
+
+var highlightedNodeFront, highlighterOptions;
+
+add_task(function* () {
+ yield addTab(TEST_URL);
+ let {toolbox, inspector, view} = yield openBoxModelView();
+ yield selectNode("div", inspector);
+
+ // Mock the highlighter by replacing the showBoxModel method.
+ toolbox.highlighter.showBoxModel = function (nodeFront, options) {
+ highlightedNodeFront = nodeFront;
+ highlighterOptions = options;
+ };
+
+ let elt = view.doc.getElementById("boxmodel-margins");
+ yield testGuideOnLayoutHover(elt, "margin", inspector, view);
+
+ elt = view.doc.getElementById("boxmodel-borders");
+ yield testGuideOnLayoutHover(elt, "border", inspector, view);
+
+ elt = view.doc.getElementById("boxmodel-padding");
+ yield testGuideOnLayoutHover(elt, "padding", inspector, view);
+
+ elt = view.doc.getElementById("boxmodel-content");
+ yield testGuideOnLayoutHover(elt, "content", inspector, view);
+});
+
+function* testGuideOnLayoutHover(elt, expectedRegion, inspector) {
+ info("Synthesizing mouseover on the boxmodel-view");
+ EventUtils.synthesizeMouse(elt, 2, 2, {type: "mouseover"},
+ elt.ownerDocument.defaultView);
+
+ info("Waiting for the node-highlight event from the toolbox");
+ yield inspector.toolbox.once("node-highlight");
+
+ is(highlightedNodeFront, inspector.selection.nodeFront,
+ "The right nodeFront was highlighted");
+ is(highlighterOptions.region, expectedRegion,
+ "Region " + expectedRegion + " was highlighted");
+}
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_rotate-labels-on-sides.js b/devtools/client/inspector/components/test/browser_boxmodel_rotate-labels-on-sides.js
new file mode 100644
index 000000000..954cd298b
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_rotate-labels-on-sides.js
@@ -0,0 +1,49 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that longer values are rotated on the side
+
+const res1 = [
+ {selector: ".boxmodel-margin.boxmodel-top > span", value: 30},
+ {selector: ".boxmodel-margin.boxmodel-left > span", value: "auto"},
+ {selector: ".boxmodel-margin.boxmodel-bottom > span", value: 30},
+ {selector: ".boxmodel-margin.boxmodel-right > span", value: "auto"},
+ {selector: ".boxmodel-padding.boxmodel-top > span", value: 20},
+ {selector: ".boxmodel-padding.boxmodel-left > span", value: 2000000},
+ {selector: ".boxmodel-padding.boxmodel-bottom > span", value: 20},
+ {selector: ".boxmodel-padding.boxmodel-right > span", value: 20},
+ {selector: ".boxmodel-border.boxmodel-top > span", value: 10},
+ {selector: ".boxmodel-border.boxmodel-left > span", value: 10},
+ {selector: ".boxmodel-border.boxmodel-bottom > span", value: 10},
+ {selector: ".boxmodel-border.boxmodel-right > span", value: 10},
+];
+
+const TEST_URI = encodeURIComponent([
+ "<style>",
+ "div { border:10px solid black; padding: 20px 20px 20px 2000000px; " +
+ "margin: 30px auto; }",
+ "</style>",
+ "<div></div>"
+].join(""));
+const LONG_TEXT_ROTATE_LIMIT = 3;
+
+add_task(function* () {
+ yield addTab("data:text/html," + TEST_URI);
+ let {inspector, view} = yield openBoxModelView();
+ yield selectNode("div", inspector);
+
+ for (let i = 0; i < res1.length; i++) {
+ let elt = view.doc.querySelector(res1[i].selector);
+ let isLong = elt.textContent.length > LONG_TEXT_ROTATE_LIMIT;
+ let classList = elt.parentNode.classList;
+ let canBeRotated = classList.contains("boxmodel-left") ||
+ classList.contains("boxmodel-right");
+ let isRotated = classList.contains("boxmodel-rotate");
+
+ is(canBeRotated && isLong,
+ isRotated, res1[i].selector + " correctly rotated.");
+ }
+});
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_sync.js b/devtools/client/inspector/components/test/browser_boxmodel_sync.js
new file mode 100644
index 000000000..a896bfe06
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_sync.js
@@ -0,0 +1,44 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test editing box model syncs with the rule view.
+
+const TEST_URI = "<p>hello</p>";
+
+add_task(function* () {
+ yield addTab("data:text/html," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openBoxModelView();
+
+ info("When a property is edited, it should sync in the rule view");
+
+ yield selectNode("p", inspector);
+
+ info("Modify padding-bottom in box model view");
+ let span = view.doc.querySelector(".boxmodel-padding.boxmodel-bottom > span");
+ EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
+ let editor = view.doc.querySelector(".styleinspector-propertyeditor");
+
+ EventUtils.synthesizeKey("7", {}, view.doc.defaultView);
+ yield waitForUpdate(inspector);
+ is(editor.value, "7", "Should have the right value in the editor.");
+ EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
+
+ let onRuleViewRefreshed = once(inspector, "rule-view-refreshed");
+ let onRuleViewSelected = once(inspector.sidebar, "ruleview-selected");
+ info("Select the rule view and check that the property was synced there");
+ let ruleView = selectRuleView(inspector);
+
+ info("Wait for the rule view to be selected");
+ yield onRuleViewSelected;
+
+ info("Wait for the rule view to be refreshed");
+ yield onRuleViewRefreshed;
+ ok(true, "The rule view was refreshed");
+
+ let ruleEditor = getRuleViewRuleEditor(ruleView, 0);
+ let textProp = ruleEditor.rule.textProps[0];
+ is(textProp.value, "7px", "The property has the right value");
+});
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_tooltips.js b/devtools/client/inspector/components/test/browser_boxmodel_tooltips.js
new file mode 100644
index 000000000..b65d2446a
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_tooltips.js
@@ -0,0 +1,126 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the regions in the box model view have tooltips, and that individual
+// values too. Also test that values that are set from a css rule have tooltips
+// referencing the rule.
+
+const TEST_URI = "<style>" +
+ "#div1 { color: red; margin: 3em; }\n" +
+ "#div2 { border-bottom: 1px solid black; background: red; }\n" +
+ "html, body, #div3 { box-sizing: border-box; padding: 0 2em; }" +
+ "</style>" +
+ "<div id='div1'></div><div id='div2'></div><div id='div3'></div>";
+
+// Test data for the tooltips over individual values.
+// Each entry should contain:
+// - selector: The selector for the node to be selected before starting to test
+// - values: An array containing objects for each of the values that are defined
+// by css rules. Each entry should contain:
+// - name: the name of the property that is set by the css rule
+// - ruleSelector: the selector of the rule
+// - styleSheetLocation: the fileName:lineNumber
+const VALUES_TEST_DATA = [{
+ selector: "#div1",
+ values: [{
+ name: "margin-top",
+ ruleSelector: "#div1",
+ styleSheetLocation: "inline:1"
+ }, {
+ name: "margin-right",
+ ruleSelector: "#div1",
+ styleSheetLocation: "inline:1"
+ }, {
+ name: "margin-bottom",
+ ruleSelector: "#div1",
+ styleSheetLocation: "inline:1"
+ }, {
+ name: "margin-left",
+ ruleSelector: "#div1",
+ styleSheetLocation: "inline:1"
+ }]
+}, {
+ selector: "#div2",
+ values: [{
+ name: "border-bottom-width",
+ ruleSelector: "#div2",
+ styleSheetLocation: "inline:2"
+ }]
+}, {
+ selector: "#div3",
+ values: [{
+ name: "padding-top",
+ ruleSelector: "html, body, #div3",
+ styleSheetLocation: "inline:3"
+ }, {
+ name: "padding-right",
+ ruleSelector: "html, body, #div3",
+ styleSheetLocation: "inline:3"
+ }, {
+ name: "padding-bottom",
+ ruleSelector: "html, body, #div3",
+ styleSheetLocation: "inline:3"
+ }, {
+ name: "padding-left",
+ ruleSelector: "html, body, #div3",
+ styleSheetLocation: "inline:3"
+ }]
+}];
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openBoxModelView();
+
+ info("Checking the regions tooltips");
+
+ ok(view.doc.querySelector("#boxmodel-margins").hasAttribute("title"),
+ "The margin region has a tooltip");
+ is(view.doc.querySelector("#boxmodel-margins").getAttribute("title"), "margin",
+ "The margin region has the correct tooltip content");
+
+ ok(view.doc.querySelector("#boxmodel-borders").hasAttribute("title"),
+ "The border region has a tooltip");
+ is(view.doc.querySelector("#boxmodel-borders").getAttribute("title"), "border",
+ "The border region has the correct tooltip content");
+
+ ok(view.doc.querySelector("#boxmodel-padding").hasAttribute("title"),
+ "The padding region has a tooltip");
+ is(view.doc.querySelector("#boxmodel-padding").getAttribute("title"), "padding",
+ "The padding region has the correct tooltip content");
+
+ ok(view.doc.querySelector("#boxmodel-content").hasAttribute("title"),
+ "The content region has a tooltip");
+ is(view.doc.querySelector("#boxmodel-content").getAttribute("title"), "content",
+ "The content region has the correct tooltip content");
+
+ for (let {selector, values} of VALUES_TEST_DATA) {
+ info("Selecting " + selector + " and checking the values tooltips");
+ yield selectNode(selector, inspector);
+
+ info("Iterate over all values");
+ for (let key in view.map) {
+ if (key === "position") {
+ continue;
+ }
+
+ let name = view.map[key].property;
+ let expectedTooltipData = values.find(o => o.name === name);
+ let el = view.doc.querySelector(view.map[key].selector);
+
+ ok(el.hasAttribute("title"), "The " + name + " value has a tooltip");
+
+ if (expectedTooltipData) {
+ info("The " + name + " value comes from a css rule");
+ let expectedTooltip = name + "\n" + expectedTooltipData.ruleSelector +
+ "\n" + expectedTooltipData.styleSheetLocation;
+ is(el.getAttribute("title"), expectedTooltip, "The tooltip is correct");
+ } else {
+ info("The " + name + " isn't set by a css rule");
+ is(el.getAttribute("title"), name, "The tooltip is correct");
+ }
+ }
+ }
+});
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_update-after-navigation.js b/devtools/client/inspector/components/test/browser_boxmodel_update-after-navigation.js
new file mode 100644
index 000000000..cb5960229
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_update-after-navigation.js
@@ -0,0 +1,91 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the box model view continues to work after a page navigation and that
+// it also works after going back
+
+const IFRAME1 = URL_ROOT + "doc_boxmodel_iframe1.html";
+const IFRAME2 = URL_ROOT + "doc_boxmodel_iframe2.html";
+
+add_task(function* () {
+ yield addTab(IFRAME1);
+ let {inspector, view, testActor} = yield openBoxModelView();
+
+ yield testFirstPage(inspector, view, testActor);
+
+ info("Navigate to the second page");
+ yield testActor.eval(`content.location.href="${IFRAME2}"`);
+ yield inspector.once("markuploaded");
+
+ yield testSecondPage(inspector, view, testActor);
+
+ info("Go back to the first page");
+ yield testActor.eval("content.history.back();");
+ yield inspector.once("markuploaded");
+
+ yield testBackToFirstPage(inspector, view, testActor);
+});
+
+function* testFirstPage(inspector, view, testActor) {
+ info("Test that the box model view works on the first page");
+
+ info("Selecting the test node");
+ yield selectNode("p", inspector);
+
+ info("Checking that the box model view shows the right value");
+ let paddingElt = view.doc.querySelector(".boxmodel-padding.boxmodel-top > span");
+ is(paddingElt.textContent, "50");
+
+ info("Listening for box model view changes and modifying the padding");
+ let onUpdated = waitForUpdate(inspector);
+ yield setStyle(testActor, "p", "padding", "20px");
+ yield onUpdated;
+ ok(true, "Box model view got updated");
+
+ info("Checking that the box model view shows the right value after update");
+ is(paddingElt.textContent, "20");
+}
+
+function* testSecondPage(inspector, view, testActor) {
+ info("Test that the box model view works on the second page");
+
+ info("Selecting the test node");
+ yield selectNode("p", inspector);
+
+ info("Checking that the box model view shows the right value");
+ let sizeElt = view.doc.querySelector(".boxmodel-size > span");
+ is(sizeElt.textContent, "100" + "\u00D7" + "100");
+
+ info("Listening for box model view changes and modifying the size");
+ let onUpdated = waitForUpdate(inspector);
+ yield setStyle(testActor, "p", "width", "200px");
+ yield onUpdated;
+ ok(true, "Box model view got updated");
+
+ info("Checking that the box model view shows the right value after update");
+ is(sizeElt.textContent, "200" + "\u00D7" + "100");
+}
+
+function* testBackToFirstPage(inspector, view, testActor) {
+ info("Test that the box model view works on the first page after going back");
+
+ info("Selecting the test node");
+ yield selectNode("p", inspector);
+
+ info("Checking that the box model view shows the right value, which is the" +
+ "modified value from step one because of the bfcache");
+ let paddingElt = view.doc.querySelector(".boxmodel-padding.boxmodel-top > span");
+ is(paddingElt.textContent, "20");
+
+ info("Listening for box model view changes and modifying the padding");
+ let onUpdated = waitForUpdate(inspector);
+ yield setStyle(testActor, "p", "padding", "100px");
+ yield onUpdated;
+ ok(true, "Box model view got updated");
+
+ info("Checking that the box model view shows the right value after update");
+ is(paddingElt.textContent, "100");
+}
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_update-after-reload.js b/devtools/client/inspector/components/test/browser_boxmodel_update-after-reload.js
new file mode 100644
index 000000000..7fc09bfa3
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_update-after-reload.js
@@ -0,0 +1,40 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the box model view continues to work after the page is reloaded
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_boxmodel_iframe1.html");
+ let {inspector, view, testActor} = yield openBoxModelView();
+
+ info("Test that the box model view works on the first page");
+ yield assertBoxModelView(inspector, view, testActor);
+
+ info("Reload the page");
+ yield testActor.reload();
+ yield inspector.once("markuploaded");
+
+ info("Test that the box model view works on the reloaded page");
+ yield assertBoxModelView(inspector, view, testActor);
+});
+
+function* assertBoxModelView(inspector, view, testActor) {
+ info("Selecting the test node");
+ yield selectNode("p", inspector);
+
+ info("Checking that the box model view shows the right value");
+ let paddingElt = view.doc.querySelector(".boxmodel-padding.boxmodel-top > span");
+ is(paddingElt.textContent, "50");
+
+ info("Listening for box model view changes and modifying the padding");
+ let onUpdated = waitForUpdate(inspector);
+ yield setStyle(testActor, "p", "padding", "20px");
+ yield onUpdated;
+ ok(true, "Box model view got updated");
+
+ info("Checking that the box model view shows the right value after update");
+ is(paddingElt.textContent, "20");
+}
diff --git a/devtools/client/inspector/components/test/browser_boxmodel_update-in-iframes.js b/devtools/client/inspector/components/test/browser_boxmodel_update-in-iframes.js
new file mode 100644
index 000000000..50014ad1c
--- /dev/null
+++ b/devtools/client/inspector/components/test/browser_boxmodel_update-in-iframes.js
@@ -0,0 +1,101 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the box model view for elements within iframes also updates when they
+// change
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_boxmodel_iframe1.html");
+ let {inspector, view, testActor} = yield openBoxModelView();
+
+ yield testResizingInIframe(inspector, view, testActor);
+ yield testReflowsAfterIframeDeletion(inspector, view, testActor);
+});
+
+function* testResizingInIframe(inspector, view, testActor) {
+ info("Test that resizing an element in an iframe updates its box model");
+
+ info("Selecting the nested test node");
+ yield selectNodeInIframe2("div", inspector);
+
+ info("Checking that the box model view shows the right value");
+ let sizeElt = view.doc.querySelector(".boxmodel-size > span");
+ is(sizeElt.textContent, "400\u00D7200");
+
+ info("Listening for box model view changes and modifying its size");
+ let onUpdated = waitForUpdate(inspector);
+ yield setStyleInIframe2(testActor, "div", "width", "200px");
+ yield onUpdated;
+ ok(true, "Box model view got updated");
+
+ info("Checking that the box model view shows the right value after update");
+ is(sizeElt.textContent, "200\u00D7200");
+}
+
+function* testReflowsAfterIframeDeletion(inspector, view, testActor) {
+ info("Test reflows are still sent to the box model view after deleting an " +
+ "iframe");
+
+ info("Deleting the iframe2");
+ yield removeIframe2(testActor);
+ yield inspector.once("inspector-updated");
+
+ info("Selecting the test node in iframe1");
+ yield selectNodeInIframe1("p", inspector);
+
+ info("Checking that the box model view shows the right value");
+ let sizeElt = view.doc.querySelector(".boxmodel-size > span");
+ is(sizeElt.textContent, "100\u00D7100");
+
+ info("Listening for box model view changes and modifying its size");
+ let onUpdated = waitForUpdate(inspector);
+ yield setStyleInIframe1(testActor, "p", "width", "200px");
+ yield onUpdated;
+ ok(true, "Box model view got updated");
+
+ info("Checking that the box model view shows the right value after update");
+ is(sizeElt.textContent, "200\u00D7100");
+}
+
+function* selectNodeInIframe1(selector, inspector) {
+ let iframe1 = yield getNodeFront("iframe", inspector);
+ let node = yield getNodeFrontInFrame(selector, iframe1, inspector);
+ yield selectNode(node, inspector);
+}
+
+function* selectNodeInIframe2(selector, inspector) {
+ let iframe1 = yield getNodeFront("iframe", inspector);
+ let iframe2 = yield getNodeFrontInFrame("iframe", iframe1, inspector);
+ let node = yield getNodeFrontInFrame(selector, iframe2, inspector);
+ yield selectNode(node, inspector);
+}
+
+function* setStyleInIframe1(testActor, selector, propertyName, value) {
+ yield testActor.eval(`
+ content.document.querySelector("iframe")
+ .contentDocument.querySelector("${selector}")
+ .style.${propertyName} = "${value}";
+ `);
+}
+
+function* setStyleInIframe2(testActor, selector, propertyName, value) {
+ yield testActor.eval(`
+ content.document.querySelector("iframe")
+ .contentDocument
+ .querySelector("iframe")
+ .contentDocument.querySelector("${selector}")
+ .style.${propertyName} = "${value}";
+ `);
+}
+
+function* removeIframe2(testActor) {
+ yield testActor.eval(`
+ content.document.querySelector("iframe")
+ .contentDocument
+ .querySelector("iframe")
+ .remove();
+ `);
+}
diff --git a/devtools/client/inspector/components/test/doc_boxmodel_iframe1.html b/devtools/client/inspector/components/test/doc_boxmodel_iframe1.html
new file mode 100644
index 000000000..eef48ce07
--- /dev/null
+++ b/devtools/client/inspector/components/test/doc_boxmodel_iframe1.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<p style="padding:50px;color:#f06;">Root page</p>
+<iframe src="doc_boxmodel_iframe2.html"></iframe>
diff --git a/devtools/client/inspector/components/test/doc_boxmodel_iframe2.html b/devtools/client/inspector/components/test/doc_boxmodel_iframe2.html
new file mode 100644
index 000000000..1f1b0463c
--- /dev/null
+++ b/devtools/client/inspector/components/test/doc_boxmodel_iframe2.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<p style="width:100px;height:100px;background:red;">iframe 1</p>
+<iframe src="data:text/html,<div style='width:400px;height:200px;background:yellow;'>iframe 2</div>"></iframe>
diff --git a/devtools/client/inspector/components/test/head.js b/devtools/client/inspector/components/test/head.js
new file mode 100644
index 000000000..fa86b5e9e
--- /dev/null
+++ b/devtools/client/inspector/components/test/head.js
@@ -0,0 +1,87 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+/* eslint no-unused-vars: [2, {"vars": "local"}] */
+/* import-globals-from ../../../framework/test/shared-head.js */
+/* import-globals-from ../../test/head.js */
+"use strict";
+
+// Import the inspector's head.js first (which itself imports shared-head.js).
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
+ this);
+
+Services.prefs.setIntPref("devtools.toolbox.footer.height", 350);
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("devtools.toolbox.footer.height");
+});
+
+/**
+ * Highlight a node and set the inspector's current selection to the node or
+ * the first match of the given css selector.
+ * @param {String|NodeFront} selectorOrNodeFront
+ * The selector for the node to be set, or the nodeFront
+ * @param {InspectorPanel} inspector
+ * The instance of InspectorPanel currently loaded in the toolbox
+ * @return a promise that resolves when the inspector is updated with the new
+ * node
+ */
+function* selectAndHighlightNode(selectorOrNodeFront, inspector) {
+ info("Highlighting and selecting the node " + selectorOrNodeFront);
+
+ let nodeFront = yield getNodeFront(selectorOrNodeFront, inspector);
+ let updated = inspector.toolbox.once("highlighter-ready");
+ inspector.selection.setNodeFront(nodeFront, "test-highlight");
+ yield updated;
+}
+
+/**
+ * Open the toolbox, with the inspector tool visible, and the computed view
+ * sidebar tab selected to display the box model view.
+ * @return a promise that resolves when the inspector is ready and the box model
+ * view is visible and ready
+ */
+function openBoxModelView() {
+ return openInspectorSidebarTab("computedview").then(data => {
+ // The actual highligher show/hide methods are mocked in box model tests.
+ // The highlighter is tested in devtools/inspector/test.
+ function mockHighlighter({highlighter}) {
+ highlighter.showBoxModel = function () {
+ return promise.resolve();
+ };
+ highlighter.hideBoxModel = function () {
+ return promise.resolve();
+ };
+ }
+ mockHighlighter(data.toolbox);
+
+ return {
+ toolbox: data.toolbox,
+ inspector: data.inspector,
+ view: data.inspector.computedview.boxModelView,
+ testActor: data.testActor
+ };
+ });
+}
+
+/**
+ * Wait for the boxmodel-view-updated event.
+ * @return a promise
+ */
+function waitForUpdate(inspector) {
+ return inspector.once("boxmodel-view-updated");
+}
+
+function getStyle(testActor, selector, propertyName) {
+ return testActor.eval(`
+ content.document.querySelector("${selector}")
+ .style.getPropertyValue("${propertyName}");
+ `);
+}
+
+function setStyle(testActor, selector, propertyName, value) {
+ return testActor.eval(`
+ content.document.querySelector("${selector}")
+ .style.${propertyName} = "${value}";
+ `);
+}