import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,6 @@
"use strict";
module.exports = {
// Extend from the shared list of defined globals for mochitests.
"extends": "../../../.eslintrc.mochitests.js"
};

View file

@ -0,0 +1,23 @@
<!doctype html>
<html>
<head>
<title>testcase for autocomplete testing</title>
<link rel="stylesheet" type="text/css" href="resources_inpage1.css"/>
<style type="text/css">
div {
font-size: 4em;
}
div > span {
text-decoration: underline;
}
div + button {
border: 2px dotted red;
}
</style>
</head>
<body>
<div>parent <span>child</span></div><button>sibling</button>
</body>
</html>

View file

@ -0,0 +1,107 @@
[DEFAULT]
tags = devtools
subsuite = devtools
support-files =
autocomplete.html
browser_styleeditor_cmd_edit.html
four.html
head.js
import.css
import.html
import2.css
inline-1.html
inline-2.html
longload.html
media-small.css
media.html
media-rules.html
media-rules.css
media-rules-sourcemaps.html
minified.html
missing.html
nostyle.html
pretty.css
resources_inpage.jsi
resources_inpage1.css
resources_inpage2.css
simple.css
simple.css.gz
simple.css.gz^headers^
simple.gz.html
simple.html
sourcemap-css/contained.css
sourcemap-css/sourcemaps.css
sourcemap-css/sourcemaps.css.map
sourcemap-css/media-rules.css
sourcemap-css/media-rules.css.map
sourcemap-css/test-bootstrap-scss.css
sourcemap-css/test-stylus.css
sourcemap-sass/sourcemaps.scss
sourcemap-sass/media-rules.scss
sourcemap-styl/test-stylus.styl
sourcemaps.html
sourcemaps-inline.html
sourcemaps-large.html
sourcemaps-watching.html
test_private.css
test_private.html
doc_long.css
doc_uncached.css
doc_uncached.html
doc_xulpage.xul
sync.html
utf-16.css
!/devtools/client/commandline/test/helpers.js
!/devtools/client/framework/test/shared-head.js
!/devtools/client/inspector/shared/test/head.js
!/devtools/client/inspector/test/head.js
!/devtools/client/inspector/test/shared-head.js
!/devtools/client/responsive.html/test/browser/devices.json
!/devtools/client/shared/test/test-actor-registry.js
!/devtools/client/shared/test/test-actor.js
[browser_styleeditor_autocomplete.js]
[browser_styleeditor_autocomplete-disabled.js]
[browser_styleeditor_bom.js]
[browser_styleeditor_bug_740541_iframes.js]
[browser_styleeditor_bug_851132_middle_click.js]
[browser_styleeditor_bug_870339.js]
[browser_styleeditor_cmd_edit.js]
[browser_styleeditor_enabled.js]
[browser_styleeditor_fetch-from-cache.js]
[browser_styleeditor_filesave.js]
[browser_styleeditor_highlight-selector.js]
[browser_styleeditor_import.js]
[browser_styleeditor_import_rule.js]
[browser_styleeditor_init.js]
[browser_styleeditor_inline_friendly_names.js]
[browser_styleeditor_loading.js]
[browser_styleeditor_loading_with_containers.js]
[browser_styleeditor_media_sidebar.js]
[browser_styleeditor_media_sidebar_links.js]
skip-if = e10s && debug # Bug 1252201 - Docshell leak on debug e10s
[browser_styleeditor_media_sidebar_sourcemaps.js]
[browser_styleeditor_missing_stylesheet.js]
[browser_styleeditor_navigate.js]
[browser_styleeditor_new.js]
[browser_styleeditor_nostyle.js]
[browser_styleeditor_opentab.js]
[browser_styleeditor_pretty.js]
[browser_styleeditor_private_perwindowpb.js]
[browser_styleeditor_reload.js]
[browser_styleeditor_scroll.js]
[browser_styleeditor_sv_keynav.js]
[browser_styleeditor_sv_resize.js]
[browser_styleeditor_selectstylesheet.js]
[browser_styleeditor_sourcemaps.js]
[browser_styleeditor_sourcemaps_inline.js]
[browser_styleeditor_sourcemap_large.js]
[browser_styleeditor_sourcemap_watching.js]
[browser_styleeditor_sync.js]
[browser_styleeditor_syncAddProperty.js]
[browser_styleeditor_syncAddRule.js]
[browser_styleeditor_syncAlreadyOpen.js]
[browser_styleeditor_syncEditSelector.js]
[browser_styleeditor_syncIntoRuleView.js]
[browser_styleeditor_transition_rule.js]
[browser_styleeditor_xul.js]

View file

@ -0,0 +1,26 @@
/* 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 autocomplete can be disabled.
const TESTCASE_URI = TEST_BASE_HTTP + "autocomplete.html";
// Pref which decides if CSS autocompletion is enabled in Style Editor or not.
const AUTOCOMPLETION_PREF = "devtools.styleeditor.autocompletion-enabled";
add_task(function* () {
Services.prefs.setBoolPref(AUTOCOMPLETION_PREF, false);
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
let editor = yield ui.editors[0].getSourceEditor();
is(editor.sourceEditor.getOption("autocomplete"), false,
"Autocompletion option does not exist");
ok(!editor.sourceEditor.getAutocompletionPopup(),
"Autocompletion popup does not exist");
});
registerCleanupFunction(() => {
Services.prefs.clearUserPref(AUTOCOMPLETION_PREF);
});

View file

@ -0,0 +1,231 @@
/* 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 autocompletion works as expected.
const TESTCASE_URI = TEST_BASE_HTTP + "autocomplete.html";
const MAX_SUGGESTIONS = 15;
const {initCssProperties} = require("devtools/shared/fronts/css-properties");
// Test cases to test that autocompletion works correctly when enabled.
// Format:
// [
// key,
// {
// total: Number of suggestions in the popup (-1 if popup is closed),
// current: Index of selected suggestion,
// inserted: 1 to check whether the selected suggestion is inserted into the
// editor or not,
// entered: 1 if the suggestion is inserted and finalized
// }
// ]
function getTestCases(cssProperties) {
let keywords = getCSSKeywords(cssProperties);
let getSuggestionNumberFor = suggestionNumberGetter(keywords);
return [
["VK_RIGHT"],
["VK_RIGHT"],
["VK_RIGHT"],
["VK_RIGHT"],
["Ctrl+Space", {total: 1, current: 0}],
["VK_LEFT"],
["VK_RIGHT"],
["VK_DOWN"],
["VK_RIGHT"],
["VK_RIGHT"],
["VK_RIGHT"],
["Ctrl+Space", { total: getSuggestionNumberFor("font"), current: 0}],
["VK_END"],
["VK_RETURN"],
["b", {total: getSuggestionNumberFor("b"), current: 0}],
["a", {total: getSuggestionNumberFor("ba"), current: 0}],
["VK_DOWN", {total: getSuggestionNumberFor("ba"), current: 0, inserted: 1}],
["VK_TAB", {total: getSuggestionNumberFor("ba"), current: 1, inserted: 1}],
["VK_RETURN", {current: 1, inserted: 1, entered: 1}],
["b", {total: getSuggestionNumberFor("background", "b"), current: 0}],
["l", {total: getSuggestionNumberFor("background", "bl"), current: 0}],
["VK_TAB", {
total: getSuggestionNumberFor("background", "bl"),
current: 0, inserted: 1
}],
["VK_DOWN", {
total: getSuggestionNumberFor("background", "bl"),
current: 1, inserted: 1
}],
["VK_UP", {
total: getSuggestionNumberFor("background", "bl"),
current: 0,
inserted: 1
}],
["VK_TAB", {
total: getSuggestionNumberFor("background", "bl"),
current: 1,
inserted: 1
}],
["VK_TAB", {
total: getSuggestionNumberFor("background", "bl"),
current: 2,
inserted: 1
}],
[";"],
["VK_RETURN"],
["c", {total: getSuggestionNumberFor("c"), current: 0}],
["o", {total: getSuggestionNumberFor("co"), current: 0}],
["VK_RETURN", {current: 0, inserted: 1}],
["r", {total: getSuggestionNumberFor("color", "r"), current: 0}],
["VK_RETURN", {current: 0, inserted: 1}],
[";"],
["VK_LEFT"],
["VK_RIGHT"],
["VK_DOWN"],
["VK_RETURN"],
["b", {total: 2, current: 0}],
["u", {total: 1, current: 0}],
["VK_RETURN", {current: 0, inserted: 1}],
["{"],
["VK_HOME"],
["VK_DOWN"],
["VK_DOWN"],
["VK_RIGHT"],
["VK_RIGHT"],
["VK_RIGHT"],
["VK_RIGHT"],
["VK_RIGHT"],
["VK_RIGHT"],
["VK_RIGHT"],
["VK_RIGHT"],
["VK_RIGHT"],
["VK_RIGHT"],
["Ctrl+Space", {total: 1, current: 0}],
];
}
add_task(function* () {
let { panel, ui } = yield openStyleEditorForURL(TESTCASE_URI);
let { cssProperties } = yield initCssProperties(panel._toolbox);
let testCases = getTestCases(cssProperties);
yield ui.selectStyleSheet(ui.editors[1].styleSheet);
let editor = yield ui.editors[1].getSourceEditor();
let sourceEditor = editor.sourceEditor;
let popup = sourceEditor.getAutocompletionPopup();
yield SimpleTest.promiseFocus(panel.panelWindow);
for (let index in testCases) {
yield testState(testCases, index, sourceEditor, popup, panel.panelWindow);
yield checkState(testCases, index, sourceEditor, popup);
}
});
function testState(testCases, index, sourceEditor, popup, panelWindow) {
let [key, details] = testCases[index];
let entered;
if (details) {
entered = details.entered;
}
let mods = {};
info("pressing key " + key + " to get result: " +
JSON.stringify(testCases[index]) + " for index " + index);
let evt = "after-suggest";
if (key == "Ctrl+Space") {
key = " ";
mods.ctrlKey = true;
} else if (key == "VK_RETURN" && entered) {
evt = "popup-hidden";
} else if (/(left|right|return|home|end)/ig.test(key) ||
(key == "VK_DOWN" && !popup.isOpen)) {
evt = "cursorActivity";
} else if (key == "VK_TAB" || key == "VK_UP" || key == "VK_DOWN") {
evt = "suggestion-entered";
}
let ready = sourceEditor.once(evt);
EventUtils.synthesizeKey(key, mods, panelWindow);
return ready;
}
function checkState(testCases, index, sourceEditor, popup) {
let deferred = defer();
executeSoon(() => {
let [, details] = testCases[index];
details = details || {};
let {total, current, inserted} = details;
if (total != undefined) {
ok(popup.isOpen, "Popup is open for index " + index);
is(total, popup.itemCount,
"Correct total suggestions for index " + index);
is(current, popup.selectedIndex,
"Correct index is selected for index " + index);
if (inserted) {
let { text } = popup.getItemAtIndex(current);
let { line, ch } = sourceEditor.getCursor();
let lineText = sourceEditor.getText(line);
is(lineText.substring(ch - text.length, ch), text,
"Current suggestion from the popup is inserted into the editor.");
}
} else {
ok(!popup.isOpen, "Popup is closed for index " + index);
if (inserted) {
let { text } = popup.getItemAtIndex(current);
let { line, ch } = sourceEditor.getCursor();
let lineText = sourceEditor.getText(line);
is(lineText.substring(ch - text.length, ch), text,
"Current suggestion from the popup is inserted into the editor.");
}
}
deferred.resolve();
});
return deferred.promise;
}
/**
* Returns a list of all property names and a map of property name vs possible
* CSS values provided by the Gecko engine.
*
* @return {Object} An object with following properties:
* - CSSProperties {Array} Array of string containing all the possible
* CSS property names.
* - CSSValues {Object|Map} A map where key is the property name and
* value is an array of string containing all the possible
* CSS values the property can have.
*/
function getCSSKeywords(cssProperties) {
let props = {};
let propNames = cssProperties.getNames();
propNames.forEach(prop => {
props[prop] = cssProperties.getValues(prop).sort();
});
return {
CSSValues: props,
CSSProperties: propNames.sort()
};
}
/**
* Returns a function that returns the number of expected suggestions for the given
* property and value. If the value is not null, returns the number of values starting
* with `value`. Returns the number of properties starting with `property` otherwise.
*/
function suggestionNumberGetter({CSSProperties, CSSValues}) {
return (property, value) => {
if (value == null) {
return CSSProperties.filter(prop => prop.startsWith(property))
.slice(0, MAX_SUGGESTIONS).length;
}
return CSSValues[property].filter(val => val.startsWith(value))
.slice(0, MAX_SUGGESTIONS).length;
};
}

View file

