|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 "use strict"; |
|
4 |
|
5 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; |
|
6 |
|
7 let { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); |
|
8 |
|
9 // Disable logging for all the tests. Both the debugger server and frontend will |
|
10 // be affected by this pref. |
|
11 let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log"); |
|
12 Services.prefs.setBoolPref("devtools.debugger.log", false); |
|
13 |
|
14 let { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); |
|
15 let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); |
|
16 let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); |
|
17 let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); |
|
18 let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {}); |
|
19 let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {}); |
|
20 |
|
21 let { CallWatcherFront } = devtools.require("devtools/server/actors/call-watcher"); |
|
22 let { CanvasFront } = devtools.require("devtools/server/actors/canvas"); |
|
23 let TiltGL = devtools.require("devtools/tilt/tilt-gl"); |
|
24 let TargetFactory = devtools.TargetFactory; |
|
25 let Toolbox = devtools.Toolbox; |
|
26 |
|
27 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/canvasdebugger/test/"; |
|
28 const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html"; |
|
29 const SIMPLE_CANVAS_TRANSPARENT_URL = EXAMPLE_URL + "doc_simple-canvas-transparent.html"; |
|
30 const SIMPLE_CANVAS_DEEP_STACK_URL = EXAMPLE_URL + "doc_simple-canvas-deep-stack.html"; |
|
31 |
|
32 // All tests are asynchronous. |
|
33 waitForExplicitFinish(); |
|
34 |
|
35 let gToolEnabled = Services.prefs.getBoolPref("devtools.canvasdebugger.enabled"); |
|
36 |
|
37 registerCleanupFunction(() => { |
|
38 info("finish() was called, cleaning up..."); |
|
39 Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging); |
|
40 Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", gToolEnabled); |
|
41 |
|
42 // Some of yhese tests use a lot of memory due to GL contexts, so force a GC |
|
43 // to help fragmentation. |
|
44 info("Forcing GC after canvas debugger test."); |
|
45 Cu.forceGC(); |
|
46 }); |
|
47 |
|
48 function addTab(aUrl, aWindow) { |
|
49 info("Adding tab: " + aUrl); |
|
50 |
|
51 let deferred = promise.defer(); |
|
52 let targetWindow = aWindow || window; |
|
53 let targetBrowser = targetWindow.gBrowser; |
|
54 |
|
55 targetWindow.focus(); |
|
56 let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl); |
|
57 let linkedBrowser = tab.linkedBrowser; |
|
58 |
|
59 linkedBrowser.addEventListener("load", function onLoad() { |
|
60 linkedBrowser.removeEventListener("load", onLoad, true); |
|
61 info("Tab added and finished loading: " + aUrl); |
|
62 deferred.resolve(tab); |
|
63 }, true); |
|
64 |
|
65 return deferred.promise; |
|
66 } |
|
67 |
|
68 function removeTab(aTab, aWindow) { |
|
69 info("Removing tab."); |
|
70 |
|
71 let deferred = promise.defer(); |
|
72 let targetWindow = aWindow || window; |
|
73 let targetBrowser = targetWindow.gBrowser; |
|
74 let tabContainer = targetBrowser.tabContainer; |
|
75 |
|
76 tabContainer.addEventListener("TabClose", function onClose(aEvent) { |
|
77 tabContainer.removeEventListener("TabClose", onClose, false); |
|
78 info("Tab removed and finished closing."); |
|
79 deferred.resolve(); |
|
80 }, false); |
|
81 |
|
82 targetBrowser.removeTab(aTab); |
|
83 return deferred.promise; |
|
84 } |
|
85 |
|
86 function handleError(aError) { |
|
87 ok(false, "Got an error: " + aError.message + "\n" + aError.stack); |
|
88 finish(); |
|
89 } |
|
90 |
|
91 let gRequiresWebGL = false; |
|
92 |
|
93 function ifTestingSupported() { |
|
94 ok(false, "You need to define a 'ifTestingSupported' function."); |
|
95 finish(); |
|
96 } |
|
97 |
|
98 function ifTestingUnsupported() { |
|
99 todo(false, "Skipping test because some required functionality isn't supported."); |
|
100 finish(); |
|
101 } |
|
102 |
|
103 function test() { |
|
104 let generator = isTestingSupported() ? ifTestingSupported : ifTestingUnsupported; |
|
105 Task.spawn(generator).then(null, handleError); |
|
106 } |
|
107 |
|
108 function createCanvas() { |
|
109 return document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); |
|
110 } |
|
111 |
|
112 function isTestingSupported() { |
|
113 if (!gRequiresWebGL) { |
|
114 info("This test does not require WebGL support."); |
|
115 return true; |
|
116 } |
|
117 |
|
118 let supported = |
|
119 !TiltGL.isWebGLForceEnabled() && |
|
120 TiltGL.isWebGLSupported() && |
|
121 TiltGL.create3DContext(createCanvas()); |
|
122 |
|
123 info("This test requires WebGL support."); |
|
124 info("Apparently, WebGL is" + (supported ? "" : " not") + " supported."); |
|
125 return supported; |
|
126 } |
|
127 |
|
128 function once(aTarget, aEventName, aUseCapture = false) { |
|
129 info("Waiting for event: '" + aEventName + "' on " + aTarget + "."); |
|
130 |
|
131 let deferred = promise.defer(); |
|
132 |
|
133 for (let [add, remove] of [ |
|
134 ["on", "off"], // Use event emitter before DOM events for consistency |
|
135 ["addEventListener", "removeEventListener"], |
|
136 ["addListener", "removeListener"] |
|
137 ]) { |
|
138 if ((add in aTarget) && (remove in aTarget)) { |
|
139 aTarget[add](aEventName, function onEvent(...aArgs) { |
|
140 aTarget[remove](aEventName, onEvent, aUseCapture); |
|
141 deferred.resolve(...aArgs); |
|
142 }, aUseCapture); |
|
143 break; |
|
144 } |
|
145 } |
|
146 |
|
147 return deferred.promise; |
|
148 } |
|
149 |
|
150 function waitForTick() { |
|
151 let deferred = promise.defer(); |
|
152 executeSoon(deferred.resolve); |
|
153 return deferred.promise; |
|
154 } |
|
155 |
|
156 function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate") { |
|
157 executeSoon(() => content.history[aDirection]()); |
|
158 return once(aTarget, aWaitForTargetEvent); |
|
159 } |
|
160 |
|
161 function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") { |
|
162 executeSoon(() => aTarget.activeTab.navigateTo(aUrl)); |
|
163 return once(aTarget, aWaitForTargetEvent); |
|
164 } |
|
165 |
|
166 function reload(aTarget, aWaitForTargetEvent = "navigate") { |
|
167 executeSoon(() => aTarget.activeTab.reload()); |
|
168 return once(aTarget, aWaitForTargetEvent); |
|
169 } |
|
170 |
|
171 function initServer() { |
|
172 if (!DebuggerServer.initialized) { |
|
173 DebuggerServer.init(() => true); |
|
174 DebuggerServer.addBrowserActors(); |
|
175 } |
|
176 } |
|
177 |
|
178 function initCallWatcherBackend(aUrl) { |
|
179 info("Initializing a call watcher front."); |
|
180 initServer(); |
|
181 |
|
182 return Task.spawn(function*() { |
|
183 let tab = yield addTab(aUrl); |
|
184 let target = TargetFactory.forTab(tab); |
|
185 let debuggee = target.window.wrappedJSObject; |
|
186 |
|
187 yield target.makeRemote(); |
|
188 |
|
189 let front = new CallWatcherFront(target.client, target.form); |
|
190 return [target, debuggee, front]; |
|
191 }); |
|
192 } |
|
193 |
|
194 function initCanavsDebuggerBackend(aUrl) { |
|
195 info("Initializing a canvas debugger front."); |
|
196 initServer(); |
|
197 |
|
198 return Task.spawn(function*() { |
|
199 let tab = yield addTab(aUrl); |
|
200 let target = TargetFactory.forTab(tab); |
|
201 let debuggee = target.window.wrappedJSObject; |
|
202 |
|
203 yield target.makeRemote(); |
|
204 |
|
205 let front = new CanvasFront(target.client, target.form); |
|
206 return [target, debuggee, front]; |
|
207 }); |
|
208 } |
|
209 |
|
210 function initCanavsDebuggerFrontend(aUrl) { |
|
211 info("Initializing a canvas debugger pane."); |
|
212 |
|
213 return Task.spawn(function*() { |
|
214 let tab = yield addTab(aUrl); |
|
215 let target = TargetFactory.forTab(tab); |
|
216 let debuggee = target.window.wrappedJSObject; |
|
217 |
|
218 yield target.makeRemote(); |
|
219 |
|
220 Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", true); |
|
221 let toolbox = yield gDevTools.showToolbox(target, "canvasdebugger"); |
|
222 let panel = toolbox.getCurrentPanel(); |
|
223 return [target, debuggee, panel]; |
|
224 }); |
|
225 } |
|
226 |
|
227 function teardown(aPanel) { |
|
228 info("Destroying the specified canvas debugger."); |
|
229 |
|
230 return promise.all([ |
|
231 once(aPanel, "destroyed"), |
|
232 removeTab(aPanel.target.tab) |
|
233 ]); |
|
234 } |