|
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 'use strict'; |
|
5 |
|
6 module.metadata = { |
|
7 'engines': { |
|
8 'Firefox': '*' |
|
9 } |
|
10 }; |
|
11 |
|
12 const { Cc, Ci, Cu } = require("chrome"); |
|
13 const { LoaderWithHookedConsole } = require('sdk/test/loader'); |
|
14 const url = require("sdk/url"); |
|
15 const timer = require("sdk/timers"); |
|
16 const self = require("sdk/self"); |
|
17 const { getMostRecentBrowserWindow } = require('sdk/window/utils'); |
|
18 const { close, open, focus } = require("sdk/window/helpers"); |
|
19 const tabs = require("sdk/tabs/utils"); |
|
20 const { merge } = require("sdk/util/object"); |
|
21 const unload = require("sdk/system/unload"); |
|
22 const fixtures = require("./fixtures"); |
|
23 |
|
24 let jetpackID = "testID"; |
|
25 try { |
|
26 jetpackID = require("sdk/self").id; |
|
27 } catch(e) {} |
|
28 |
|
29 function openNewWindowTab(url, options) { |
|
30 return open('chrome://browser/content/browser.xul', { |
|
31 features: { |
|
32 chrome: true, |
|
33 toolbar: true |
|
34 } |
|
35 }).then(focus).then(function(window) { |
|
36 if (options.onLoad) { |
|
37 options.onLoad({ target: { defaultView: window } }) |
|
38 } |
|
39 |
|
40 return newTab; |
|
41 }); |
|
42 } |
|
43 |
|
44 exports.testDeprecationMessage = function(assert, done) { |
|
45 let { loader } = LoaderWithHookedConsole(module, onMessage); |
|
46 |
|
47 // Intercept all console method calls |
|
48 let calls = []; |
|
49 function onMessage(type, msg) { |
|
50 assert.equal(type, 'error', 'the only message is an error'); |
|
51 assert.ok(/^DEPRECATED:/.test(msg), 'deprecated'); |
|
52 loader.unload(); |
|
53 done(); |
|
54 } |
|
55 loader.require('sdk/widget'); |
|
56 } |
|
57 |
|
58 exports.testConstructor = function(assert, done) { |
|
59 let { loader: loader0 } = LoaderWithHookedConsole(module); |
|
60 const widgets = loader0.require("sdk/widget"); |
|
61 let browserWindow = getMostRecentBrowserWindow(); |
|
62 let doc = browserWindow.document; |
|
63 let AddonsMgrListener; |
|
64 |
|
65 AddonsMgrListener = { |
|
66 onInstalling: () => {}, |
|
67 onInstalled: () => {}, |
|
68 onUninstalling: () => {}, |
|
69 onUninstalled: () => {} |
|
70 }; |
|
71 |
|
72 let container = () => doc.getElementById("nav-bar"); |
|
73 let getWidgets = () => container() ? container().querySelectorAll('[id^="widget\:"]') : []; |
|
74 let widgetCount = () => getWidgets().length; |
|
75 let widgetStartCount = widgetCount(); |
|
76 let widgetNode = (index) => getWidgets()[index]; |
|
77 |
|
78 // Test basic construct/destroy |
|
79 AddonsMgrListener.onInstalling(); |
|
80 let w = widgets.Widget({ id: "basic-construct-destroy", label: "foo", content: "bar" }); |
|
81 AddonsMgrListener.onInstalled(); |
|
82 assert.equal(widgetCount(), widgetStartCount + 1, "panel has correct number of child elements after widget construction"); |
|
83 |
|
84 // test widget height |
|
85 assert.equal(widgetNode(0).firstChild.boxObject.height, 16, "widget has correct default height"); |
|
86 |
|
87 AddonsMgrListener.onUninstalling(); |
|
88 w.destroy(); |
|
89 AddonsMgrListener.onUninstalled(); |
|
90 w.destroy(); |
|
91 assert.pass("Multiple destroys do not cause an error"); |
|
92 assert.equal(widgetCount(), widgetStartCount, "panel has correct number of child elements after destroy"); |
|
93 |
|
94 // Test automatic widget destroy on unload |
|
95 let { loader } = LoaderWithHookedConsole(module); |
|
96 let widgetsFromLoader = loader.require("sdk/widget"); |
|
97 let widgetStartCount = widgetCount(); |
|
98 let w = widgetsFromLoader.Widget({ id: "destroy-on-unload", label: "foo", content: "bar" }); |
|
99 assert.equal(widgetCount(), widgetStartCount + 1, "widget has been correctly added"); |
|
100 loader.unload(); |
|
101 assert.equal(widgetCount(), widgetStartCount, "widget has been destroyed on module unload"); |
|
102 |
|
103 // Test nothing |
|
104 assert.throws( |
|
105 function() widgets.Widget({}), |
|
106 /^The widget must have a non-empty label property\.$/, |
|
107 "throws on no properties"); |
|
108 |
|
109 // Test no label |
|
110 assert.throws( |
|
111 function() widgets.Widget({content: "foo"}), |
|
112 /^The widget must have a non-empty label property\.$/, |
|
113 "throws on no label"); |
|
114 |
|
115 // Test empty label |
|
116 assert.throws( |
|
117 function() widgets.Widget({label: "", content: "foo"}), |
|
118 /^The widget must have a non-empty label property\.$/, |
|
119 "throws on empty label"); |
|
120 |
|
121 // Test no content or image |
|
122 assert.throws( |
|
123 function() widgets.Widget({id: "no-content-throws", label: "foo"}), |
|
124 /^No content or contentURL property found\. Widgets must have one or the other\.$/, |
|
125 "throws on no content"); |
|
126 |
|
127 // Test empty content, no image |
|
128 assert.throws( |
|
129 function() widgets.Widget({id:"empty-content-throws", label: "foo", content: ""}), |
|
130 /^No content or contentURL property found\. Widgets must have one or the other\.$/, |
|
131 "throws on empty content"); |
|
132 |
|
133 // Test empty image, no content |
|
134 assert.throws( |
|
135 function() widgets.Widget({id:"empty-image-throws", label: "foo", image: ""}), |
|
136 /^No content or contentURL property found\. Widgets must have one or the other\.$/, |
|
137 "throws on empty content"); |
|
138 |
|
139 // Test empty content, empty image |
|
140 assert.throws( |
|
141 function() widgets.Widget({id:"empty-image-and-content-throws", label: "foo", content: "", image: ""}), |
|
142 /^No content or contentURL property found. Widgets must have one or the other\.$/, |
|
143 "throws on empty content"); |
|
144 |
|
145 // Test duplicated ID |
|
146 let duplicateID = widgets.Widget({id: "foo", label: "foo", content: "bar"}); |
|
147 assert.throws( |
|
148 function() widgets.Widget({id: "foo", label: "bar", content: "bar"}), |
|
149 /^This widget ID is already used: foo$/, |
|
150 "throws on duplicated id"); |
|
151 duplicateID.destroy(); |
|
152 |
|
153 // Test Bug 652527 |
|
154 assert.throws( |
|
155 function() widgets.Widget({id: "", label: "bar", content: "bar"}), |
|
156 /^You have to specify a unique value for the id property of your widget in order for the application to remember its position\./, |
|
157 "throws on falsey id"); |
|
158 |
|
159 // Test duplicate label, different ID |
|
160 let w1 = widgets.Widget({id: "id1", label: "foo", content: "bar"}); |
|
161 let w2 = widgets.Widget({id: "id2", label: "foo", content: "bar"}); |
|
162 w1.destroy(); |
|
163 w2.destroy(); |
|
164 |
|
165 // Test position restore on create/destroy/create |
|
166 // Create 3 ordered widgets |
|
167 let w1 = widgets.Widget({id: "position-first", label:"first", content: "bar"}); |
|
168 let w2 = widgets.Widget({id: "position-second", label:"second", content: "bar"}); |
|
169 let w3 = widgets.Widget({id: "position-third", label:"third", content: "bar"}); |
|
170 // Remove the middle widget |
|
171 assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is the second widget inserted"); |
|
172 w2.destroy(); |
|
173 assert.equal(widgetNode(1).getAttribute("label"), "third", "second widget is removed, so second widget is now the third one"); |
|
174 w2 = widgets.Widget({id: "position-second", label:"second", content: "bar"}); |
|
175 assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is created again, at the same location"); |
|
176 // Cleanup this testcase |
|
177 AddonsMgrListener.onUninstalling(); |
|
178 w1.destroy(); |
|
179 w2.destroy(); |
|
180 w3.destroy(); |
|
181 AddonsMgrListener.onUninstalled(); |
|
182 |
|
183 // Helper for testing a single widget. |
|
184 // Confirms proper addition and content setup. |
|
185 function testSingleWidget(widgetOptions) { |
|
186 // We have to display which test is being run, because here we do not |
|
187 // use the regular test framework but rather a custom one that iterates |
|
188 // the `tests` array. |
|
189 assert.pass("executing: " + widgetOptions.id); |
|
190 |
|
191 let startCount = widgetCount(); |
|
192 let widget = widgets.Widget(widgetOptions); |
|
193 let node = widgetNode(startCount); |
|
194 assert.ok(node, "widget node at index"); |
|
195 assert.equal(node.tagName, "toolbaritem", "widget element is correct"); |
|
196 assert.equal(widget.width + "px", node.style.minWidth, "widget width is correct"); |
|
197 assert.equal(widgetCount(), startCount + 1, "container has correct number of child elements"); |
|
198 let content = node.firstElementChild; |
|
199 assert.ok(content, "found content"); |
|
200 assert.ok(/iframe|image/.test(content.tagName), "content is iframe or image"); |
|
201 return widget; |
|
202 } |
|
203 |
|
204 // Array of widgets to test |
|
205 // and a function to test them. |
|
206 let tests = []; |
|
207 function nextTest() { |
|
208 assert.equal(widgetCount(), 0, "widget in last test property cleaned itself up"); |
|
209 if (!tests.length) { |
|
210 loader0.unload(); |
|
211 done(); |
|
212 } |
|
213 else |
|
214 timer.setTimeout(tests.shift(), 0); |
|
215 } |
|
216 function doneTest() nextTest(); |
|
217 |
|
218 // text widget |
|
219 tests.push(function testTextWidget() testSingleWidget({ |
|
220 id: "text-single", |
|
221 label: "text widget", |
|
222 content: "oh yeah", |
|
223 contentScript: "self.postMessage(document.body.innerHTML);", |
|
224 contentScriptWhen: "end", |
|
225 onMessage: function (message) { |
|
226 assert.equal(this.content, message, "content matches"); |
|
227 this.destroy(); |
|
228 doneTest(); |
|
229 } |
|
230 })); |
|
231 |
|
232 // html widget |
|
233 tests.push(function testHTMLWidget() testSingleWidget({ |
|
234 id: "html", |
|
235 label: "html widget", |
|
236 content: "<div>oh yeah</div>", |
|
237 contentScript: "self.postMessage(document.body.innerHTML);", |
|
238 contentScriptWhen: "end", |
|
239 onMessage: function (message) { |
|
240 assert.equal(this.content, message, "content matches"); |
|
241 this.destroy(); |
|
242 doneTest(); |
|
243 } |
|
244 })); |
|
245 |
|
246 // image url widget |
|
247 tests.push(function testImageURLWidget() testSingleWidget({ |
|
248 id: "image", |
|
249 label: "image url widget", |
|
250 contentURL: fixtures.url("test.html"), |
|
251 contentScript: "self.postMessage({title: document.title, " + |
|
252 "tag: document.body.firstElementChild.tagName, " + |
|
253 "content: document.body.firstElementChild.innerHTML});", |
|
254 contentScriptWhen: "end", |
|
255 onMessage: function (message) { |
|
256 assert.equal(message.title, "foo", "title matches"); |
|
257 assert.equal(message.tag, "P", "element matches"); |
|
258 assert.equal(message.content, "bar", "element content matches"); |
|
259 this.destroy(); |
|
260 doneTest(); |
|
261 } |
|
262 })); |
|
263 |
|
264 // web uri widget |
|
265 tests.push(function testWebURIWidget() testSingleWidget({ |
|
266 id: "web", |
|
267 label: "web uri widget", |
|
268 contentURL: fixtures.url("test.html"), |
|
269 contentScript: "self.postMessage({title: document.title, " + |
|
270 "tag: document.body.firstElementChild.tagName, " + |
|
271 "content: document.body.firstElementChild.innerHTML});", |
|
272 contentScriptWhen: "end", |
|
273 onMessage: function (message) { |
|
274 assert.equal(message.title, "foo", "title matches"); |
|
275 assert.equal(message.tag, "P", "element matches"); |
|
276 assert.equal(message.content, "bar", "element content matches"); |
|
277 this.destroy(); |
|
278 doneTest(); |
|
279 } |
|
280 })); |
|
281 |
|
282 // event: onclick + content |
|
283 tests.push(function testOnclickEventContent() testSingleWidget({ |
|
284 id: "click-content", |
|
285 label: "click test widget - content", |
|
286 content: "<div id='me'>foo</div>", |
|
287 contentScript: "var evt = new MouseEvent('click', {button: 0});" + |
|
288 "document.getElementById('me').dispatchEvent(evt);", |
|
289 contentScriptWhen: "end", |
|
290 onClick: function() { |
|
291 assert.pass("onClick called"); |
|
292 this.destroy(); |
|
293 doneTest(); |
|
294 } |
|
295 })); |
|
296 |
|
297 // event: onmouseover + content |
|
298 tests.push(function testOnmouseoverEventContent() testSingleWidget({ |
|
299 id: "mouseover-content", |
|
300 label: "mouseover test widget - content", |
|
301 content: "<div id='me'>foo</div>", |
|
302 contentScript: "var evt = new MouseEvent('mouseover'); " + |
|
303 "document.getElementById('me').dispatchEvent(evt);", |
|
304 contentScriptWhen: "end", |
|
305 onMouseover: function() { |
|
306 assert.pass("onMouseover called"); |
|
307 this.destroy(); |
|
308 doneTest(); |
|
309 } |
|
310 })); |
|
311 |
|
312 // event: onmouseout + content |
|
313 tests.push(function testOnmouseoutEventContent() testSingleWidget({ |
|
314 id: "mouseout-content", |
|
315 label: "mouseout test widget - content", |
|
316 content: "<div id='me'>foo</div>", |
|
317 contentScript: "var evt = new MouseEvent('mouseout');" + |
|
318 "document.getElementById('me').dispatchEvent(evt);", |
|
319 contentScriptWhen: "end", |
|
320 onMouseout: function() { |
|
321 assert.pass("onMouseout called"); |
|
322 this.destroy(); |
|
323 doneTest(); |
|
324 } |
|
325 })); |
|
326 |
|
327 // event: onclick + image |
|
328 tests.push(function testOnclickEventImage() testSingleWidget({ |
|
329 id: "click-image", |
|
330 label: "click test widget - image", |
|
331 contentURL: fixtures.url("moz_favicon.ico"), |
|
332 contentScript: "var evt = new MouseEvent('click'); " + |
|
333 "document.body.firstElementChild.dispatchEvent(evt);", |
|
334 contentScriptWhen: "end", |
|
335 onClick: function() { |
|
336 assert.pass("onClick called"); |
|
337 this.destroy(); |
|
338 doneTest(); |
|
339 } |
|
340 })); |
|
341 |
|
342 // event: onmouseover + image |
|
343 tests.push(function testOnmouseoverEventImage() testSingleWidget({ |
|
344 id: "mouseover-image", |
|
345 label: "mouseover test widget - image", |
|
346 contentURL: fixtures.url("moz_favicon.ico"), |
|
347 contentScript: "var evt = new MouseEvent('mouseover');" + |
|
348 "document.body.firstElementChild.dispatchEvent(evt);", |
|
349 contentScriptWhen: "end", |
|
350 onMouseover: function() { |
|
351 assert.pass("onMouseover called"); |
|
352 this.destroy(); |
|
353 doneTest(); |
|
354 } |
|
355 })); |
|
356 |
|
357 // event: onmouseout + image |
|
358 tests.push(function testOnmouseoutEventImage() testSingleWidget({ |
|
359 id: "mouseout-image", |
|
360 label: "mouseout test widget - image", |
|
361 contentURL: fixtures.url("moz_favicon.ico"), |
|
362 contentScript: "var evt = new MouseEvent('mouseout'); " + |
|
363 "document.body.firstElementChild.dispatchEvent(evt);", |
|
364 contentScriptWhen: "end", |
|
365 onMouseout: function() { |
|
366 assert.pass("onMouseout called"); |
|
367 this.destroy(); |
|
368 doneTest(); |
|
369 } |
|
370 })); |
|
371 |
|
372 // test multiple widgets |
|
373 tests.push(function testMultipleWidgets() { |
|
374 let w1 = widgets.Widget({id: "first", label: "first widget", content: "first content"}); |
|
375 let w2 = widgets.Widget({id: "second", label: "second widget", content: "second content"}); |
|
376 |
|
377 w1.destroy(); |
|
378 w2.destroy(); |
|
379 |
|
380 doneTest(); |
|
381 }); |
|
382 |
|
383 // test updating widget content |
|
384 let loads = 0; |
|
385 tests.push(function testUpdatingWidgetContent() testSingleWidget({ |
|
386 id: "content-updating", |
|
387 label: "content update test widget", |
|
388 content: "<div id='me'>foo</div>", |
|
389 contentScript: "self.postMessage(1)", |
|
390 contentScriptWhen: "ready", |
|
391 onMessage: function(message) { |
|
392 if (!this.flag) { |
|
393 this.content = "<div id='me'>bar</div>"; |
|
394 this.flag = 1; |
|
395 } |
|
396 else { |
|
397 assert.equal(this.content, "<div id='me'>bar</div>", 'content is as expected'); |
|
398 this.destroy(); |
|
399 doneTest(); |
|
400 } |
|
401 } |
|
402 })); |
|
403 |
|
404 // test updating widget contentURL |
|
405 let url1 = "data:text/html;charset=utf-8,<body>foodle</body>"; |
|
406 let url2 = "data:text/html;charset=utf-8,<body>nistel</body>"; |
|
407 |
|
408 tests.push(function testUpdatingContentURL() testSingleWidget({ |
|
409 id: "content-url-updating", |
|
410 label: "content update test widget", |
|
411 contentURL: url1, |
|
412 contentScript: "self.postMessage(document.location.href);", |
|
413 contentScriptWhen: "end", |
|
414 onMessage: function(message) { |
|
415 if (!this.flag) { |
|
416 assert.equal(this.contentURL.toString(), url1); |
|
417 assert.equal(message, url1); |
|
418 this.contentURL = url2; |
|
419 this.flag = 1; |
|
420 } |
|
421 else { |
|
422 assert.equal(this.contentURL.toString(), url2); |
|
423 assert.equal(message, url2); |
|
424 this.destroy(); |
|
425 doneTest(); |
|
426 } |
|
427 } |
|
428 })); |
|
429 |
|
430 // test tooltip |
|
431 tests.push(function testTooltip() testSingleWidget({ |
|
432 id: "text-with-tooltip", |
|
433 label: "text widget", |
|
434 content: "oh yeah", |
|
435 tooltip: "foo", |
|
436 contentScript: "self.postMessage(1)", |
|
437 contentScriptWhen: "ready", |
|
438 onMessage: function(message) { |
|
439 assert.equal(this.tooltip, "foo", "tooltip matches"); |
|
440 this.destroy(); |
|
441 doneTest(); |
|
442 } |
|
443 })); |
|
444 |
|
445 // test tooltip fallback to label |
|
446 tests.push(function testTooltipFallback() testSingleWidget({ |
|
447 id: "fallback", |
|
448 label: "fallback", |
|
449 content: "oh yeah", |
|
450 contentScript: "self.postMessage(1)", |
|
451 contentScriptWhen: "ready", |
|
452 onMessage: function(message) { |
|
453 assert.equal(this.tooltip, this.label, "tooltip fallbacks to label"); |
|
454 this.destroy(); |
|
455 doneTest(); |
|
456 } |
|
457 })); |
|
458 |
|
459 // test updating widget tooltip |
|
460 let updated = false; |
|
461 tests.push(function testUpdatingTooltip() testSingleWidget({ |
|
462 id: "tooltip-updating", |
|
463 label: "tooltip update test widget", |
|
464 tooltip: "foo", |
|
465 content: "<div id='me'>foo</div>", |
|
466 contentScript: "self.postMessage(1)", |
|
467 contentScriptWhen: "ready", |
|
468 onMessage: function(message) { |
|
469 this.tooltip = "bar"; |
|
470 assert.equal(this.tooltip, "bar", "tooltip gets updated"); |
|
471 this.destroy(); |
|
472 doneTest(); |
|
473 } |
|
474 })); |
|
475 |
|
476 // test allow attribute |
|
477 tests.push(function testDefaultAllow() testSingleWidget({ |
|
478 id: "allow-default", |
|
479 label: "allow.script attribute", |
|
480 content: "<script>document.title = 'ok';</script>", |
|
481 contentScript: "self.postMessage(document.title)", |
|
482 onMessage: function(message) { |
|
483 assert.equal(message, "ok", "scripts are evaluated by default"); |
|
484 this.destroy(); |
|
485 doneTest(); |
|
486 } |
|
487 })); |
|
488 |
|
489 tests.push(function testExplicitAllow() testSingleWidget({ |
|
490 id: "allow-explicit", |
|
491 label: "allow.script attribute", |
|
492 allow: {script: true}, |
|
493 content: "<script>document.title = 'ok';</script>", |
|
494 contentScript: "self.postMessage(document.title)", |
|
495 onMessage: function(message) { |
|
496 assert.equal(message, "ok", "scripts are evaluated when we want to"); |
|
497 this.destroy(); |
|
498 doneTest(); |
|
499 } |
|
500 })); |
|
501 |
|
502 tests.push(function testExplicitDisallow() testSingleWidget({ |
|
503 id: "allow-explicit-disallow", |
|
504 label: "allow.script attribute", |
|
505 content: "<script>document.title = 'ok';</script>", |
|
506 allow: {script: false}, |
|
507 contentScript: "self.postMessage(document.title)", |
|
508 onMessage: function(message) { |
|
509 assert.notEqual(message, "ok", "scripts aren't evaluated when " + |
|
510 "explicitly blocked it"); |
|
511 this.destroy(); |
|
512 doneTest(); |
|
513 } |
|
514 })); |
|
515 |
|
516 // test multiple windows |
|
517 tests.push(function testMultipleWindows() { |
|
518 assert.pass('executing test multiple windows'); |
|
519 openNewWindowTab("about:blank", { inNewWindow: true, onLoad: function(e) { |
|
520 let browserWindow = e.target.defaultView; |
|
521 assert.ok(browserWindow, 'window was opened'); |
|
522 let doc = browserWindow.document; |
|
523 let container = () => doc.getElementById("nav-bar"); |
|
524 let widgetCount2 = () => container() ? container().querySelectorAll('[id^="widget\:"]').length : 0; |
|
525 let widgetStartCount2 = widgetCount2(); |
|
526 |
|
527 let w1Opts = {id:"first-multi-window", label: "first widget", content: "first content"}; |
|
528 let w1 = testSingleWidget(w1Opts); |
|
529 assert.equal(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first widget"); |
|
530 |
|
531 let w2Opts = {id:"second-multi-window", label: "second widget", content: "second content"}; |
|
532 let w2 = testSingleWidget(w2Opts); |
|
533 assert.equal(widgetCount2(), widgetStartCount2 + 2, "2nd window has correct number of child elements after second widget"); |
|
534 |
|
535 w1.destroy(); |
|
536 assert.equal(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first destroy"); |
|
537 w2.destroy(); |
|
538 assert.equal(widgetCount2(), widgetStartCount2, "2nd window has correct number of child elements after second destroy"); |
|
539 |
|
540 close(browserWindow).then(doneTest); |
|
541 }}); |
|
542 }); |
|
543 |
|
544 // test window closing |
|
545 tests.push(function testWindowClosing() { |
|
546 // 1/ Create a new widget |
|
547 let w1Opts = { |
|
548 id:"first-win-closing", |
|
549 label: "first widget", |
|
550 content: "first content", |
|
551 contentScript: "self.port.on('event', function () self.port.emit('event'))" |
|
552 }; |
|
553 let widget = testSingleWidget(w1Opts); |
|
554 let windows = loader0.require("sdk/windows").browserWindows; |
|
555 |
|
556 // 2/ Retrieve a WidgetView for the initial browser window |
|
557 let acceptDetach = false; |
|
558 let mainView = widget.getView(windows.activeWindow); |
|
559 assert.ok(mainView, "Got first widget view"); |
|
560 mainView.on("detach", function () { |
|
561 // 8/ End of our test. Accept detach event only when it occurs after |
|
562 // widget.destroy() |
|
563 if (acceptDetach) |
|
564 doneTest(); |
|
565 else |
|
566 assert.fail("View on initial window should not be destroyed"); |
|
567 }); |
|
568 mainView.port.on("event", function () { |
|
569 // 7/ Receive event sent during 6/ and cleanup our test |
|
570 acceptDetach = true; |
|
571 widget.destroy(); |
|
572 }); |
|
573 |
|
574 // 3/ First: open a new browser window |
|
575 windows.open({ |
|
576 url: "about:blank", |
|
577 onOpen: function(window) { |
|
578 // 4/ Retrieve a WidgetView for this new window |
|
579 let view = widget.getView(window); |
|
580 assert.ok(view, "Got second widget view"); |
|
581 view.port.on("event", function () { |
|
582 assert.fail("We should not receive event on the detach view"); |
|
583 }); |
|
584 view.on("detach", function () { |
|
585 // The related view is destroyed |
|
586 // 6/ Send a custom event |
|
587 assert.throws(function () { |
|
588 view.port.emit("event"); |
|
589 }, |
|
590 /^The widget has been destroyed and can no longer be used.$/, |
|
591 "emit on a destroyed view should throw"); |
|
592 widget.port.emit("event"); |
|
593 }); |
|
594 |
|
595 // 5/ Destroy this window |
|
596 window.close(); |
|
597 } |
|
598 }); |
|
599 }); |
|
600 |
|
601 if (false) { |
|
602 tests.push(function testAddonBarHide() { |
|
603 // Hide the addon-bar |
|
604 browserWindow.setToolbarVisibility(container(), false); |
|
605 assert.ok(container().collapsed, |
|
606 "1st window starts with an hidden addon-bar"); |
|
607 |
|
608 // Then open a browser window and verify that the addon-bar remains hidden |
|
609 openNewWindowTab("about:blank", { inNewWindow: true, onLoad: function(e) { |
|
610 let browserWindow2 = e.target.defaultView; |
|
611 let doc2 = browserWindow2.document; |
|
612 function container2() doc2.getElementById("addon-bar"); |
|
613 function widgetCount2() container2() ? container2().childNodes.length : 0; |
|
614 let widgetStartCount2 = widgetCount2(); |
|
615 assert.ok(container2().collapsed, |
|
616 "2nd window starts with an hidden addon-bar"); |
|
617 |
|
618 let w1Opts = {id:"first-addonbar-hide", label: "first widget", content: "first content"}; |
|
619 let w1 = testSingleWidget(w1Opts); |
|
620 assert.equal(widgetCount2(), widgetStartCount2 + 1, |
|
621 "2nd window has correct number of child elements after" + |
|
622 "widget creation"); |
|
623 assert.ok(!container().collapsed, "1st window has a visible addon-bar"); |
|
624 assert.ok(!container2().collapsed, "2nd window has a visible addon-bar"); |
|
625 w1.destroy(); |
|
626 assert.equal(widgetCount2(), widgetStartCount2, |
|
627 "2nd window has correct number of child elements after" + |
|
628 "widget destroy"); |
|
629 |
|
630 assert.ok(container().collapsed, "1st window has an hidden addon-bar"); |
|
631 assert.ok(container2().collapsed, "2nd window has an hidden addon-bar"); |
|
632 |
|
633 // Reset addon-bar visibility before exiting this test |
|
634 browserWindow.setToolbarVisibility(container(), true); |
|
635 |
|
636 close(browserWindow2).then(doneTest); |
|
637 }}); |
|
638 }); |
|
639 } |
|
640 |
|
641 // test widget.width |
|
642 tests.push(function testWidgetWidth() testSingleWidget({ |
|
643 id: "text-test-width", |
|
644 label: "test widget.width", |
|
645 content: "test width", |
|
646 width: 64, |
|
647 contentScript: "self.postMessage(1)", |
|
648 contentScriptWhen: "ready", |
|
649 onMessage: function(message) { |
|
650 assert.equal(this.width, 64, 'width is 64'); |
|
651 |
|
652 let node = widgetNode(0); |
|
653 assert.equal(this.width, node.style.minWidth.replace("px", "")); |
|
654 assert.equal(this.width, node.firstElementChild.style.width.replace("px", "")); |
|
655 this.width = 48; |
|
656 assert.equal(this.width, node.style.minWidth.replace("px", "")); |
|
657 assert.equal(this.width, node.firstElementChild.style.width.replace("px", "")); |
|
658 |
|
659 this.destroy(); |
|
660 doneTest(); |
|
661 } |
|
662 })); |
|
663 |
|
664 // test click handler not respond to right-click |
|
665 let clickCount = 0; |
|
666 tests.push(function testNoRightClick() testSingleWidget({ |
|
667 id: "right-click-content", |
|
668 label: "click test widget - content", |
|
669 content: "<div id='me'>foo</div>", |
|
670 contentScript: // Left click |
|
671 "var evt = new MouseEvent('click', {button: 0});" + |
|
672 "document.getElementById('me').dispatchEvent(evt); " + |
|
673 // Middle click |
|
674 "evt = new MouseEvent('click', {button: 1});" + |
|
675 "document.getElementById('me').dispatchEvent(evt); " + |
|
676 // Right click |
|
677 "evt = new MouseEvent('click', {button: 2});" + |
|
678 "document.getElementById('me').dispatchEvent(evt); " + |
|
679 // Mouseover |
|
680 "evt = new MouseEvent('mouseover');" + |
|
681 "document.getElementById('me').dispatchEvent(evt);", |
|
682 contentScriptWhen: "end", |
|
683 onClick: function() clickCount++, |
|
684 onMouseover: function() { |
|
685 assert.equal(clickCount, 1, "only left click was sent to click handler"); |
|
686 this.destroy(); |
|
687 doneTest(); |
|
688 } |
|
689 })); |
|
690 |
|
691 // kick off test execution |
|
692 doneTest(); |
|
693 }; |
|
694 |
|
695 exports.testWidgetWithValidPanel = function(assert, done) { |
|
696 let { loader } = LoaderWithHookedConsole(module); |
|
697 const { Widget } = loader.require("sdk/widget"); |
|
698 const { Panel } = loader.require("sdk/panel"); |
|
699 |
|
700 let widget1 = Widget({ |
|
701 id: "testWidgetWithValidPanel", |
|
702 label: "panel widget 1", |
|
703 content: "<div id='me'>foo</div>", |
|
704 contentScript: "var evt = new MouseEvent('click', {button: 0});" + |
|
705 "document.body.dispatchEvent(evt);", |
|
706 contentScriptWhen: "end", |
|
707 panel: Panel({ |
|
708 contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>", |
|
709 onShow: function() { |
|
710 let { document } = getMostRecentBrowserWindow(); |
|
711 let widgetEle = document.getElementById("widget:" + jetpackID + "-" + widget1.id); |
|
712 let panelEle = document.getElementById('mainPopupSet').lastChild; |
|
713 // See bug https://bugzilla.mozilla.org/show_bug.cgi?id=859592 |
|
714 assert.equal(panelEle.getAttribute("type"), "arrow", 'the panel is a arrow type'); |
|
715 assert.strictEqual(panelEle.anchorNode, widgetEle, 'the panel is properly anchored to the widget'); |
|
716 |
|
717 widget1.destroy(); |
|
718 loader.unload(); |
|
719 assert.pass("panel displayed on click"); |
|
720 done(); |
|
721 } |
|
722 }) |
|
723 }); |
|
724 }; |
|
725 |
|
726 exports.testWidgetWithInvalidPanel = function(assert) { |
|
727 let { loader } = LoaderWithHookedConsole(module); |
|
728 const widgets = loader.require("sdk/widget"); |
|
729 |
|
730 assert.throws( |
|
731 function() { |
|
732 widgets.Widget({ |
|
733 id: "panel2", |
|
734 label: "panel widget 2", |
|
735 panel: {} |
|
736 }); |
|
737 }, |
|
738 /^The option \"panel\" must be one of the following types: null, undefined, object$/, |
|
739 "widget.panel must be a Panel object"); |
|
740 loader.unload(); |
|
741 }; |
|
742 |
|
743 exports.testPanelWidget3 = function testPanelWidget3(assert, done) { |
|
744 let { loader } = LoaderWithHookedConsole(module); |
|
745 const widgets = loader.require("sdk/widget"); |
|
746 const { Panel } = loader.require("sdk/panel"); |
|
747 |
|
748 let onClickCalled = false; |
|
749 let widget3 = widgets.Widget({ |
|
750 id: "panel3", |
|
751 label: "panel widget 3", |
|
752 content: "<div id='me'>foo</div>", |
|
753 contentScript: "var evt = new MouseEvent('click', {button: 0});" + |
|
754 "document.body.firstElementChild.dispatchEvent(evt);", |
|
755 contentScriptWhen: "end", |
|
756 onClick: function() { |
|
757 onClickCalled = true; |
|
758 this.panel.show(); |
|
759 }, |
|
760 panel: Panel({ |
|
761 contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>", |
|
762 onShow: function() { |
|
763 assert.ok( |
|
764 onClickCalled, |
|
765 "onClick called on click for widget with both panel and onClick"); |
|
766 widget3.destroy(); |
|
767 loader.unload(); |
|
768 done(); |
|
769 } |
|
770 }) |
|
771 }); |
|
772 }; |
|
773 |
|
774 exports.testWidgetWithPanelInMenuPanel = function(assert, done) { |
|
775 const { CustomizableUI } = Cu.import("resource:///modules/CustomizableUI.jsm", {}); |
|
776 let { loader } = LoaderWithHookedConsole(module); |
|
777 const widgets = loader.require("sdk/widget"); |
|
778 const { Panel } = loader.require("sdk/panel"); |
|
779 |
|
780 let widget1 = widgets.Widget({ |
|
781 id: "panel1", |
|
782 label: "panel widget 1", |
|
783 content: "<div id='me'>foo</div>", |
|
784 contentScript: "new " + function() { |
|
785 self.port.on('click', () => { |
|
786 let evt = new MouseEvent('click', {button: 0}); |
|
787 document.body.dispatchEvent(evt); |
|
788 }); |
|
789 }, |
|
790 contentScriptWhen: "end", |
|
791 panel: Panel({ |
|
792 contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>", |
|
793 onShow: function() { |
|
794 let { document } = getMostRecentBrowserWindow(); |
|
795 let { anchorNode } = document.getElementById('mainPopupSet').lastChild; |
|
796 let panelButtonNode = document.getElementById("PanelUI-menu-button"); |
|
797 |
|
798 assert.strictEqual(anchorNode, panelButtonNode, |
|
799 'the panel is anchored to the panel menu button instead of widget'); |
|
800 |
|
801 widget1.destroy(); |
|
802 loader.unload(); |
|
803 done(); |
|
804 } |
|
805 }) |
|
806 }); |
|
807 |
|
808 let widgetId = "widget:" + jetpackID + "-" + widget1.id; |
|
809 |
|
810 CustomizableUI.addListener({ |
|
811 onWidgetAdded: function(id) { |
|
812 if (id !== widgetId) return; |
|
813 |
|
814 let { document, PanelUI } = getMostRecentBrowserWindow(); |
|
815 |
|
816 PanelUI.panel.addEventListener('popupshowing', function onshow({type}) { |
|
817 this.removeEventListener(type, onshow); |
|
818 widget1.port.emit('click'); |
|
819 }); |
|
820 |
|
821 document.getElementById("PanelUI-menu-button").click() |
|
822 } |
|
823 }); |
|
824 |
|
825 CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL); |
|
826 }; |
|
827 |
|
828 exports.testWidgetMessaging = function testWidgetMessaging(assert, done) { |
|
829 let { loader } = LoaderWithHookedConsole(module); |
|
830 const widgets = loader.require("sdk/widget"); |
|
831 |
|
832 let origMessage = "foo"; |
|
833 let widget = widgets.Widget({ |
|
834 id: "widget-messaging", |
|
835 label: "foo", |
|
836 content: "<bar>baz</bar>", |
|
837 contentScriptWhen: "end", |
|
838 contentScript: "self.on('message', function(data) { self.postMessage(data); }); self.postMessage('ready');", |
|
839 onMessage: function(message) { |
|
840 if (message == "ready") |
|
841 widget.postMessage(origMessage); |
|
842 else { |
|
843 assert.equal(origMessage, message); |
|
844 widget.destroy(); |
|
845 loader.unload(); |
|
846 done(); |
|
847 } |
|
848 } |
|
849 }); |
|
850 }; |
|
851 |
|
852 exports.testWidgetViews = function testWidgetViews(assert, done) { |
|
853 let { loader } = LoaderWithHookedConsole(module); |
|
854 const widgets = loader.require("sdk/widget"); |
|
855 |
|
856 let widget = widgets.Widget({ |
|
857 id: "widget-views", |
|
858 label: "foo", |
|
859 content: "<bar>baz</bar>", |
|
860 contentScriptWhen: "ready", |
|
861 contentScript: "self.on('message', function(data) self.postMessage(data)); self.postMessage('ready')", |
|
862 onAttach: function(view) { |
|
863 assert.pass("WidgetView created"); |
|
864 view.on("message", function () { |
|
865 assert.pass("Got message in WidgetView"); |
|
866 widget.destroy(); |
|
867 }); |
|
868 view.on("detach", function () { |
|
869 assert.pass("WidgetView destroyed"); |
|
870 loader.unload(); |
|
871 done(); |
|
872 }); |
|
873 } |
|
874 }); |
|
875 }; |
|
876 |
|
877 exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(assert, done) { |
|
878 let { loader } = LoaderWithHookedConsole(module); |
|
879 const widgets = loader.require("sdk/widget"); |
|
880 const { browserWindows } = loader.require("sdk/windows"); |
|
881 |
|
882 let view = null; |
|
883 let widget = widgets.Widget({ |
|
884 id: "widget-view-ui-events", |
|
885 label: "foo", |
|
886 content: "<div id='me'>foo</div>", |
|
887 contentScript: "var evt = new MouseEvent('click', {button: 0});" + |
|
888 "document.getElementById('me').dispatchEvent(evt);", |
|
889 contentScriptWhen: "ready", |
|
890 onAttach: function(attachView) { |
|
891 view = attachView; |
|
892 assert.pass("Got attach event"); |
|
893 }, |
|
894 onClick: function (eventView) { |
|
895 assert.equal(view, eventView, |
|
896 "event first argument is equal to the WidgetView"); |
|
897 let view2 = widget.getView(browserWindows.activeWindow); |
|
898 assert.equal(view, view2, |
|
899 "widget.getView return the same WidgetView"); |
|
900 widget.destroy(); |
|
901 loader.unload(); |
|
902 done(); |
|
903 } |
|
904 }); |
|
905 }; |
|
906 |
|
907 exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(assert, done) { |
|
908 let { loader } = LoaderWithHookedConsole(module); |
|
909 const widgets = loader.require("sdk/widget"); |
|
910 |
|
911 let widget = widgets.Widget({ |
|
912 id: "widget-view-custom-events", |
|
913 label: "foo", |
|
914 content: "<div id='me'>foo</div>", |
|
915 contentScript: "self.port.emit('event', 'ok');", |
|
916 contentScriptWhen: "ready", |
|
917 onAttach: function(view) { |
|
918 view.port.on("event", function (data) { |
|
919 assert.equal(data, "ok", |
|
920 "event argument is valid on WidgetView"); |
|
921 }); |
|
922 }, |
|
923 }); |
|
924 widget.port.on("event", function (data) { |
|
925 assert.equal(data, "ok", "event argument is valid on Widget"); |
|
926 widget.destroy(); |
|
927 loader.unload(); |
|
928 done(); |
|
929 }); |
|
930 }; |
|
931 |
|
932 exports.testWidgetViewsTooltip = function testWidgetViewsTooltip(assert, done) { |
|
933 let { loader } = LoaderWithHookedConsole(module); |
|
934 const widgets = loader.require("sdk/widget"); |
|
935 const { browserWindows } = loader.require("sdk/windows"); |
|
936 |
|
937 let widget = new widgets.Widget({ |
|
938 id: "widget-views-tooltip", |
|
939 label: "foo", |
|
940 content: "foo" |
|
941 }); |
|
942 let view = widget.getView(browserWindows.activeWindow); |
|
943 widget.tooltip = null; |
|
944 assert.equal(view.tooltip, "foo", |
|
945 "view tooltip defaults to base widget label"); |
|
946 assert.equal(widget.tooltip, "foo", |
|
947 "tooltip defaults to base widget label"); |
|
948 widget.destroy(); |
|
949 loader.unload(); |
|
950 done(); |
|
951 }; |
|
952 |
|
953 exports.testWidgetMove = function testWidgetMove(assert, done) { |
|
954 let { loader } = LoaderWithHookedConsole(module); |
|
955 const widgets = loader.require("sdk/widget"); |
|
956 |
|
957 let browserWindow = getMostRecentBrowserWindow(); |
|
958 let doc = browserWindow.document; |
|
959 |
|
960 let label = "unique-widget-label"; |
|
961 let origMessage = "message after node move"; |
|
962 let gotFirstReady = false; |
|
963 |
|
964 let widget = widgets.Widget({ |
|
965 id: "widget-move", |
|
966 label: label, |
|
967 content: "<bar>baz</bar>", |
|
968 contentScriptWhen: "ready", |
|
969 contentScript: "self.on('message', function(data) { self.postMessage(data); }); self.postMessage('ready');", |
|
970 onMessage: function(message) { |
|
971 if (message == "ready") { |
|
972 if (!gotFirstReady) { |
|
973 assert.pass("Got first ready event"); |
|
974 let widgetNode = doc.querySelector('toolbaritem[label="' + label + '"]'); |
|
975 let parent = widgetNode.parentNode; |
|
976 parent.insertBefore(widgetNode, parent.firstChild); |
|
977 gotFirstReady = true; |
|
978 } |
|
979 else { |
|
980 assert.pass("Got second ready event"); |
|
981 widget.postMessage(origMessage); |
|
982 } |
|
983 } |
|
984 else { |
|
985 assert.equal(origMessage, message, "Got message after node move"); |
|
986 widget.destroy(); |
|
987 loader.unload(); |
|
988 done(); |
|
989 } |
|
990 } |
|
991 }); |
|
992 }; |
|
993 |
|
994 /* |
|
995 The bug is exhibited when a widget with HTML content has it's content |
|
996 changed to new HTML content with a pound in it. Because the src of HTML |
|
997 content is converted to a data URI, the underlying iframe doesn't |
|
998 consider the content change a navigation change, so doesn't load |
|
999 the new content. |
|
1000 */ |
|
1001 exports.testWidgetWithPound = function testWidgetWithPound(assert, done) { |
|
1002 let { loader } = LoaderWithHookedConsole(module); |
|
1003 const widgets = loader.require("sdk/widget"); |
|
1004 |
|
1005 function getWidgetContent(widget) { |
|
1006 let browserWindow = getMostRecentBrowserWindow(); |
|
1007 let doc = browserWindow.document; |
|
1008 let widgetNode = doc.querySelector('toolbaritem[label="' + widget.label + '"]'); |
|
1009 assert.ok(widgetNode, 'found widget node in the front-end'); |
|
1010 return widgetNode.firstChild.contentDocument.body.innerHTML; |
|
1011 } |
|
1012 |
|
1013 let count = 0; |
|
1014 let widget = widgets.Widget({ |
|
1015 id: "1", |
|
1016 label: "foo", |
|
1017 content: "foo", |
|
1018 contentScript: "window.addEventListener('load', self.postMessage, false);", |
|
1019 onMessage: function() { |
|
1020 count++; |
|
1021 if (count == 1) { |
|
1022 widget.content = "foo#"; |
|
1023 } |
|
1024 else { |
|
1025 assert.equal(getWidgetContent(widget), "foo#", "content updated to pound?"); |
|
1026 widget.destroy(); |
|
1027 loader.unload(); |
|
1028 done(); |
|
1029 } |
|
1030 } |
|
1031 }); |
|
1032 }; |
|
1033 |
|
1034 exports.testContentScriptOptionsOption = function(assert, done) { |
|
1035 let { loader } = LoaderWithHookedConsole(module); |
|
1036 const { Widget } = loader.require("sdk/widget"); |
|
1037 |
|
1038 let widget = Widget({ |
|
1039 id: "widget-script-options", |
|
1040 label: "fooz", |
|
1041 content: "fooz", |
|
1042 contentScript: "self.postMessage( [typeof self.options.d, self.options] );", |
|
1043 contentScriptWhen: "end", |
|
1044 contentScriptOptions: {a: true, b: [1,2,3], c: "string", d: function(){ return 'test'}}, |
|
1045 onMessage: function(msg) { |
|
1046 assert.equal( msg[0], 'undefined', 'functions are stripped from contentScriptOptions' ); |
|
1047 assert.equal( typeof msg[1], 'object', 'object as contentScriptOptions' ); |
|
1048 assert.equal( msg[1].a, true, 'boolean in contentScriptOptions' ); |
|
1049 assert.equal( msg[1].b.join(), '1,2,3', 'array and numbers in contentScriptOptions' ); |
|
1050 assert.equal( msg[1].c, 'string', 'string in contentScriptOptions' ); |
|
1051 widget.destroy(); |
|
1052 loader.unload(); |
|
1053 done(); |
|
1054 } |
|
1055 }); |
|
1056 }; |
|
1057 |
|
1058 exports.testOnAttachWithoutContentScript = function(assert, done) { |
|
1059 let { loader } = LoaderWithHookedConsole(module); |
|
1060 const { Widget } = loader.require("sdk/widget"); |
|
1061 |
|
1062 let widget = Widget({ |
|
1063 id: "onAttachNoCS", |
|
1064 label: "onAttachNoCS", |
|
1065 content: "onAttachNoCS", |
|
1066 onAttach: function (view) { |
|
1067 assert.pass("received attach event"); |
|
1068 widget.destroy(); |
|
1069 loader.unload(); |
|
1070 done(); |
|
1071 } |
|
1072 }); |
|
1073 }; |
|
1074 |
|
1075 exports.testPostMessageOnAttach = function(assert, done) { |
|
1076 let { loader } = LoaderWithHookedConsole(module); |
|
1077 const { Widget } = loader.require("sdk/widget"); |
|
1078 |
|
1079 let widget = Widget({ |
|
1080 id: "onAttach", |
|
1081 label: "onAttach", |
|
1082 content: "onAttach", |
|
1083 // 1) Send a message immediatly after `attach` event |
|
1084 onAttach: function (view) { |
|
1085 view.postMessage("ok"); |
|
1086 }, |
|
1087 // 2) Listen to it and forward it back to the widget |
|
1088 contentScript: "self.on('message', self.postMessage);", |
|
1089 // 3) Listen to this forwarded message |
|
1090 onMessage: function (msg) { |
|
1091 assert.equal( msg, "ok", "postMessage works on `attach` event"); |
|
1092 widget.destroy(); |
|
1093 loader.unload(); |
|
1094 done(); |
|
1095 } |
|
1096 }); |
|
1097 }; |
|
1098 |
|
1099 exports.testPostMessageOnLocationChange = function(assert, done) { |
|
1100 let { loader } = LoaderWithHookedConsole(module); |
|
1101 const { Widget } = loader.require("sdk/widget"); |
|
1102 |
|
1103 let attachEventCount = 0; |
|
1104 let messagesCount = 0; |
|
1105 let widget = Widget({ |
|
1106 id: "onLocationChange", |
|
1107 label: "onLocationChange", |
|
1108 content: "onLocationChange", |
|
1109 contentScript: "new " + function ContentScriptScope() { |
|
1110 // Emit an event when content script is applied in order to know when |
|
1111 // the first document is loaded so that we can load the 2nd one |
|
1112 self.postMessage("ready"); |
|
1113 // And forward any incoming message back to the widget to see if |
|
1114 // messaging is working on 2nd document |
|
1115 self.on("message", self.postMessage); |
|
1116 }, |
|
1117 onMessage: function (msg) { |
|
1118 messagesCount++; |
|
1119 if (messagesCount == 1) { |
|
1120 assert.equal(msg, "ready", "First document is loaded"); |
|
1121 widget.content = "location changed"; |
|
1122 } |
|
1123 else if (messagesCount == 2) { |
|
1124 assert.equal(msg, "ready", "Second document is loaded"); |
|
1125 widget.postMessage("ok"); |
|
1126 } |
|
1127 else if (messagesCount == 3) { |
|
1128 assert.equal(msg, "ok", |
|
1129 "We receive the message sent to the 2nd document"); |
|
1130 widget.destroy(); |
|
1131 loader.unload(); |
|
1132 done(); |
|
1133 } |
|
1134 } |
|
1135 }); |
|
1136 }; |
|
1137 |
|
1138 exports.testSVGWidget = function(assert, done) { |
|
1139 let { loader } = LoaderWithHookedConsole(module); |
|
1140 const { Widget } = loader.require("sdk/widget"); |
|
1141 |
|
1142 // use of capital SVG here is intended, that was failing.. |
|
1143 let SVG_URL = fixtures.url("mofo_logo.SVG"); |
|
1144 |
|
1145 let widget = Widget({ |
|
1146 id: "mozilla-svg-logo", |
|
1147 label: "moz foundation logo", |
|
1148 contentURL: SVG_URL, |
|
1149 contentScript: "self.postMessage({count: window.document.images.length, src: window.document.images[0].src});", |
|
1150 onMessage: function(data) { |
|
1151 widget.destroy(); |
|
1152 assert.equal(data.count, 1, 'only one image'); |
|
1153 assert.equal(data.src, SVG_URL, 'only one image'); |
|
1154 loader.unload(); |
|
1155 done(); |
|
1156 } |
|
1157 }); |
|
1158 }; |
|
1159 |
|
1160 exports.testReinsertion = function(assert, done) { |
|
1161 let { loader } = LoaderWithHookedConsole(module); |
|
1162 const { Widget } = loader.require("sdk/widget"); |
|
1163 const WIDGETID = "test-reinsertion"; |
|
1164 let browserWindow = getMostRecentBrowserWindow(); |
|
1165 |
|
1166 let widget = Widget({ |
|
1167 id: "test-reinsertion", |
|
1168 label: "test reinsertion", |
|
1169 content: "Test", |
|
1170 }); |
|
1171 let realWidgetId = "widget:" + jetpackID + "-" + WIDGETID; |
|
1172 // Remove the widget: |
|
1173 |
|
1174 browserWindow.CustomizableUI.removeWidgetFromArea(realWidgetId); |
|
1175 |
|
1176 openNewWindowTab("about:blank", { inNewWindow: true, onLoad: function(e) { |
|
1177 assert.equal(e.target.defaultView.document.getElementById(realWidgetId), null); |
|
1178 close(e.target.defaultView).then(_ => { |
|
1179 loader.unload(); |
|
1180 done(); |
|
1181 }); |
|
1182 }}); |
|
1183 }; |
|
1184 |
|
1185 exports.testWideWidget = function testWideWidget(assert) { |
|
1186 let { loader } = LoaderWithHookedConsole(module); |
|
1187 const widgets = loader.require("sdk/widget"); |
|
1188 const { document, CustomizableUI, gCustomizeMode, setTimeout } = getMostRecentBrowserWindow(); |
|
1189 |
|
1190 let wideWidget = widgets.Widget({ |
|
1191 id: "my-wide-widget", |
|
1192 label: "wide-wdgt", |
|
1193 content: "foo", |
|
1194 width: 200 |
|
1195 }); |
|
1196 |
|
1197 let widget = widgets.Widget({ |
|
1198 id: "my-regular-widget", |
|
1199 label: "reg-wdgt", |
|
1200 content: "foo" |
|
1201 }); |
|
1202 |
|
1203 let wideWidgetNode = document.querySelector("toolbaritem[label=wide-wdgt]"); |
|
1204 let widgetNode = document.querySelector("toolbaritem[label=reg-wdgt]"); |
|
1205 |
|
1206 assert.equal(wideWidgetNode, null, |
|
1207 "Wide Widget are not added to UI"); |
|
1208 |
|
1209 assert.notEqual(widgetNode, null, |
|
1210 "regular size widget are in the UI"); |
|
1211 }; |
|
1212 |
|
1213 require("sdk/test").run(exports); |