@ -0,0 +1,34 @@
/* 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";
const BOM_CSS = TEST_BASE_HTTPS + "utf-16.css";
const DOCUMENT = "data:text/html;charset=UTF-8," +
encodeURIComponent(
["<!DOCTYPE html>",
"<html>",
" <head>",
" <title>Bug 1301854</title>",
' <link rel="stylesheet" type="text/css" href="' + BOM_CSS + '">',
" </head>",
" <body>",
" </body>",
"</html>"
].join("\n"));
const CONTENTS = "// Note that this file must be utf-16 with a " +
"BOM for the test to make sense.\n";
add_task(function* () {
let {ui} = yield openStyleEditorForURL(DOCUMENT);
is(ui.editors.length, 1, "correct number of editors");
let editor = ui.editors[0];
yield editor.getSourceEditor();
let text = editor.sourceEditor.getText();
is(text, CONTENTS, "editor contains expected text");
});

View file

@ -0,0 +1,76 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that sheets inside iframes are shown in the editor.
add_task(function* () {
function makeStylesheet(selector) {
return ("data:text/css;charset=UTF-8," +
encodeURIComponent(selector + " { }"));
}
function makeDocument(stylesheets, framedDocuments) {
stylesheets = stylesheets || [];
framedDocuments = framedDocuments || [];
return "data:text/html;charset=UTF-8," + encodeURIComponent(
Array.prototype.concat.call(
["<!DOCTYPE html>",
"<html>",
"<head>",
"<title>Bug 740541</title>"],
stylesheets.map(function (sheet) {
return '<link rel="stylesheet" type="text/css" href="' + sheet + '">';
}),
["</head>",
"<body>"],
framedDocuments.map(function (doc) {
return '<iframe src="' + doc + '"></iframe>';
}),
["</body>",
"</html>"]
).join("\n"));
}
const DOCUMENT_WITH_INLINE_STYLE = "data:text/html;charset=UTF-8," +
encodeURIComponent(
["<!DOCTYPE html>",
"<html>",
" <head>",
" <title>Bug 740541</title>",
' <style type="text/css">',
" .something {",
" }",
" </style>",
" </head>",
" <body>",
" </body>",
" </html>"
].join("\n"));
const FOUR = TEST_BASE_HTTP + "four.html";
const SIMPLE = TEST_BASE_HTTP + "simple.css";
const SIMPLE_DOCUMENT = TEST_BASE_HTTP + "simple.html";
const TESTCASE_URI = makeDocument(
[makeStylesheet(".a")],
[makeDocument([],
[FOUR,
DOCUMENT_WITH_INLINE_STYLE]),
makeDocument([makeStylesheet(".b"),
SIMPLE],
[makeDocument([makeStylesheet(".c")],
[])]),
makeDocument([SIMPLE], []),
SIMPLE_DOCUMENT
]);
const EXPECTED_STYLE_SHEET_COUNT = 12;
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, EXPECTED_STYLE_SHEET_COUNT,
"Got the expected number of style sheets.");
});

View file

@ -0,0 +1,56 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that middle click on style sheet doesn't open styleeditor.xul in a new
// tab (bug 851132).
const TESTCASE_URI = TEST_BASE_HTTP + "four.html";
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
gBrowser.tabContainer.addEventListener("TabOpen", onTabAdded, false);
yield ui.editors[0].getSourceEditor();
info("first editor selected");
info("Left-clicking on the second editor link.");
yield clickOnStyleSheetLink(ui.editors[1], 0);
info("Waiting for the second editor to be selected.");
let editor = yield ui.once("editor-selected");
ok(editor.sourceEditor.hasFocus(),
"Left mouse click gave second editor focus.");
// middle mouse click should not open a new tab
info("Middle clicking on the third editor link.");
yield clickOnStyleSheetLink(ui.editors[2], 1);
});
/**
* A helper that clicks on style sheet link in the sidebar.
*
* @param {StyleSheetEditor} editor
* The editor of which link should be clicked.
* @param {MouseEvent.button} button
* The button to click the link with.
*/
function* clickOnStyleSheetLink(editor, button) {
let window = editor._window;
let link = editor.summary.querySelector(".stylesheet-name");
info("Waiting for focus.");
yield SimpleTest.promiseFocus(window);
info("Pressing button " + button + " on style sheet name link.");
EventUtils.synthesizeMouseAtCenter(link, { button }, window);
}
function onTabAdded() {
ok(false, "middle mouse click has opened a new tab");
}
registerCleanupFunction(function () {
gBrowser.tabContainer.removeEventListener("TabOpen", onTabAdded, false);
});

View file

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const SIMPLE = TEST_BASE_HTTP + "simple.css";
const DOCUMENT_WITH_ONE_STYLESHEET = "data:text/html;charset=UTF-8," +
encodeURIComponent(
["<!DOCTYPE html>",
"<html>",
" <head>",
" <title>Bug 870339</title>",
' <link rel="stylesheet" type="text/css" href="' + SIMPLE + '">',
" </head>",
" <body>",
" </body>",
"</html>"
].join("\n"));
add_task(function* () {
let { ui } = yield openStyleEditorForURL(DOCUMENT_WITH_ONE_STYLESHEET);
// Spam the _onNewDocument callback multiple times before the
// StyleEditorActor has a chance to respond to the first one.
const SPAM_COUNT = 2;
for (let i = 0; i < SPAM_COUNT; ++i) {
ui._onNewDocument();
}
// Wait for the StyleEditorActor to respond to each "newDocument"
// message.
yield new Promise(resolve => {
let loadCount = 0;
ui.on("stylesheets-reset", function onReset() {
++loadCount;
if (loadCount == SPAM_COUNT) {
ui.off("stylesheets-reset", onReset);
// No matter how large SPAM_COUNT is, the number of style
// sheets should never be more than the number of style sheets
// in the document.
is(ui.editors.length, 1, "correct style sheet count");
resolve();
}
});
});
});

