|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 const Cu = Components.utils; |
|
6 const Ci = Components.interfaces; |
|
7 const Cc = Components.classes; |
|
8 |
|
9 // Services.prefs.setBoolPref("devtools.debugger.log", true); |
|
10 // SimpleTest.registerCleanupFunction(() => { |
|
11 // Services.prefs.clearUserPref("devtools.debugger.log"); |
|
12 // }); |
|
13 |
|
14 //Services.prefs.setBoolPref("devtools.dump.emit", true); |
|
15 |
|
16 let tempScope = {}; |
|
17 Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm", tempScope); |
|
18 let LayoutHelpers = tempScope.LayoutHelpers; |
|
19 |
|
20 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", tempScope); |
|
21 let TargetFactory = devtools.TargetFactory; |
|
22 |
|
23 Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope); |
|
24 let console = tempScope.console; |
|
25 |
|
26 // Import the GCLI test helper |
|
27 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/")); |
|
28 Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this); |
|
29 |
|
30 gDevTools.testing = true; |
|
31 SimpleTest.registerCleanupFunction(() => { |
|
32 gDevTools.testing = false; |
|
33 }); |
|
34 |
|
35 SimpleTest.registerCleanupFunction(() => { |
|
36 console.error("Here we are\n"); |
|
37 let {DebuggerServer} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {}); |
|
38 console.error("DebuggerServer open connections: " + Object.getOwnPropertyNames(DebuggerServer._connections).length); |
|
39 |
|
40 Services.prefs.clearUserPref("devtools.dump.emit"); |
|
41 Services.prefs.clearUserPref("devtools.inspector.activeSidebar"); |
|
42 }); |
|
43 |
|
44 /** |
|
45 * Simple DOM node accesor function that takes either a node or a string css |
|
46 * selector as argument and returns the corresponding node |
|
47 * @param {String|DOMNode} nodeOrSelector |
|
48 * @return {DOMNode} |
|
49 */ |
|
50 function getNode(nodeOrSelector) { |
|
51 return typeof nodeOrSelector === "string" ? |
|
52 content.document.querySelector(nodeOrSelector) : |
|
53 nodeOrSelector; |
|
54 } |
|
55 |
|
56 /** |
|
57 * Set the inspector's current selection to a node or to the first match of the |
|
58 * given css selector |
|
59 * @param {InspectorPanel} inspector The instance of InspectorPanel currently |
|
60 * loaded in the toolbox |
|
61 * @param {String} reason Defaults to "test" which instructs the inspector not |
|
62 * to highlight the node upon selection |
|
63 * @param {String} reason Defaults to "test" which instructs the inspector not to highlight the node upon selection |
|
64 * @return a promise that resolves when the inspector is updated with the new |
|
65 * node |
|
66 */ |
|
67 function selectNode(nodeOrSelector, inspector, reason="test") { |
|
68 info("Selecting the node " + nodeOrSelector); |
|
69 let node = getNode(nodeOrSelector); |
|
70 let updated = inspector.once("inspector-updated"); |
|
71 inspector.selection.setNode(node, reason); |
|
72 return updated; |
|
73 } |
|
74 |
|
75 /** |
|
76 * Open the toolbox, with the inspector tool visible. |
|
77 * @param {Function} cb Optional callback, if you don't want to use the returned |
|
78 * promise |
|
79 * @return a promise that resolves when the inspector is ready |
|
80 */ |
|
81 let openInspector = Task.async(function*(cb) { |
|
82 info("Opening the inspector"); |
|
83 let target = TargetFactory.forTab(gBrowser.selectedTab); |
|
84 |
|
85 let inspector, toolbox; |
|
86 |
|
87 // Checking if the toolbox and the inspector are already loaded |
|
88 // The inspector-updated event should only be waited for if the inspector |
|
89 // isn't loaded yet |
|
90 toolbox = gDevTools.getToolbox(target); |
|
91 if (toolbox) { |
|
92 inspector = toolbox.getPanel("inspector"); |
|
93 if (inspector) { |
|
94 info("Toolbox and inspector already open"); |
|
95 if (cb) { |
|
96 return cb(inspector, toolbox); |
|
97 } else { |
|
98 return { |
|
99 toolbox: toolbox, |
|
100 inspector: inspector |
|
101 }; |
|
102 } |
|
103 } |
|
104 } |
|
105 |
|
106 info("Opening the toolbox"); |
|
107 toolbox = yield gDevTools.showToolbox(target, "inspector"); |
|
108 yield waitForToolboxFrameFocus(toolbox); |
|
109 inspector = toolbox.getPanel("inspector"); |
|
110 |
|
111 info("Waiting for the inspector to update"); |
|
112 yield inspector.once("inspector-updated"); |
|
113 |
|
114 if (cb) { |
|
115 return cb(inspector, toolbox); |
|
116 } else { |
|
117 return { |
|
118 toolbox: toolbox, |
|
119 inspector: inspector |
|
120 }; |
|
121 } |
|
122 }); |
|
123 |
|
124 /** |
|
125 * Wait for the toolbox frame to receive focus after it loads |
|
126 * @param {Toolbox} toolbox |
|
127 * @return a promise that resolves when focus has been received |
|
128 */ |
|
129 function waitForToolboxFrameFocus(toolbox) { |
|
130 info("Making sure that the toolbox's frame is focused"); |
|
131 let def = promise.defer(); |
|
132 let win = toolbox.frame.contentWindow; |
|
133 waitForFocus(def.resolve, win); |
|
134 return def.promise; |
|
135 } |
|
136 |
|
137 /** |
|
138 * Open the toolbox, with the inspector tool visible, and the sidebar that |
|
139 * corresponds to the given id selected |
|
140 * @return a promise that resolves when the inspector is ready and the sidebar |
|
141 * view is visible and ready |
|
142 */ |
|
143 let openInspectorSideBar = Task.async(function*(id) { |
|
144 let {toolbox, inspector} = yield openInspector(); |
|
145 |
|
146 if (!hasSideBarTab(inspector, id)) { |
|
147 info("Waiting for the " + id + " sidebar to be ready"); |
|
148 yield inspector.sidebar.once(id + "-ready"); |
|
149 } |
|
150 |
|
151 info("Selecting the " + id + " sidebar"); |
|
152 inspector.sidebar.select(id); |
|
153 |
|
154 return { |
|
155 toolbox: toolbox, |
|
156 inspector: inspector, |
|
157 view: inspector.sidebar.getWindowForTab(id)[id].view |
|
158 }; |
|
159 }); |
|
160 |
|
161 /** |
|
162 * Open the toolbox, with the inspector tool visible, and the computed-view |
|
163 * sidebar tab selected. |
|
164 * @return a promise that resolves when the inspector is ready and the computed |
|
165 * view is visible and ready |
|
166 */ |
|
167 function openComputedView() { |
|
168 return openInspectorSideBar("computedview"); |
|
169 } |
|
170 |
|
171 /** |
|
172 * Open the toolbox, with the inspector tool visible, and the rule-view |
|
173 * sidebar tab selected. |
|
174 * @return a promise that resolves when the inspector is ready and the rule |
|
175 * view is visible and ready |
|
176 */ |
|
177 function openRuleView() { |
|
178 return openInspectorSideBar("ruleview"); |
|
179 } |
|
180 |
|
181 /** |
|
182 * Checks whether the inspector's sidebar corresponding to the given id already |
|
183 * exists |
|
184 * @param {InspectorPanel} |
|
185 * @param {String} |
|
186 * @return {Boolean} |
|
187 */ |
|
188 function hasSideBarTab(inspector, id) { |
|
189 return !!inspector.sidebar.getWindowForTab(id); |
|
190 } |
|
191 |
|
192 function getActiveInspector() |
|
193 { |
|
194 let target = TargetFactory.forTab(gBrowser.selectedTab); |
|
195 return gDevTools.getToolbox(target).getPanel("inspector"); |
|
196 } |
|
197 |
|
198 function getNodeFront(node) |
|
199 { |
|
200 let inspector = getActiveInspector(); |
|
201 return inspector.walker.frontForRawNode(node); |
|
202 } |
|
203 |
|
204 function getHighlighter() |
|
205 { |
|
206 return gBrowser.selectedBrowser.parentNode.querySelector(".highlighter-container"); |
|
207 } |
|
208 |
|
209 function getSimpleBorderRect() { |
|
210 let {p1, p2, p3, p4} = getBoxModelStatus().border.points; |
|
211 |
|
212 return { |
|
213 top: p1.y, |
|
214 left: p1.x, |
|
215 width: p2.x - p1.x, |
|
216 height: p4.y - p1.y |
|
217 }; |
|
218 } |
|
219 |
|
220 function getBoxModelRoot() { |
|
221 let highlighter = getHighlighter(); |
|
222 return highlighter.querySelector(".box-model-root"); |
|
223 } |
|
224 |
|
225 function getBoxModelStatus() { |
|
226 let root = getBoxModelRoot(); |
|
227 let inspector = getActiveInspector(); |
|
228 |
|
229 return { |
|
230 visible: !root.hasAttribute("hidden"), |
|
231 currentNode: inspector.walker.currentNode, |
|
232 margin: { |
|
233 points: getPointsForRegion("margin"), |
|
234 visible: isRegionHidden("margin") |
|
235 }, |
|
236 border: { |
|
237 points: getPointsForRegion("border"), |
|
238 visible: isRegionHidden("border") |
|
239 }, |
|
240 padding: { |
|
241 points: getPointsForRegion("padding"), |
|
242 visible: isRegionHidden("padding") |
|
243 }, |
|
244 content: { |
|
245 points: getPointsForRegion("content"), |
|
246 visible: isRegionHidden("content") |
|
247 }, |
|
248 guides: { |
|
249 top: getGuideStatus("top"), |
|
250 right: getGuideStatus("right"), |
|
251 bottom: getGuideStatus("bottom"), |
|
252 left: getGuideStatus("left") |
|
253 } |
|
254 }; |
|
255 } |
|
256 |
|
257 function getGuideStatus(location) { |
|
258 let root = getBoxModelRoot(); |
|
259 let guide = root.querySelector(".box-model-guide-" + location); |
|
260 |
|
261 return { |
|
262 visible: !guide.hasAttribute("hidden"), |
|
263 x1: guide.getAttribute("x1"), |
|
264 y1: guide.getAttribute("y1"), |
|
265 x2: guide.getAttribute("x2"), |
|
266 y2: guide.getAttribute("y2") |
|
267 }; |
|
268 } |
|
269 |
|
270 function getPointsForRegion(region) { |
|
271 let root = getBoxModelRoot(); |
|
272 let box = root.querySelector(".box-model-" + region); |
|
273 let points = box.getAttribute("points").split(/[, ]/); |
|
274 |
|
275 // We multiply each value by 1 to cast it into a number |
|
276 return { |
|
277 p1: { |
|
278 x: parseFloat(points[0]), |
|
279 y: parseFloat(points[1]) |
|
280 }, |
|
281 p2: { |
|
282 x: parseFloat(points[2]), |
|
283 y: parseFloat(points[3]) |
|
284 }, |
|
285 p3: { |
|
286 x: parseFloat(points[4]), |
|
287 y: parseFloat(points[5]) |
|
288 }, |
|
289 p4: { |
|
290 x: parseFloat(points[6]), |
|
291 y: parseFloat(points[7]) |
|
292 } |
|
293 }; |
|
294 } |
|
295 |
|
296 function isRegionHidden(region) { |
|
297 let root = getBoxModelRoot(); |
|
298 let box = root.querySelector(".box-model-" + region); |
|
299 |
|
300 return !box.hasAttribute("hidden"); |
|
301 } |
|
302 |
|
303 function isHighlighting() |
|
304 { |
|
305 let root = getBoxModelRoot(); |
|
306 return !root.hasAttribute("hidden"); |
|
307 } |
|
308 |
|
309 function getHighlitNode() |
|
310 { |
|
311 if (isHighlighting()) { |
|
312 let helper = new LayoutHelpers(window.content); |
|
313 let points = getBoxModelStatus().content.points; |
|
314 let x = (points.p1.x + points.p2.x + points.p3.x + points.p4.x) / 4; |
|
315 let y = (points.p1.y + points.p2.y + points.p3.y + points.p4.y) / 4; |
|
316 |
|
317 return helper.getElementFromPoint(window.content.document, x, y); |
|
318 } |
|
319 } |
|
320 |
|
321 function computedView() |
|
322 { |
|
323 let sidebar = getActiveInspector().sidebar; |
|
324 let iframe = sidebar.tabbox.querySelector(".iframe-computedview"); |
|
325 return iframe.contentWindow.computedView; |
|
326 } |
|
327 |
|
328 function computedViewTree() |
|
329 { |
|
330 return computedView().view; |
|
331 } |
|
332 |
|
333 function ruleView() |
|
334 { |
|
335 let sidebar = getActiveInspector().sidebar; |
|
336 let iframe = sidebar.tabbox.querySelector(".iframe-ruleview"); |
|
337 return iframe.contentWindow.ruleView; |
|
338 } |
|
339 |
|
340 function getComputedView() { |
|
341 let inspector = getActiveInspector(); |
|
342 return inspector.sidebar.getWindowForTab("computedview").computedview.view; |
|
343 } |
|
344 |
|
345 function waitForView(aName, aCallback) { |
|
346 let inspector = getActiveInspector(); |
|
347 if (inspector.sidebar.getTab(aName)) { |
|
348 aCallback(); |
|
349 } else { |
|
350 inspector.sidebar.once(aName + "-ready", aCallback); |
|
351 } |
|
352 } |
|
353 |
|
354 function synthesizeKeyFromKeyTag(aKeyId) { |
|
355 let key = document.getElementById(aKeyId); |
|
356 isnot(key, null, "Successfully retrieved the <key> node"); |
|
357 |
|
358 let modifiersAttr = key.getAttribute("modifiers"); |
|
359 |
|
360 let name = null; |
|
361 |
|
362 if (key.getAttribute("keycode")) |
|
363 name = key.getAttribute("keycode"); |
|
364 else if (key.getAttribute("key")) |
|
365 name = key.getAttribute("key"); |
|
366 |
|
367 isnot(name, null, "Successfully retrieved keycode/key"); |
|
368 |
|
369 let modifiers = { |
|
370 shiftKey: modifiersAttr.match("shift"), |
|
371 ctrlKey: modifiersAttr.match("ctrl"), |
|
372 altKey: modifiersAttr.match("alt"), |
|
373 metaKey: modifiersAttr.match("meta"), |
|
374 accelKey: modifiersAttr.match("accel") |
|
375 } |
|
376 |
|
377 EventUtils.synthesizeKey(name, modifiers); |
|
378 } |
|
379 |
|
380 function focusSearchBoxUsingShortcut(panelWin, callback) { |
|
381 panelWin.focus(); |
|
382 let key = panelWin.document.getElementById("nodeSearchKey"); |
|
383 isnot(key, null, "Successfully retrieved the <key> node"); |
|
384 |
|
385 let modifiersAttr = key.getAttribute("modifiers"); |
|
386 |
|
387 let name = null; |
|
388 |
|
389 if (key.getAttribute("keycode")) { |
|
390 name = key.getAttribute("keycode"); |
|
391 } else if (key.getAttribute("key")) { |
|
392 name = key.getAttribute("key"); |
|
393 } |
|
394 |
|
395 isnot(name, null, "Successfully retrieved keycode/key"); |
|
396 |
|
397 let modifiers = { |
|
398 shiftKey: modifiersAttr.match("shift"), |
|
399 ctrlKey: modifiersAttr.match("ctrl"), |
|
400 altKey: modifiersAttr.match("alt"), |
|
401 metaKey: modifiersAttr.match("meta"), |
|
402 accelKey: modifiersAttr.match("accel") |
|
403 } |
|
404 |
|
405 let searchBox = panelWin.document.getElementById("inspector-searchbox"); |
|
406 searchBox.addEventListener("focus", function onFocus() { |
|
407 searchBox.removeEventListener("focus", onFocus, false); |
|
408 callback && callback(); |
|
409 }, false); |
|
410 EventUtils.synthesizeKey(name, modifiers); |
|
411 } |
|
412 |
|
413 function getComputedPropertyValue(aName) |
|
414 { |
|
415 let computedview = getComputedView(); |
|
416 let props = computedview.styleDocument.querySelectorAll(".property-view"); |
|
417 |
|
418 for (let prop of props) { |
|
419 let name = prop.querySelector(".property-name"); |
|
420 |
|
421 if (name.textContent === aName) { |
|
422 let value = prop.querySelector(".property-value"); |
|
423 return value.textContent; |
|
424 } |
|
425 } |
|
426 } |
|
427 |
|
428 function getContainerForRawNode(markupView, rawNode) |
|
429 { |
|
430 let front = markupView.walker.frontForRawNode(rawNode); |
|
431 let container = markupView.getContainer(front); |
|
432 return container; |
|
433 } |
|
434 |
|
435 SimpleTest.registerCleanupFunction(function () { |
|
436 let target = TargetFactory.forTab(gBrowser.selectedTab); |
|
437 gDevTools.closeToolbox(target); |
|
438 }); |