|
1 /* vim: set ts=2 et sw=2 tw=80: */ |
|
2 /* Any copyright is dedicated to the Public Domain. |
|
3 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
4 |
|
5 Components.utils.import("resource://gre/modules/Task.jsm"); |
|
6 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); |
|
7 let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); |
|
8 |
|
9 const TESTCASE_URI_HTML = TEST_BASE + "sourcemaps.html"; |
|
10 const TESTCASE_URI_CSS = TEST_BASE + "sourcemap-css/sourcemaps.css"; |
|
11 const TESTCASE_URI_CSS2 = TEST_BASE + "sourcemap-css/contained.css"; |
|
12 const TESTCASE_URI_REG_CSS = TEST_BASE + "simple.css"; |
|
13 const TESTCASE_URI_SCSS = TEST_BASE + "sourcemap-sass/sourcemaps.scss"; |
|
14 const TESTCASE_URI_MAP = TEST_BASE + "sourcemap-css/sourcemaps.css.map"; |
|
15 const TESTCASE_SCSS_NAME = "sourcemaps.scss"; |
|
16 |
|
17 const SOURCE_MAP_PREF = "devtools.styleeditor.source-maps-enabled"; |
|
18 const TRANSITIONS_PREF = "devtools.styleeditor.transitions"; |
|
19 |
|
20 const CSS_TEXT = "* { color: blue }"; |
|
21 |
|
22 const Cc = Components.classes; |
|
23 const Ci = Components.interfaces; |
|
24 |
|
25 let tempScope = {}; |
|
26 Components.utils.import("resource://gre/modules/FileUtils.jsm", tempScope); |
|
27 Components.utils.import("resource://gre/modules/NetUtil.jsm", tempScope); |
|
28 let FileUtils = tempScope.FileUtils; |
|
29 let NetUtil = tempScope.NetUtil; |
|
30 |
|
31 function test() |
|
32 { |
|
33 waitForExplicitFinish(); |
|
34 |
|
35 Services.prefs.setBoolPref(SOURCE_MAP_PREF, true); |
|
36 Services.prefs.setBoolPref(TRANSITIONS_PREF, false); |
|
37 |
|
38 Task.spawn(function() { |
|
39 // copy all our files over so we don't screw them up for other tests |
|
40 let HTMLFile = yield copy(TESTCASE_URI_HTML, ["sourcemaps.html"]); |
|
41 let CSSFile = yield copy(TESTCASE_URI_CSS, ["sourcemap-css", "sourcemaps.css"]); |
|
42 let CSSFile2 = yield copy(TESTCASE_URI_CSS2, ["sourcemap-css", "contained.css"]); |
|
43 yield copy(TESTCASE_URI_SCSS, ["sourcemap-sass", "sourcemaps.scss"]); |
|
44 yield copy(TESTCASE_URI_MAP, ["sourcemap-css", "sourcemaps.css.map"]); |
|
45 yield copy(TESTCASE_URI_REG_CSS, ["simple.css"]); |
|
46 |
|
47 let uri = Services.io.newFileURI(HTMLFile); |
|
48 let testcaseURI = uri.resolve(""); |
|
49 |
|
50 let editor = yield openEditor(testcaseURI); |
|
51 |
|
52 let element = content.document.querySelector("div"); |
|
53 let style = content.getComputedStyle(element, null); |
|
54 |
|
55 is(style.color, "rgb(255, 0, 102)", "div is red before saving file"); |
|
56 |
|
57 editor.styleSheet.relatedStyleSheet.once("style-applied", function() { |
|
58 is(style.color, "rgb(0, 0, 255)", "div is blue after saving file"); |
|
59 finishUp(); |
|
60 }); |
|
61 |
|
62 yield pauseForTimeChange(); |
|
63 |
|
64 // Edit and save Sass in the editor. This will start off a file-watching |
|
65 // process waiting for the CSS file to change. |
|
66 yield editSCSS(editor); |
|
67 |
|
68 // We can't run Sass or another compiler, so we fake it by just |
|
69 // directly changing the CSS file. |
|
70 yield editCSSFile(CSSFile); |
|
71 |
|
72 info("wrote to CSS file"); |
|
73 }) |
|
74 } |
|
75 |
|
76 function openEditor(testcaseURI) { |
|
77 let deferred = promise.defer(); |
|
78 |
|
79 addTabAndOpenStyleEditors(5, panel => { |
|
80 let UI = panel.UI; |
|
81 |
|
82 // wait for 5 editors - 1 for first style sheet, 2 for the |
|
83 // generated style sheets, and 2 for original source after it |
|
84 // loads and replaces the generated style sheets. |
|
85 let editor = UI.editors[1]; |
|
86 if (getStylesheetNameFor(editor) != TESTCASE_SCSS_NAME) { |
|
87 editor = UI.editors[2]; |
|
88 } |
|
89 is(getStylesheetNameFor(editor), TESTCASE_SCSS_NAME, "found scss editor"); |
|
90 |
|
91 let link = getLinkFor(editor); |
|
92 link.click(); |
|
93 |
|
94 editor.getSourceEditor().then(deferred.resolve); |
|
95 }); |
|
96 content.location = testcaseURI; |
|
97 |
|
98 return deferred.promise; |
|
99 } |
|
100 |
|
101 function editSCSS(editor) { |
|
102 let deferred = promise.defer(); |
|
103 |
|
104 let pos = {line: 0, ch: 0}; |
|
105 editor.sourceEditor.replaceText(CSS_TEXT, pos, pos); |
|
106 |
|
107 editor.saveToFile(null, function (file) { |
|
108 ok(file, "Scss file should be saved"); |
|
109 deferred.resolve(); |
|
110 }); |
|
111 |
|
112 return deferred.promise; |
|
113 } |
|
114 |
|
115 function editCSSFile(CSSFile) { |
|
116 return write(CSS_TEXT, CSSFile); |
|
117 } |
|
118 |
|
119 function pauseForTimeChange() { |
|
120 let deferred = promise.defer(); |
|
121 |
|
122 // We have to wait for the system time to turn over > 1000 ms so that |
|
123 // our file's last change time will show a change. This reflects what |
|
124 // would happen in real life with a user manually saving the file. |
|
125 setTimeout(deferred.resolve, 2000); |
|
126 |
|
127 return deferred.promise; |
|
128 } |
|
129 |
|
130 function finishUp() { |
|
131 Services.prefs.clearUserPref(SOURCE_MAP_PREF); |
|
132 Services.prefs.clearUserPref(TRANSITIONS_PREF); |
|
133 finish(); |
|
134 } |
|
135 |
|
136 /* Helpers */ |
|
137 |
|
138 function getLinkFor(editor) { |
|
139 return editor.summary.querySelector(".stylesheet-name"); |
|
140 } |
|
141 |
|
142 function getStylesheetNameFor(editor) { |
|
143 return editor.summary.querySelector(".stylesheet-name > label") |
|
144 .getAttribute("value") |
|
145 } |
|
146 |
|
147 function copy(aSrcChromeURL, aDestFilePath) |
|
148 { |
|
149 let destFile = FileUtils.getFile("ProfD", aDestFilePath); |
|
150 return write(read(aSrcChromeURL), destFile); |
|
151 } |
|
152 |
|
153 function read(aSrcChromeURL) |
|
154 { |
|
155 let scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"] |
|
156 .getService(Ci.nsIScriptableInputStream); |
|
157 |
|
158 let channel = Services.io.newChannel(aSrcChromeURL, null, null); |
|
159 let input = channel.open(); |
|
160 scriptableStream.init(input); |
|
161 |
|
162 let data = ""; |
|
163 while (input.available()) { |
|
164 data = data.concat(scriptableStream.read(input.available())); |
|
165 } |
|
166 scriptableStream.close(); |
|
167 input.close(); |
|
168 |
|
169 return data; |
|
170 } |
|
171 |
|
172 function write(aData, aFile) |
|
173 { |
|
174 let deferred = promise.defer(); |
|
175 |
|
176 let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] |
|
177 .createInstance(Ci.nsIScriptableUnicodeConverter); |
|
178 |
|
179 converter.charset = "UTF-8"; |
|
180 |
|
181 let istream = converter.convertToInputStream(aData); |
|
182 let ostream = FileUtils.openSafeFileOutputStream(aFile); |
|
183 |
|
184 NetUtil.asyncCopy(istream, ostream, function(status) { |
|
185 if (!Components.isSuccessCode(status)) { |
|
186 info("Coudln't write to " + aFile.path); |
|
187 return; |
|
188 } |
|
189 deferred.resolve(aFile); |
|
190 }); |
|
191 |
|
192 return deferred.promise; |
|
193 } |