View file

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Resources</title>
<script type="text/javascript;version=1.8" id="script1">
"use strict";
window.addEventListener("load", function onload() {
let pid = document.getElementById("pid");
let div = document.createElement("div");
div.id = "divid";
div.classList.add("divclass");
div.appendChild(document.createTextNode("div"));
div.setAttribute("data-a1", "div");
pid.parentNode.appendChild(div);
});
</script>
<script src="resources_inpage.jsi"></script>
<link rel="stylesheet" type="text/css" href="resources_inpage1.css"/>
<link rel="stylesheet" type="text/css" href="resources_inpage2.css"/>
<style type="text/css">
p { color: #800; }
div { color: #008; }
h4 { color: #080; }
h3 { color: #880; }
</style>
</head>
<body>
<style type="text/css" id=style2>
.pclass { background-color: #FEE; }
.divclass { background-color: #EEF; }
.h4class { background-color: #EFE; }
.h3class { background-color: #FFE; }
</style>
<p class="pclass" id="pid" data-a1="p">paragraph</p>
<script>
"use strict";
let pid = document.getElementById("pid");
let h4 = document.createElement("h4");
h4.id = "h4id";
h4.classList.add("h4class");
h4.appendChild(document.createTextNode("h4"));
h4.setAttribute("data-a1", "h4");
pid.parentNode.appendChild(h4);
</script>
</body>
</html>

View file

@ -0,0 +1,215 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that the edit command works
// Import the GCLI test helper
/* import-globals-from ../../commandline/test/helpers.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/commandline/test/helpers.js",
this);
const TEST_URI = "http://example.com/browser/devtools/client/styleeditor/" +
"test/browser_styleeditor_cmd_edit.html";
add_task(function* () {
let options = yield helpers.openTab(TEST_URI);
yield helpers.openToolbar(options);
yield helpers.audit(options, [
{
setup: "edit",
check: {
input: "edit",
hints: " <resource> [line]",
markup: "VVVV",
status: "ERROR",
args: {
resource: { status: "INCOMPLETE" },
line: { status: "VALID" },
}
},
},
{
setup: "edit i",
check: {
input: "edit i",
hints: "nline-css [line]",
markup: "VVVVVI",
status: "ERROR",
args: {
resource: { arg: " i", status: "INCOMPLETE" },
line: { status: "VALID" },
}
},
},
{
setup: "edit c",
check: {
input: "edit c",
hints: "ss#style2 [line]",
markup: "VVVVVI",
status: "ERROR",
args: {
resource: { arg: " c", status: "INCOMPLETE" },
line: { status: "VALID" },
}
},
},
{
setup: "edit http",
check: {
input: "edit http",
hints: "://example.com/browser/devtools/client/styleeditor/test/" +
"resources_inpage1.css [line]",
markup: "VVVVVIIII",
status: "ERROR",
args: {
resource: {
arg: " http",
status: "INCOMPLETE",
message: "Value required for \u2018resource\u2019."
},
line: { status: "VALID" },
}
},
},
{
setup: "edit page1",
check: {
input: "edit page1",
hints: " [line] -> http://example.com/browser/devtools/client/" +
"styleeditor/test/resources_inpage1.css",
markup: "VVVVVIIIII",
status: "ERROR",
args: {
resource: {
arg: " page1",
status: "INCOMPLETE",
message: "Value required for \u2018resource\u2019."
},
line: { status: "VALID" },
}
},
},
{
setup: "edit page2",
check: {
input: "edit page2",
hints: " [line] -> http://example.com/browser/devtools/client/" +
"styleeditor/test/resources_inpage2.css",
markup: "VVVVVIIIII",
status: "ERROR",
args: {
resource: {
arg: " page2",
status: "INCOMPLETE",
message: "Value required for \u2018resource\u2019."
},
line: { status: "VALID" },
}
},
},
{
setup: "edit stylez",
check: {
input: "edit stylez",
hints: " [line]",
markup: "VVVVVEEEEEE",
status: "ERROR",
args: {
resource: {
arg: " stylez",
status: "ERROR", message: "Can\u2019t use \u2018stylez\u2019." },
line: { status: "VALID" },
}
},
},
{
setup: "edit css#style2",
check: {
input: "edit css#style2",
hints: " [line]",
markup: "VVVVVVVVVVVVVVV",
status: "VALID",
args: {
resource: { arg: " css#style2", status: "VALID", message: "" },
line: { status: "VALID" },
}
},
},
{
setup: "edit css#style2 5",
check: {
input: "edit css#style2 5",
hints: "",
markup: "VVVVVVVVVVVVVVVVV",
status: "VALID",
args: {
resource: { arg: " css#style2", status: "VALID", message: "" },
line: { value: 5, arg: " 5", status: "VALID" },
}
},
},
{
setup: "edit css#style2 0",
check: {
input: "edit css#style2 0",
hints: "",
markup: "VVVVVVVVVVVVVVVVE",
status: "ERROR",
args: {
resource: { arg: " css#style2", status: "VALID", message: "" },
line: {
arg: " 0",
status: "ERROR",
message: "0 is smaller than minimum allowed: 1."
},
}
},
},
{
setup: "edit css#style2 -1",
check: {
input: "edit css#style2 -1",
hints: "",
markup: "VVVVVVVVVVVVVVVVEE",
status: "ERROR",
args: {
resource: { arg: " css#style2", status: "VALID", message: "" },
line: {
arg: " -1",
status: "ERROR",
message: "-1 is smaller than minimum allowed: 1."
},
}
},
}
]);
let toolbox = gDevTools.getToolbox(options.target);
ok(toolbox == null, "toolbox is closed");
yield helpers.audit(options, [
{
setup: "edit css#style2",
check: {
input: "edit css#style2",
},
exec: { output: "" }
},
]);
toolbox = gDevTools.getToolbox(options.target);
ok(toolbox != null, "toolbox is open");
let styleEditor = toolbox.getCurrentPanel();
ok(typeof styleEditor.selectStyleSheet === "function", "styleeditor is open");
yield toolbox.destroy();
yield helpers.closeToolbar(options);
yield helpers.closeTab(options);
});

View file

@ -0,0 +1,56 @@
/* 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 style sheets can be disabled and enabled.
// https rather than chrome to improve coverage
const TESTCASE_URI = TEST_BASE_HTTPS + "simple.html";
add_task(function* () {
let { panel, ui } = yield openStyleEditorForURL(TESTCASE_URI);
let editor = yield ui.editors[0].getSourceEditor();
let summary = editor.summary;
let enabledToggle = summary.querySelector(".stylesheet-enabled");
ok(enabledToggle, "enabled toggle button exists");
is(editor.styleSheet.disabled, false,
"first stylesheet is initially enabled");
is(summary.classList.contains("disabled"), false,
"first stylesheet is initially enabled, UI does not have DISABLED class");
info("Disabling the first stylesheet.");
yield toggleEnabled(editor, enabledToggle, panel.panelWindow);
is(editor.styleSheet.disabled, true, "first stylesheet is now disabled");
is(summary.classList.contains("disabled"), true,
"first stylesheet is now disabled, UI has DISABLED class");
info("Enabling the first stylesheet again.");
yield toggleEnabled(editor, enabledToggle, panel.panelWindow);
is(editor.styleSheet.disabled, false,
"first stylesheet is now enabled again");
is(summary.classList.contains("disabled"), false,
"first stylesheet is now enabled again, UI does not have DISABLED class");
});
function* toggleEnabled(editor, enabledToggle, panelWindow) {
let changed = editor.once("property-change");
info("Waiting for focus.");
yield SimpleTest.promiseFocus(panelWindow);
info("Clicking on the toggle.");
EventUtils.synthesizeMouseAtCenter(enabledToggle, {}, panelWindow);
info("Waiting for stylesheet to be disabled.");
let property = yield changed;
while (property !== "disabled") {
info("Ignoring property-change for '" + property + "'.");
property = yield editor.once("property-change");
}
}

View file

@ -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";
// A test to ensure Style Editor doesn't bybass cache when loading style sheet
// contents (bug 978688).
const TEST_URL = TEST_BASE_HTTP + "doc_uncached.html";
add_task(function* () {
info("Opening netmonitor");
let tab = yield addTab("about:blank");
let target = TargetFactory.forTab(tab);
let toolbox = yield gDevTools.showToolbox(target, "netmonitor");
let netmonitor = toolbox.getPanel("netmonitor");
netmonitor._view.RequestsMenu.lazyUpdate = false;
info("Navigating to test page");
yield navigateTo(TEST_URL);
info("Opening Style Editor");
let styleeditor = yield toolbox.selectTool("styleeditor");
info("Waiting for the source to be loaded.");
yield styleeditor.UI.editors[0].getSourceEditor();
info("Checking Netmonitor contents.");
let attachments = [];
for (let item of netmonitor._view.RequestsMenu) {
if (item.attachment.url.endsWith("doc_uncached.css")) {
attachments.push(item.attachment);
}
}
is(attachments.length, 2,
"Got two requests for doc_uncached.css after Style Editor was loaded.");
ok(attachments[1].fromCache,
"Second request was loaded from browser cache");
});

View file

@ -0,0 +1,99 @@
/* 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 'Save' function works.
const TESTCASE_URI_HTML = TEST_BASE_HTTP + "simple.html";
const TESTCASE_URI_CSS = TEST_BASE_HTTP + "simple.css";
var tempScope = {};
Components.utils.import("resource://gre/modules/FileUtils.jsm", tempScope);
Components.utils.import("resource://gre/modules/NetUtil.jsm", tempScope);
var FileUtils = tempScope.FileUtils;
var NetUtil = tempScope.NetUtil;
add_task(function* () {
let htmlFile = yield copy(TESTCASE_URI_HTML, "simple.html");
yield copy(TESTCASE_URI_CSS, "simple.css");
let uri = Services.io.newFileURI(htmlFile);
let filePath = uri.resolve("");
let { ui } = yield openStyleEditorForURL(filePath);
let editor = ui.editors[0];
yield editor.getSourceEditor();
info("Editing the style sheet.");
let dirty = editor.sourceEditor.once("dirty-change");
let beginCursor = {line: 0, ch: 0};
editor.sourceEditor.replaceText("DIRTY TEXT", beginCursor, beginCursor);
yield dirty;
is(editor.sourceEditor.isClean(), false, "Editor is dirty.");
ok(editor.summary.classList.contains("unsaved"),
"Star icon is present in the corresponding summary.");
info("Saving the changes.");
dirty = editor.sourceEditor.once("dirty-change");
editor.saveToFile(null, function (file) {
ok(file, "file should get saved directly when using a file:// URI");
});
yield dirty;
is(editor.sourceEditor.isClean(), true, "Editor is clean.");
ok(!editor.summary.classList.contains("unsaved"),
"Star icon is not present in the corresponding summary.");
});
function copy(srcChromeURL, destFileName) {
let deferred = defer();
let destFile = FileUtils.getFile("ProfD", [destFileName]);
write(read(srcChromeURL), destFile, deferred.resolve);
return deferred.promise;
}
function read(srcChromeURL) {
let scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
.getService(Ci.nsIScriptableInputStream);
let channel = NetUtil.newChannel({
uri: srcChromeURL,
loadUsingSystemPrincipal: true
});
let input = channel.open2();
scriptableStream.init(input);
let data = "";
while (input.available()) {
data = data.concat(scriptableStream.read(input.available()));
}
scriptableStream.close();
input.close();
return data;
}
function write(data, file, callback) {
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let istream = converter.convertToInputStream(data);
let ostream = FileUtils.openSafeFileOutputStream(file);
NetUtil.asyncCopy(istream, ostream, function (status) {
if (!Components.isSuccessCode(status)) {
info("Couldn't write to " + file.path);
return;
}
callback(file);
});
}

View file

@ -0,0 +1,48 @@
/* 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 hovering over a simple selector in the style-editor requests the
// highlighting of the corresponding nodes
const TEST_URL = "data:text/html;charset=utf8," +
"<style>div{color:red}</style><div>highlighter test</div>";
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TEST_URL);
let editor = ui.editors[0];
// Mock the highlighter so we can locally assert that things happened
// correctly instead of accessing the highlighter elements
editor.highlighter = {
isShown: false,
options: null,
show: function (node, options) {
this.isShown = true;
this.options = options;
return promise.resolve();
},
hide: function () {
this.isShown = false;
}
};
info("Expecting a node-highlighted event");
let onHighlighted = editor.once("node-highlighted");
info("Simulate a mousemove event on the div selector");
editor._onMouseMove({clientX: 56, clientY: 10});
yield onHighlighted;
ok(editor.highlighter.isShown, "The highlighter is now shown");
is(editor.highlighter.options.selector, "div", "The selector is correct");
info("Simulate a mousemove event elsewhere in the editor");
editor._onMouseMove({clientX: 16, clientY: 0});
ok(!editor.highlighter.isShown, "The highlighter is now hidden");
});

View file

@ -0,0 +1,55 @@
/* 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 import button in the UI works.
// http rather than chrome to improve coverage
const TESTCASE_URI = TEST_BASE_HTTP + "simple.html";
var tempScope = {};
Components.utils.import("resource://gre/modules/FileUtils.jsm", tempScope);
var FileUtils = tempScope.FileUtils;
const FILENAME = "styleeditor-import-test.css";
const SOURCE = "body{background:red;}";
add_task(function* () {
let { panel, ui } = yield openStyleEditorForURL(TESTCASE_URI);
let added = ui.once("editor-added");
importSheet(ui, panel.panelWindow);
info("Waiting for editor to be added for the imported sheet.");
let editor = yield added;
is(editor.savedFile.leafName, FILENAME,
"imported stylesheet will be saved directly into the same file");
is(editor.friendlyName, FILENAME,
"imported stylesheet has the same name as the filename");
});
function importSheet(ui, panelWindow) {
// create file to import first
let file = FileUtils.getFile("ProfD", [FILENAME]);
let ostream = FileUtils.openSafeFileOutputStream(file);
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let istream = converter.convertToInputStream(SOURCE);
NetUtil.asyncCopy(istream, ostream, function () {
FileUtils.closeSafeFileOutputStream(ostream);
// click the import button now that the file to import is ready
ui._mockImportFile = file;
waitForFocus(function () {
let document = panelWindow.document;
let importButton = document.querySelector(".style-editor-importButton");
ok(importButton, "import button exists");
EventUtils.synthesizeMouseAtCenter(importButton, {}, panelWindow);
}, panelWindow);
});
}

View file

@ -0,0 +1,25 @@
/* 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 style editor shows sheets loaded with @import rules.
// http rather than chrome to improve coverage
const TESTCASE_URI = TEST_BASE_HTTP + "import.html";
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, 3,
"there are 3 stylesheets after loading @imports");
is(ui.editors[0].styleSheet.href, TEST_BASE_HTTP + "simple.css",
"stylesheet 1 is simple.css");
is(ui.editors[1].styleSheet.href, TEST_BASE_HTTP + "import.css",
"stylesheet 2 is import.css");
is(ui.editors[2].styleSheet.href, TEST_BASE_HTTP + "import2.css",
"stylesheet 3 is import2.css");
});

View file

@ -0,0 +1,45 @@
"use strict";
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Checks that style editor contains correct stylesheets after initialization.
const TESTCASE_URI = TEST_BASE_HTTP + "simple.html";
const EXPECTED_SHEETS = [
{
sheetIndex: 0,
name: /^simple.css$/,
rules: 1,
active: true
}, {
sheetIndex: 1,
name: /^<.*>$/,
rules: 3,
active: false
}
];
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, 2, "The UI contains two style sheets.");
checkSheet(ui.editors[0], EXPECTED_SHEETS[0]);
checkSheet(ui.editors[1], EXPECTED_SHEETS[1]);
});
function checkSheet(editor, expected) {
is(editor.styleSheet.styleSheetIndex, expected.sheetIndex,
"Style sheet has correct index.");
let summary = editor.summary;
let name = summary.querySelector(".stylesheet-name > label")
.getAttribute("value");
ok(expected.name.test(name), "The name '" + name + "' is correct.");
let ruleCount = summary.querySelector(".stylesheet-rule-count").textContent;
is(parseInt(ruleCount, 10), expected.rules, "the rule count is correct");
is(summary.classList.contains("splitview-active"), expected.active,
"The active status for this sheet is correct.");
}

View file

@ -0,0 +1,88 @@
/* 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 inline style sheets get correct names if they are saved to disk and
// that those names survice a reload but not navigation to another page.
const FIRST_TEST_PAGE = TEST_BASE_HTTP + "inline-1.html";
const SECOND_TEST_PAGE = TEST_BASE_HTTP + "inline-2.html";
const SAVE_PATH = "test.css";
add_task(function* () {
let { ui } = yield openStyleEditorForURL(FIRST_TEST_PAGE);
testIndentifierGeneration(ui);
yield saveFirstInlineStyleSheet(ui);
yield testFriendlyNamesAfterSave(ui);
yield reloadPageAndWaitForStyleSheets(ui);
yield testFriendlyNamesAfterSave(ui);
yield navigateToAndWaitForStyleSheets(SECOND_TEST_PAGE, ui);
yield testFriendlyNamesAfterNavigation(ui);
});
function testIndentifierGeneration(ui) {
let fakeStyleSheetFile = {
"href": "http://example.com/test.css",
"nodeHref": "http://example.com/",
"styleSheetIndex": 1
};
let fakeInlineStyleSheet = {
"href": null,
"nodeHref": "http://example.com/",
"styleSheetIndex": 2
};
is(ui.getStyleSheetIdentifier(fakeStyleSheetFile),
"http://example.com/test.css",
"URI is the identifier of style sheet file.");
is(ui.getStyleSheetIdentifier(fakeInlineStyleSheet),
"inline-2-at-http://example.com/",
"Inline sheets are identified by their page and position in the page.");
}
function saveFirstInlineStyleSheet(ui) {
let deferred = defer();
let editor = ui.editors[0];
let destFile = FileUtils.getFile("ProfD", [SAVE_PATH]);
editor.saveToFile(destFile, function (file) {
ok(file, "File was correctly saved.");
deferred.resolve();
});
return deferred.promise;
}
function testFriendlyNamesAfterSave(ui) {
let firstEditor = ui.editors[0];
let secondEditor = ui.editors[1];
// The friendly name of first sheet should've been remembered, the second
// should not be the same (bug 969900).
is(firstEditor.friendlyName, SAVE_PATH,
"Friendly name is correct for the saved inline style sheet.");
isnot(secondEditor.friendlyName, SAVE_PATH,
"Friendly name for the second inline sheet isn't the same as the first.");
return promise.resolve(null);
}
function testFriendlyNamesAfterNavigation(ui) {
let firstEditor = ui.editors[0];
let secondEditor = ui.editors[1];
// Inline style sheets shouldn't have the name of previously saved file as the
// page is different.
isnot(firstEditor.friendlyName, SAVE_PATH,
"The first editor doesn't have the save path as a friendly name.");
isnot(secondEditor.friendlyName, SAVE_PATH,
"The second editor doesn't have the save path as a friendly name.");
return promise.resolve(null);
}

View file

@ -0,0 +1,36 @@
/* 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 style editor loads correctly.
const TESTCASE_URI = TEST_BASE_HTTP + "longload.html";
add_task(function* () {
// launch Style Editor right when the tab is created (before load)
// this checks that the Style Editor still launches correctly when it is
// opened *while* the page is still loading. The Style Editor should not
// signal that it is loaded until the accompanying content page is loaded.
let tabAdded = addTab(TESTCASE_URI);
let target = TargetFactory.forTab(gBrowser.selectedTab);
let styleEditorLoaded = gDevTools.showToolbox(target, "styleeditor");
yield Promise.all([tabAdded, styleEditorLoaded]);
let toolbox = gDevTools.getToolbox(target);
let panel = toolbox.getPanel("styleeditor");
let { panelWindow } = panel;
let root = panelWindow.document.querySelector(".splitview-root");
ok(!root.classList.contains("loading"),
"style editor root element does not have 'loading' class name anymore");
let button = panelWindow.document.querySelector(".style-editor-newButton");
ok(!button.hasAttribute("disabled"),
"new style sheet button is enabled");
button = panelWindow.document.querySelector(".style-editor-importButton");
ok(!button.hasAttribute("disabled"),
"import button is enabled");
});

View file

@ -0,0 +1,63 @@
/* 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 stylesheets can be loaded correctly with containers
// (bug 1282660).
const TESTCASE_URI = TEST_BASE_HTTP + "simple.html";
const EXPECTED_SHEETS = [
{
sheetIndex: 0,
name: /^simple.css$/,
rules: 1,
active: true
}, {
sheetIndex: 1,
name: /^<.*>$/,
rules: 3,
active: false
}
];
add_task(function* () {
// Using the personal container.
let userContextId = 1;
let { tab } = yield* openTabInUserContext(TESTCASE_URI, userContextId);
let { ui } = yield openStyleEditor(tab);
is(ui.editors.length, 2, "The UI contains two style sheets.");
checkSheet(ui.editors[0], EXPECTED_SHEETS[0]);
checkSheet(ui.editors[1], EXPECTED_SHEETS[1]);
});
function* openTabInUserContext(uri, userContextId) {
// Open the tab in the correct userContextId.
let tab = gBrowser.addTab(uri, {userContextId});
// Select tab and make sure its browser is focused.
gBrowser.selectedTab = tab;
tab.ownerDocument.defaultView.focus();
let browser = gBrowser.getBrowserForTab(tab);
yield BrowserTestUtils.browserLoaded(browser);
return {tab, browser};
}
function checkSheet(editor, expected) {
is(editor.styleSheet.styleSheetIndex, expected.sheetIndex,
"Style sheet has correct index.");
let summary = editor.summary;
let name = summary.querySelector(".stylesheet-name > label")
.getAttribute("value");
ok(expected.name.test(name), "The name '" + name + "' is correct.");
let ruleCount = summary.querySelector(".stylesheet-rule-count").textContent;
is(parseInt(ruleCount, 10), expected.rules, "the rule count is correct");
is(summary.classList.contains("splitview-active"), expected.active,
"The active status for this sheet is correct.");
}

View file

@ -0,0 +1,143 @@
/* 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";
// https rather than chrome to improve coverage
const TESTCASE_URI = TEST_BASE_HTTPS + "media-rules.html";
const MEDIA_PREF = "devtools.styleeditor.showMediaSidebar";
const RESIZE = 300;
const LABELS = ["not all", "all", "(max-width: 400px)",
"(min-height: 300px) and (max-height: 320px)",
"(max-width: 600px)"];
const LINE_NOS = [1, 7, 19, 25, 31];
const NEW_RULE = "\n@media (max-width: 600px) { div { color: blue; } }";
waitForExplicitFinish();
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, 2, "correct number of editors");
// Test first plain css editor
let plainEditor = ui.editors[0];
yield openEditor(plainEditor);
testPlainEditor(plainEditor);
// Test editor with @media rules
let mediaEditor = ui.editors[1];
yield openEditor(mediaEditor);
testMediaEditor(mediaEditor);
// Test that sidebar hides when flipping pref
yield testShowHide(ui, mediaEditor);
// Test adding a rule updates the list
yield testMediaRuleAdded(ui, mediaEditor);
// Test resizing and seeing @media matching state change
let originalWidth = window.outerWidth;
let originalHeight = window.outerHeight;
let onMatchesChange = listenForMediaChange(ui);
window.resizeTo(RESIZE, RESIZE);
yield onMatchesChange;
testMediaMatchChanged(mediaEditor);
window.resizeTo(originalWidth, originalHeight);
});
function testPlainEditor(editor) {
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
is(sidebar.hidden, true, "sidebar is hidden on editor without @media");
}
function testMediaEditor(editor) {
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
is(sidebar.hidden, false, "sidebar is showing on editor with @media");
let entries = [...sidebar.querySelectorAll(".media-rule-label")];
is(entries.length, 4, "four @media rules displayed in sidebar");
testRule(entries[0], LABELS[0], false, LINE_NOS[0]);
testRule(entries[1], LABELS[1], true, LINE_NOS[1]);
testRule(entries[2], LABELS[2], false, LINE_NOS[2]);
testRule(entries[3], LABELS[3], false, LINE_NOS[3]);
}
function testMediaMatchChanged(editor) {
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
let cond = sidebar.querySelectorAll(".media-rule-condition")[2];
is(cond.textContent, "(max-width: 400px)",
"third rule condition text is correct");
ok(!cond.classList.contains("media-condition-unmatched"),
"media rule is now matched after resizing");
}
function* testShowHide(UI, editor) {
let sidebarChange = listenForMediaChange(UI);
Services.prefs.setBoolPref(MEDIA_PREF, false);
yield sidebarChange;
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
is(sidebar.hidden, true, "sidebar is hidden after flipping pref");
sidebarChange = listenForMediaChange(UI);
Services.prefs.clearUserPref(MEDIA_PREF);
yield sidebarChange;
is(sidebar.hidden, false, "sidebar is showing after flipping pref back");
}
function* testMediaRuleAdded(UI, editor) {
yield editor.getSourceEditor();
let text = editor.sourceEditor.getText();
text += NEW_RULE;
let listChange = listenForMediaChange(UI);
editor.sourceEditor.setText(text);
yield listChange;
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
let entries = [...sidebar.querySelectorAll(".media-rule-label")];
is(entries.length, 5, "five @media rules after changing text");
testRule(entries[4], LABELS[4], false, LINE_NOS[4]);
}
function testRule(rule, text, matches, lineno) {
let cond = rule.querySelector(".media-rule-condition");
is(cond.textContent, text, "media label is correct for " + text);
let matched = !cond.classList.contains("media-condition-unmatched");
ok(matches ? matched : !matched,
"media rule is " + (matches ? "matched" : "unmatched"));
let line = rule.querySelector(".media-rule-line");
is(line.textContent, ":" + lineno, "correct line number shown");
}
/* Helpers */
function openEditor(editor) {
getLinkFor(editor).click();
return editor.getSourceEditor();
}
function listenForMediaChange(UI) {
let deferred = defer();
UI.once("media-list-changed", () => {
deferred.resolve();
});
return deferred.promise;
}
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}

View file

@ -0,0 +1,144 @@
/* 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";
/* Tests responsive mode links for
* @media sidebar width and height related conditions */
const asyncStorage = require("devtools/shared/async-storage");
Services.prefs.setCharPref("devtools.devices.url",
"http://example.com/browser/devtools/client/responsive.html/test/browser/devices.json");
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.devices.url");
asyncStorage.removeItem("devtools.devices.url_cache");
});
const mgr = "resource://devtools/client/responsivedesign/responsivedesign.jsm";
const {ResponsiveUIManager} = Cu.import(mgr, {});
const TESTCASE_URI = TEST_BASE_HTTPS + "media-rules.html";
const responsiveModeToggleClass = ".media-responsive-mode-toggle";
add_task(function* () {
let {ui} = yield openStyleEditorForURL(TESTCASE_URI);
let editor = ui.editors[1];
yield openEditor(editor);
let tab = gBrowser.selectedTab;
testNumberOfLinks(editor);
yield testMediaLink(editor, tab, ui, 2, "width", 400);
yield testMediaLink(editor, tab, ui, 3, "height", 300);
yield closeRDM(tab, ui);
doFinalChecks(editor);
});
function testNumberOfLinks(editor) {
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
let conditions = sidebar.querySelectorAll(".media-rule-condition");
info("Testing if media rules have the appropriate number of links");
ok(!conditions[0].querySelector(responsiveModeToggleClass),
"There should be no links in the first media rule.");
ok(!conditions[1].querySelector(responsiveModeToggleClass),
"There should be no links in the second media rule.");
ok(conditions[2].querySelector(responsiveModeToggleClass),
"There should be 1 responsive mode link in the media rule");
is(conditions[3].querySelectorAll(responsiveModeToggleClass).length, 2,
"There should be 2 responsive mode links in the media rule");
}
function* testMediaLink(editor, tab, ui, itemIndex, type, value) {
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
let conditions = sidebar.querySelectorAll(".media-rule-condition");
let onMediaChange = once(ui, "media-list-changed");
info("Launching responsive mode");
conditions[itemIndex].querySelector(responsiveModeToggleClass).click();
let rdmUI = ResponsiveUIManager.getResponsiveUIForTab(tab);
let onContentResize = waitForResizeTo(rdmUI, type, value);
rdmUI.transitionsEnabled = false;
info("Waiting for the @media list to update");
yield onMediaChange;
yield onContentResize;
ok(ResponsiveUIManager.isActiveForTab(tab),
"Responsive mode should be active.");
conditions = sidebar.querySelectorAll(".media-rule-condition");
ok(!conditions[itemIndex].classList.contains("media-condition-unmatched"),
"media rule should now be matched after responsive mode is active");
let dimension = (yield getSizing(rdmUI))[type];
is(dimension, value, `${type} should be properly set.`);
}
function* closeRDM(tab, ui) {
info("Closing responsive mode");
ResponsiveUIManager.toggle(window, tab);
let onMediaChange = waitForNEvents(ui, "media-list-changed", 2);
yield once(ResponsiveUIManager, "off");
yield onMediaChange;
ok(!ResponsiveUIManager.isActiveForTab(tab),
"Responsive mode should no longer be active.");
}
function doFinalChecks(editor) {
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
let conditions = sidebar.querySelectorAll(".media-rule-condition");
conditions = sidebar.querySelectorAll(".media-rule-condition");
ok(conditions[2].classList.contains("media-condition-unmatched"),
"The width condition should now be unmatched");
ok(conditions[3].classList.contains("media-condition-unmatched"),
"The height condition should now be unmatched");
}
/* Helpers */
function waitForResizeTo(rdmUI, type, value) {
return new Promise(resolve => {
let onResize = (_, data) => {
if (data[type] != value) {
return;
}
ResponsiveUIManager.off("content-resize", onResize);
if (rdmUI.off) {
rdmUI.off("content-resize", onResize);
}
info(`Got content-resize to a ${type} of ${value}`);
resolve();
};
info(`Waiting for content-resize to a ${type} of ${value}`);
// Old RDM emits on manager
ResponsiveUIManager.on("content-resize", onResize);
// New RDM emits on ui
if (rdmUI.on) {
rdmUI.on("content-resize", onResize);
}
});
}
function* getSizing(rdmUI) {
let browser = rdmUI.getViewportBrowser();
let sizing = yield ContentTask.spawn(browser, {}, function* () {
return {
width: content.innerWidth,
height: content.innerHeight
};
});
return sizing;
}
function openEditor(editor) {
getLinkFor(editor).click();
return editor.getSourceEditor();
}
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}

View file

@ -0,0 +1,71 @@
/* 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";
// https rather than chrome to improve coverage
const TESTCASE_URI = TEST_BASE_HTTPS + "media-rules-sourcemaps.html";
const MAP_PREF = "devtools.styleeditor.source-maps-enabled";
const LABELS = ["screen and (max-width: 320px)",
"screen and (min-width: 1200px)"];
const LINE_NOS = [5, 8];
waitForExplicitFinish();
add_task(function* () {
Services.prefs.setBoolPref(MAP_PREF, true);
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
yield listenForMediaChange(ui);
is(ui.editors.length, 1, "correct number of editors");
// Test editor with @media rules
let mediaEditor = ui.editors[0];
yield openEditor(mediaEditor);
testMediaEditor(mediaEditor);
Services.prefs.clearUserPref(MAP_PREF);
});
function testMediaEditor(editor) {
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
is(sidebar.hidden, false, "sidebar is showing on editor with @media");
let entries = [...sidebar.querySelectorAll(".media-rule-label")];
is(entries.length, 2, "two @media rules displayed in sidebar");
testRule(entries[0], LABELS[0], LINE_NOS[0]);
testRule(entries[1], LABELS[1], LINE_NOS[1]);
}
function testRule(rule, text, lineno) {
let cond = rule.querySelector(".media-rule-condition");
is(cond.textContent, text, "media label is correct for " + text);
let line = rule.querySelector(".media-rule-line");
is(line.textContent, ":" + lineno, "correct line number shown");
}
/* Helpers */
function openEditor(editor) {
getLinkFor(editor).click();
return editor.getSourceEditor();
}
function listenForMediaChange(UI) {
let deferred = defer();
UI.once("media-list-changed", () => {
deferred.resolve();
});
return deferred.promise;
}
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}

View file

@ -0,0 +1,30 @@
"use strict";
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Checks that the style editor manages to finalize its stylesheet loading phase
// even if one stylesheet is missing, and that an error message is displayed.
const TESTCASE_URI = TEST_BASE + "missing.html";
add_task(function* () {
let { ui, toolbox, panel } = yield openStyleEditorForURL(TESTCASE_URI);
// Note that we're not testing for a specific number of stylesheet editors
// below because the test-page is loaded with chrome:// URL and, right now,
// that means UA stylesheets are shown. So we avoid hardcoding the number of
// stylesheets here.
ok(ui.editors.length, "The UI contains style sheets.");
let rootEl = panel.panelWindow.document.getElementById("style-editor-chrome");
ok(!rootEl.classList.contains("loading"), "The loading indicator is hidden");
let notifBox = toolbox.getNotificationBox();
let notif = notifBox.getCurrentNotification();
ok(notif, "The notification box contains a message");
ok(notif.label.indexOf("Style sheet could not be loaded") !== -1,
"The error message is the correct one");
ok(notif.label.indexOf("missing-stylesheet.css") !== -1,
"The error message contains the missing stylesheet's URL");
});

View file

@ -0,0 +1,32 @@
/* 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 selected sheet and cursor position is reset during navigation.
const TESTCASE_URI = TEST_BASE_HTTPS + "simple.html";
const NEW_URI = TEST_BASE_HTTPS + "media.html";
const LINE_NO = 5;
const COL_NO = 3;
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, 2, "Two sheets present after load.");
info("Selecting the second editor");
yield ui.selectStyleSheet(ui.editors[1].styleSheet, LINE_NO, COL_NO);
yield navigateToAndWaitForStyleSheets(NEW_URI, ui);
info("Waiting for source editor to be ready.");
yield ui.editors[0].getSourceEditor();
is(ui.selectedEditor, ui.editors[0], "first editor is selected");
let {line, ch} = ui.selectedEditor.sourceEditor.getCursor();
is(line, 0, "first line is selected");
is(ch, 0, "first column is selected");
});

View file

@ -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 new sheets can be added and edited.
const TESTCASE_URI = TEST_BASE_HTTP + "simple.html";
const TESTCASE_CSS_SOURCE = "body{background-color:red;";
add_task(function* () {
let { panel, ui } = yield openStyleEditorForURL(TESTCASE_URI);
let editor = yield createNew(ui, panel.panelWindow);
yield testInitialState(editor);
let originalHref = editor.styleSheet.href;
let waitForPropertyChange = onPropertyChange(editor);
yield typeInEditor(editor, panel.panelWindow);
yield waitForPropertyChange;
testUpdated(editor, originalHref);
});
function createNew(ui, panelWindow) {
info("Creating a new stylesheet now");
let deferred = defer();
ui.once("editor-added", (ev, editor) => {
editor.getSourceEditor().then(deferred.resolve);
});
waitForFocus(function () {
// create a new style sheet
let newButton = panelWindow.document
.querySelector(".style-editor-newButton");
ok(newButton, "'new' button exists");
EventUtils.synthesizeMouseAtCenter(newButton, {}, panelWindow);
}, panelWindow);
return deferred.promise;
}
function onPropertyChange(editor) {
let deferred = defer();
editor.styleSheet.on("property-change", function onProp(property) {
// wait for text to be entered fully
let text = editor.sourceEditor.getText();
if (property == "ruleCount" && text == TESTCASE_CSS_SOURCE + "}") {
editor.styleSheet.off("property-change", onProp);
deferred.resolve();
}
});
return deferred.promise;
}
function* testInitialState(editor) {
info("Testing the initial state of the new editor");
let summary = editor.summary;
ok(editor.sourceLoaded, "new editor is loaded when attached");
ok(editor.isNew, "new editor has isNew flag");
ok(editor.sourceEditor.hasFocus(), "new editor has focus");
summary = editor.summary;
let ruleCount = summary.querySelector(".stylesheet-rule-count").textContent;
is(parseInt(ruleCount, 10), 0, "new editor initially shows 0 rules");
let color = yield getComputedStyleProperty({
selector: "body",
name: "background-color"
});
is(color, "rgb(255, 255, 255)",
"content's background color is initially white");
}
function typeInEditor(editor, panelWindow) {
let deferred = defer();
waitForFocus(function () {
for (let c of TESTCASE_CSS_SOURCE) {
EventUtils.synthesizeKey(c, {}, panelWindow);
}
ok(editor.unsaved, "new editor has unsaved flag");
deferred.resolve();
}, panelWindow);
return deferred.promise;
}
function testUpdated(editor, originalHref) {
info("Testing the state of the new editor after editing it");
is(editor.sourceEditor.getText(), TESTCASE_CSS_SOURCE + "}",
"rule bracket has been auto-closed");
let ruleCount = editor.summary.querySelector(".stylesheet-rule-count")
.textContent;
is(parseInt(ruleCount, 10), 1,
"new editor shows 1 rule after modification");
is(editor.styleSheet.href, originalHref,
"style sheet href did not change");
}

View file

@ -0,0 +1,28 @@
/* 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 'no styles' indicator is shown if a page doesn't contain any style
// sheets.
const TESTCASE_URI = TEST_BASE_HTTP + "nostyle.html";
add_task(function* () {
let { panel } = yield openStyleEditorForURL(TESTCASE_URI);
let { panelWindow } = panel;
let root = panelWindow.document.querySelector(".splitview-root");
ok(!root.classList.contains("loading"),
"style editor root element does not have 'loading' class name anymore");
ok(root.querySelector(".empty.placeholder"), "showing 'no style' indicator");
let button = panelWindow.document.querySelector(".style-editor-newButton");
ok(!button.hasAttribute("disabled"),
"new style sheet button is enabled");
button = panelWindow.document.querySelector(".style-editor-importButton");
ok(!button.hasAttribute("disabled"),
"import button is enabled");
});

View file

@ -0,0 +1,121 @@
/* 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";
// A test to check the 'Open Link in new tab' functionality in the
// context menu item for stylesheets (bug 992947).
const TESTCASE_URI = TEST_BASE_HTTPS + "simple.html";
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
yield rightClickStyleSheet(ui, ui.editors[0]);
is(ui._openLinkNewTabItem.getAttribute("disabled"), "false",
"The menu item is not disabled");
is(ui._openLinkNewTabItem.getAttribute("hidden"), "false",
"The menu item is not hidden");
let url = "https://example.com/browser/devtools/client/styleeditor/test/" +
"simple.css";
is(ui._contextMenuStyleSheet.href, url, "Correct URL for sheet");
let originalOpenUILinkIn = ui._window.openUILinkIn;
let tabOpenedDefer = defer();
ui._window.openUILinkIn = newUrl => {
// Reset the actual openUILinkIn function before proceeding.
ui._window.openUILinkIn = originalOpenUILinkIn;
is(newUrl, url, "The correct tab has been opened");
tabOpenedDefer.resolve();
};
ui._openLinkNewTabItem.click();
info(`Waiting for a tab to open - ${url}`);
yield tabOpenedDefer.promise;
yield rightClickInlineStyleSheet(ui, ui.editors[1]);
is(ui._openLinkNewTabItem.getAttribute("disabled"), "true",
"The menu item is disabled");
is(ui._openLinkNewTabItem.getAttribute("hidden"), "false",
"The menu item is not hidden");
yield rightClickNoStyleSheet(ui);
is(ui._openLinkNewTabItem.getAttribute("hidden"), "true",
"The menu item is not hidden");
});
function onPopupShow(contextMenu) {
let deferred = defer();
contextMenu.addEventListener("popupshown", function onpopupshown() {
contextMenu.removeEventListener("popupshown", onpopupshown);
deferred.resolve();
});
return deferred.promise;
}
function onPopupHide(contextMenu) {
let deferred = defer();
contextMenu.addEventListener("popuphidden", function popuphidden() {
contextMenu.removeEventListener("popuphidden", popuphidden);
deferred.resolve();
});
return deferred.promise;
}
function rightClickStyleSheet(ui, editor) {
let deferred = defer();
onPopupShow(ui._contextMenu).then(()=> {
onPopupHide(ui._contextMenu).then(() => {
deferred.resolve();
});
ui._contextMenu.hidePopup();
});
EventUtils.synthesizeMouseAtCenter(
editor.summary.querySelector(".stylesheet-name"),
{button: 2, type: "contextmenu"},
ui._window);
return deferred.promise;
}
function rightClickInlineStyleSheet(ui, editor) {
let deferred = defer();
onPopupShow(ui._contextMenu).then(()=> {
onPopupHide(ui._contextMenu).then(() => {
deferred.resolve();
});
ui._contextMenu.hidePopup();
});
EventUtils.synthesizeMouseAtCenter(
editor.summary.querySelector(".stylesheet-name"),
{button: 2, type: "contextmenu"},
ui._window);
return deferred.promise;
}
function rightClickNoStyleSheet(ui) {
let deferred = defer();
onPopupShow(ui._contextMenu).then(()=> {
onPopupHide(ui._contextMenu).then(() => {
deferred.resolve();
});
ui._contextMenu.hidePopup();
});
EventUtils.synthesizeMouseAtCenter(
ui._panelDoc.querySelector("#splitview-tpl-summary-stylesheet"),
{button: 2, type: "contextmenu"},
ui._window);
return deferred.promise;
}

View file

@ -0,0 +1,68 @@
/* 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 minified sheets are automatically prettified but other are left
// untouched.
const TESTCASE_URI = TEST_BASE_HTTP + "minified.html";
/*
body {
background:white;
}
div {
font-size:4em;
color:red
}
span {
color:green;
}
*/
const PRETTIFIED_SOURCE = "" +
"body \{\r?\n" +
"\tbackground\:white;\r?\n" +
"\}\r?\n" +
"div \{\r?\n" +
"\tfont\-size\:4em;\r?\n" +
"\tcolor\:red\r?\n" +
"\}\r?\n" +
"span \{\r?\n" +
"\tcolor\:green;\r?\n" +
"\}\r?\n";
/*
body { background: red; }
div {
font-size: 5em;
color: red
}
*/
const ORIGINAL_SOURCE = "" +
"body \{ background\: red; \}\r?\n" +
"div \{\r?\n" +
"font\-size\: 5em;\r?\n" +
"color\: red\r?\n" +
"\}";
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, 2, "Two sheets present.");
info("Testing minified style sheet.");
let editor = yield ui.editors[0].getSourceEditor();
let prettifiedSourceRE = new RegExp(PRETTIFIED_SOURCE);
ok(prettifiedSourceRE.test(editor.sourceEditor.getText()),
"minified source has been prettified automatically");
info("Selecting second, non-minified style sheet.");
yield ui.selectStyleSheet(ui.editors[1].styleSheet);
editor = ui.editors[1];
let originalSourceRE = new RegExp(ORIGINAL_SOURCE);
ok(originalSourceRE.test(editor.sourceEditor.getText()),
"non-minified source has been left untouched");
});

