summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/computed/test
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /devtools/client/inspector/computed/test
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'devtools/client/inspector/computed/test')
-rw-r--r--devtools/client/inspector/computed/test/.eslintrc.js6
-rw-r--r--devtools/client/inspector/computed/test/browser.ini41
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_browser-styles.js52
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_cycle_color.js71
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_getNodeInfo.js178
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_keybindings_01.js83
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_keybindings_02.js66
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_matched-selectors-toggle.js104
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_matched-selectors_01.js40
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_matched-selectors_02.js41
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_media-queries.js36
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_no-results-placeholder.js70
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_original-source-link.js73
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_pseudo-element_01.js39
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_refresh-on-style-change_01.js30
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_search-filter.js66
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_search-filter_clear.js71
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js84
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_search-filter_escape-keypress.js75
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_search-filter_noproperties.js61
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_select-and-copy-styles.js118
-rw-r--r--devtools/client/inspector/computed/test/browser_computed_style-editor-link.js142
-rw-r--r--devtools/client/inspector/computed/test/doc_matched_selectors.html28
-rw-r--r--devtools/client/inspector/computed/test/doc_media_queries.html21
-rw-r--r--devtools/client/inspector/computed/test/doc_pseudoelement.html131
-rw-r--r--devtools/client/inspector/computed/test/doc_sourcemaps.css7
-rw-r--r--devtools/client/inspector/computed/test/doc_sourcemaps.css.map7
-rw-r--r--devtools/client/inspector/computed/test/doc_sourcemaps.html11
-rw-r--r--devtools/client/inspector/computed/test/doc_sourcemaps.scss10
-rw-r--r--devtools/client/inspector/computed/test/head.js157
30 files changed, 1919 insertions, 0 deletions
diff --git a/devtools/client/inspector/computed/test/.eslintrc.js b/devtools/client/inspector/computed/test/.eslintrc.js
new file mode 100644
index 000000000..698ae9181
--- /dev/null
+++ b/devtools/client/inspector/computed/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/computed/test/browser.ini b/devtools/client/inspector/computed/test/browser.ini
new file mode 100644
index 000000000..33293e1eb
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser.ini
@@ -0,0 +1,41 @@
+[DEFAULT]
+tags = devtools
+subsuite = devtools
+support-files =
+ doc_matched_selectors.html
+ doc_media_queries.html
+ doc_pseudoelement.html
+ doc_sourcemaps.css
+ doc_sourcemaps.css.map
+ doc_sourcemaps.html
+ doc_sourcemaps.scss
+ 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_computed_browser-styles.js]
+[browser_computed_cycle_color.js]
+[browser_computed_getNodeInfo.js]
+[browser_computed_keybindings_01.js]
+[browser_computed_keybindings_02.js]
+[browser_computed_matched-selectors-toggle.js]
+[browser_computed_matched-selectors_01.js]
+[browser_computed_matched-selectors_02.js]
+[browser_computed_media-queries.js]
+[browser_computed_no-results-placeholder.js]
+[browser_computed_original-source-link.js]
+[browser_computed_pseudo-element_01.js]
+[browser_computed_refresh-on-style-change_01.js]
+[browser_computed_search-filter.js]
+[browser_computed_search-filter_clear.js]
+[browser_computed_search-filter_context-menu.js]
+subsuite = clipboard
+[browser_computed_search-filter_escape-keypress.js]
+[browser_computed_search-filter_noproperties.js]
+[browser_computed_select-and-copy-styles.js]
+subsuite = clipboard
+[browser_computed_style-editor-link.js]
diff --git a/devtools/client/inspector/computed/test/browser_computed_browser-styles.js b/devtools/client/inspector/computed/test/browser_computed_browser-styles.js
new file mode 100644
index 000000000..32de63650
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_browser-styles.js
@@ -0,0 +1,52 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the checkbox to include browser styles works properly.
+
+const TEST_URI = `
+ <style type="text/css">
+ .matches {
+ color: #F00;
+ }
+ </style>
+ <span id="matches" class="matches">Some styled text</span>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("#matches", inspector);
+
+ info("Checking the default styles");
+ is(isPropertyVisible("color", view), true,
+ "span #matches color property is visible");
+ is(isPropertyVisible("background-color", view), false,
+ "span #matches background-color property is hidden");
+
+ info("Toggling the browser styles");
+ let doc = view.styleDocument;
+ let checkbox = doc.querySelector(".includebrowserstyles");
+ let onRefreshed = inspector.once("computed-view-refreshed");
+ checkbox.click();
+ yield onRefreshed;
+
+ info("Checking the browser styles");
+ is(isPropertyVisible("color", view), true,
+ "span color property is visible");
+ is(isPropertyVisible("background-color", view), true,
+ "span background-color property is visible");
+});
+
+function isPropertyVisible(name, view) {
+ info("Checking property visibility for " + name);
+ let propertyViews = view.propertyViews;
+ for (let propView of propertyViews) {
+ if (propView.name == name) {
+ return propView.visible;
+ }
+ }
+ return false;
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_cycle_color.js b/devtools/client/inspector/computed/test/browser_computed_cycle_color.js
new file mode 100644
index 000000000..c9892fafe
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_cycle_color.js
@@ -0,0 +1,71 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Computed view color cycling test.
+
+const TEST_URI = `
+ <style type="text/css">
+ .matches {
+ color: #f00;
+ }
+ </style>
+ <span id="matches" class="matches">Some styled text</span>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("#matches", inspector);
+
+ info("Checking the property itself");
+ let container = getComputedViewPropertyView(view, "color").valueNode;
+ checkColorCycling(container, view);
+
+ info("Checking matched selectors");
+ container = yield getComputedViewMatchedRules(view, "color");
+ yield checkColorCycling(container, view);
+});
+
+function* checkColorCycling(container, view) {
+ let valueNode = container.querySelector(".computedview-color");
+ let win = view.styleWindow;
+
+ // "Authored" (default; currently the computed value)
+ is(valueNode.textContent, "rgb(255, 0, 0)",
+ "Color displayed as an RGB value.");
+
+ let tests = [{
+ value: "red",
+ comment: "Color displayed as a color name."
+ }, {
+ value: "#f00",
+ comment: "Color displayed as an authored value."
+ }, {
+ value: "hsl(0, 100%, 50%)",
+ comment: "Color displayed as an HSL value again."
+ }, {
+ value: "rgb(255, 0, 0)",
+ comment: "Color displayed as an RGB value again."
+ }];
+
+ for (let test of tests) {
+ yield checkSwatchShiftClick(container, win, test.value, test.comment);
+ }
+}
+
+function* checkSwatchShiftClick(container, win, expectedValue, comment) {
+ let swatch = container.querySelector(".computedview-colorswatch");
+ let valueNode = container.querySelector(".computedview-color");
+ swatch.scrollIntoView();
+
+ let onUnitChange = swatch.once("unit-change");
+ EventUtils.synthesizeMouseAtCenter(swatch, {
+ type: "mousedown",
+ shiftKey: true
+ }, win);
+ yield onUnitChange;
+ is(valueNode.textContent, expectedValue, comment);
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_getNodeInfo.js b/devtools/client/inspector/computed/test/browser_computed_getNodeInfo.js
new file mode 100644
index 000000000..30113e7ec
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_getNodeInfo.js
@@ -0,0 +1,178 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests various output of the computed-view's getNodeInfo method.
+// This method is used by the HighlightersOverlay and TooltipsOverlay on mouseover to
+// decide which highlighter or tooltip to show when hovering over a value/name/selector
+// if any.
+//
+// For instance, browser_ruleview_selector-highlighter_01.js and
+// browser_ruleview_selector-highlighter_02.js test that the selector
+// highlighter appear when hovering over a selector in the rule-view.
+// Since the code to make this work for the computed-view is 90% the same,
+// there is no need for testing it again here.
+// This test however serves as a unit test for getNodeInfo.
+
+const {
+ VIEW_NODE_SELECTOR_TYPE,
+ VIEW_NODE_PROPERTY_TYPE,
+ VIEW_NODE_VALUE_TYPE,
+ VIEW_NODE_IMAGE_URL_TYPE
+} = require("devtools/client/inspector/shared/node-types");
+
+const TEST_URI = `
+ <style type="text/css">
+ body {
+ background: red;
+ color: white;
+ }
+ div {
+ background: green;
+ }
+ div div {
+ background-color: yellow;
+ background-image: url(chrome://global/skin/icons/warning-64.png);
+ color: red;
+ }
+ </style>
+ <div><div id="testElement">Test element</div></div>
+`;
+
+// Each item in this array must have the following properties:
+// - desc {String} will be logged for information
+// - getHoveredNode {Generator Function} received the computed-view instance as
+// argument and must return the node to be tested
+// - assertNodeInfo {Function} should check the validity of the nodeInfo
+// argument it receives
+const TEST_DATA = [
+ {
+ desc: "Testing a null node",
+ getHoveredNode: function* () {
+ return null;
+ },
+ assertNodeInfo: function (nodeInfo) {
+ is(nodeInfo, null);
+ }
+ },
+ {
+ desc: "Testing a useless node",
+ getHoveredNode: function* (view) {
+ return view.element;
+ },
+ assertNodeInfo: function (nodeInfo) {
+ is(nodeInfo, null);
+ }
+ },
+ {
+ desc: "Testing a property name",
+ getHoveredNode: function* (view) {
+ return getComputedViewProperty(view, "color").nameSpan;
+ },
+ assertNodeInfo: function (nodeInfo) {
+ is(nodeInfo.type, VIEW_NODE_PROPERTY_TYPE);
+ ok("property" in nodeInfo.value);
+ ok("value" in nodeInfo.value);
+ is(nodeInfo.value.property, "color");
+ is(nodeInfo.value.value, "rgb(255, 0, 0)");
+ }
+ },
+ {
+ desc: "Testing a property value",
+ getHoveredNode: function* (view) {
+ return getComputedViewProperty(view, "color").valueSpan;
+ },
+ assertNodeInfo: function (nodeInfo) {
+ is(nodeInfo.type, VIEW_NODE_VALUE_TYPE);
+ ok("property" in nodeInfo.value);
+ ok("value" in nodeInfo.value);
+ is(nodeInfo.value.property, "color");
+ is(nodeInfo.value.value, "rgb(255, 0, 0)");
+ }
+ },
+ {
+ desc: "Testing an image url",
+ getHoveredNode: function* (view) {
+ let {valueSpan} = getComputedViewProperty(view, "background-image");
+ return valueSpan.querySelector(".theme-link");
+ },
+ assertNodeInfo: function (nodeInfo) {
+ is(nodeInfo.type, VIEW_NODE_IMAGE_URL_TYPE);
+ ok("property" in nodeInfo.value);
+ ok("value" in nodeInfo.value);
+ is(nodeInfo.value.property, "background-image");
+ is(nodeInfo.value.value,
+ "url(\"chrome://global/skin/icons/warning-64.png\")");
+ is(nodeInfo.value.url, "chrome://global/skin/icons/warning-64.png");
+ }
+ },
+ {
+ desc: "Testing a matched rule selector (bestmatch)",
+ getHoveredNode: function* (view) {
+ let el = yield getComputedViewMatchedRules(view, "background-color");
+ return el.querySelector(".bestmatch");
+ },
+ assertNodeInfo: function (nodeInfo) {
+ is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
+ is(nodeInfo.value, "div div");
+ }
+ },
+ {
+ desc: "Testing a matched rule selector (matched)",
+ getHoveredNode: function* (view) {
+ let el = yield getComputedViewMatchedRules(view, "background-color");
+ return el.querySelector(".matched");
+ },
+ assertNodeInfo: function (nodeInfo) {
+ is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
+ is(nodeInfo.value, "div");
+ }
+ },
+ {
+ desc: "Testing a matched rule selector (parentmatch)",
+ getHoveredNode: function* (view) {
+ let el = yield getComputedViewMatchedRules(view, "color");
+ return el.querySelector(".parentmatch");
+ },
+ assertNodeInfo: function (nodeInfo) {
+ is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
+ is(nodeInfo.value, "body");
+ }
+ },
+ {
+ desc: "Testing a matched rule value",
+ getHoveredNode: function* (view) {
+ let el = yield getComputedViewMatchedRules(view, "color");
+ return el.querySelector(".other-property-value");
+ },
+ assertNodeInfo: function (nodeInfo) {
+ is(nodeInfo.type, VIEW_NODE_VALUE_TYPE);
+ is(nodeInfo.value.property, "color");
+ is(nodeInfo.value.value, "red");
+ }
+ },
+ {
+ desc: "Testing a matched rule stylesheet link",
+ getHoveredNode: function* (view) {
+ let el = yield getComputedViewMatchedRules(view, "color");
+ return el.querySelector(".rule-link .theme-link");
+ },
+ assertNodeInfo: function (nodeInfo) {
+ is(nodeInfo, null);
+ }
+ }
+];
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("#testElement", inspector);
+
+ for (let {desc, getHoveredNode, assertNodeInfo} of TEST_DATA) {
+ info(desc);
+ let nodeInfo = view.getNodeInfo(yield getHoveredNode(view));
+ assertNodeInfo(nodeInfo);
+ }
+});
diff --git a/devtools/client/inspector/computed/test/browser_computed_keybindings_01.js b/devtools/client/inspector/computed/test/browser_computed_keybindings_01.js
new file mode 100644
index 000000000..199e125af
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_keybindings_01.js
@@ -0,0 +1,83 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests computed view key bindings.
+
+const TEST_URI = `
+ <style type="text/css">
+ .matches {
+ color: #F00;
+ }
+ </style>
+ <span class="matches">Some styled text</span>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ yield selectNode(".matches", inspector);
+
+ let propView = getFirstVisiblePropertyView(view);
+ let rulesTable = propView.matchedSelectorsContainer;
+ let matchedExpander = propView.element;
+
+ info("Focusing the property");
+ matchedExpander.scrollIntoView();
+ let onMatchedExpanderFocus = once(matchedExpander, "focus", true);
+ EventUtils.synthesizeMouseAtCenter(matchedExpander, {}, view.styleWindow);
+ yield onMatchedExpanderFocus;
+
+ yield checkToggleKeyBinding(view.styleWindow, "VK_SPACE", rulesTable,
+ inspector);
+ yield checkToggleKeyBinding(view.styleWindow, "VK_RETURN", rulesTable,
+ inspector);
+ yield checkHelpLinkKeybinding(view);
+});
+
+function getFirstVisiblePropertyView(view) {
+ let propView = null;
+ view.propertyViews.some(p => {
+ if (p.visible) {
+ propView = p;
+ return true;
+ }
+ return false;
+ });
+
+ return propView;
+}
+
+function* checkToggleKeyBinding(win, key, rulesTable, inspector) {
+ info("Pressing " + key + " key a couple of times to check that the " +
+ "property gets expanded/collapsed");
+
+ let onExpand = inspector.once("computed-view-property-expanded");
+ let onCollapse = inspector.once("computed-view-property-collapsed");
+
+ info("Expanding the property");
+ EventUtils.synthesizeKey(key, {}, win);
+ yield onExpand;
+ isnot(rulesTable.innerHTML, "", "The property has been expanded");
+
+ info("Collapsing the property");
+ EventUtils.synthesizeKey(key, {}, win);
+ yield onCollapse;
+ is(rulesTable.innerHTML, "", "The property has been collapsed");
+}
+
+function checkHelpLinkKeybinding(view) {
+ info("Check that MDN link is opened on \"F1\"");
+ let def = defer();
+
+ let propView = getFirstVisiblePropertyView(view);
+ propView.mdnLinkClick = function (event) {
+ ok(true, "Pressing F1 opened the MDN link");
+ def.resolve();
+ };
+
+ EventUtils.synthesizeKey("VK_F1", {}, view.styleWindow);
+ return def.promise;
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_keybindings_02.js b/devtools/client/inspector/computed/test/browser_computed_keybindings_02.js
new file mode 100644
index 000000000..2a9220ec8
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_keybindings_02.js
@@ -0,0 +1,66 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests the computed-view keyboard navigation.
+
+const TEST_URI = `
+ <style type="text/css">
+ span {
+ font-variant: small-caps;
+ color: #000000;
+ }
+ .nomatches {
+ color: #ff0000;
+ }
+ </style>
+ <div id="first" style="margin: 10em;
+ font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA">
+ <h1>Some header text</h1>
+ <p id="salutation" style="font-size: 12pt">hi.</p>
+ <p id="body" style="font-size: 12pt">I am a test-case. This text exists
+ solely to provide some things to <span style="color: yellow">
+ highlight</span> and <span style="font-weight: bold">count</span>
+ style list-items in the box at right. If you are reading this,
+ you should go do something else instead. Maybe read a book. Or better
+ yet, write some test-cases for another bit of code.
+ <span style="font-style: italic">some text</span></p>
+ <p id="closing">more text</p>
+ <p>even more text</p>
+ </div>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("span", inspector);
+
+ info("Selecting the first computed style in the list");
+ let firstStyle = view.styleDocument.querySelector(".property-view");
+ ok(firstStyle, "First computed style found in panel");
+ firstStyle.focus();
+
+ info("Tab to select the 2nd style and press return");
+ let onExpanded = inspector.once("computed-view-property-expanded");
+ EventUtils.synthesizeKey("VK_TAB", {});
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ yield onExpanded;
+
+ info("Verify the 2nd style has been expanded");
+ let secondStyleSelectors = view.styleDocument.querySelectorAll(
+ ".property-content .matchedselectors")[1];
+ ok(secondStyleSelectors.childNodes.length > 0, "Matched selectors expanded");
+
+ info("Tab back up and test the same thing, with space");
+ onExpanded = inspector.once("computed-view-property-expanded");
+ EventUtils.synthesizeKey("VK_TAB", {shiftKey: true});
+ EventUtils.synthesizeKey("VK_SPACE", {});
+ yield onExpanded;
+
+ info("Verify the 1st style has been expanded too");
+ let firstStyleSelectors = view.styleDocument.querySelectorAll(
+ ".property-content .matchedselectors")[0];
+ ok(firstStyleSelectors.childNodes.length > 0, "Matched selectors expanded");
+});
diff --git a/devtools/client/inspector/computed/test/browser_computed_matched-selectors-toggle.js b/devtools/client/inspector/computed/test/browser_computed_matched-selectors-toggle.js
new file mode 100644
index 000000000..abbbb77be
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_matched-selectors-toggle.js
@@ -0,0 +1,104 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the computed view properties can be expanded and collapsed with
+// either the twisty or by dbl-clicking on the container.
+
+const TEST_URI = `
+ <style type="text/css"> ,
+ html { color: #000000; font-size: 15pt; }
+ h1 { color: red; }
+ </style>
+ <h1>Some header text</h1>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("h1", inspector);
+
+ yield testExpandOnTwistyClick(view, inspector);
+ yield testCollapseOnTwistyClick(view, inspector);
+ yield testExpandOnDblClick(view, inspector);
+ yield testCollapseOnDblClick(view, inspector);
+});
+
+function* testExpandOnTwistyClick({styleDocument, styleWindow}, inspector) {
+ info("Testing that a property expands on twisty click");
+
+ info("Getting twisty element");
+ let twisty = styleDocument.querySelector("#propertyContainer .expandable");
+ ok(twisty, "Twisty found");
+
+ let onExpand = inspector.once("computed-view-property-expanded");
+ info("Clicking on the twisty element");
+ twisty.click();
+
+ yield onExpand;
+
+ // Expanded means the matchedselectors div is not empty
+ let div = styleDocument.querySelector(".property-content .matchedselectors");
+ ok(div.childNodes.length > 0,
+ "Matched selectors are expanded on twisty click");
+}
+
+function* testCollapseOnTwistyClick({styleDocument, styleWindow}, inspector) {
+ info("Testing that a property collapses on twisty click");
+
+ info("Getting twisty element");
+ let twisty = styleDocument.querySelector("#propertyContainer .expandable");
+ ok(twisty, "Twisty found");
+
+ let onCollapse = inspector.once("computed-view-property-collapsed");
+ info("Clicking on the twisty element");
+ twisty.click();
+
+ yield onCollapse;
+
+ // Collapsed means the matchedselectors div is empty
+ let div = styleDocument.querySelector(".property-content .matchedselectors");
+ ok(div.childNodes.length === 0,
+ "Matched selectors are collapsed on twisty click");
+}
+
+function* testExpandOnDblClick({styleDocument, styleWindow}, inspector) {
+ info("Testing that a property expands on container dbl-click");
+
+ info("Getting computed property container");
+ let container = styleDocument.querySelector(".property-view");
+ ok(container, "Container found");
+
+ container.scrollIntoView();
+
+ let onExpand = inspector.once("computed-view-property-expanded");
+ info("Dbl-clicking on the container");
+ EventUtils.synthesizeMouseAtCenter(container, {clickCount: 2}, styleWindow);
+
+ yield onExpand;
+
+ // Expanded means the matchedselectors div is not empty
+ let div = styleDocument.querySelector(".property-content .matchedselectors");
+ ok(div.childNodes.length > 0, "Matched selectors are expanded on dblclick");
+}
+
+function* testCollapseOnDblClick({styleDocument, styleWindow}, inspector) {
+ info("Testing that a property collapses on container dbl-click");
+
+ info("Getting computed property container");
+ let container = styleDocument.querySelector(".property-view");
+ ok(container, "Container found");
+
+ let onCollapse = inspector.once("computed-view-property-collapsed");
+ info("Dbl-clicking on the container");
+ EventUtils.synthesizeMouseAtCenter(container, {clickCount: 2}, styleWindow);
+
+ yield onCollapse;
+
+ // Collapsed means the matchedselectors div is empty
+ let div = styleDocument.querySelector(".property-content .matchedselectors");
+ ok(div.childNodes.length === 0,
+ "Matched selectors are collapsed on dblclick");
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_matched-selectors_01.js b/devtools/client/inspector/computed/test/browser_computed_matched-selectors_01.js
new file mode 100644
index 000000000..66cabe7a9
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_matched-selectors_01.js
@@ -0,0 +1,40 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Checking selector counts, matched rules and titles in the computed-view.
+
+const {PropertyView} =
+ require("devtools/client/inspector/computed/computed");
+const TEST_URI = URL_ROOT + "doc_matched_selectors.html";
+
+add_task(function* () {
+ yield addTab(TEST_URI);
+ let {inspector, view} = yield openComputedView();
+
+ yield selectNode("#test", inspector);
+ yield testMatchedSelectors(view, inspector);
+});
+
+function* testMatchedSelectors(view, inspector) {
+ info("checking selector counts, matched rules and titles");
+
+ let nodeFront = yield getNodeFront("#test", inspector);
+ is(nodeFront, view._viewedElement,
+ "style inspector node matches the selected node");
+
+ let propertyView = new PropertyView(view, "color");
+ propertyView.buildMain();
+ propertyView.buildSelectorContainer();
+ propertyView.matchedExpanded = true;
+
+ yield propertyView.refreshMatchedSelectors();
+
+ let numMatchedSelectors = propertyView.matchedSelectors.length;
+ is(numMatchedSelectors, 6,
+ "CssLogic returns the correct number of matched selectors for div");
+ is(propertyView.hasMatchedSelectors, true,
+ "hasMatchedSelectors returns true");
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_matched-selectors_02.js b/devtools/client/inspector/computed/test/browser_computed_matched-selectors_02.js
new file mode 100644
index 000000000..43172d55f
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_matched-selectors_02.js
@@ -0,0 +1,41 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests for matched selector texts in the computed view.
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8,<div style='color:blue;'></div>");
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("div", inspector);
+
+ info("Checking the color property view");
+ let propertyView = getPropertyView(view, "color");
+ ok(propertyView, "found PropertyView for color");
+ is(propertyView.hasMatchedSelectors, true, "hasMatchedSelectors is true");
+
+ info("Expanding the matched selectors");
+ propertyView.matchedExpanded = true;
+ yield propertyView.refreshMatchedSelectors();
+
+ let span = propertyView.matchedSelectorsContainer
+ .querySelector("span.rule-text");
+ ok(span, "Found the first table row");
+
+ let selector = propertyView.matchedSelectorViews[0];
+ ok(selector, "Found the first matched selector view");
+});
+
+function getPropertyView(computedView, name) {
+ let propertyView = null;
+ computedView.propertyViews.some(function (view) {
+ if (view.name == name) {
+ propertyView = view;
+ return true;
+ }
+ return false;
+ });
+ return propertyView;
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_media-queries.js b/devtools/client/inspector/computed/test/browser_computed_media-queries.js
new file mode 100644
index 000000000..79cccb49b
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_media-queries.js
@@ -0,0 +1,36 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that we correctly display appropriate media query titles in the
+// property view.
+
+const TEST_URI = URL_ROOT + "doc_media_queries.html";
+
+var {PropertyView} = require("devtools/client/inspector/computed/computed");
+
+add_task(function* () {
+ yield addTab(TEST_URI);
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("div", inspector);
+ yield checkPropertyView(view);
+});
+
+function checkPropertyView(view) {
+ let propertyView = new PropertyView(view, "width");
+ propertyView.buildMain();
+ propertyView.buildSelectorContainer();
+ propertyView.matchedExpanded = true;
+
+ return propertyView.refreshMatchedSelectors().then(() => {
+ let numMatchedSelectors = propertyView.matchedSelectors.length;
+
+ is(numMatchedSelectors, 2,
+ "Property view has the correct number of matched selectors for div");
+
+ is(propertyView.hasMatchedSelectors, true,
+ "hasMatchedSelectors returns true");
+ });
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_no-results-placeholder.js b/devtools/client/inspector/computed/test/browser_computed_no-results-placeholder.js
new file mode 100644
index 000000000..b1371abd7
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_no-results-placeholder.js
@@ -0,0 +1,70 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the no results placeholder works properly.
+
+const TEST_URI = `
+ <style type="text/css">
+ .matches {
+ color: #F00;
+ }
+ </style>
+ <span id="matches" class="matches">Some styled text</span>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("#matches", inspector);
+
+ yield enterInvalidFilter(inspector, view);
+ checkNoResultsPlaceholderShown(view);
+
+ yield clearFilterText(inspector, view);
+ checkNoResultsPlaceholderHidden(view);
+});
+
+function* enterInvalidFilter(inspector, computedView) {
+ let searchbar = computedView.searchField;
+ let searchTerm = "xxxxx";
+
+ info("setting filter text to \"" + searchTerm + "\"");
+
+ let onRefreshed = inspector.once("computed-view-refreshed");
+ searchbar.focus();
+ synthesizeKeys(searchTerm, computedView.styleWindow);
+ yield onRefreshed;
+}
+
+function checkNoResultsPlaceholderShown(computedView) {
+ info("Checking that the no results placeholder is shown");
+
+ let placeholder = computedView.noResults;
+ let win = computedView.styleWindow;
+ let display = win.getComputedStyle(placeholder).display;
+ is(display, "block", "placeholder is visible");
+}
+
+function* clearFilterText(inspector, computedView) {
+ info("Clearing the filter text");
+
+ let searchbar = computedView.searchField;
+
+ let onRefreshed = inspector.once("computed-view-refreshed");
+ searchbar.focus();
+ searchbar.value = "";
+ EventUtils.synthesizeKey("c", {}, computedView.styleWindow);
+ yield onRefreshed;
+}
+
+function checkNoResultsPlaceholderHidden(computedView) {
+ info("Checking that the no results placeholder is hidden");
+
+ let placeholder = computedView.noResults;
+ let win = computedView.styleWindow;
+ let display = win.getComputedStyle(placeholder).display;
+ is(display, "none", "placeholder is hidden");
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_original-source-link.js b/devtools/client/inspector/computed/test/browser_computed_original-source-link.js
new file mode 100644
index 000000000..1bceed4e3
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_original-source-link.js
@@ -0,0 +1,73 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the computed view shows the original source link when source maps
+// are enabled.
+
+const TESTCASE_URI = URL_ROOT_SSL + "doc_sourcemaps.html";
+const PREF = "devtools.styleeditor.source-maps-enabled";
+const SCSS_LOC = "doc_sourcemaps.scss:4";
+const CSS_LOC = "doc_sourcemaps.css:1";
+
+add_task(function* () {
+ info("Turning the pref " + PREF + " on");
+ Services.prefs.setBoolPref(PREF, true);
+
+ yield addTab(TESTCASE_URI);
+ let {toolbox, inspector, view} = yield openComputedView();
+ yield selectNode("div", inspector);
+
+ info("Expanding the first property");
+ yield expandComputedViewPropertyByIndex(view, 0);
+
+ info("Verifying the link text");
+ // Forcing a call to updateSourceLink on the SelectorView here. The
+ // computed-view already does it, but we have no way of waiting for it to be
+ // done here, so just call it again and wait for the returned promise to
+ // resolve.
+ let propertyView = getComputedViewPropertyView(view, "color");
+ yield propertyView.matchedSelectorViews[0].updateSourceLink();
+ verifyLinkText(view, SCSS_LOC);
+
+ info("Toggling the pref");
+ let onLinksUpdated = inspector.once("computed-view-sourcelinks-updated");
+ Services.prefs.setBoolPref(PREF, false);
+ yield onLinksUpdated;
+
+ info("Verifying that the link text has changed after the pref change");
+ yield verifyLinkText(view, CSS_LOC);
+
+ info("Toggling the pref again");
+ onLinksUpdated = inspector.once("computed-view-sourcelinks-updated");
+ Services.prefs.setBoolPref(PREF, true);
+ yield onLinksUpdated;
+
+ info("Testing that clicking on the link works");
+ yield testClickingLink(toolbox, view);
+
+ info("Turning the pref " + PREF + " off");
+ Services.prefs.clearUserPref(PREF);
+});
+
+function* testClickingLink(toolbox, view) {
+ let onEditor = waitForStyleEditor(toolbox, "doc_sourcemaps.scss");
+
+ info("Clicking the computedview stylesheet link");
+ let link = getComputedViewLinkByIndex(view, 0);
+ link.scrollIntoView();
+ link.click();
+
+ let editor = yield onEditor;
+
+ let {line} = editor.sourceEditor.getCursor();
+ is(line, 3, "cursor is at correct line number in original source");
+}
+
+function verifyLinkText(view, text) {
+ let link = getComputedViewLinkByIndex(view, 0);
+ is(link.textContent, text,
+ "Linked text changed to display the correct location");
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_pseudo-element_01.js b/devtools/client/inspector/computed/test/browser_computed_pseudo-element_01.js
new file mode 100644
index 000000000..9ca5451a5
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_pseudo-element_01.js
@@ -0,0 +1,39 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that pseudoelements are displayed correctly in the rule view.
+
+const TEST_URI = URL_ROOT + "doc_pseudoelement.html";
+
+add_task(function* () {
+ yield addTab(TEST_URI);
+ let {inspector, view} = yield openComputedView();
+ yield testTopLeft(inspector, view);
+});
+
+function* testTopLeft(inspector, view) {
+ let node = yield getNodeFront("#topleft", inspector.markup);
+ yield selectNode(node, inspector);
+ let float = getComputedViewPropertyValue(view, "float");
+ is(float, "left", "The computed view shows the correct float");
+
+ let children = yield inspector.markup.walker.children(node);
+ is(children.nodes.length, 3, "Element has correct number of children");
+
+ let beforeElement = children.nodes[0];
+ yield selectNode(beforeElement, inspector);
+ let top = getComputedViewPropertyValue(view, "top");
+ is(top, "0px", "The computed view shows the correct top");
+ let left = getComputedViewPropertyValue(view, "left");
+ is(left, "0px", "The computed view shows the correct left");
+
+ let afterElement = children.nodes[children.nodes.length - 1];
+ yield selectNode(afterElement, inspector);
+ top = getComputedViewPropertyValue(view, "top");
+ is(top, "50%", "The computed view shows the correct top");
+ left = getComputedViewPropertyValue(view, "left");
+ is(left, "50%", "The computed view shows the correct left");
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_refresh-on-style-change_01.js b/devtools/client/inspector/computed/test/browser_computed_refresh-on-style-change_01.js
new file mode 100644
index 000000000..43f210307
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_refresh-on-style-change_01.js
@@ -0,0 +1,30 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the computed view refreshes when the current node has its style
+// changed.
+
+const TEST_URI = "<div id='testdiv' style='font-size:10px;'>Test div!</div>";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view, testActor} = yield openComputedView();
+ yield selectNode("#testdiv", inspector);
+
+ let fontSize = getComputedViewPropertyValue(view, "font-size");
+ is(fontSize, "10px", "The computed view shows the right font-size");
+
+ info("Changing the node's style and waiting for the update");
+ let onUpdated = inspector.once("computed-view-refreshed");
+ yield testActor.setAttribute("#testdiv", "style",
+ "font-size: 15px; color: red;");
+ yield onUpdated;
+
+ fontSize = getComputedViewPropertyValue(view, "font-size");
+ is(fontSize, "15px", "The computed view shows the updated font-size");
+ let color = getComputedViewPropertyValue(view, "color");
+ is(color, "rgb(255, 0, 0)", "The computed view also shows the color now");
+});
diff --git a/devtools/client/inspector/computed/test/browser_computed_search-filter.js b/devtools/client/inspector/computed/test/browser_computed_search-filter.js
new file mode 100644
index 000000000..10ba82293
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_search-filter.js
@@ -0,0 +1,66 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the search filter works properly.
+
+const TEST_URI = `
+ <style type="text/css">
+ .matches {
+ color: #F00;
+ }
+ </style>
+ <span id="matches" class="matches">Some styled text</span>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("#matches", inspector);
+ yield testToggleDefaultStyles(inspector, view);
+ yield testAddTextInFilter(inspector, view);
+});
+
+function* testToggleDefaultStyles(inspector, computedView) {
+ info("checking \"Browser styles\" checkbox");
+ let checkbox = computedView.includeBrowserStylesCheckbox;
+ let onRefreshed = inspector.once("computed-view-refreshed");
+ checkbox.click();
+ yield onRefreshed;
+}
+
+function* testAddTextInFilter(inspector, computedView) {
+ info("setting filter text to \"color\"");
+ let doc = computedView.styleDocument;
+ let boxModelWrapper = doc.querySelector("#boxmodel-wrapper");
+ let searchField = computedView.searchField;
+ let onRefreshed = inspector.once("computed-view-refreshed");
+ let win = computedView.styleWindow;
+
+ // First check to make sure that accel + F doesn't focus search if the
+ // container isn't focused
+ inspector.panelWin.focus();
+ EventUtils.synthesizeKey("f", { accelKey: true });
+ isnot(inspector.panelDoc.activeElement, searchField,
+ "Search field isn't focused");
+
+ computedView.element.focus();
+ EventUtils.synthesizeKey("f", { accelKey: true });
+ is(inspector.panelDoc.activeElement, searchField, "Search field is focused");
+
+ synthesizeKeys("color", win);
+ yield onRefreshed;
+
+ ok(boxModelWrapper.hidden, "Box model is hidden");
+
+ info("check that the correct properties are visible");
+
+ let propertyViews = computedView.propertyViews;
+ propertyViews.forEach(propView => {
+ let name = propView.name;
+ is(propView.visible, name.indexOf("color") > -1,
+ "span " + name + " property visibility check");
+ });
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_search-filter_clear.js b/devtools/client/inspector/computed/test/browser_computed_search-filter_clear.js
new file mode 100644
index 000000000..bd989854f
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_search-filter_clear.js
@@ -0,0 +1,71 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the search filter clear button works properly.
+
+const TEST_URI = `
+ <style type="text/css">
+ .matches {
+ color: #F00;
+ background-color: #00F;
+ border-color: #0F0;
+ }
+ </style>
+ <span id="matches" class="matches">Some styled text</span>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("#matches", inspector);
+ yield testAddTextInFilter(inspector, view);
+ yield testClearSearchFilter(inspector, view);
+});
+
+function* testAddTextInFilter(inspector, computedView) {
+ info("Setting filter text to \"background-color\"");
+
+ let win = computedView.styleWindow;
+ let propertyViews = computedView.propertyViews;
+ let searchField = computedView.searchField;
+
+ searchField.focus();
+ synthesizeKeys("background-color", win);
+ yield inspector.once("computed-view-refreshed");
+
+ info("Check that the correct properties are visible");
+
+ propertyViews.forEach((propView) => {
+ let name = propView.name;
+ is(propView.visible, name.indexOf("background-color") > -1,
+ "span " + name + " property visibility check");
+ });
+}
+
+function* testClearSearchFilter(inspector, computedView) {
+ info("Clearing the search filter");
+
+ let win = computedView.styleWindow;
+ let doc = computedView.styleDocument;
+ let boxModelWrapper = doc.querySelector("#boxmodel-wrapper");
+ let propertyViews = computedView.propertyViews;
+ let searchField = computedView.searchField;
+ let searchClearButton = computedView.searchClearButton;
+ let onRefreshed = inspector.once("computed-view-refreshed");
+
+ EventUtils.synthesizeMouseAtCenter(searchClearButton, {}, win);
+ yield onRefreshed;
+
+ ok(!boxModelWrapper.hidden, "Box model is displayed");
+
+ info("Check that the correct properties are visible");
+
+ ok(!searchField.value, "Search filter is cleared");
+ propertyViews.forEach((propView) => {
+ is(propView.visible, propView.hasMatchedSelectors,
+ "span " + propView.name + " property visibility check");
+ });
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js b/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js
new file mode 100644
index 000000000..b5dbe4475
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js
@@ -0,0 +1,84 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests computed view search filter context menu works properly.
+
+const TEST_INPUT = "h1";
+
+const TEST_URI = "<h1>test filter context menu</h1>";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {toolbox, inspector, view} = yield openComputedView();
+ yield selectNode("h1", inspector);
+
+ let win = view.styleWindow;
+ let searchField = view.searchField;
+ let searchContextMenu = toolbox.textBoxContextMenuPopup;
+ ok(searchContextMenu,
+ "The search filter context menu is loaded in the computed view");
+
+ let cmdUndo = searchContextMenu.querySelector("[command=cmd_undo]");
+ let cmdDelete = searchContextMenu.querySelector("[command=cmd_delete]");
+ let cmdSelectAll = searchContextMenu.querySelector("[command=cmd_selectAll]");
+ let cmdCut = searchContextMenu.querySelector("[command=cmd_cut]");
+ let cmdCopy = searchContextMenu.querySelector("[command=cmd_copy]");
+ let cmdPaste = searchContextMenu.querySelector("[command=cmd_paste]");
+
+ info("Opening context menu");
+
+ emptyClipboard();
+
+ let onFocus = once(searchField, "focus");
+ searchField.focus();
+ yield onFocus;
+
+ let onContextMenuPopup = once(searchContextMenu, "popupshowing");
+ EventUtils.synthesizeMouse(searchField, 2, 2,
+ {type: "contextmenu", button: 2}, win);
+ yield onContextMenuPopup;
+
+ is(cmdUndo.getAttribute("disabled"), "true", "cmdUndo is disabled");
+ is(cmdDelete.getAttribute("disabled"), "true", "cmdDelete is disabled");
+ is(cmdSelectAll.getAttribute("disabled"), "true", "cmdSelectAll is disabled");
+
+ // Cut/Copy items are enabled in context menu even if there
+ // is no selection. See also Bug 1303033
+ is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled");
+ is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled");
+
+ if (isWindows()) {
+ // emptyClipboard only works on Windows (666254), assert paste only for this OS.
+ is(cmdPaste.getAttribute("disabled"), "true", "cmdPaste is disabled");
+ }
+
+ info("Closing context menu");
+ let onContextMenuHidden = once(searchContextMenu, "popuphidden");
+ searchContextMenu.hidePopup();
+ yield onContextMenuHidden;
+
+ info("Copy text in search field using the context menu");
+ searchField.value = TEST_INPUT;
+ searchField.select();
+ EventUtils.synthesizeMouse(searchField, 2, 2,
+ {type: "contextmenu", button: 2}, win);
+ yield onContextMenuPopup;
+ yield waitForClipboardPromise(() => cmdCopy.click(), TEST_INPUT);
+ searchContextMenu.hidePopup();
+ yield onContextMenuHidden;
+
+ info("Reopen context menu and check command properties");
+ EventUtils.synthesizeMouse(searchField, 2, 2,
+ {type: "contextmenu", button: 2}, win);
+ yield onContextMenuPopup;
+
+ is(cmdUndo.getAttribute("disabled"), "", "cmdUndo is enabled");
+ is(cmdDelete.getAttribute("disabled"), "", "cmdDelete is enabled");
+ is(cmdSelectAll.getAttribute("disabled"), "", "cmdSelectAll is enabled");
+ is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled");
+ is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled");
+ is(cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled");
+});
diff --git a/devtools/client/inspector/computed/test/browser_computed_search-filter_escape-keypress.js b/devtools/client/inspector/computed/test/browser_computed_search-filter_escape-keypress.js
new file mode 100644
index 000000000..e52e2cc89
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_search-filter_escape-keypress.js
@@ -0,0 +1,75 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Avoid test timeouts on Linux debug builds where the test takes just a bit too long to
+// run (see bug 1258081).
+requestLongerTimeout(2);
+
+// Tests that search filter escape keypress will clear the search field.
+
+const TEST_URI = `
+ <style type="text/css">
+ .matches {
+ color: #F00;
+ }
+ </style>
+ <span id="matches" class="matches">Some styled text</span>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("#matches", inspector);
+ yield testAddTextInFilter(inspector, view);
+ yield testEscapeKeypress(inspector, view);
+});
+
+function* testAddTextInFilter(inspector, computedView) {
+ info("Setting filter text to \"background-color\"");
+
+ let win = computedView.styleWindow;
+ let propertyViews = computedView.propertyViews;
+ let searchField = computedView.searchField;
+ let checkbox = computedView.includeBrowserStylesCheckbox;
+
+ info("Include browser styles");
+ checkbox.click();
+ yield inspector.once("computed-view-refreshed");
+
+ searchField.focus();
+ synthesizeKeys("background-color", win);
+ yield inspector.once("computed-view-refreshed");
+
+ info("Check that the correct properties are visible");
+
+ propertyViews.forEach((propView) => {
+ let name = propView.name;
+ is(propView.visible, name.indexOf("background-color") > -1,
+ "span " + name + " property visibility check");
+ });
+}
+
+function* testEscapeKeypress(inspector, computedView) {
+ info("Pressing the escape key on search filter");
+
+ let win = computedView.styleWindow;
+ let propertyViews = computedView.propertyViews;
+ let searchField = computedView.searchField;
+ let onRefreshed = inspector.once("computed-view-refreshed");
+
+ searchField.focus();
+ EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
+ yield onRefreshed;
+
+ info("Check that the correct properties are visible");
+
+ ok(!searchField.value, "Search filter is cleared");
+ propertyViews.forEach((propView) => {
+ let name = propView.name;
+ is(propView.visible, true,
+ "span " + name + " property is visible");
+ });
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_search-filter_noproperties.js b/devtools/client/inspector/computed/test/browser_computed_search-filter_noproperties.js
new file mode 100644
index 000000000..99ee6d58a
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_search-filter_noproperties.js
@@ -0,0 +1,61 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the "no-results" message is displayed when selecting an invalid element or
+// when all properties have been filtered out.
+
+const TEST_URI = `
+ <style type="text/css">
+ .matches {
+ color: #F00;
+ background-color: #00F;
+ border-color: #0F0;
+ }
+ </style>
+ <div>
+ <!-- comment node -->
+ <span id="matches" class="matches">Some styled text</span>
+ </div>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ let propertyViews = view.propertyViews;
+
+ info("Select the #matches node");
+ let matchesNode = yield getNodeFront("#matches", inspector);
+ let onRefresh = inspector.once("computed-view-refreshed");
+ yield selectNode(matchesNode, inspector);
+ yield onRefresh;
+
+ ok(propertyViews.filter(p => p.visible).length > 0, "CSS properties are displayed");
+ ok(view.noResults.hasAttribute("hidden"), "no-results message is hidden");
+
+ info("Select a comment node");
+ let commentNode = yield inspector.walker.previousSibling(matchesNode);
+ yield selectNode(commentNode, inspector);
+
+ is(propertyViews.filter(p => p.visible).length, 0, "No properties displayed");
+ ok(!view.noResults.hasAttribute("hidden"), "no-results message is displayed");
+
+ info("Select the #matches node again");
+ onRefresh = inspector.once("computed-view-refreshed");
+ yield selectNode(matchesNode, inspector);
+ yield onRefresh;
+
+ ok(propertyViews.filter(p => p.visible).length > 0, "CSS properties are displayed");
+ ok(view.noResults.hasAttribute("hidden"), "no-results message is hidden");
+
+ info("Filter by 'will-not-match' and check the no-results message is displayed");
+ let searchField = view.searchField;
+ searchField.focus();
+ synthesizeKeys("will-not-match", view.styleWindow);
+ yield inspector.once("computed-view-refreshed");
+
+ is(propertyViews.filter(p => p.visible).length, 0, "No properties displayed");
+ ok(!view.noResults.hasAttribute("hidden"), "no-results message is displayed");
+});
diff --git a/devtools/client/inspector/computed/test/browser_computed_select-and-copy-styles.js b/devtools/client/inspector/computed/test/browser_computed_select-and-copy-styles.js
new file mode 100644
index 000000000..ce8be59ad
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_select-and-copy-styles.js
@@ -0,0 +1,118 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that properties can be selected and copied from the computed view.
+
+const osString = Services.appinfo.OS;
+
+const TEST_URI = `
+ <style type="text/css">
+ span {
+ font-variant-caps: small-caps;
+ color: #000000;
+ }
+ .nomatches {
+ color: #ff0000;
+ }
+ </style>
+ <div id="first" style="margin: 10em;
+ font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA">
+ <h1>Some header text</h1>
+ <p id="salutation" style="font-size: 12pt">hi.</p>
+ <p id="body" style="font-size: 12pt">I am a test-case. This text exists
+ solely to provide some things to <span style="color: yellow">
+ highlight</span> and <span style="font-weight: bold">count</span>
+ style list-items in the box at right. If you are reading this,
+ you should go do something else instead. Maybe read a book. Or better
+ yet, write some test-cases for another bit of code.
+ <span style="font-style: italic">some text</span></p>
+ <p id="closing">more text</p>
+ <p>even more text</p>
+ </div>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openComputedView();
+ yield selectNode("span", inspector);
+ yield checkCopySelection(view);
+ yield checkSelectAll(view);
+});
+
+function* checkCopySelection(view) {
+ info("Testing selection copy");
+
+ let contentDocument = view.styleDocument;
+ let props = contentDocument.querySelectorAll(".property-view");
+ ok(props, "captain, we have the property-view nodes");
+
+ let range = contentDocument.createRange();
+ range.setStart(props[1], 0);
+ range.setEnd(props[3], 2);
+ contentDocument.defaultView.getSelection().addRange(range);
+
+ info("Checking that cssHtmlTree.siBoundCopy() returns the correct " +
+ "clipboard value");
+
+ let expectedPattern = "font-family: helvetica,sans-serif;[\\r\\n]+" +
+ "font-size: 16px;[\\r\\n]+" +
+ "font-variant-caps: small-caps;[\\r\\n]*";
+
+ try {
+ yield waitForClipboardPromise(() => fireCopyEvent(props[0]),
+ () => checkClipboardData(expectedPattern));
+ } catch (e) {
+ failedClipboard(expectedPattern);
+ }
+}
+
+function* checkSelectAll(view) {
+ info("Testing select-all copy");
+
+ let contentDoc = view.styleDocument;
+ let prop = contentDoc.querySelector(".property-view");
+
+ info("Checking that _onSelectAll() then copy returns the correct " +
+ "clipboard value");
+ view._contextmenu._onSelectAll();
+ let expectedPattern = "color: rgb\\(255, 255, 0\\);[\\r\\n]+" +
+ "font-family: helvetica,sans-serif;[\\r\\n]+" +
+ "font-size: 16px;[\\r\\n]+" +
+ "font-variant-caps: small-caps;[\\r\\n]*";
+
+ try {
+ yield waitForClipboardPromise(() => fireCopyEvent(prop),
+ () => checkClipboardData(expectedPattern));
+ } catch (e) {
+ failedClipboard(expectedPattern);
+ }
+}
+
+function checkClipboardData(expectedPattern) {
+ let actual = SpecialPowers.getClipboardData("text/unicode");
+ let expectedRegExp = new RegExp(expectedPattern, "g");
+ return expectedRegExp.test(actual);
+}
+
+function failedClipboard(expectedPattern) {
+ // Format expected text for comparison
+ let terminator = osString == "WINNT" ? "\r\n" : "\n";
+ expectedPattern = expectedPattern.replace(/\[\\r\\n\][+*]/g, terminator);
+ expectedPattern = expectedPattern.replace(/\\\(/g, "(");
+ expectedPattern = expectedPattern.replace(/\\\)/g, ")");
+
+ let actual = SpecialPowers.getClipboardData("text/unicode");
+
+ // Trim the right hand side of our strings. This is because expectedPattern
+ // accounts for windows sometimes adding a newline to our copied data.
+ expectedPattern = expectedPattern.trimRight();
+ actual = actual.trimRight();
+
+ dump("TEST-UNEXPECTED-FAIL | Clipboard text does not match expected ... " +
+ "results (escaped for accurate comparison):\n");
+ info("Actual: " + escape(actual));
+ info("Expected: " + escape(expectedPattern));
+}
diff --git a/devtools/client/inspector/computed/test/browser_computed_style-editor-link.js b/devtools/client/inspector/computed/test/browser_computed_style-editor-link.js
new file mode 100644
index 000000000..6a95fd83f
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser_computed_style-editor-link.js
@@ -0,0 +1,142 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Unknown sheet source");
+
+// Tests the links from the computed view to the style editor.
+
+const STYLESHEET_URL = "data:text/css," + encodeURIComponent(
+ ".highlight {color: blue}");
+
+const DOCUMENT_URL = "data:text/html;charset=utf-8," + encodeURIComponent(
+ `<html>
+ <head>
+ <title>Computed view style editor link test</title>
+ <style type="text/css">
+ html { color: #000000; }
+ span { font-variant: small-caps; color: #000000; }
+ .nomatches {color: #ff0000;}</style> <div id="first" style="margin: 10em;
+ font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA">
+ </style>
+ <style>
+ div { color: #f06; }
+ </style>
+ <link rel="stylesheet" type="text/css" href="${STYLESHEET_URL}">
+ </head>
+ <body>
+ <h1>Some header text</h1>
+ <p id="salutation" style="font-size: 12pt">hi.</p>
+ <p id="body" style="font-size: 12pt">I am a test-case. This text exists
+ solely to provide some things to
+ <span style="color: yellow" class="highlight">
+ highlight</span> and <span style="font-weight: bold">count</span>
+ style list-items in the box at right. If you are reading this,
+ you should go do something else instead. Maybe read a book. Or better
+ yet, write some test-cases for another bit of code.
+ <span style="font-style: italic">some text</span></p>
+ <p id="closing">more text</p>
+ <p>even more text</p>
+ </div>
+ </body>
+ </html>`);
+
+add_task(function* () {
+ yield addTab(DOCUMENT_URL);
+ let {toolbox, inspector, view, testActor} = yield openComputedView();
+ yield selectNode("span", inspector);
+
+ yield testInlineStyle(view);
+ yield testFirstInlineStyleSheet(view, toolbox, testActor);
+ yield testSecondInlineStyleSheet(view, toolbox, testActor);
+ yield testExternalStyleSheet(view, toolbox, testActor);
+});
+
+function* testInlineStyle(view) {
+ info("Testing inline style");
+
+ yield expandComputedViewPropertyByIndex(view, 0);
+
+ let onTab = waitForTab();
+ info("Clicking on the first rule-link in the computed-view");
+ clickLinkByIndex(view, 0);
+
+ let tab = yield onTab;
+
+ let tabURI = tab.linkedBrowser.documentURI.spec;
+ ok(tabURI.startsWith("view-source:"), "View source tab is open");
+ info("Closing tab");
+ gBrowser.removeTab(tab);
+}
+
+function* testFirstInlineStyleSheet(view, toolbox, testActor) {
+ info("Testing inline stylesheet");
+
+ info("Listening for toolbox switch to the styleeditor");
+ let onSwitch = waitForStyleEditor(toolbox);
+
+ info("Clicking an inline stylesheet");
+ clickLinkByIndex(view, 2);
+ let editor = yield onSwitch;
+
+ ok(true, "Switched to the style-editor panel in the toolbox");
+
+ yield validateStyleEditorSheet(editor, 0, testActor);
+}
+
+function* testSecondInlineStyleSheet(view, toolbox, testActor) {
+ info("Testing second inline stylesheet");
+
+ info("Waiting for the stylesheet editor to be selected");
+ let panel = toolbox.getCurrentPanel();
+ let onSelected = panel.UI.once("editor-selected");
+
+ info("Switching back to the inspector panel in the toolbox");
+ yield toolbox.selectTool("inspector");
+
+ info("Clicking on second inline stylesheet link");
+ clickLinkByIndex(view, 4);
+ let editor = yield onSelected;
+
+ is(toolbox.currentToolId, "styleeditor",
+ "The style editor is selected again");
+ yield validateStyleEditorSheet(editor, 1, testActor);
+}
+
+function* testExternalStyleSheet(view, toolbox, testActor) {
+ info("Testing external stylesheet");
+
+ info("Waiting for the stylesheet editor to be selected");
+ let panel = toolbox.getCurrentPanel();
+ let onSelected = panel.UI.once("editor-selected");
+
+ info("Switching back to the inspector panel in the toolbox");
+ yield toolbox.selectTool("inspector");
+
+ info("Clicking on an external stylesheet link");
+ clickLinkByIndex(view, 1);
+ let editor = yield onSelected;
+
+ is(toolbox.currentToolId, "styleeditor",
+ "The style editor is selected again");
+ yield validateStyleEditorSheet(editor, 2, testActor);
+}
+
+function* validateStyleEditorSheet(editor, expectedSheetIndex, testActor) {
+ info("Validating style editor stylesheet");
+ let expectedHref = yield testActor.eval(`
+ document.styleSheets[${expectedSheetIndex}].href;
+ `);
+ is(editor.styleSheet.href, expectedHref,
+ "loaded stylesheet matches document stylesheet");
+}
+
+function clickLinkByIndex(view, index) {
+ let link = getComputedViewLinkByIndex(view, index);
+ link.scrollIntoView();
+ link.click();
+}
diff --git a/devtools/client/inspector/computed/test/doc_matched_selectors.html b/devtools/client/inspector/computed/test/doc_matched_selectors.html
new file mode 100644
index 000000000..8fe007409
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_matched_selectors.html
@@ -0,0 +1,28 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+ <head>
+ <style>
+ .matched1, .matched2, .matched3, .matched4, .matched5 {
+ color: #000;
+ }
+
+ div {
+ position: absolute;
+ top: 40px;
+ left: 20px;
+ border: 1px solid #000;
+ color: #111;
+ width: 100px;
+ height: 50px;
+ }
+ </style>
+ </head>
+ <body>
+ inspectstyle($("test"));
+ <div id="test" class="matched1 matched2 matched3 matched4 matched5">Test div</div>
+ <div id="dummy">
+ <div></div>
+ </div>
+ </body>
+</html>
diff --git a/devtools/client/inspector/computed/test/doc_media_queries.html b/devtools/client/inspector/computed/test/doc_media_queries.html
new file mode 100644
index 000000000..819e1ea7a
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_media_queries.html
@@ -0,0 +1,21 @@
+<html>
+<head>
+ <title>test</title>
+ <style>
+ div {
+ width: 1000px;
+ height: 100px;
+ background-color: #f00;
+ }
+
+ @media screen and (min-width: 1px) {
+ div {
+ width: 200px;
+ }
+ }
+ </style>
+</head>
+<body>
+<div></div>
+</body>
+</html>
diff --git a/devtools/client/inspector/computed/test/doc_pseudoelement.html b/devtools/client/inspector/computed/test/doc_pseudoelement.html
new file mode 100644
index 000000000..6145d4bf1
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_pseudoelement.html
@@ -0,0 +1,131 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+ <head>
+ <style>
+
+body {
+ color: #333;
+}
+
+.box {
+ float:left;
+ width: 128px;
+ height: 128px;
+ background: #ddd;
+ padding: 32px;
+ margin: 32px;
+ position:relative;
+}
+
+.box:first-line {
+ color: orange;
+ background: red;
+}
+
+.box:first-letter {
+ color: green;
+}
+
+* {
+ cursor: default;
+}
+
+nothing {
+ cursor: pointer;
+}
+
+p::-moz-selection {
+ color: white;
+ background: black;
+}
+p::selection {
+ color: white;
+ background: black;
+}
+
+p:first-line {
+ background: blue;
+}
+p:first-letter {
+ color: red;
+ font-size: 130%;
+}
+
+.box:before {
+ background: green;
+ content: " ";
+ position: absolute;
+ height:32px;
+ width:32px;
+}
+
+.box:after {
+ background: red;
+ content: " ";
+ position: absolute;
+ border-radius: 50%;
+ height:32px;
+ width:32px;
+ top: 50%;
+ left: 50%;
+ margin-top: -16px;
+ margin-left: -16px;
+}
+
+.topleft:before {
+ top:0;
+ left:0;
+}
+
+.topleft:first-line {
+ color: orange;
+}
+.topleft::selection {
+ color: orange;
+}
+
+.topright:before {
+ top:0;
+ right:0;
+}
+
+.bottomright:before {
+ bottom:10px;
+ right:10px;
+ color: red;
+}
+
+.bottomright:before {
+ bottom:0;
+ right:0;
+}
+
+.bottomleft:before {
+ bottom:0;
+ left:0;
+}
+
+ </style>
+ </head>
+ <body>
+ <h1>ruleview pseudoelement($("test"));</h1>
+
+ <div id="topleft" class="box topleft">
+ <p>Top Left<br />Position</p>
+ </div>
+
+ <div id="topright" class="box topright">
+ <p>Top Right<br />Position</p>
+ </div>
+
+ <div id="bottomright" class="box bottomright">
+ <p>Bottom Right<br />Position</p>
+ </div>
+
+ <div id="bottomleft" class="box bottomleft">
+ <p>Bottom Left<br />Position</p>
+ </div>
+
+ </body>
+</html>
diff --git a/devtools/client/inspector/computed/test/doc_sourcemaps.css b/devtools/client/inspector/computed/test/doc_sourcemaps.css
new file mode 100644
index 000000000..a9b437a40
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_sourcemaps.css
@@ -0,0 +1,7 @@
+div {
+ color: #ff0066; }
+
+span {
+ background-color: #EEE; }
+
+/*# sourceMappingURL=doc_sourcemaps.css.map */ \ No newline at end of file
diff --git a/devtools/client/inspector/computed/test/doc_sourcemaps.css.map b/devtools/client/inspector/computed/test/doc_sourcemaps.css.map
new file mode 100644
index 000000000..0f7486fd9
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_sourcemaps.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "AAGA,GAAI;EACF,KAAK,EAHU,OAAI;;AAMrB,IAAK;EACH,gBAAgB,EAAE,IAAI",
+"sources": ["doc_sourcemaps.scss"],
+"names": [],
+"file": "doc_sourcemaps.css"
+}
diff --git a/devtools/client/inspector/computed/test/doc_sourcemaps.html b/devtools/client/inspector/computed/test/doc_sourcemaps.html
new file mode 100644
index 000000000..0014e55fe
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_sourcemaps.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<html>
+<head>
+ <title>testcase for testing CSS source maps</title>
+ <link rel="stylesheet" type="text/css" href="simple.css"/>
+ <link rel="stylesheet" type="text/css" href="doc_sourcemaps.css"/>
+</head>
+<body>
+ <div>source maps <span>testcase</span></div>
+</body>
+</html>
diff --git a/devtools/client/inspector/computed/test/doc_sourcemaps.scss b/devtools/client/inspector/computed/test/doc_sourcemaps.scss
new file mode 100644
index 000000000..0ff6c471b
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_sourcemaps.scss
@@ -0,0 +1,10 @@
+
+$paulrougetpink: #f06;
+
+div {
+ color: $paulrougetpink;
+}
+
+span {
+ background-color: #EEE;
+} \ No newline at end of file
diff --git a/devtools/client/inspector/computed/test/head.js b/devtools/client/inspector/computed/test/head.js
new file mode 100644
index 000000000..17c47be1a
--- /dev/null
+++ b/devtools/client/inspector/computed/test/head.js
@@ -0,0 +1,157 @@
+/* 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 ../../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);
+
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("devtools.defaultColorUnit");
+});
+
+/**
+ * Dispatch the copy event on the given element
+ */
+function fireCopyEvent(element) {
+ let evt = element.ownerDocument.createEvent("Event");
+ evt.initEvent("copy", true, true);
+ element.dispatchEvent(evt);
+}
+
+/**
+ * Get references to the name and value span nodes corresponding to a given
+ * property name in the computed-view
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {String} name
+ * The name of the property to retrieve
+ * @return an object {nameSpan, valueSpan}
+ */
+function getComputedViewProperty(view, name) {
+ let prop;
+ for (let property of view.styleDocument.querySelectorAll(".property-view")) {
+ let nameSpan = property.querySelector(".property-name");
+ let valueSpan = property.querySelector(".property-value");
+
+ if (nameSpan.textContent === name) {
+ prop = {nameSpan: nameSpan, valueSpan: valueSpan};
+ break;
+ }
+ }
+ return prop;
+}
+
+/**
+ * Get an instance of PropertyView from the computed-view.
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {String} name
+ * The name of the property to retrieve
+ * @return {PropertyView}
+ */
+function getComputedViewPropertyView(view, name) {
+ let propView;
+ for (let propertyView of view.propertyViews) {
+ if (propertyView._propertyInfo.name === name) {
+ propView = propertyView;
+ break;
+ }
+ }
+ return propView;
+}
+
+/**
+ * Get a reference to the property-content element for a given property name in
+ * the computed-view.
+ * A property-content element always follows (nextSibling) the property itself
+ * and is only shown when the twisty icon is expanded on the property.
+ * A property-content element contains matched rules, with selectors,
+ * properties, values and stylesheet links
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {String} name
+ * The name of the property to retrieve
+ * @return {Promise} A promise that resolves to the property matched rules
+ * container
+ */
+var getComputedViewMatchedRules = Task.async(function* (view, name) {
+ let expander;
+ let propertyContent;
+ for (let property of view.styleDocument.querySelectorAll(".property-view")) {
+ let nameSpan = property.querySelector(".property-name");
+ if (nameSpan.textContent === name) {
+ expander = property.querySelector(".expandable");
+ propertyContent = property.nextSibling;
+ break;
+ }
+ }
+
+ if (!expander.hasAttribute("open")) {
+ // Need to expand the property
+ let onExpand = view.inspector.once("computed-view-property-expanded");
+ expander.click();
+ yield onExpand;
+ }
+
+ return propertyContent;
+});
+
+/**
+ * Get the text value of the property corresponding to a given name in the
+ * computed-view
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {String} name
+ * The name of the property to retrieve
+ * @return {String} The property value
+ */
+function getComputedViewPropertyValue(view, name, propertyName) {
+ return getComputedViewProperty(view, name, propertyName)
+ .valueSpan.textContent;
+}
+
+/**
+ * Expand a given property, given its index in the current property list of
+ * the computed view
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {Number} index
+ * The index of the property to be expanded
+ * @return a promise that resolves when the property has been expanded, or
+ * rejects if the property was not found
+ */
+function expandComputedViewPropertyByIndex(view, index) {
+ info("Expanding property " + index + " in the computed view");
+ let expandos = view.styleDocument.querySelectorAll("#propertyContainer .expandable");
+ if (!expandos.length || !expandos[index]) {
+ return promise.reject();
+ }
+
+ let onExpand = view.inspector.once("computed-view-property-expanded");
+ expandos[index].click();
+ return onExpand;
+}
+
+/**
+ * Get a rule-link from the computed-view given its index
+ *
+ * @param {CssComputedView} view
+ * The instance of the computed view panel
+ * @param {Number} index
+ * The index of the link to be retrieved
+ * @return {DOMNode} The link at the given index, if one exists, null otherwise
+ */
+function getComputedViewLinkByIndex(view, index) {
+ let links = view.styleDocument.querySelectorAll(".rule-link .link");
+ return links[index];
+}