Bug 1006231 - Get original source content for a stylesheet from source map's 'sourcesContent'. r=fitzgen

This commit is contained in:
Heather Arthur 2014-05-08 15:25:00 +02:00
parent 6e76e84a1e
commit 1354cc3bea
7 changed files with 146 additions and 103 deletions

View File

@ -25,6 +25,7 @@ support-files =
simple.css.gz^headers^
simple.gz.html
simple.html
sourcemap-css/contained.css
sourcemap-css/sourcemaps.css
sourcemap-css/sourcemaps.css.map
sourcemap-sass/sourcemaps.scss

View File

@ -8,9 +8,11 @@ let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
const TESTCASE_URI_HTML = TEST_BASE + "sourcemaps.html";
const TESTCASE_URI_CSS = TEST_BASE + "sourcemap-css/sourcemaps.css";
const TESTCASE_URI_CSS2 = TEST_BASE + "sourcemap-css/contained.css";
const TESTCASE_URI_REG_CSS = TEST_BASE + "simple.css";
const TESTCASE_URI_SCSS = TEST_BASE + "sourcemap-sass/sourcemaps.scss";
const TESTCASE_URI_MAP = TEST_BASE + "sourcemap-css/sourcemaps.css.map";
const TESTCASE_SCSS_NAME = "sourcemaps.scss";
const PREF = "devtools.styleeditor.source-maps-enabled";
@ -35,6 +37,7 @@ function test()
// 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"]);
let CSSFile2 = yield copy(TESTCASE_URI_CSS2, ["sourcemap-css", "contained.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"]);
@ -71,15 +74,19 @@ function test()
function openEditor(testcaseURI) {
let deferred = promise.defer();
addTabAndOpenStyleEditors(3, panel => {
addTabAndOpenStyleEditors(5, panel => {
let UI = panel.UI;
// wait for 3 editors - 1 for first style sheet, 1 for the
// generated style sheet, and 1 for original source after it
// loads and replaces the generated style sheet.
// wait for 5 editors - 1 for first style sheet, 2 for the
// generated style sheets, and 2 for original source after it
// loads and replaces the generated style sheets.
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 = getStylesheetNameLinkFor(editor);
let link = getLinkFor(editor);
link.click();
editor.getSourceEditor().then(deferred.resolve);
@ -125,10 +132,15 @@ function finishUp() {
/* Helpers */
function getStylesheetNameLinkFor(editor) {
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}
function getStylesheetNameFor(editor) {
return editor.summary.querySelector(".stylesheet-name > label")
.getAttribute("value")
}
function copy(aSrcChromeURL, aDestFilePath)
{
let destFile = FileUtils.getFile("ProfD", aDestFilePath);

View File

@ -6,106 +6,116 @@
const TESTCASE_URI = TEST_BASE_HTTPS + "sourcemaps.html";
const PREF = "devtools.styleeditor.source-maps-enabled";
function test()
{
waitForExplicitFinish();
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIiwic291cmNlcyI6WyJzYXNzL2NvbnRhaW5lZC5zY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBO0VBQ0UsT0FISyIsInNvdXJjZXNDb250ZW50IjpbIiRwaW5rOiAjZjA2O1xuXG4jaGVhZGVyIHtcbiAgY29sb3I6ICRwaW5rO1xufSJdfQ==*/"
].join("\n")
}
const cssNames = ["sourcemaps.css", "contained.css"];
const scssNames = ["sourcemaps.scss", "contained.scss"];
waitForExplicitFinish();
let test = asyncTest(function*() {
Services.prefs.setBoolPref(PREF, true);
// wait for 3 editors - 1 for first style sheet, 1 for the
// generated style sheet, and 1 for original source after it
// loads and replaces the generated style sheet.
addTabAndOpenStyleEditors(3, panel => runTests(panel.UI));
let {UI} = yield addTabAndOpenStyleEditors(5, null, TESTCASE_URI);
content.location = TESTCASE_URI;
}
is(UI.editors.length, 3,
"correct number of editors with source maps enabled");
function runTests(UI)
{
is(UI.editors.length, 2);
// Test first plain css editor
testFirstEditor(UI.editors[0]);
let firstEditor = UI.editors[0];
testFirstEditor(firstEditor);
// Test Scss editors
yield testEditor(UI.editors[1], scssNames);
yield testEditor(UI.editors[2], scssNames);
let ScssEditor = UI.editors[1];
// Test disabling original sources
yield togglePref(UI);
let link = getStylesheetNameLinkFor(ScssEditor);
link.click();
is(UI.editors.length, 3, "correct number of editors after pref toggled");
ScssEditor.getSourceEditor().then(() => {
testScssEditor(ScssEditor);
// Test CSS editors
yield testEditor(UI.editors[1], cssNames);
yield testEditor(UI.editors[2], cssNames);
togglePref(UI);
});
}
function togglePref(UI) {
let count = 0;
UI.on("editor-added", (event, editor) => {
if (++count == 2) {
testTogglingPref(UI);
}
})
Services.prefs.setBoolPref(PREF, false);
}
function testTogglingPref(UI) {
is(UI.editors.length, 2, "correct number of editors after pref toggled");
let CSSEditor = UI.editors[1];
let link = getStylesheetNameLinkFor(CSSEditor);
link.click();
CSSEditor.getSourceEditor().then(() => {
testCSSEditor(CSSEditor);
finishUp();
})
}
Services.prefs.clearUserPref(PREF);
});
function testFirstEditor(editor) {
let name = getStylesheetNameFor(editor);
is(name, "simple.css", "First style sheet display name is correct");
}
function testScssEditor(editor) {
function testEditor(editor, possibleNames) {
let name = getStylesheetNameFor(editor);
is(name, "sourcemaps.scss", "Original source display name is correct");
ok(possibleNames.indexOf(name) >= 0, name + " editor name is correct");
let text = editor.sourceEditor.getText();
return openEditor(editor).then(() => {
let expectedText = contents[name];
is(text, "\n\
$paulrougetpink: #f06;\n\
\n\
div {\n\
color: $paulrougetpink;\n\
}\n\
\n\
span {\n\
background-color: #EEE;\n\
}", "Original source text is correct");
}
function testCSSEditor(editor) {
let name = getStylesheetNameFor(editor);
is(name, "sourcemaps.css", "CSS source display name is correct");
let text = editor.sourceEditor.getText();
is(text, "div {\n\
color: #ff0066; }\n\
\n\
span {\n\
background-color: #EEE; }\n\
\n\
/*# sourceMappingURL=sourcemaps.css.map */", "CSS text is correct");
let text = editor.sourceEditor.getText();
is(text, expectedText, name + " editor contains expected text");
});
}
/* Helpers */
function getStylesheetNameLinkFor(editor) {
function togglePref(UI) {
let deferred = promise.defer();
let count = 0;
UI.on("editor-added", (event, editor) => {
if (++count == 3) {
deferred.resolve();
}
})
Services.prefs.setBoolPref(PREF, false);
return deferred.promise;
}
function openEditor(editor) {
getLinkFor(editor).click();
return editor.getSourceEditor();
}
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}
@ -113,8 +123,3 @@ function getStylesheetNameFor(editor) {
return editor.summary.querySelector(".stylesheet-name > label")
.getAttribute("value")
}
function finishUp() {
Services.prefs.clearUserPref(PREF);
finish();
}

View File

@ -6,13 +6,11 @@ const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/styleeditor/
const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/styleeditor/test/";
const TEST_HOST = 'mochi.test:8888';
let tempScope = {};
Cu.import("resource://gre/modules/devtools/Loader.jsm", tempScope);
let TargetFactory = tempScope.devtools.TargetFactory;
Cu.import("resource://gre/modules/LoadContextInfo.jsm", tempScope);
let LoadContextInfo = tempScope.LoadContextInfo;
Cu.import("resource://gre/modules/devtools/Console.jsm", tempScope);
let console = tempScope.console;
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let TargetFactory = devtools.TargetFactory;
let {LoadContextInfo} = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {});
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
let gPanelWindow;
let cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
@ -28,6 +26,13 @@ SimpleTest.registerCleanupFunction(() => {
gDevTools.testing = false;
});
/**
* Define an async test based on a generator function
*/
function asyncTest(generator) {
return () => Task.spawn(generator).then(null, ok.bind(null, false)).then(finish);
}
function cleanup()
{
gPanelWindow = null;
@ -36,16 +41,25 @@ function cleanup()
}
}
function addTabAndOpenStyleEditors(count, callback) {
function addTabAndOpenStyleEditors(count, callback, uri) {
let deferred = promise.defer();
let currentCount = 0;
let panel;
addTabAndCheckOnStyleEditorAdded(p => panel = p, function () {
currentCount++;
info(currentCount + " of " + count + " editors opened");
if (currentCount == count) {
callback(panel);
if (callback) {
callback(panel);
}
deferred.resolve(panel);
}
});
if (uri) {
content.location = uri;
}
return deferred.promise;
}
function addTabAndCheckOnStyleEditorAdded(callbackOnce, callbackOnAdded) {

View File

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

View File

@ -4,6 +4,7 @@
<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"
</head>
<body>
<div>source maps <span>testcase</span></div>

View File

@ -405,12 +405,13 @@ let StyleSheetActor = protocol.ActorClass({
}
let docHref;
if (this.rawSheet.ownerNode) {
if (this.rawSheet.ownerNode instanceof Ci.nsIDOMHTMLDocument) {
docHref = this.rawSheet.ownerNode.location.href;
let ownerNode = this.rawSheet.ownerNode;
if (ownerNode) {
if (ownerNode instanceof Ci.nsIDOMHTMLDocument) {
docHref = ownerNode.location.href;
}
if (this.rawSheet.ownerNode.ownerDocument) {
docHref = this.rawSheet.ownerNode.ownerDocument.location.href;
else if (ownerNode.ownerDocument && ownerNode.ownerDocument.location) {
docHref = ownerNode.ownerDocument.location.href;
}
}
@ -846,6 +847,11 @@ let OriginalSourceActor = protocol.ActorClass({
if (this.text) {
return promise.resolve(this.text);
}
let content = this.sourceMap.sourceContentFor(this.url);
if (content) {
this.text = content;
return promise.resolve(content);
}
return fetch(this.url, { window: this.window }).then(({content}) => {
this.text = content;
return content;