View file

@ -0,0 +1,85 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// This test makes sure that the style editor does not store any
// content CSS files in the permanent cache when opened from PB mode.
const TEST_URL = "http://" + TEST_HOST + "/browser/devtools/client/" +
"styleeditor/test/test_private.html";
const {LoadContextInfo} =
Cu.import("resource://gre/modules/LoadContextInfo.jsm", {});
const cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
.getService(Ci.nsICacheStorageService);
add_task(function* () {
info("Opening a new private window");
let win = OpenBrowserWindow({private: true});
yield waitForDelayedStartupFinished(win);
info("Clearing the browser cache");
cache.clear();
let { toolbox, ui } = yield openStyleEditorForURL(TEST_URL, win);
is(ui.editors.length, 1, "The style editor contains one sheet.");
let editor = ui.editors[0];
yield editor.getSourceEditor();
yield checkDiskCacheFor(TEST_HOST);
yield toolbox.destroy();
let onUnload = new Promise(done => {
win.addEventListener("unload", function listener(event) {
if (event.target == win.document) {
win.removeEventListener("unload", listener);
done();
}
});
});
win.close();
yield onUnload;
});
function checkDiskCacheFor(host) {
let foundPrivateData = false;
let deferred = defer();
Visitor.prototype = {
onCacheStorageInfo: function (num) {
info("disk storage contains " + num + " entries");
},
onCacheEntryInfo: function (uri) {
let urispec = uri.asciiSpec;
info(urispec);
foundPrivateData |= urispec.includes(host);
},
onCacheEntryVisitCompleted: function () {
is(foundPrivateData, false, "web content present in disk cache");
deferred.resolve();
}
};
function Visitor() {}
let storage = cache.diskCacheStorage(LoadContextInfo.default, false);
storage.asyncVisitStorage(new Visitor(),
/* Do walk entries */
true);
return deferred.promise;
}
function waitForDelayedStartupFinished(win) {
let deferred = defer();
Services.obs.addObserver(function observer(subject, topic) {
if (win == subject) {
Services.obs.removeObserver(observer, topic);
deferred.resolve();
}
}, "browser-delayed-startup-finished", false);
return deferred.promise;
}

