|
1 /* vim:set ts=2 sw=2 sts=2 et: */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 const TEST_URI = "http://example.com/browser/dom/tests/browser/test-console-api.html"; |
|
7 |
|
8 var gWindow, gLevel, gArgs, gTestDriver, gStyle; |
|
9 |
|
10 function test() { |
|
11 waitForExplicitFinish(); |
|
12 |
|
13 var tab = gBrowser.addTab(TEST_URI); |
|
14 gBrowser.selectedTab = tab; |
|
15 var browser = gBrowser.selectedBrowser; |
|
16 |
|
17 registerCleanupFunction(function () { |
|
18 gWindow = gLevel = gArgs = gTestDriver = null; |
|
19 gBrowser.removeTab(tab); |
|
20 }); |
|
21 |
|
22 ConsoleObserver.init(); |
|
23 |
|
24 browser.addEventListener("DOMContentLoaded", function onLoad(event) { |
|
25 browser.removeEventListener("DOMContentLoaded", onLoad, false); |
|
26 executeSoon(function test_executeSoon() { |
|
27 gWindow = browser.contentWindow; |
|
28 consoleAPISanityTest(); |
|
29 gTestDriver = observeConsoleTest(); |
|
30 gTestDriver.next(); |
|
31 }); |
|
32 |
|
33 }, false); |
|
34 } |
|
35 |
|
36 function testConsoleData(aMessageObject) { |
|
37 let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID); |
|
38 is(messageWindow, gWindow, "found correct window by window ID"); |
|
39 |
|
40 is(aMessageObject.level, gLevel, "expected level received"); |
|
41 ok(aMessageObject.arguments, "we have arguments"); |
|
42 |
|
43 switch (gLevel) { |
|
44 case "trace": { |
|
45 is(aMessageObject.arguments.length, 0, "arguments.length matches"); |
|
46 is(aMessageObject.stacktrace.toSource(), gArgs.toSource(), |
|
47 "stack trace is correct"); |
|
48 break |
|
49 } |
|
50 case "count": { |
|
51 is(aMessageObject.counter.label, gArgs[0].label, "label matches"); |
|
52 is(aMessageObject.counter.count, gArgs[0].count, "count matches"); |
|
53 break; |
|
54 } |
|
55 default: { |
|
56 is(aMessageObject.arguments.length, gArgs.length, "arguments.length matches"); |
|
57 gArgs.forEach(function (a, i) { |
|
58 // Waive Xray so that we don't get messed up by Xray ToString. |
|
59 // |
|
60 // It'd be nice to just use XPCNativeWrapper.unwrap here, but there are |
|
61 // a number of dumb reasons we can't. See bug 868675. |
|
62 var arg = aMessageObject.arguments[i]; |
|
63 if (Components.utils.isXrayWrapper(arg)) |
|
64 arg = arg.wrappedJSObject; |
|
65 is(arg, a, "correct arg " + i); |
|
66 }); |
|
67 |
|
68 if (gStyle) { |
|
69 is(aMessageObject.styles.length, gStyle.length, "styles.length matches"); |
|
70 is(aMessageObject.styles + "", gStyle + "", "styles match"); |
|
71 } else { |
|
72 ok(!aMessageObject.styles || aMessageObject.styles.length === 0, |
|
73 "styles match"); |
|
74 } |
|
75 } |
|
76 } |
|
77 |
|
78 gTestDriver.next(); |
|
79 } |
|
80 |
|
81 function testLocationData(aMessageObject) { |
|
82 let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID); |
|
83 is(messageWindow, gWindow, "found correct window by window ID"); |
|
84 |
|
85 is(aMessageObject.level, gLevel, "expected level received"); |
|
86 ok(aMessageObject.arguments, "we have arguments"); |
|
87 |
|
88 is(aMessageObject.filename, gArgs[0].filename, "filename matches"); |
|
89 is(aMessageObject.lineNumber, gArgs[0].lineNumber, "lineNumber matches"); |
|
90 is(aMessageObject.functionName, gArgs[0].functionName, "functionName matches"); |
|
91 is(aMessageObject.arguments.length, gArgs[0].arguments.length, "arguments.length matches"); |
|
92 gArgs[0].arguments.forEach(function (a, i) { |
|
93 is(aMessageObject.arguments[i], a, "correct arg " + i); |
|
94 }); |
|
95 |
|
96 startNativeCallbackTest(); |
|
97 } |
|
98 |
|
99 function startNativeCallbackTest() { |
|
100 // Reset the observer function to cope with the fabricated test data. |
|
101 ConsoleObserver.observe = function CO_observe(aSubject, aTopic, aData) { |
|
102 try { |
|
103 testNativeCallback(aSubject.wrappedJSObject); |
|
104 } catch (ex) { |
|
105 // XXX Bug 906593 - Exceptions in this function currently aren't |
|
106 // reported, because of some XPConnect weirdness, so report them manually |
|
107 ok(false, "Exception thrown in CO_observe: " + ex); |
|
108 } |
|
109 }; |
|
110 |
|
111 let button = gWindow.document.getElementById("test-nativeCallback"); |
|
112 ok(button, "found #test-nativeCallback button"); |
|
113 EventUtils.synthesizeMouseAtCenter(button, {}, gWindow); |
|
114 } |
|
115 |
|
116 function testNativeCallback(aMessageObject) { |
|
117 is(aMessageObject.level, "log", "expected level received"); |
|
118 is(aMessageObject.filename, "", "filename matches"); |
|
119 is(aMessageObject.lineNumber, 0, "lineNumber matches"); |
|
120 is(aMessageObject.functionName, "", "functionName matches"); |
|
121 |
|
122 startGroupTest(); |
|
123 } |
|
124 |
|
125 function startGroupTest() { |
|
126 // Reset the observer function to cope with the fabricated test data. |
|
127 ConsoleObserver.observe = function CO_observe(aSubject, aTopic, aData) { |
|
128 try { |
|
129 testConsoleGroup(aSubject.wrappedJSObject); |
|
130 } catch (ex) { |
|
131 // XXX Bug 906593 - Exceptions in this function currently aren't |
|
132 // reported, because of some XPConnect weirdness, so report them manually |
|
133 ok(false, "Exception thrown in CO_observe: " + ex); |
|
134 } |
|
135 }; |
|
136 let button = gWindow.document.getElementById("test-groups"); |
|
137 ok(button, "found #test-groups button"); |
|
138 EventUtils.synthesizeMouseAtCenter(button, {}, gWindow); |
|
139 } |
|
140 |
|
141 function testConsoleGroup(aMessageObject) { |
|
142 let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID); |
|
143 is(messageWindow, gWindow, "found correct window by window ID"); |
|
144 |
|
145 ok(aMessageObject.level == "group" || |
|
146 aMessageObject.level == "groupCollapsed" || |
|
147 aMessageObject.level == "groupEnd", |
|
148 "expected level received"); |
|
149 |
|
150 is(aMessageObject.functionName, "testGroups", "functionName matches"); |
|
151 ok(aMessageObject.lineNumber >= 46 && aMessageObject.lineNumber <= 50, |
|
152 "lineNumber matches"); |
|
153 if (aMessageObject.level == "groupCollapsed") { |
|
154 is(aMessageObject.groupName, "a group", "groupCollapsed groupName matches"); |
|
155 is(aMessageObject.arguments[0], "a", "groupCollapsed arguments[0] matches"); |
|
156 is(aMessageObject.arguments[1], "group", "groupCollapsed arguments[0] matches"); |
|
157 } |
|
158 else if (aMessageObject.level == "group") { |
|
159 is(aMessageObject.groupName, "b group", "group groupName matches"); |
|
160 is(aMessageObject.arguments[0], "b", "group arguments[0] matches"); |
|
161 is(aMessageObject.arguments[1], "group", "group arguments[1] matches"); |
|
162 } |
|
163 else if (aMessageObject.level == "groupEnd") { |
|
164 let groupName = Array.prototype.join.call(aMessageObject.arguments, " "); |
|
165 is(groupName,"b group", "groupEnd arguments matches"); |
|
166 is(aMessageObject.groupName, "b group", "groupEnd groupName matches"); |
|
167 } |
|
168 |
|
169 if (aMessageObject.level == "groupEnd") { |
|
170 startTimeTest(); |
|
171 } |
|
172 } |
|
173 |
|
174 function startTraceTest() { |
|
175 gLevel = "trace"; |
|
176 gArgs = [ |
|
177 {filename: TEST_URI, functionName: "window.foobar585956c", language: 2, lineNumber: 6}, |
|
178 {filename: TEST_URI, functionName: "foobar585956b", language: 2, lineNumber: 11}, |
|
179 {filename: TEST_URI, functionName: "foobar585956a", language: 2, lineNumber: 15}, |
|
180 {filename: TEST_URI, functionName: "onclick", language: 2, lineNumber: 1} |
|
181 ]; |
|
182 |
|
183 let button = gWindow.document.getElementById("test-trace"); |
|
184 ok(button, "found #test-trace button"); |
|
185 EventUtils.synthesizeMouseAtCenter(button, {}, gWindow); |
|
186 } |
|
187 |
|
188 function startLocationTest() { |
|
189 // Reset the observer function to cope with the fabricated test data. |
|
190 ConsoleObserver.observe = function CO_observe(aSubject, aTopic, aData) { |
|
191 try { |
|
192 testLocationData(aSubject.wrappedJSObject); |
|
193 } catch (ex) { |
|
194 // XXX Bug 906593 - Exceptions in this function currently aren't |
|
195 // reported, because of some XPConnect weirdness, so report them manually |
|
196 ok(false, "Exception thrown in CO_observe: " + ex); |
|
197 } |
|
198 }; |
|
199 gLevel = "log"; |
|
200 gArgs = [ |
|
201 {filename: TEST_URI, functionName: "foobar646025", arguments: ["omg", "o", "d"], lineNumber: 19} |
|
202 ]; |
|
203 |
|
204 let button = gWindow.document.getElementById("test-location"); |
|
205 ok(button, "found #test-location button"); |
|
206 EventUtils.synthesizeMouseAtCenter(button, {}, gWindow); |
|
207 } |
|
208 |
|
209 function expect(level) { |
|
210 gLevel = level; |
|
211 gArgs = Array.slice(arguments, 1); |
|
212 } |
|
213 |
|
214 function observeConsoleTest() { |
|
215 let win = XPCNativeWrapper.unwrap(gWindow); |
|
216 expect("log", "arg"); |
|
217 win.console.log("arg"); |
|
218 yield undefined; |
|
219 |
|
220 expect("info", "arg", "extra arg"); |
|
221 win.console.info("arg", "extra arg"); |
|
222 yield undefined; |
|
223 |
|
224 expect("warn", "Lesson 1: PI is approximately equal to 3"); |
|
225 win.console.warn("Lesson %d: %s is approximately equal to %1.0f", |
|
226 1, |
|
227 "PI", |
|
228 3.14159); |
|
229 yield undefined; |
|
230 |
|
231 expect("warn", "Lesson 1: PI is approximately equal to 3.14"); |
|
232 win.console.warn("Lesson %d: %s is approximately equal to %1.2f", |
|
233 1, |
|
234 "PI", |
|
235 3.14159); |
|
236 yield undefined; |
|
237 |
|
238 expect("warn", "Lesson 1: PI is approximately equal to 3.141590"); |
|
239 win.console.warn("Lesson %d: %s is approximately equal to %f", |
|
240 1, |
|
241 "PI", |
|
242 3.14159); |
|
243 yield undefined; |
|
244 |
|
245 expect("warn", "Lesson 1: PI is approximately equal to 3.1415900"); |
|
246 win.console.warn("Lesson %d: %s is approximately equal to %0.7f", |
|
247 1, |
|
248 "PI", |
|
249 3.14159); |
|
250 yield undefined; |
|
251 |
|
252 expect("log", "%d, %s, %l"); |
|
253 win.console.log("%d, %s, %l"); |
|
254 yield undefined; |
|
255 |
|
256 expect("log", "%a %b %g"); |
|
257 win.console.log("%a %b %g"); |
|
258 yield undefined; |
|
259 |
|
260 expect("log", "%a %b %g", "a", "b"); |
|
261 win.console.log("%a %b %g", "a", "b"); |
|
262 yield undefined; |
|
263 |
|
264 expect("log", "2, a, %l", 3); |
|
265 win.console.log("%d, %s, %l", 2, "a", 3); |
|
266 yield undefined; |
|
267 |
|
268 // Bug #692550 handle null and undefined. |
|
269 expect("log", "null, undefined"); |
|
270 win.console.log("%s, %s", null, undefined); |
|
271 yield undefined; |
|
272 |
|
273 // Bug #696288 handle object as first argument. |
|
274 let obj = { a: 1 }; |
|
275 expect("log", obj, "a"); |
|
276 win.console.log(obj, "a"); |
|
277 yield undefined; |
|
278 |
|
279 expect("dir", win.toString()); |
|
280 win.console.dir(win); |
|
281 yield undefined; |
|
282 |
|
283 expect("error", "arg"); |
|
284 win.console.error("arg"); |
|
285 yield undefined; |
|
286 |
|
287 expect("exception", "arg"); |
|
288 win.console.exception("arg"); |
|
289 yield undefined; |
|
290 |
|
291 expect("log", "foobar"); |
|
292 gStyle = ["color:red;foobar;;"]; |
|
293 win.console.log("%cfoobar", gStyle[0]); |
|
294 yield undefined; |
|
295 |
|
296 let obj4 = { d: 4 }; |
|
297 expect("warn", "foobar", obj4, "test", "bazbazstr", "last"); |
|
298 gStyle = [null, null, null, "color:blue;", "color:red"]; |
|
299 win.console.warn("foobar%Otest%cbazbaz%s%clast", obj4, gStyle[3], "str", gStyle[4]); |
|
300 yield undefined; |
|
301 |
|
302 let obj3 = { c: 3 }; |
|
303 expect("info", "foobar", "bazbaz", obj3, "%comg", "color:yellow"); |
|
304 gStyle = [null, "color:pink;"]; |
|
305 win.console.info("foobar%cbazbaz", gStyle[1], obj3, "%comg", "color:yellow"); |
|
306 yield undefined; |
|
307 |
|
308 gStyle = null; |
|
309 let obj2 = { b: 2 }; |
|
310 expect("log", "omg ", obj, " foo ", 4, obj2); |
|
311 win.console.log("omg %o foo %o", obj, 4, obj2); |
|
312 yield undefined; |
|
313 |
|
314 expect("assert", "message"); |
|
315 win.console.assert(false, "message"); |
|
316 yield undefined; |
|
317 |
|
318 expect("count", { label: "label a", count: 1 }) |
|
319 win.console.count("label a"); |
|
320 yield undefined; |
|
321 |
|
322 expect("count", { label: "label b", count: 1 }) |
|
323 win.console.count("label b"); |
|
324 yield undefined; |
|
325 |
|
326 expect("count", { label: "label a", count: 2 }) |
|
327 win.console.count("label a"); |
|
328 yield undefined; |
|
329 |
|
330 expect("count", { label: "label b", count: 2 }) |
|
331 win.console.count("label b"); |
|
332 yield undefined; |
|
333 |
|
334 startTraceTest(); |
|
335 yield undefined; |
|
336 |
|
337 startLocationTest(); |
|
338 yield undefined; |
|
339 } |
|
340 |
|
341 function consoleAPISanityTest() { |
|
342 let win = XPCNativeWrapper.unwrap(gWindow); |
|
343 ok(win.console, "we have a console attached"); |
|
344 ok(win.console, "we have a console attached, 2nd attempt"); |
|
345 |
|
346 ok(win.console.log, "console.log is here"); |
|
347 ok(win.console.info, "console.info is here"); |
|
348 ok(win.console.warn, "console.warn is here"); |
|
349 ok(win.console.error, "console.error is here"); |
|
350 ok(win.console.exception, "console.exception is here"); |
|
351 ok(win.console.trace, "console.trace is here"); |
|
352 ok(win.console.dir, "console.dir is here"); |
|
353 ok(win.console.group, "console.group is here"); |
|
354 ok(win.console.groupCollapsed, "console.groupCollapsed is here"); |
|
355 ok(win.console.groupEnd, "console.groupEnd is here"); |
|
356 ok(win.console.time, "console.time is here"); |
|
357 ok(win.console.timeEnd, "console.timeEnd is here"); |
|
358 ok(win.console.assert, "console.assert is here"); |
|
359 ok(win.console.count, "console.count is here"); |
|
360 } |
|
361 |
|
362 function startTimeTest() { |
|
363 // Reset the observer function to cope with the fabricated test data. |
|
364 ConsoleObserver.observe = function CO_observe(aSubject, aTopic, aData) { |
|
365 try { |
|
366 testConsoleTime(aSubject.wrappedJSObject); |
|
367 } catch (ex) { |
|
368 // XXX Bug 906593 - Exceptions in this function currently aren't |
|
369 // reported, because of some XPConnect weirdness, so report them manually |
|
370 ok(false, "Exception thrown in CO_observe: " + ex); |
|
371 } |
|
372 }; |
|
373 gLevel = "time"; |
|
374 gArgs = [ |
|
375 {filename: TEST_URI, lineNumber: 23, functionName: "startTimer", |
|
376 arguments: ["foo"], |
|
377 timer: { name: "foo" }, |
|
378 } |
|
379 ]; |
|
380 |
|
381 let button = gWindow.document.getElementById("test-time"); |
|
382 ok(button, "found #test-time button"); |
|
383 EventUtils.synthesizeMouseAtCenter(button, {}, gWindow); |
|
384 } |
|
385 |
|
386 function testConsoleTime(aMessageObject) { |
|
387 let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID); |
|
388 is(messageWindow, gWindow, "found correct window by window ID"); |
|
389 |
|
390 is(aMessageObject.level, gLevel, "expected level received"); |
|
391 |
|
392 is(aMessageObject.filename, gArgs[0].filename, "filename matches"); |
|
393 is(aMessageObject.lineNumber, gArgs[0].lineNumber, "lineNumber matches"); |
|
394 is(aMessageObject.functionName, gArgs[0].functionName, "functionName matches"); |
|
395 is(aMessageObject.timer.name, gArgs[0].timer.name, "timer.name matches"); |
|
396 ok(aMessageObject.timer.started, "timer.started exists"); |
|
397 |
|
398 gArgs[0].arguments.forEach(function (a, i) { |
|
399 is(aMessageObject.arguments[i], a, "correct arg " + i); |
|
400 }); |
|
401 |
|
402 startTimeEndTest(); |
|
403 } |
|
404 |
|
405 function startTimeEndTest() { |
|
406 // Reset the observer function to cope with the fabricated test data. |
|
407 ConsoleObserver.observe = function CO_observe(aSubject, aTopic, aData) { |
|
408 try { |
|
409 testConsoleTimeEnd(aSubject.wrappedJSObject); |
|
410 } catch (ex) { |
|
411 // XXX Bug 906593 - Exceptions in this function currently aren't |
|
412 // reported, because of some XPConnect weirdness, so report them manually |
|
413 ok(false, "Exception thrown in CO_observe: " + ex); |
|
414 } |
|
415 }; |
|
416 gLevel = "timeEnd"; |
|
417 gArgs = [ |
|
418 {filename: TEST_URI, lineNumber: 27, functionName: "stopTimer", |
|
419 arguments: ["foo"], |
|
420 timer: { name: "foo" }, |
|
421 }, |
|
422 ]; |
|
423 |
|
424 let button = gWindow.document.getElementById("test-timeEnd"); |
|
425 ok(button, "found #test-timeEnd button"); |
|
426 EventUtils.synthesizeMouseAtCenter(button, {}, gWindow); |
|
427 } |
|
428 |
|
429 function testConsoleTimeEnd(aMessageObject) { |
|
430 let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID); |
|
431 is(messageWindow, gWindow, "found correct window by window ID"); |
|
432 |
|
433 is(aMessageObject.level, gLevel, "expected level received"); |
|
434 ok(aMessageObject.arguments, "we have arguments"); |
|
435 |
|
436 is(aMessageObject.filename, gArgs[0].filename, "filename matches"); |
|
437 is(aMessageObject.lineNumber, gArgs[0].lineNumber, "lineNumber matches"); |
|
438 is(aMessageObject.functionName, gArgs[0].functionName, "functionName matches"); |
|
439 is(aMessageObject.arguments.length, gArgs[0].arguments.length, "arguments.length matches"); |
|
440 is(aMessageObject.timer.name, gArgs[0].timer.name, "timer name matches"); |
|
441 is(typeof aMessageObject.timer.duration, "number", "timer duration is a number"); |
|
442 info("timer duration: " + aMessageObject.timer.duration); |
|
443 ok(aMessageObject.timer.duration >= 0, "timer duration is positive"); |
|
444 |
|
445 gArgs[0].arguments.forEach(function (a, i) { |
|
446 is(aMessageObject.arguments[i], a, "correct arg " + i); |
|
447 }); |
|
448 |
|
449 startEmptyTimerTest(); |
|
450 } |
|
451 |
|
452 function startEmptyTimerTest() { |
|
453 // Reset the observer function to cope with the fabricated test data. |
|
454 ConsoleObserver.observe = function CO_observe(aSubject, aTopic, aData) { |
|
455 try { |
|
456 testEmptyTimer(aSubject.wrappedJSObject); |
|
457 } catch (ex) { |
|
458 // XXX Bug 906593 - Exceptions in this function currently aren't |
|
459 // reported, because of some XPConnect weirdness, so report them manually |
|
460 ok(false, "Exception thrown in CO_observe: " + ex); |
|
461 } |
|
462 }; |
|
463 |
|
464 let button = gWindow.document.getElementById("test-namelessTimer"); |
|
465 ok(button, "found #test-namelessTimer button"); |
|
466 EventUtils.synthesizeMouseAtCenter(button, {}, gWindow); |
|
467 } |
|
468 |
|
469 function testEmptyTimer(aMessageObject) { |
|
470 let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID); |
|
471 is(messageWindow, gWindow, "found correct window by window ID"); |
|
472 |
|
473 ok(aMessageObject.level == "time" || aMessageObject.level == "timeEnd", |
|
474 "expected level received"); |
|
475 is(aMessageObject.arguments.length, 0, "we don't have arguments"); |
|
476 ok(!aMessageObject.timer, "we don't have a timer"); |
|
477 |
|
478 is(aMessageObject.functionName, "namelessTimer", "functionName matches"); |
|
479 ok(aMessageObject.lineNumber == 31 || aMessageObject.lineNumber == 32, |
|
480 "lineNumber matches"); |
|
481 // Test finished |
|
482 ConsoleObserver.destroy(); |
|
483 finish(); |
|
484 } |
|
485 |
|
486 var ConsoleObserver = { |
|
487 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), |
|
488 |
|
489 init: function CO_init() { |
|
490 Services.obs.addObserver(this, "console-api-log-event", false); |
|
491 }, |
|
492 |
|
493 destroy: function CO_destroy() { |
|
494 Services.obs.removeObserver(this, "console-api-log-event"); |
|
495 }, |
|
496 |
|
497 observe: function CO_observe(aSubject, aTopic, aData) { |
|
498 try { |
|
499 testConsoleData(aSubject.wrappedJSObject); |
|
500 } catch (ex) { |
|
501 // XXX Bug 906593 - Exceptions in this function currently aren't |
|
502 // reported, because of some XPConnect weirdness, so report them manually |
|
503 ok(false, "Exception thrown in CO_observe: " + ex); |
|
504 } |
|
505 } |
|
506 }; |
|
507 |
|
508 function getWindowId(aWindow) |
|
509 { |
|
510 return aWindow.QueryInterface(Ci.nsIInterfaceRequestor) |
|
511 .getInterface(Ci.nsIDOMWindowUtils) |
|
512 .outerWindowID; |
|
513 } |