View file

@ -0,0 +1,34 @@
/* 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 selected sheet and cursor position persists during reload.
const TESTCASE_URI = TEST_BASE_HTTPS + "simple.html";
const LINE_NO = 5;
const COL_NO = 3;
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, 2, "Two sheets present after load.");
info("Selecting the second editor");
yield ui.selectStyleSheet(ui.editors[1].styleSheet, LINE_NO, COL_NO);
yield reloadPageAndWaitForStyleSheets(ui);
is(ui.editors.length, 2, "Two sheets present after reload.");
info("Waiting for source editor to be ready.");
yield ui.editors[1].getSourceEditor();
is(ui.selectedEditor, ui.editors[1],
"second editor is selected after reload");
let {line, ch} = ui.selectedEditor.sourceEditor.getCursor();
is(line, LINE_NO, "correct line selected");
is(ch, COL_NO, "correct column selected");
});

View file

@ -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 editor scrolls to correct line if it's selected with
// * selectStyleSheet (specified line)
// * click on the sidebar item (line before the editor was unselected)
// See bug 1148086.
const SIMPLE = TEST_BASE_HTTP + "simple.css";
const LONG = TEST_BASE_HTTP + "doc_long.css";
const DOCUMENT_WITH_LONG_SHEET = "data:text/html;charset=UTF-8," +
encodeURIComponent(
["<!DOCTYPE html>",
"<html>",
" <head>",
" <title>Editor scroll test page</title>",
' <link rel="stylesheet" type="text/css" href="' + SIMPLE + '">',
' <link rel="stylesheet" type="text/css" href="' + LONG + '">',
" </head>",
" <body>Editor scroll test page</body>",
"</html>"
].join("\n"));
const LINE_TO_SELECT = 201;
add_task(function* () {
let { ui } = yield openStyleEditorForURL(DOCUMENT_WITH_LONG_SHEET);
is(ui.editors.length, 2, "Two editors present.");
let simpleEditor = ui.editors[0];
let longEditor = ui.editors[1];
info(`Selecting doc_long.css and scrolling to line ${LINE_TO_SELECT}`);
// We need to wait for editor-selected if we want to check the scroll
// position as scrolling occurs after selectStyleSheet resolves but before the
// event is emitted.
let selectEventPromise = waitForEditorToBeSelected(longEditor, ui);
ui.selectStyleSheet(longEditor.styleSheet, LINE_TO_SELECT);
yield selectEventPromise;
info("Checking that the correct line is visible after initial load");
let { from, to } = longEditor.sourceEditor.getViewport();
info(`Lines ${from}-${to} are visible (expected ${LINE_TO_SELECT}).`);
ok(from <= LINE_TO_SELECT, "The editor scrolled too much.");
ok(to >= LINE_TO_SELECT, "The editor scrolled too little.");
let initialScrollTop = longEditor.sourceEditor.getScrollInfo().top;
info(`Storing scrollTop = ${initialScrollTop} for later comparison.`);
info("Selecting the first editor (simple.css)");
yield ui.selectStyleSheet(simpleEditor.styleSheet);
info("Selecting doc_long.css again.");
selectEventPromise = waitForEditorToBeSelected(longEditor, ui);
// Can't use ui.selectStyleSheet here as it will scroll the editor back to top
// and we want to check that the previous scroll position is restored.
let summary = yield ui.getEditorSummary(longEditor);
ui._view.activeSummary = summary;
info("Waiting for doc_long.css to be selected.");
yield selectEventPromise;
let scrollTop = longEditor.sourceEditor.getScrollInfo().top;
is(scrollTop, initialScrollTop,
"Scroll top was restored after the sheet was selected again.");
});
/**
* A helper that waits "editor-selected" event for given editor.
*
* @param {StyleSheetEditor} editor
* The editor to wait for.
* @param {StyleEditorUI} ui
* The StyleEditorUI the editor belongs to.
*/
var waitForEditorToBeSelected = Task.async(function* (editor, ui) {
info(`Waiting for ${editor.friendlyName} to be selected.`);
let selected = yield ui.once("editor-selected");
while (selected != editor) {
info(`Ignored editor-selected for editor ${editor.friendlyName}.`);
selected = yield ui.once("editor-selected");
}
info(`Got editor-selected for ${editor.friendlyName}.`);
});

View file

@ -0,0 +1,26 @@
/* 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 StyleEditorUI.selectStyleSheet selects the correct sheet, line and
// column.
const TESTCASE_URI = TEST_BASE_HTTPS + "simple.html";
const LINE_NO = 5;
const COL_NO = 0;
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
let editor = ui.editors[1];
info("Selecting style sheet #1.");
yield ui.selectStyleSheet(editor.styleSheet.href, LINE_NO);
is(ui.selectedEditor, ui.editors[1], "Second editor is selected.");
let {line, ch} = ui.selectedEditor.sourceEditor.getCursor();
is(line, LINE_NO, "correct line selected");
is(ch, COL_NO, "correct column selected");
});

View file

@ -0,0 +1,33 @@
/* 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";
// Covers the case from Bug 1128747, where loading a sourcemapped
// file prevents the correct editor from being selected on load,
// and causes a second iframe to be appended when the user clicks
// editor in the list.
const TESTCASE_URI = TEST_BASE_HTTPS + "sourcemaps-large.html";
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
yield openEditor(ui.editors[0]);
let iframes = ui.selectedEditor.details.querySelectorAll("iframe");
is(iframes.length, 1, "There is only one editor iframe");
ok(ui.selectedEditor.summary.classList.contains("splitview-active"),
"The editor is selected");
});
function openEditor(editor) {
getLinkFor(editor).click();
return editor.getSourceEditor();
}
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}

View file

@ -0,0 +1,162 @@
/* 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";
const TESTCASE_URI_HTML = TEST_BASE_HTTP + "sourcemaps-watching.html";
const TESTCASE_URI_CSS = TEST_BASE_HTTP + "sourcemap-css/sourcemaps.css";
const TESTCASE_URI_REG_CSS = TEST_BASE_HTTP + "simple.css";
const TESTCASE_URI_SCSS = TEST_BASE_HTTP + "sourcemap-sass/sourcemaps.scss";
const TESTCASE_URI_MAP = TEST_BASE_HTTP + "sourcemap-css/sourcemaps.css.map";
const TESTCASE_SCSS_NAME = "sourcemaps.scss";
const TRANSITIONS_PREF = "devtools.styleeditor.transitions";
const CSS_TEXT = "* { color: blue }";
const {FileUtils} = Components.utils.import("resource://gre/modules/FileUtils.jsm", {});
const {NetUtil} = Components.utils.import("resource://gre/modules/NetUtil.jsm", {});
add_task(function* () {
yield new Promise(resolve => {
SpecialPowers.pushPrefEnv({"set": [
[TRANSITIONS_PREF, false]
]}, resolve);
});
// copy all our files over so we don't screw them up for other tests
let HTMLFile = yield copy(TESTCASE_URI_HTML, ["sourcemaps.html"]);
let CSSFile = yield copy(TESTCASE_URI_CSS,
["sourcemap-css", "sourcemaps.css"]);
yield copy(TESTCASE_URI_SCSS, ["sourcemap-sass", "sourcemaps.scss"]);
yield copy(TESTCASE_URI_MAP, ["sourcemap-css", "sourcemaps.css.map"]);
yield copy(TESTCASE_URI_REG_CSS, ["simple.css"]);
let uri = Services.io.newFileURI(HTMLFile);
let testcaseURI = uri.resolve("");
let { ui } = yield openStyleEditorForURL(testcaseURI);
let editor = ui.editors[1];
if (getStylesheetNameFor(editor) != TESTCASE_SCSS_NAME) {
editor = ui.editors[2];
}
is(getStylesheetNameFor(editor), TESTCASE_SCSS_NAME, "found scss editor");
let link = getLinkFor(editor);
link.click();
yield editor.getSourceEditor();
let color = yield getComputedStyleProperty({selector: "div", name: "color"});
is(color, "rgb(255, 0, 102)", "div is red before saving file");
// let styleApplied = defer();
let styleApplied = editor.once("style-applied");
yield pauseForTimeChange();
// Edit and save Sass in the editor. This will start off a file-watching
// process waiting for the CSS file to change.
yield editSCSS(editor);
// We can't run Sass or another compiler, so we fake it by just
// directly changing the CSS file.
yield editCSSFile(CSSFile);
info("wrote to CSS file, waiting for style-applied event");
yield styleApplied;
color = yield getComputedStyleProperty({selector: "div", name: "color"});
is(color, "rgb(0, 0, 255)", "div is blue after saving file");
});
function editSCSS(editor) {
let deferred = defer();
editor.sourceEditor.setText(CSS_TEXT);
editor.saveToFile(null, function (file) {
ok(file, "Scss file should be saved");
deferred.resolve();
});
return deferred.promise;
}
function editCSSFile(CSSFile) {
return write(CSS_TEXT, CSSFile);
}
function pauseForTimeChange() {
let deferred = defer();
// We have to wait for the system time to turn over > 1000 ms so that
// our file's last change time will show a change. This reflects what
// would happen in real life with a user manually saving the file.
setTimeout(deferred.resolve, 2000);
return deferred.promise;
}
/* Helpers */
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}
function getStylesheetNameFor(editor) {
return editor.summary.querySelector(".stylesheet-name > label")
.getAttribute("value");
}
function copy(srcChromeURL, destFilePath) {
let destFile = FileUtils.getFile("ProfD", destFilePath);
return write(read(srcChromeURL), destFile);
}
function read(srcChromeURL) {
let scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
.getService(Ci.nsIScriptableInputStream);
let channel = NetUtil.newChannel({
uri: srcChromeURL,
loadUsingSystemPrincipal: true
});
let input = channel.open2();
scriptableStream.init(input);
let data = "";
while (input.available()) {
data = data.concat(scriptableStream.read(input.available()));
}
scriptableStream.close();
input.close();
return data;
}
function write(data, file) {
let deferred = defer();
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let istream = converter.convertToInputStream(data);
let ostream = FileUtils.openSafeFileOutputStream(file);
NetUtil.asyncCopy(istream, ostream, function (status) {
if (!Components.isSuccessCode(status)) {
info("Coudln't write to " + file.path);
return;
}
deferred.resolve(file);
});
return deferred.promise;
}

View file

@ -0,0 +1,149 @@
/* 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";
// https rather than chrome to improve coverage
const TESTCASE_URI = TEST_BASE_HTTPS + "sourcemaps.html";
const PREF = "devtools.styleeditor.source-maps-enabled";
const contents = {
"sourcemaps.scss": [
"",
"$paulrougetpink: #f06;",
"",
"div {",
" color: $paulrougetpink;",
"}",
"",
"span {",
" background-color: #EEE;",
"}"
].join("\n"),
"contained.scss": [
"$pink: #f06;",
"",
"#header {",
" color: $pink;",
"}"
].join("\n"),
"sourcemaps.css": [
"div {",
" color: #ff0066; }",
"",
"span {",
" background-color: #EEE; }",
"",
"/*# sourceMappingURL=sourcemaps.css.map */"
].join("\n"),
"contained.css": [
"#header {",
" color: #f06; }",
"",
"/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJma" +
"WxlIjoiIiwic291cmNlcyI6WyJzYXNzL2NvbnRhaW5lZC5zY3NzIl0sIm5hbWVzIjpbXSwi" +
"bWFwcGluZ3MiOiJBQUVBO0VBQ0UsT0FISyIsInNvdXJjZXNDb250ZW50IjpbIiRwaW5rOiA" +
"jZjA2O1xuXG4jaGVhZGVyIHtcbiAgY29sb3I6ICRwaW5rO1xufSJdfQ==*/"
].join("\n"),
"test-stylus.styl": [
"paulrougetpink = #f06;",
"",
"div",
" color: paulrougetpink",
"",
"span",
" background-color: #EEE",
""
].join("\n"),
"test-stylus.css": [
"div {",
" color: #f06;",
"}",
"span {",
" background-color: #eee;",
"}",
"/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb" +
"3VyY2VzIjpbInRlc3Qtc3R5bHVzLnN0eWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFB" +
"RUE7RUFDRSxPQUFPLEtBQVA7O0FBRUY7RUFDRSxrQkFBa0IsS0FBbEIiLCJmaWxlIjoidGV" +
"zdC1zdHlsdXMuY3NzIiwic291cmNlc0NvbnRlbnQiOlsicGF1bHJvdWdldHBpbmsgPSAjZj" +
"A2O1xuXG5kaXZcbiAgY29sb3I6IHBhdWxyb3VnZXRwaW5rXG5cbnNwYW5cbiAgYmFja2dyb" +
"3VuZC1jb2xvcjogI0VFRVxuIl19 */"
].join("\n")
};
const cssNames = ["sourcemaps.css", "contained.css", "test-stylus.css"];
const origNames = ["sourcemaps.scss", "contained.scss", "test-stylus.styl"];
waitForExplicitFinish();
add_task(function* () {
let {ui} = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, 4,
"correct number of editors with source maps enabled");
// Test first plain css editor
testFirstEditor(ui.editors[0]);
// Test Scss editors
yield testEditor(ui.editors[1], origNames);
yield testEditor(ui.editors[2], origNames);
yield testEditor(ui.editors[3], origNames);
// Test disabling original sources
yield togglePref(ui);
is(ui.editors.length, 4, "correct number of editors after pref toggled");
// Test CSS editors
yield testEditor(ui.editors[1], cssNames);
yield testEditor(ui.editors[2], cssNames);
yield testEditor(ui.editors[3], cssNames);
Services.prefs.clearUserPref(PREF);
});
function testFirstEditor(editor) {
let name = getStylesheetNameFor(editor);
is(name, "simple.css", "First style sheet display name is correct");
}
function testEditor(editor, possibleNames) {
let name = getStylesheetNameFor(editor);
ok(possibleNames.indexOf(name) >= 0, name + " editor name is correct");
return openEditor(editor).then(() => {
let expectedText = contents[name];
let text = editor.sourceEditor.getText();
is(text, expectedText, name + " editor contains expected text");
});
}
/* Helpers */
function togglePref(UI) {
let editorsPromise = UI.once("stylesheets-reset");
let selectedPromise = UI.once("editor-selected");
Services.prefs.setBoolPref(PREF, false);
return promise.all([editorsPromise, selectedPromise]);
}
function openEditor(editor) {
getLinkFor(editor).click();
return editor.getSourceEditor();
}
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}
function getStylesheetNameFor(editor) {
return editor.summary.querySelector(".stylesheet-name > label")
.getAttribute("value");
}

View file

@ -0,0 +1,85 @@
/* 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";
// https rather than chrome to improve coverage
const TESTCASE_URI = TEST_BASE_HTTPS + "sourcemaps-inline.html";
const PREF = "devtools.styleeditor.source-maps-enabled";
const sassContent = `body {
background-color: black;
& > h1 {
color: white;
}
}
`;
const cssContent = `body {
background-color: black;
}
body > h1 {
color: white;
}
` +
"/*# sourceMappingURL=data:application/json;base64,ewoidmVyc2lvbiI6IDMsCiJtY" +
"XBwaW5ncyI6ICJBQUFBLElBQUs7RUFDSCxnQkFBZ0IsRUFBRSxLQUFLO0VBQ3ZCLFNBQU87SUFD" +
"TCxLQUFLLEVBQUUsS0FBSyIsCiJzb3VyY2VzIjogWyJ0ZXN0LnNjc3MiXSwKInNvdXJjZXNDb25" +
"0ZW50IjogWyJib2R5IHtcbiAgYmFja2dyb3VuZC1jb2xvcjogYmxhY2s7XG4gICYgPiBoMSB7XG" +
"4gICAgY29sb3I6IHdoaXRlO1xuICB9XG59XG4iXSwKIm5hbWVzIjogW10sCiJmaWxlIjogInRlc" +
"3QuY3NzIgp9Cg== */";
add_task(function* () {
let {ui} = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, 1,
"correct number of editors with source maps enabled");
yield testEditor(ui.editors[0], "test.scss", sassContent);
// Test disabling original sources
yield togglePref(ui);
is(ui.editors.length, 1, "correct number of editors after pref toggled");
// Test CSS editors
yield testEditor(ui.editors[0], "<inline style sheet #1>", cssContent);
Services.prefs.clearUserPref(PREF);
});
function* testEditor(editor, expectedName, expectedText) {
let name = getStylesheetNameFor(editor);
is(expectedName, name, name + " editor name is correct");
yield openEditor(editor);
let text = editor.sourceEditor.getText();
is(text, expectedText, name + " editor contains expected text");
}
/* Helpers */
function togglePref(UI) {
let editorsPromise = UI.once("stylesheets-reset");
let selectedPromise = UI.once("editor-selected");
Services.prefs.setBoolPref(PREF, false);
return promise.all([editorsPromise, selectedPromise]);
}
function openEditor(editor) {
getLinkFor(editor).click();
return editor.getSourceEditor();
}
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}
function getStylesheetNameFor(editor) {
return editor.summary.querySelector(".stylesheet-name > label")
.getAttribute("value");
}

View file

@ -0,0 +1,65 @@
/* 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 style sheet list can be navigated with keyboard.
const TESTCASE_URI = TEST_BASE_HTTP + "four.html";
add_task(function* () {
let { panel, ui } = yield openStyleEditorForURL(TESTCASE_URI);
info("Waiting for source editor to load.");
yield ui.editors[0].getSourceEditor();
let selected = ui.once("editor-selected");
info("Testing keyboard navigation on the sheet list.");
testKeyboardNavigation(ui.editors[0], panel);
info("Waiting for editor #2 to be selected due to keyboard navigation.");
yield selected;
ok(ui.editors[2].sourceEditor.hasFocus(), "Editor #2 has focus.");
});
function getStylesheetNameLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}
function testKeyboardNavigation(editor, panel) {
let panelWindow = panel.panelWindow;
let ui = panel.UI;
waitForFocus(function () {
let summary = editor.summary;
EventUtils.synthesizeMouseAtCenter(summary, {}, panelWindow);
let item = getStylesheetNameLinkFor(ui.editors[0]);
is(panelWindow.document.activeElement, item,
"editor 0 item is the active element");
EventUtils.synthesizeKey("VK_DOWN", {}, panelWindow);
item = getStylesheetNameLinkFor(ui.editors[1]);
is(panelWindow.document.activeElement, item,
"editor 1 item is the active element");
EventUtils.synthesizeKey("VK_HOME", {}, panelWindow);
item = getStylesheetNameLinkFor(ui.editors[0]);
is(panelWindow.document.activeElement, item,
"fist editor item is the active element");
EventUtils.synthesizeKey("VK_END", {}, panelWindow);
item = getStylesheetNameLinkFor(ui.editors[3]);
is(panelWindow.document.activeElement, item,
"last editor item is the active element");
EventUtils.synthesizeKey("VK_UP", {}, panelWindow);
item = getStylesheetNameLinkFor(ui.editors[2]);
is(panelWindow.document.activeElement, item,
"editor 2 item is the active element");
EventUtils.synthesizeKey("VK_RETURN", {}, panelWindow);
// this will attach and give focus editor 2
}, panelWindow);
}

View file

@ -0,0 +1,48 @@
/* 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 resizing the source editor container doesn't move the caret.
const TESTCASE_URI = TEST_BASE_HTTP + "simple.html";
const {Toolbox} = require("devtools/client/framework/toolbox");
add_task(function* () {
let { toolbox, ui } = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, 2, "There are 2 style sheets initially");
info("Changing toolbox host to a window.");
yield toolbox.switchHost(Toolbox.HostType.WINDOW);
let editor = yield ui.editors[0].getSourceEditor();
let originalSourceEditor = editor.sourceEditor;
let hostWindow = toolbox.win.parent;
let originalWidth = hostWindow.outerWidth;
let originalHeight = hostWindow.outerHeight;
// to check the caret is preserved
originalSourceEditor.setCursor(originalSourceEditor.getPosition(4));
info("Resizing window.");
hostWindow.resizeTo(120, 480);
let sourceEditor = ui.editors[0].sourceEditor;
is(sourceEditor, originalSourceEditor,
"the editor still references the same Editor instance");
is(sourceEditor.getOffset(sourceEditor.getCursor()), 4,
"the caret position has been preserved");
info("Restoring window to original size.");
hostWindow.resizeTo(originalWidth, originalHeight);
});
registerCleanupFunction(() => {
// Restore the host type for other tests.
Services.prefs.clearUserPref("devtools.toolbox.host");
});

View file

@ -0,0 +1,72 @@
/* 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 changes in the style inspector are synchronized into the
// style editor.
const TESTCASE_URI = TEST_BASE_HTTP + "sync.html";
const expectedText = `
body {
border-width: 15px;
/*! color: red; */
}
#testid {
/*! font-size: 4em; */
}
`;
function* closeAndReopenToolbox() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
yield gDevTools.closeToolbox(target);
let { ui: newui } = yield openStyleEditor();
return newui;
}
add_task(function* () {
yield addTab(TESTCASE_URI);
let { inspector, view } = yield openRuleView();
yield selectNode("#testid", inspector);
let ruleEditor = getRuleViewRuleEditor(view, 1);
// Disable the "font-size" property.
let propEditor = ruleEditor.rule.textProps[0].editor;
let onModification = view.once("ruleview-changed");
propEditor.enable.click();
yield onModification;
// Disable the "color" property. Note that this property is in a
// rule that also contains a non-inherited property -- so this test
// is also testing that property editing works properly in this
// situation.
ruleEditor = getRuleViewRuleEditor(view, 3);
propEditor = ruleEditor.rule.textProps[1].editor;
onModification = view.once("ruleview-changed");
propEditor.enable.click();
yield onModification;
let { ui } = yield openStyleEditor();
let editor = yield ui.editors[0].getSourceEditor();
let text = editor.sourceEditor.getText();
is(text, expectedText, "style inspector changes are synced");
// Close and reopen the toolbox, to see that the edited text remains
// available.
ui = yield closeAndReopenToolbox();
editor = yield ui.editors[0].getSourceEditor();
text = editor.sourceEditor.getText();
is(text, expectedText, "changes remain after close and reopen");
// For the time being, the actor does not update the style's owning
// node's textContent. See bug 1205380.
let textContent = yield ContentTask.spawn(gBrowser.selectedBrowser, null,
function* () {
return content.document.querySelector("style").textContent;
});
isnot(textContent, expectedText, "changes not written back to style node");
});

View file

@ -0,0 +1,45 @@
/* 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 adding a new rule is synced to the style editor.
const TESTCASE_URI = TEST_BASE_HTTP + "sync.html";
const expectedText = `
body {
border-width: 15px;
color: red;
}
#testid {
font-size: 4em;
/*! background-color: yellow; */
}
`;
add_task(function* () {
yield addTab(TESTCASE_URI);
let { inspector, view } = yield openRuleView();
yield selectNode("#testid", inspector);
info("Focusing a new property name in the rule-view");
let ruleEditor = getRuleViewRuleEditor(view, 1);
let editor = yield focusEditableField(view, ruleEditor.closeBrace);
is(inplaceEditor(ruleEditor.newPropSpan), editor,
"The new property editor has focus");
let input = editor.input;
input.value = "/* background-color: yellow; */";
info("Pressing return to commit and focus the new value field");
let onModifications = view.once("ruleview-changed");
EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow);
yield onModifications;
let { ui } = yield openStyleEditor();
let sourceEditor = yield ui.editors[0].getSourceEditor();
let text = sourceEditor.sourceEditor.getText();
is(text, expectedText, "selector edits are synced");
});

View file

@ -0,0 +1,31 @@
/* 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 adding a new rule is synced to the style editor.
const TESTCASE_URI = TEST_BASE_HTTP + "sync.html";
const expectedText = `
#testid {
}`;
add_task(function* () {
yield addTab(TESTCASE_URI);
let { inspector, view } = yield openRuleView();
yield selectNode("#testid", inspector);
let onRuleViewChanged = once(view, "ruleview-changed");
view.addRuleButton.click();
yield onRuleViewChanged;
let { ui } = yield openStyleEditor();
info("Selecting the second editor");
yield ui.selectStyleSheet(ui.editors[1].styleSheet);
let editor = ui.editors[1];
let text = editor.sourceEditor.getText();
is(text, expectedText, "selector edits are synced");
});

View file

@ -0,0 +1,50 @@
/* 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 changes in the style inspector are synchronized into the
// style editor.
const TESTCASE_URI = TEST_BASE_HTTP + "sync.html";
const expectedText = `
body {
border-width: 15px;
color: red;
}
#testid {
/*! font-size: 4em; */
}
`;
add_task(function* () {
yield addTab(TESTCASE_URI);
let { inspector, view, toolbox } = yield openRuleView();
// In this test, make sure the style editor is open before making
// changes in the inspector.
let { ui } = yield openStyleEditor();
let editor = yield ui.editors[0].getSourceEditor();
let onEditorChange = defer();
editor.sourceEditor.on("change", onEditorChange.resolve);
yield toolbox.getPanel("inspector");
yield selectNode("#testid", inspector);
let ruleEditor = getRuleViewRuleEditor(view, 1);
// Disable the "font-size" property.
let propEditor = ruleEditor.rule.textProps[0].editor;
let onModification = view.once("ruleview-changed");
propEditor.enable.click();
yield onModification;
yield openStyleEditor();
yield onEditorChange.promise;
let text = editor.sourceEditor.getText();
is(text, expectedText, "style inspector changes are synced");
});

View file

@ -0,0 +1,39 @@
/* 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 changes in the style inspector are synchronized into the
// style editor.
const TESTCASE_URI = TEST_BASE_HTTP + "sync.html";
const expectedText = `
body {
border-width: 15px;
color: red;
}
#testid, span {
font-size: 4em;
}
`;
add_task(function* () {
yield addTab(TESTCASE_URI);
let { inspector, view } = yield openRuleView();
yield selectNode("#testid", inspector);
let ruleEditor = getRuleViewRuleEditor(view, 1);
let editor = yield focusEditableField(view, ruleEditor.selectorText);
editor.input.value = "#testid, span";
let onRuleViewChanged = once(view, "ruleview-changed");
EventUtils.synthesizeKey("VK_RETURN", {});
yield onRuleViewChanged;
let { ui } = yield openStyleEditor();
editor = yield ui.editors[0].getSourceEditor();
let text = editor.sourceEditor.getText();
is(text, expectedText, "selector edits are synced");
});

View file

@ -0,0 +1,48 @@
/* 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 changes in the style editor are synchronized into the
// style inspector.
const TEST_URI = `
<style type='text/css'>
</style>
<div id='testid' class='testclass'>Styled Node</div>
`;
const TESTCASE_CSS_SOURCE = "#testid { color: chartreuse; }";
add_task(function* () {
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
let {inspector, view} = yield openRuleView();
yield selectNode("#testid", inspector);
let { panel, ui } = yield openStyleEditor();
let editor = yield ui.editors[0].getSourceEditor();
let waitForRuleView = view.once("ruleview-refreshed");
yield typeInEditor(editor, panel.panelWindow);
yield waitForRuleView;
let value = getRuleViewPropertyValue(view, "#testid", "color");
is(value, "chartreuse", "check that edits were synced to rule view");
});
function typeInEditor(editor, panelWindow) {
let deferred = defer();
waitForFocus(function () {
for (let c of TESTCASE_CSS_SOURCE) {
EventUtils.synthesizeKey(c, {}, panelWindow);
}
ok(editor.unsaved, "new editor has unsaved flag");
deferred.resolve();
}, panelWindow);
return deferred.promise;
}

View file

@ -0,0 +1,51 @@
/* 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";
const TESTCASE_URI = TEST_BASE_HTTPS + "simple.html";
const NEW_RULE = "body { background-color: purple; }";
add_task(function* () {
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, 2, "correct number of editors");
let editor = ui.editors[0];
yield openEditor(editor);
// Set text twice in a row
let styleChanges = listenForStyleChange(editor.styleSheet);
editor.sourceEditor.setText(NEW_RULE);
editor.sourceEditor.setText(NEW_RULE + " ");
yield styleChanges;
let rules = yield ContentTask.spawn(gBrowser.selectedBrowser, 0,
function* (index) {
let sheet = content.document.styleSheets[index];
return [...sheet.cssRules].map(rule => rule.cssText);
});
// Test that we removed the transition rule, but kept the rule we added
is(rules.length, 1, "only one rule in stylesheet");
is(rules[0], NEW_RULE, "stylesheet only contains rule we added");
});
/* Helpers */
function openEditor(editor) {
let link = editor.summary.querySelector(".stylesheet-name");
link.click();
return editor.getSourceEditor();
}
function listenForStyleChange(sheet) {
let deferred = defer();
sheet.on("style-applied", deferred.resolve);
return deferred.promise;
}

View file

@ -0,0 +1,22 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that the style-editor initializes correctly for XUL windows.
"use strict";
waitForExplicitFinish();
const TEST_URL = TEST_BASE + "doc_xulpage.xul";
add_task(function* () {
let tab = yield addTab(TEST_URL);
let target = TargetFactory.forTab(tab);
let toolbox = yield gDevTools.showToolbox(target, "styleeditor");
let panel = toolbox.getCurrentPanel();
ok(panel,
"The style-editor panel did initialize correctly for the XUL window");
});

View file

@ -0,0 +1,403 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
div {
z-index: 1;
}
div {
z-index: 2;
}
div {
z-index: 3;
}
div {
z-index: 4;
}
div {
z-index: 5;
}
div {
z-index: 6;
}
div {
z-index: 7;
}
div {
z-index: 8;
}
div {
z-index: 9;
}
div {
z-index: 10;
}
div {
z-index: 11;
}
div {
z-index: 12;
}
div {
z-index: 13;
}
div {
z-index: 14;
}
div {
z-index: 15;
}
div {
z-index: 16;
}
div {
z-index: 17;
}
div {
z-index: 18;
}
div {
z-index: 19;
}
div {
z-index: 20;
}
div {
z-index: 21;
}
div {
z-index: 22;
}
div {
z-index: 23;
}
div {
z-index: 24;
}
div {
z-index: 25;
}
div {
z-index: 26;
}
div {
z-index: 27;
}
div {
z-index: 28;
}
div {
z-index: 29;
}
div {
z-index: 30;
}
div {
z-index: 31;
}
div {
z-index: 32;
}
div {
z-index: 33;
}
div {
z-index: 34;
}
div {
z-index: 35;
}
div {
z-index: 36;
}
div {
z-index: 37;
}
div {
z-index: 38;
}
div {
z-index: 39;
}
div {
z-index: 40;
}
div {
z-index: 41;
}
div {
z-index: 42;
}
div {
z-index: 43;
}
div {
z-index: 44;
}
div {
z-index: 45;
}
div {
z-index: 46;
}
div {
z-index: 47;
}
div {
z-index: 48;
}
div {
z-index: 49;
}
div {
z-index: 50;
}
div {
z-index: 51;
}
div {
z-index: 52;
}
div {
z-index: 53;
}
div {
z-index: 54;
}
div {
z-index: 55;
}
div {
z-index: 56;
}
div {
z-index: 57;
}
div {
z-index: 58;
}
div {
z-index: 59;
}
div {
z-index: 60;
}
div {
z-index: 61;
}
div {
z-index: 62;
}
div {
z-index: 63;
}
div {
z-index: 64;
}
div {
z-index: 65;
}
div {
z-index: 66;
}
div {
z-index: 67;
}
div {
z-index: 68;
}
div {
z-index: 69;
}
div {
z-index: 70;
}
div {
z-index: 71;
}
div {
z-index: 72;
}
div {
z-index: 73;
}
div {
z-index: 74;
}
div {
z-index: 75;
}
div {
z-index: 76;
}
div {
z-index: 77;
}
div {
z-index: 78;
}
div {
z-index: 79;
}
div {
z-index: 80;
}
div {
z-index: 81;
}
div {
z-index: 82;
}
div {
z-index: 83;
}
div {
z-index: 84;
}
div {
z-index: 85;
}
div {
z-index: 86;
}
div {
z-index: 87;
}
div {
z-index: 88;
}
div {
z-index: 89;
}
div {
z-index: 90;
}
div {
z-index: 91;
}
div {
z-index: 92;
}
div {
z-index: 93;
}
div {
z-index: 94;
}
div {
z-index: 95;
}
div {
z-index: 96;
}
div {
z-index: 97;
}
div {
z-index: 98;
}
div {
z-index: 99;
}
div {
z-index: 100;
}

View file

@ -0,0 +1,16 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* ☺ */
body {
background: white;
}
div {
font-size: 4em;
}
div > span {
text-decoration: underline;
}

View file

@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<title>uncached testcase</title>
<link rel="stylesheet" charset="UTF-8" type="text/css" media="screen" href="doc_uncached.css"/>
</head>
<body>
<div>uncached <span>testcase</span></div>
</body>
</html>

View file

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<?xml-stylesheet href="simple.css" type="text/css"?>
<!DOCTYPE window>
<window xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<label value="Simple XUL document" />
</window>

View file

@ -0,0 +1,25 @@
<!doctype html>
<html>
<head>
<title>four stylesheets</title>
<link rel="stylesheet" type="text/css" media="scren" href="simple.css"/>
<style type="text/css">
div {
font-size: 2em;
}
</style>
<style type="text/css">
span {
font-size: 3em;
}
</style>
<style type="text/css">
p {
font-size: 4em;
}
</style>
</head>
<body>
<div>four <span>stylesheets</span></div>
</body>
</html>

View file

@ -0,0 +1,121 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* All top-level definitions here are exports. */
/* eslint no-unused-vars: [2, {"vars": "local"}] */
"use strict";
/* import-globals-from ../../inspector/shared/test/head.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/inspector/shared/test/head.js", this);
const TEST_BASE = "chrome://mochitests/content/browser/devtools/client/styleeditor/test/";
const TEST_BASE_HTTP = "http://example.com/browser/devtools/client/styleeditor/test/";
const TEST_BASE_HTTPS = "https://example.com/browser/devtools/client/styleeditor/test/";
const TEST_HOST = "mochi.test:8888";
/**
* Add a new test tab in the browser and load the given url.
* @param {String} url The url to be loaded in the new tab
* @param {Window} win The window to add the tab to (default: current window).
* @return a promise that resolves to the tab object when the url is loaded
*/
var addTab = function (url, win) {
info("Adding a new tab with URL: '" + url + "'");
let def = defer();
let targetWindow = win || window;
let targetBrowser = targetWindow.gBrowser;
let tab = targetBrowser.selectedTab = targetBrowser.addTab(url);
BrowserTestUtils.browserLoaded(targetBrowser.selectedBrowser)
.then(function () {
info("URL '" + url + "' loading complete");
def.resolve(tab);
});
return def.promise;
};
/**
* Navigate the currently selected tab to a new URL and wait for it to load.
* @param {String} url The url to be loaded in the current tab.
* @return a promise that resolves when the page has fully loaded.
*/
var navigateTo = Task.async(function* (url) {
info(`Navigating to ${url}`);
let browser = gBrowser.selectedBrowser;
let navigating = defer();
browser.addEventListener("load", function onload() {
browser.removeEventListener("load", onload, true);
navigating.resolve();
}, true);
browser.loadURI(url);
yield navigating.promise;
});
var navigateToAndWaitForStyleSheets = Task.async(function* (url, ui) {
let onReset = ui.once("stylesheets-reset");
yield navigateTo(url);
yield onReset;
});
var reloadPageAndWaitForStyleSheets = Task.async(function* (ui) {
info("Reloading the page.");
let onReset = ui.once("stylesheets-reset");
let browser = gBrowser.selectedBrowser;
yield ContentTask.spawn(browser, null, "() => content.location.reload()");
yield onReset;
});
/**
* Open the style editor for the current tab.
*/
var openStyleEditor = Task.async(function* (tab) {
if (!tab) {
tab = gBrowser.selectedTab;
}
let target = TargetFactory.forTab(tab);
let toolbox = yield gDevTools.showToolbox(target, "styleeditor");
let panel = toolbox.getPanel("styleeditor");
let ui = panel.UI;
return { toolbox, panel, ui };
});
/**
* Creates a new tab in specified window navigates it to the given URL and
* opens style editor in it.
*/
var openStyleEditorForURL = Task.async(function* (url, win) {
let tab = yield addTab(url, win);
let result = yield openStyleEditor(tab);
result.tab = tab;
return result;
});
/**
* Send an async message to the frame script and get back the requested
* computed style property.
*
* @param {String} selector
* The selector used to obtain the element.
* @param {String} pseudo
* pseudo id to query, or null.
* @param {String} name
* name of the property.
*/
var getComputedStyleProperty = function* (args) {
return yield ContentTask.spawn(gBrowser.selectedBrowser, args,
function ({selector, pseudo, name}) {
let element = content.document.querySelector(selector);
let style = content.getComputedStyle(element, pseudo);
return style.getPropertyValue(name);
}
);
};

View file

@ -0,0 +1,10 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
@import url(import2.css);
body {
margin: 0;
}

View file

@ -0,0 +1,11 @@
<!doctype html>
<html>
<head>
<title>import testcase</title>
<link rel="stylesheet" charset="UTF-8" type="text/css" media="screen" href="simple.css"/>
<link rel="stylesheet" charset="UTF-8" type="text/css" media="screen" href="import.css"/>
</head>
<body>
<div>import <span>testcase</span></div>
</body>
</html>

View file

@ -0,0 +1,10 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
@import url(import.css);
p {
padding: 5px;
}

View file

@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<title>Inline test page #1</title>
<style type="text/css">
.second {
font-size:2em;
}
</style>
<style type="text/css">
.first {
font-size:3em;
}
</style>
</head>
<body class="first">
Inline test page #1
</body>
</html>

View file

@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<title>Inline test page #2</title>
<style type="text/css">
.second {
font-size:2em;
}
</style>
<style type="text/css">
.first {
font-size:3em;
}
</style>
</head>
<body class="second">
Inline test page #2
</body>
</html>

View file

@ -0,0 +1,29 @@
<!doctype html>
<html>
<head>
<title>Long load</title>
<link rel="stylesheet" charset="UTF-8" type="text/css" media="screen" href="simple.css"/>
<style type="text/css">
body {
background: white;
}
div {
font-size: 4em;
}
div > span {
text-decoration: underline;
}
</style>
</head>
<body>
Time passes:
<script type="application/javascript;version=1.8">
"use strict";
for (let i = 0; i < 5000; i++) {
document.write("<br>...");
}
</script>
</body>
</html>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="sourcemap-css/media-rules.css"
</head>
<body>
<div>
Testing style editor media sidebar with source maps
</div>
</body>
</html>

View file

@ -0,0 +1,29 @@
@media not all {
div {
color: blue;
}
}
@media all {
div {
color: red;
}
}
div {
width: 20px;
height: 20px;
background-color: ghostwhite;
}
@media (max-width: 400px) {
div {
color: green;
}
}
@media (min-height: 300px) and (max-height: 320px) {
div {
color: orange;
}
}

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="simple.css"/>
<link rel="stylesheet" href="media-rules.css"/>
</head>
<body>
<div>
Testing style editor media sidebar
</div>
</body>
</html>

View file

@ -0,0 +1,5 @@
/* this stylesheet applies when min-width<400px */
body {
background: red;
}

View file

@ -0,0 +1,11 @@
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="simple.css" media="screen,print"/>
<link rel="stylesheet" type="text/css" href="media-small.css" media="screen and (min-width: 200px)"/>
</head>
<body>
<div>test for media labels</div>
</body>
</html>

View file

@ -0,0 +1,15 @@
<!doctype html>
<html>
<head>
<title>minified testcase</title>
<link rel="stylesheet" href="pretty.css"/>
<style type="text/css">body { background: red; }
div {
font-size: 5em;
color: red
}</style>
</head>
<body>
<div>minified <span>testcase</span></div>
</body>
</html>

View file

@ -0,0 +1,11 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>missing stylesheet testcase</title>
<link rel="stylesheet" charset="utf-8" type="text/css" media="screen" href="missing-stylesheet.css"/>
<link rel="stylesheet" charset="utf-8" type="text/css" media="screen" href="simple.css"/>
</head>
<body>
</body>
</html>

View file

@ -0,0 +1,5 @@
<html>
<div>
Page with no stylesheets
</div>
</html>

View file

@ -0,0 +1,2 @@
body{background:white;}div{font-size:4em;color:red}span{color:green;}

View file

@ -0,0 +1,12 @@
// This script is used from within browser_styleeditor_cmd_edit.html
window.addEventListener('load', function() {
var pid = document.getElementById('pid');
var h3 = document.createElement('h3');
h3.id = 'h3id';
h3.classList.add('h3class');
h3.appendChild(document.createTextNode('h3'));
h3.setAttribute('data-a1', 'h3');
pid.parentNode.appendChild(h3);
});

View file

@ -0,0 +1,11 @@
@charset "utf-8";
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
#pid { border-top: 2px dotted #F00; }
#divid { border-top: 2px dotted #00F; }
#h4id { border-top: 2px dotted #0F0; }
#h3id { border-top: 2px dotted #FF0; }

View file

@ -0,0 +1,11 @@
@charset "utf-8";
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
*[data-a1=p] { border-left: 4px solid #F00; }
*[data-a1=div] { border-left: 4px solid #00F; }
*[data-a1=h4] { border-left: 4px solid #0F0; }
*[data-a1=h3] { border-left: 4px solid #FF0; }

View file

@ -0,0 +1,9 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* ☺ */
body {
margin: 0;
}

Binary file not shown.

View file

@ -0,0 +1,4 @@
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Type: text/css

View file

@ -0,0 +1,23 @@
<!doctype html>
<html>
<head>
<title>simple testcase</title>
<link rel="stylesheet" type="text/css" media="scren" href="simple.css.gz"/>
<style type="text/css">
body {
background: white;
}
div {
font-size: 4em;
}
div > span {
text-decoration: underline;
}
</style>
</head>
<body>
<div>simple <span>testcase</span></div>
</body>
</html>

View file

@ -0,0 +1,24 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>simple testcase</title>
<link rel="stylesheet" charset="UTF-8" type="text/css" media="screen" href="simple.css"/>
<style type="text/css">
body {
background: white;
}
div {
font-size: 4em;
}
div > span {
text-decoration: underline;
}
</style>
</head>
<body>
<div>simple <span>testcase</span></div>
</body>
</html>

View file

@ -0,0 +1,4 @@
#header {
color: #f06; }
/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIiwic291cmNlcyI6WyJzYXNzL2NvbnRhaW5lZC5zY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBO0VBQ0UsT0FISyIsInNvdXJjZXNDb250ZW50IjpbIiRwaW5rOiAjZjA2O1xuXG4jaGVhZGVyIHtcbiAgY29sb3I6ICRwaW5rO1xufSJdfQ==*/

View file

@ -0,0 +1,8 @@
@media screen and (max-width: 320px) {
div {
width: 100px; } }
@media screen and (min-width: 1200px) {
div {
width: 400px; } }
/*# sourceMappingURL=media-rules.css.map */

View file

@ -0,0 +1,6 @@
{
"version": 3,
"mappings": "AAIE,oCAA4C;EAD9C,GAAI;IAEA,KAAK,EAAE,KAAK;AAEd,qCAA4C;EAJ9C,GAAI;IAKA,KAAK,EAAE,KAAK",
"sources": ["../sourcemap-sass/media-rules.scss"],
"file": "media-rules.css"
}

View file

@ -0,0 +1,7 @@
div {
color: #ff0066; }
span {
background-color: #EEE; }
/*# sourceMappingURL=sourcemaps.css.map */

View file

@ -0,0 +1,6 @@
{
"version": 3,
"mappings": "AAGA,GAAI;EACF,KAAK,EAHU,OAAI;;AAMrB,IAAK;EACH,gBAAgB,EAAE,IAAI",
"sources": ["../sourcemap-sass/sourcemaps.scss"],
"file": "sourcemaps.css"
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,7 @@
div {
color: #f06;
}
span {
background-color: #eee;
}
/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3Qtc3R5bHVzLnN0eWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUE7RUFDRSxPQUFPLEtBQVA7O0FBRUY7RUFDRSxrQkFBa0IsS0FBbEIiLCJmaWxlIjoidGVzdC1zdHlsdXMuY3NzIiwic291cmNlc0NvbnRlbnQiOlsicGF1bHJvdWdldHBpbmsgPSAjZjA2O1xuXG5kaXZcbiAgY29sb3I6IHBhdWxyb3VnZXRwaW5rXG5cbnNwYW5cbiAgYmFja2dyb3VuZC1jb2xvcjogI0VFRVxuIl19 */

View file

@ -0,0 +1,11 @@
$break-small: 320px;
$break-large: 1200px;
div {
@media screen and (max-width: $break-small) {
width: 100px;
}
@media screen and (min-width: $break-large) {
width: 400px;
}
}

View file

@ -0,0 +1,10 @@
$paulrougetpink: #f06;
div {
color: $paulrougetpink;
}
span {
background-color: #EEE;
}

View file

@ -0,0 +1,7 @@
paulrougetpink = #f06;
div
color: paulrougetpink
span
background-color: #EEE

View file

@ -0,0 +1,17 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>testcase for testing CSS source maps in inline style</title>
<style type="text/css">body {
background-color: black;
}
body > h1 {
color: white;
}
/*# sourceMappingURL=data:application/json;base64,ewoidmVyc2lvbiI6IDMsCiJtYXBwaW5ncyI6ICJBQUFBLElBQUs7RUFDSCxnQkFBZ0IsRUFBRSxLQUFLO0VBQ3ZCLFNBQU87SUFDTCxLQUFLLEVBQUUsS0FBSyIsCiJzb3VyY2VzIjogWyJ0ZXN0LnNjc3MiXSwKInNvdXJjZXNDb250ZW50IjogWyJib2R5IHtcbiAgYmFja2dyb3VuZC1jb2xvcjogYmxhY2s7XG4gICYgPiBoMSB7XG4gICAgY29sb3I6IHdoaXRlO1xuICB9XG59XG4iXSwKIm5hbWVzIjogW10sCiJmaWxlIjogInRlc3QuY3NzIgp9Cg== */</style>
</head>
<body>
<h1>Source maps testcase</div>
</body>
</html>

View file

@ -0,0 +1,11 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>testcase for a loading error with CSS source maps</title>
<link rel="stylesheet" type="text/css" href="sourcemap-css/test-bootstrap-scss.css"/>
</head>
<body>
<div>source maps <span>testcase</span> (see Bug 1128747)</div>
</body>
</html>

View file

@ -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="sourcemap-css/sourcemaps.css?test=1"/>
</head>
<body>
<div>source maps <span>testcase</span></div>
</body>
</html>

View file

@ -0,0 +1,13 @@
<!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="sourcemap-css/sourcemaps.css?test=1"/>
<link rel="stylesheet" type="text/css" href="sourcemap-css/contained.css"/>
<link rel="stylesheet" type="text/css" href="sourcemap-css/test-stylus.css"/>
</head>
<body>
<div>source maps <span>testcase</span></div>
</body>
</html>

View file

@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>simple testcase</title>
<style type="text/css">
body {
border-width: 15px;
color: red;
}
#testid {
font-size: 4em;
}
</style>
</head>
<body>
<div id="testid">simple testcase</div>
</body>
</html>

View file

@ -0,0 +1,3 @@
body {
background-color: red;
}

View file

@ -0,0 +1,7 @@
<html>
<head>
<link rel="stylesheet" href="test_private.css"></link>
</head>
<body>
</body>
</html>

Binary file not shown.