1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/test/test-widget.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1213 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +'use strict'; 1.8 + 1.9 +module.metadata = { 1.10 + 'engines': { 1.11 + 'Firefox': '*' 1.12 + } 1.13 +}; 1.14 + 1.15 +const { Cc, Ci, Cu } = require("chrome"); 1.16 +const { LoaderWithHookedConsole } = require('sdk/test/loader'); 1.17 +const url = require("sdk/url"); 1.18 +const timer = require("sdk/timers"); 1.19 +const self = require("sdk/self"); 1.20 +const { getMostRecentBrowserWindow } = require('sdk/window/utils'); 1.21 +const { close, open, focus } = require("sdk/window/helpers"); 1.22 +const tabs = require("sdk/tabs/utils"); 1.23 +const { merge } = require("sdk/util/object"); 1.24 +const unload = require("sdk/system/unload"); 1.25 +const fixtures = require("./fixtures"); 1.26 + 1.27 +let jetpackID = "testID"; 1.28 +try { 1.29 + jetpackID = require("sdk/self").id; 1.30 +} catch(e) {} 1.31 + 1.32 +function openNewWindowTab(url, options) { 1.33 + return open('chrome://browser/content/browser.xul', { 1.34 + features: { 1.35 + chrome: true, 1.36 + toolbar: true 1.37 + } 1.38 + }).then(focus).then(function(window) { 1.39 + if (options.onLoad) { 1.40 + options.onLoad({ target: { defaultView: window } }) 1.41 + } 1.42 + 1.43 + return newTab; 1.44 + }); 1.45 +} 1.46 + 1.47 +exports.testDeprecationMessage = function(assert, done) { 1.48 + let { loader } = LoaderWithHookedConsole(module, onMessage); 1.49 + 1.50 + // Intercept all console method calls 1.51 + let calls = []; 1.52 + function onMessage(type, msg) { 1.53 + assert.equal(type, 'error', 'the only message is an error'); 1.54 + assert.ok(/^DEPRECATED:/.test(msg), 'deprecated'); 1.55 + loader.unload(); 1.56 + done(); 1.57 + } 1.58 + loader.require('sdk/widget'); 1.59 +} 1.60 + 1.61 +exports.testConstructor = function(assert, done) { 1.62 + let { loader: loader0 } = LoaderWithHookedConsole(module); 1.63 + const widgets = loader0.require("sdk/widget"); 1.64 + let browserWindow = getMostRecentBrowserWindow(); 1.65 + let doc = browserWindow.document; 1.66 + let AddonsMgrListener; 1.67 + 1.68 + AddonsMgrListener = { 1.69 + onInstalling: () => {}, 1.70 + onInstalled: () => {}, 1.71 + onUninstalling: () => {}, 1.72 + onUninstalled: () => {} 1.73 + }; 1.74 + 1.75 + let container = () => doc.getElementById("nav-bar"); 1.76 + let getWidgets = () => container() ? container().querySelectorAll('[id^="widget\:"]') : []; 1.77 + let widgetCount = () => getWidgets().length; 1.78 + let widgetStartCount = widgetCount(); 1.79 + let widgetNode = (index) => getWidgets()[index]; 1.80 + 1.81 + // Test basic construct/destroy 1.82 + AddonsMgrListener.onInstalling(); 1.83 + let w = widgets.Widget({ id: "basic-construct-destroy", label: "foo", content: "bar" }); 1.84 + AddonsMgrListener.onInstalled(); 1.85 + assert.equal(widgetCount(), widgetStartCount + 1, "panel has correct number of child elements after widget construction"); 1.86 + 1.87 + // test widget height 1.88 + assert.equal(widgetNode(0).firstChild.boxObject.height, 16, "widget has correct default height"); 1.89 + 1.90 + AddonsMgrListener.onUninstalling(); 1.91 + w.destroy(); 1.92 + AddonsMgrListener.onUninstalled(); 1.93 + w.destroy(); 1.94 + assert.pass("Multiple destroys do not cause an error"); 1.95 + assert.equal(widgetCount(), widgetStartCount, "panel has correct number of child elements after destroy"); 1.96 + 1.97 + // Test automatic widget destroy on unload 1.98 + let { loader } = LoaderWithHookedConsole(module); 1.99 + let widgetsFromLoader = loader.require("sdk/widget"); 1.100 + let widgetStartCount = widgetCount(); 1.101 + let w = widgetsFromLoader.Widget({ id: "destroy-on-unload", label: "foo", content: "bar" }); 1.102 + assert.equal(widgetCount(), widgetStartCount + 1, "widget has been correctly added"); 1.103 + loader.unload(); 1.104 + assert.equal(widgetCount(), widgetStartCount, "widget has been destroyed on module unload"); 1.105 + 1.106 + // Test nothing 1.107 + assert.throws( 1.108 + function() widgets.Widget({}), 1.109 + /^The widget must have a non-empty label property\.$/, 1.110 + "throws on no properties"); 1.111 + 1.112 + // Test no label 1.113 + assert.throws( 1.114 + function() widgets.Widget({content: "foo"}), 1.115 + /^The widget must have a non-empty label property\.$/, 1.116 + "throws on no label"); 1.117 + 1.118 + // Test empty label 1.119 + assert.throws( 1.120 + function() widgets.Widget({label: "", content: "foo"}), 1.121 + /^The widget must have a non-empty label property\.$/, 1.122 + "throws on empty label"); 1.123 + 1.124 + // Test no content or image 1.125 + assert.throws( 1.126 + function() widgets.Widget({id: "no-content-throws", label: "foo"}), 1.127 + /^No content or contentURL property found\. Widgets must have one or the other\.$/, 1.128 + "throws on no content"); 1.129 + 1.130 + // Test empty content, no image 1.131 + assert.throws( 1.132 + function() widgets.Widget({id:"empty-content-throws", label: "foo", content: ""}), 1.133 + /^No content or contentURL property found\. Widgets must have one or the other\.$/, 1.134 + "throws on empty content"); 1.135 + 1.136 + // Test empty image, no content 1.137 + assert.throws( 1.138 + function() widgets.Widget({id:"empty-image-throws", label: "foo", image: ""}), 1.139 + /^No content or contentURL property found\. Widgets must have one or the other\.$/, 1.140 + "throws on empty content"); 1.141 + 1.142 + // Test empty content, empty image 1.143 + assert.throws( 1.144 + function() widgets.Widget({id:"empty-image-and-content-throws", label: "foo", content: "", image: ""}), 1.145 + /^No content or contentURL property found. Widgets must have one or the other\.$/, 1.146 + "throws on empty content"); 1.147 + 1.148 + // Test duplicated ID 1.149 + let duplicateID = widgets.Widget({id: "foo", label: "foo", content: "bar"}); 1.150 + assert.throws( 1.151 + function() widgets.Widget({id: "foo", label: "bar", content: "bar"}), 1.152 + /^This widget ID is already used: foo$/, 1.153 + "throws on duplicated id"); 1.154 + duplicateID.destroy(); 1.155 + 1.156 + // Test Bug 652527 1.157 + assert.throws( 1.158 + function() widgets.Widget({id: "", label: "bar", content: "bar"}), 1.159 + /^You have to specify a unique value for the id property of your widget in order for the application to remember its position\./, 1.160 + "throws on falsey id"); 1.161 + 1.162 + // Test duplicate label, different ID 1.163 + let w1 = widgets.Widget({id: "id1", label: "foo", content: "bar"}); 1.164 + let w2 = widgets.Widget({id: "id2", label: "foo", content: "bar"}); 1.165 + w1.destroy(); 1.166 + w2.destroy(); 1.167 + 1.168 + // Test position restore on create/destroy/create 1.169 + // Create 3 ordered widgets 1.170 + let w1 = widgets.Widget({id: "position-first", label:"first", content: "bar"}); 1.171 + let w2 = widgets.Widget({id: "position-second", label:"second", content: "bar"}); 1.172 + let w3 = widgets.Widget({id: "position-third", label:"third", content: "bar"}); 1.173 + // Remove the middle widget 1.174 + assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is the second widget inserted"); 1.175 + w2.destroy(); 1.176 + assert.equal(widgetNode(1).getAttribute("label"), "third", "second widget is removed, so second widget is now the third one"); 1.177 + w2 = widgets.Widget({id: "position-second", label:"second", content: "bar"}); 1.178 + assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is created again, at the same location"); 1.179 + // Cleanup this testcase 1.180 + AddonsMgrListener.onUninstalling(); 1.181 + w1.destroy(); 1.182 + w2.destroy(); 1.183 + w3.destroy(); 1.184 + AddonsMgrListener.onUninstalled(); 1.185 + 1.186 + // Helper for testing a single widget. 1.187 + // Confirms proper addition and content setup. 1.188 + function testSingleWidget(widgetOptions) { 1.189 + // We have to display which test is being run, because here we do not 1.190 + // use the regular test framework but rather a custom one that iterates 1.191 + // the `tests` array. 1.192 + assert.pass("executing: " + widgetOptions.id); 1.193 + 1.194 + let startCount = widgetCount(); 1.195 + let widget = widgets.Widget(widgetOptions); 1.196 + let node = widgetNode(startCount); 1.197 + assert.ok(node, "widget node at index"); 1.198 + assert.equal(node.tagName, "toolbaritem", "widget element is correct"); 1.199 + assert.equal(widget.width + "px", node.style.minWidth, "widget width is correct"); 1.200 + assert.equal(widgetCount(), startCount + 1, "container has correct number of child elements"); 1.201 + let content = node.firstElementChild; 1.202 + assert.ok(content, "found content"); 1.203 + assert.ok(/iframe|image/.test(content.tagName), "content is iframe or image"); 1.204 + return widget; 1.205 + } 1.206 + 1.207 + // Array of widgets to test 1.208 + // and a function to test them. 1.209 + let tests = []; 1.210 + function nextTest() { 1.211 + assert.equal(widgetCount(), 0, "widget in last test property cleaned itself up"); 1.212 + if (!tests.length) { 1.213 + loader0.unload(); 1.214 + done(); 1.215 + } 1.216 + else 1.217 + timer.setTimeout(tests.shift(), 0); 1.218 + } 1.219 + function doneTest() nextTest(); 1.220 + 1.221 + // text widget 1.222 + tests.push(function testTextWidget() testSingleWidget({ 1.223 + id: "text-single", 1.224 + label: "text widget", 1.225 + content: "oh yeah", 1.226 + contentScript: "self.postMessage(document.body.innerHTML);", 1.227 + contentScriptWhen: "end", 1.228 + onMessage: function (message) { 1.229 + assert.equal(this.content, message, "content matches"); 1.230 + this.destroy(); 1.231 + doneTest(); 1.232 + } 1.233 + })); 1.234 + 1.235 + // html widget 1.236 + tests.push(function testHTMLWidget() testSingleWidget({ 1.237 + id: "html", 1.238 + label: "html widget", 1.239 + content: "<div>oh yeah</div>", 1.240 + contentScript: "self.postMessage(document.body.innerHTML);", 1.241 + contentScriptWhen: "end", 1.242 + onMessage: function (message) { 1.243 + assert.equal(this.content, message, "content matches"); 1.244 + this.destroy(); 1.245 + doneTest(); 1.246 + } 1.247 + })); 1.248 + 1.249 + // image url widget 1.250 + tests.push(function testImageURLWidget() testSingleWidget({ 1.251 + id: "image", 1.252 + label: "image url widget", 1.253 + contentURL: fixtures.url("test.html"), 1.254 + contentScript: "self.postMessage({title: document.title, " + 1.255 + "tag: document.body.firstElementChild.tagName, " + 1.256 + "content: document.body.firstElementChild.innerHTML});", 1.257 + contentScriptWhen: "end", 1.258 + onMessage: function (message) { 1.259 + assert.equal(message.title, "foo", "title matches"); 1.260 + assert.equal(message.tag, "P", "element matches"); 1.261 + assert.equal(message.content, "bar", "element content matches"); 1.262 + this.destroy(); 1.263 + doneTest(); 1.264 + } 1.265 + })); 1.266 + 1.267 + // web uri widget 1.268 + tests.push(function testWebURIWidget() testSingleWidget({ 1.269 + id: "web", 1.270 + label: "web uri widget", 1.271 + contentURL: fixtures.url("test.html"), 1.272 + contentScript: "self.postMessage({title: document.title, " + 1.273 + "tag: document.body.firstElementChild.tagName, " + 1.274 + "content: document.body.firstElementChild.innerHTML});", 1.275 + contentScriptWhen: "end", 1.276 + onMessage: function (message) { 1.277 + assert.equal(message.title, "foo", "title matches"); 1.278 + assert.equal(message.tag, "P", "element matches"); 1.279 + assert.equal(message.content, "bar", "element content matches"); 1.280 + this.destroy(); 1.281 + doneTest(); 1.282 + } 1.283 + })); 1.284 + 1.285 + // event: onclick + content 1.286 + tests.push(function testOnclickEventContent() testSingleWidget({ 1.287 + id: "click-content", 1.288 + label: "click test widget - content", 1.289 + content: "<div id='me'>foo</div>", 1.290 + contentScript: "var evt = new MouseEvent('click', {button: 0});" + 1.291 + "document.getElementById('me').dispatchEvent(evt);", 1.292 + contentScriptWhen: "end", 1.293 + onClick: function() { 1.294 + assert.pass("onClick called"); 1.295 + this.destroy(); 1.296 + doneTest(); 1.297 + } 1.298 + })); 1.299 + 1.300 + // event: onmouseover + content 1.301 + tests.push(function testOnmouseoverEventContent() testSingleWidget({ 1.302 + id: "mouseover-content", 1.303 + label: "mouseover test widget - content", 1.304 + content: "<div id='me'>foo</div>", 1.305 + contentScript: "var evt = new MouseEvent('mouseover'); " + 1.306 + "document.getElementById('me').dispatchEvent(evt);", 1.307 + contentScriptWhen: "end", 1.308 + onMouseover: function() { 1.309 + assert.pass("onMouseover called"); 1.310 + this.destroy(); 1.311 + doneTest(); 1.312 + } 1.313 + })); 1.314 + 1.315 + // event: onmouseout + content 1.316 + tests.push(function testOnmouseoutEventContent() testSingleWidget({ 1.317 + id: "mouseout-content", 1.318 + label: "mouseout test widget - content", 1.319 + content: "<div id='me'>foo</div>", 1.320 + contentScript: "var evt = new MouseEvent('mouseout');" + 1.321 + "document.getElementById('me').dispatchEvent(evt);", 1.322 + contentScriptWhen: "end", 1.323 + onMouseout: function() { 1.324 + assert.pass("onMouseout called"); 1.325 + this.destroy(); 1.326 + doneTest(); 1.327 + } 1.328 + })); 1.329 + 1.330 + // event: onclick + image 1.331 + tests.push(function testOnclickEventImage() testSingleWidget({ 1.332 + id: "click-image", 1.333 + label: "click test widget - image", 1.334 + contentURL: fixtures.url("moz_favicon.ico"), 1.335 + contentScript: "var evt = new MouseEvent('click'); " + 1.336 + "document.body.firstElementChild.dispatchEvent(evt);", 1.337 + contentScriptWhen: "end", 1.338 + onClick: function() { 1.339 + assert.pass("onClick called"); 1.340 + this.destroy(); 1.341 + doneTest(); 1.342 + } 1.343 + })); 1.344 + 1.345 + // event: onmouseover + image 1.346 + tests.push(function testOnmouseoverEventImage() testSingleWidget({ 1.347 + id: "mouseover-image", 1.348 + label: "mouseover test widget - image", 1.349 + contentURL: fixtures.url("moz_favicon.ico"), 1.350 + contentScript: "var evt = new MouseEvent('mouseover');" + 1.351 + "document.body.firstElementChild.dispatchEvent(evt);", 1.352 + contentScriptWhen: "end", 1.353 + onMouseover: function() { 1.354 + assert.pass("onMouseover called"); 1.355 + this.destroy(); 1.356 + doneTest(); 1.357 + } 1.358 + })); 1.359 + 1.360 + // event: onmouseout + image 1.361 + tests.push(function testOnmouseoutEventImage() testSingleWidget({ 1.362 + id: "mouseout-image", 1.363 + label: "mouseout test widget - image", 1.364 + contentURL: fixtures.url("moz_favicon.ico"), 1.365 + contentScript: "var evt = new MouseEvent('mouseout'); " + 1.366 + "document.body.firstElementChild.dispatchEvent(evt);", 1.367 + contentScriptWhen: "end", 1.368 + onMouseout: function() { 1.369 + assert.pass("onMouseout called"); 1.370 + this.destroy(); 1.371 + doneTest(); 1.372 + } 1.373 + })); 1.374 + 1.375 + // test multiple widgets 1.376 + tests.push(function testMultipleWidgets() { 1.377 + let w1 = widgets.Widget({id: "first", label: "first widget", content: "first content"}); 1.378 + let w2 = widgets.Widget({id: "second", label: "second widget", content: "second content"}); 1.379 + 1.380 + w1.destroy(); 1.381 + w2.destroy(); 1.382 + 1.383 + doneTest(); 1.384 + }); 1.385 + 1.386 + // test updating widget content 1.387 + let loads = 0; 1.388 + tests.push(function testUpdatingWidgetContent() testSingleWidget({ 1.389 + id: "content-updating", 1.390 + label: "content update test widget", 1.391 + content: "<div id='me'>foo</div>", 1.392 + contentScript: "self.postMessage(1)", 1.393 + contentScriptWhen: "ready", 1.394 + onMessage: function(message) { 1.395 + if (!this.flag) { 1.396 + this.content = "<div id='me'>bar</div>"; 1.397 + this.flag = 1; 1.398 + } 1.399 + else { 1.400 + assert.equal(this.content, "<div id='me'>bar</div>", 'content is as expected'); 1.401 + this.destroy(); 1.402 + doneTest(); 1.403 + } 1.404 + } 1.405 + })); 1.406 + 1.407 + // test updating widget contentURL 1.408 + let url1 = "data:text/html;charset=utf-8,<body>foodle</body>"; 1.409 + let url2 = "data:text/html;charset=utf-8,<body>nistel</body>"; 1.410 + 1.411 + tests.push(function testUpdatingContentURL() testSingleWidget({ 1.412 + id: "content-url-updating", 1.413 + label: "content update test widget", 1.414 + contentURL: url1, 1.415 + contentScript: "self.postMessage(document.location.href);", 1.416 + contentScriptWhen: "end", 1.417 + onMessage: function(message) { 1.418 + if (!this.flag) { 1.419 + assert.equal(this.contentURL.toString(), url1); 1.420 + assert.equal(message, url1); 1.421 + this.contentURL = url2; 1.422 + this.flag = 1; 1.423 + } 1.424 + else { 1.425 + assert.equal(this.contentURL.toString(), url2); 1.426 + assert.equal(message, url2); 1.427 + this.destroy(); 1.428 + doneTest(); 1.429 + } 1.430 + } 1.431 + })); 1.432 + 1.433 + // test tooltip 1.434 + tests.push(function testTooltip() testSingleWidget({ 1.435 + id: "text-with-tooltip", 1.436 + label: "text widget", 1.437 + content: "oh yeah", 1.438 + tooltip: "foo", 1.439 + contentScript: "self.postMessage(1)", 1.440 + contentScriptWhen: "ready", 1.441 + onMessage: function(message) { 1.442 + assert.equal(this.tooltip, "foo", "tooltip matches"); 1.443 + this.destroy(); 1.444 + doneTest(); 1.445 + } 1.446 + })); 1.447 + 1.448 + // test tooltip fallback to label 1.449 + tests.push(function testTooltipFallback() testSingleWidget({ 1.450 + id: "fallback", 1.451 + label: "fallback", 1.452 + content: "oh yeah", 1.453 + contentScript: "self.postMessage(1)", 1.454 + contentScriptWhen: "ready", 1.455 + onMessage: function(message) { 1.456 + assert.equal(this.tooltip, this.label, "tooltip fallbacks to label"); 1.457 + this.destroy(); 1.458 + doneTest(); 1.459 + } 1.460 + })); 1.461 + 1.462 + // test updating widget tooltip 1.463 + let updated = false; 1.464 + tests.push(function testUpdatingTooltip() testSingleWidget({ 1.465 + id: "tooltip-updating", 1.466 + label: "tooltip update test widget", 1.467 + tooltip: "foo", 1.468 + content: "<div id='me'>foo</div>", 1.469 + contentScript: "self.postMessage(1)", 1.470 + contentScriptWhen: "ready", 1.471 + onMessage: function(message) { 1.472 + this.tooltip = "bar"; 1.473 + assert.equal(this.tooltip, "bar", "tooltip gets updated"); 1.474 + this.destroy(); 1.475 + doneTest(); 1.476 + } 1.477 + })); 1.478 + 1.479 + // test allow attribute 1.480 + tests.push(function testDefaultAllow() testSingleWidget({ 1.481 + id: "allow-default", 1.482 + label: "allow.script attribute", 1.483 + content: "<script>document.title = 'ok';</script>", 1.484 + contentScript: "self.postMessage(document.title)", 1.485 + onMessage: function(message) { 1.486 + assert.equal(message, "ok", "scripts are evaluated by default"); 1.487 + this.destroy(); 1.488 + doneTest(); 1.489 + } 1.490 + })); 1.491 + 1.492 + tests.push(function testExplicitAllow() testSingleWidget({ 1.493 + id: "allow-explicit", 1.494 + label: "allow.script attribute", 1.495 + allow: {script: true}, 1.496 + content: "<script>document.title = 'ok';</script>", 1.497 + contentScript: "self.postMessage(document.title)", 1.498 + onMessage: function(message) { 1.499 + assert.equal(message, "ok", "scripts are evaluated when we want to"); 1.500 + this.destroy(); 1.501 + doneTest(); 1.502 + } 1.503 + })); 1.504 + 1.505 + tests.push(function testExplicitDisallow() testSingleWidget({ 1.506 + id: "allow-explicit-disallow", 1.507 + label: "allow.script attribute", 1.508 + content: "<script>document.title = 'ok';</script>", 1.509 + allow: {script: false}, 1.510 + contentScript: "self.postMessage(document.title)", 1.511 + onMessage: function(message) { 1.512 + assert.notEqual(message, "ok", "scripts aren't evaluated when " + 1.513 + "explicitly blocked it"); 1.514 + this.destroy(); 1.515 + doneTest(); 1.516 + } 1.517 + })); 1.518 + 1.519 + // test multiple windows 1.520 + tests.push(function testMultipleWindows() { 1.521 + assert.pass('executing test multiple windows'); 1.522 + openNewWindowTab("about:blank", { inNewWindow: true, onLoad: function(e) { 1.523 + let browserWindow = e.target.defaultView; 1.524 + assert.ok(browserWindow, 'window was opened'); 1.525 + let doc = browserWindow.document; 1.526 + let container = () => doc.getElementById("nav-bar"); 1.527 + let widgetCount2 = () => container() ? container().querySelectorAll('[id^="widget\:"]').length : 0; 1.528 + let widgetStartCount2 = widgetCount2(); 1.529 + 1.530 + let w1Opts = {id:"first-multi-window", label: "first widget", content: "first content"}; 1.531 + let w1 = testSingleWidget(w1Opts); 1.532 + assert.equal(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first widget"); 1.533 + 1.534 + let w2Opts = {id:"second-multi-window", label: "second widget", content: "second content"}; 1.535 + let w2 = testSingleWidget(w2Opts); 1.536 + assert.equal(widgetCount2(), widgetStartCount2 + 2, "2nd window has correct number of child elements after second widget"); 1.537 + 1.538 + w1.destroy(); 1.539 + assert.equal(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first destroy"); 1.540 + w2.destroy(); 1.541 + assert.equal(widgetCount2(), widgetStartCount2, "2nd window has correct number of child elements after second destroy"); 1.542 + 1.543 + close(browserWindow).then(doneTest); 1.544 + }}); 1.545 + }); 1.546 + 1.547 + // test window closing 1.548 + tests.push(function testWindowClosing() { 1.549 + // 1/ Create a new widget 1.550 + let w1Opts = { 1.551 + id:"first-win-closing", 1.552 + label: "first widget", 1.553 + content: "first content", 1.554 + contentScript: "self.port.on('event', function () self.port.emit('event'))" 1.555 + }; 1.556 + let widget = testSingleWidget(w1Opts); 1.557 + let windows = loader0.require("sdk/windows").browserWindows; 1.558 + 1.559 + // 2/ Retrieve a WidgetView for the initial browser window 1.560 + let acceptDetach = false; 1.561 + let mainView = widget.getView(windows.activeWindow); 1.562 + assert.ok(mainView, "Got first widget view"); 1.563 + mainView.on("detach", function () { 1.564 + // 8/ End of our test. Accept detach event only when it occurs after 1.565 + // widget.destroy() 1.566 + if (acceptDetach) 1.567 + doneTest(); 1.568 + else 1.569 + assert.fail("View on initial window should not be destroyed"); 1.570 + }); 1.571 + mainView.port.on("event", function () { 1.572 + // 7/ Receive event sent during 6/ and cleanup our test 1.573 + acceptDetach = true; 1.574 + widget.destroy(); 1.575 + }); 1.576 + 1.577 + // 3/ First: open a new browser window 1.578 + windows.open({ 1.579 + url: "about:blank", 1.580 + onOpen: function(window) { 1.581 + // 4/ Retrieve a WidgetView for this new window 1.582 + let view = widget.getView(window); 1.583 + assert.ok(view, "Got second widget view"); 1.584 + view.port.on("event", function () { 1.585 + assert.fail("We should not receive event on the detach view"); 1.586 + }); 1.587 + view.on("detach", function () { 1.588 + // The related view is destroyed 1.589 + // 6/ Send a custom event 1.590 + assert.throws(function () { 1.591 + view.port.emit("event"); 1.592 + }, 1.593 + /^The widget has been destroyed and can no longer be used.$/, 1.594 + "emit on a destroyed view should throw"); 1.595 + widget.port.emit("event"); 1.596 + }); 1.597 + 1.598 + // 5/ Destroy this window 1.599 + window.close(); 1.600 + } 1.601 + }); 1.602 + }); 1.603 + 1.604 + if (false) { 1.605 + tests.push(function testAddonBarHide() { 1.606 + // Hide the addon-bar 1.607 + browserWindow.setToolbarVisibility(container(), false); 1.608 + assert.ok(container().collapsed, 1.609 + "1st window starts with an hidden addon-bar"); 1.610 + 1.611 + // Then open a browser window and verify that the addon-bar remains hidden 1.612 + openNewWindowTab("about:blank", { inNewWindow: true, onLoad: function(e) { 1.613 + let browserWindow2 = e.target.defaultView; 1.614 + let doc2 = browserWindow2.document; 1.615 + function container2() doc2.getElementById("addon-bar"); 1.616 + function widgetCount2() container2() ? container2().childNodes.length : 0; 1.617 + let widgetStartCount2 = widgetCount2(); 1.618 + assert.ok(container2().collapsed, 1.619 + "2nd window starts with an hidden addon-bar"); 1.620 + 1.621 + let w1Opts = {id:"first-addonbar-hide", label: "first widget", content: "first content"}; 1.622 + let w1 = testSingleWidget(w1Opts); 1.623 + assert.equal(widgetCount2(), widgetStartCount2 + 1, 1.624 + "2nd window has correct number of child elements after" + 1.625 + "widget creation"); 1.626 + assert.ok(!container().collapsed, "1st window has a visible addon-bar"); 1.627 + assert.ok(!container2().collapsed, "2nd window has a visible addon-bar"); 1.628 + w1.destroy(); 1.629 + assert.equal(widgetCount2(), widgetStartCount2, 1.630 + "2nd window has correct number of child elements after" + 1.631 + "widget destroy"); 1.632 + 1.633 + assert.ok(container().collapsed, "1st window has an hidden addon-bar"); 1.634 + assert.ok(container2().collapsed, "2nd window has an hidden addon-bar"); 1.635 + 1.636 + // Reset addon-bar visibility before exiting this test 1.637 + browserWindow.setToolbarVisibility(container(), true); 1.638 + 1.639 + close(browserWindow2).then(doneTest); 1.640 + }}); 1.641 + }); 1.642 + } 1.643 + 1.644 + // test widget.width 1.645 + tests.push(function testWidgetWidth() testSingleWidget({ 1.646 + id: "text-test-width", 1.647 + label: "test widget.width", 1.648 + content: "test width", 1.649 + width: 64, 1.650 + contentScript: "self.postMessage(1)", 1.651 + contentScriptWhen: "ready", 1.652 + onMessage: function(message) { 1.653 + assert.equal(this.width, 64, 'width is 64'); 1.654 + 1.655 + let node = widgetNode(0); 1.656 + assert.equal(this.width, node.style.minWidth.replace("px", "")); 1.657 + assert.equal(this.width, node.firstElementChild.style.width.replace("px", "")); 1.658 + this.width = 48; 1.659 + assert.equal(this.width, node.style.minWidth.replace("px", "")); 1.660 + assert.equal(this.width, node.firstElementChild.style.width.replace("px", "")); 1.661 + 1.662 + this.destroy(); 1.663 + doneTest(); 1.664 + } 1.665 + })); 1.666 + 1.667 + // test click handler not respond to right-click 1.668 + let clickCount = 0; 1.669 + tests.push(function testNoRightClick() testSingleWidget({ 1.670 + id: "right-click-content", 1.671 + label: "click test widget - content", 1.672 + content: "<div id='me'>foo</div>", 1.673 + contentScript: // Left click 1.674 + "var evt = new MouseEvent('click', {button: 0});" + 1.675 + "document.getElementById('me').dispatchEvent(evt); " + 1.676 + // Middle click 1.677 + "evt = new MouseEvent('click', {button: 1});" + 1.678 + "document.getElementById('me').dispatchEvent(evt); " + 1.679 + // Right click 1.680 + "evt = new MouseEvent('click', {button: 2});" + 1.681 + "document.getElementById('me').dispatchEvent(evt); " + 1.682 + // Mouseover 1.683 + "evt = new MouseEvent('mouseover');" + 1.684 + "document.getElementById('me').dispatchEvent(evt);", 1.685 + contentScriptWhen: "end", 1.686 + onClick: function() clickCount++, 1.687 + onMouseover: function() { 1.688 + assert.equal(clickCount, 1, "only left click was sent to click handler"); 1.689 + this.destroy(); 1.690 + doneTest(); 1.691 + } 1.692 + })); 1.693 + 1.694 + // kick off test execution 1.695 + doneTest(); 1.696 +}; 1.697 + 1.698 +exports.testWidgetWithValidPanel = function(assert, done) { 1.699 + let { loader } = LoaderWithHookedConsole(module); 1.700 + const { Widget } = loader.require("sdk/widget"); 1.701 + const { Panel } = loader.require("sdk/panel"); 1.702 + 1.703 + let widget1 = Widget({ 1.704 + id: "testWidgetWithValidPanel", 1.705 + label: "panel widget 1", 1.706 + content: "<div id='me'>foo</div>", 1.707 + contentScript: "var evt = new MouseEvent('click', {button: 0});" + 1.708 + "document.body.dispatchEvent(evt);", 1.709 + contentScriptWhen: "end", 1.710 + panel: Panel({ 1.711 + contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>", 1.712 + onShow: function() { 1.713 + let { document } = getMostRecentBrowserWindow(); 1.714 + let widgetEle = document.getElementById("widget:" + jetpackID + "-" + widget1.id); 1.715 + let panelEle = document.getElementById('mainPopupSet').lastChild; 1.716 + // See bug https://bugzilla.mozilla.org/show_bug.cgi?id=859592 1.717 + assert.equal(panelEle.getAttribute("type"), "arrow", 'the panel is a arrow type'); 1.718 + assert.strictEqual(panelEle.anchorNode, widgetEle, 'the panel is properly anchored to the widget'); 1.719 + 1.720 + widget1.destroy(); 1.721 + loader.unload(); 1.722 + assert.pass("panel displayed on click"); 1.723 + done(); 1.724 + } 1.725 + }) 1.726 + }); 1.727 +}; 1.728 + 1.729 +exports.testWidgetWithInvalidPanel = function(assert) { 1.730 + let { loader } = LoaderWithHookedConsole(module); 1.731 + const widgets = loader.require("sdk/widget"); 1.732 + 1.733 + assert.throws( 1.734 + function() { 1.735 + widgets.Widget({ 1.736 + id: "panel2", 1.737 + label: "panel widget 2", 1.738 + panel: {} 1.739 + }); 1.740 + }, 1.741 + /^The option \"panel\" must be one of the following types: null, undefined, object$/, 1.742 + "widget.panel must be a Panel object"); 1.743 + loader.unload(); 1.744 +}; 1.745 + 1.746 +exports.testPanelWidget3 = function testPanelWidget3(assert, done) { 1.747 + let { loader } = LoaderWithHookedConsole(module); 1.748 + const widgets = loader.require("sdk/widget"); 1.749 + const { Panel } = loader.require("sdk/panel"); 1.750 + 1.751 + let onClickCalled = false; 1.752 + let widget3 = widgets.Widget({ 1.753 + id: "panel3", 1.754 + label: "panel widget 3", 1.755 + content: "<div id='me'>foo</div>", 1.756 + contentScript: "var evt = new MouseEvent('click', {button: 0});" + 1.757 + "document.body.firstElementChild.dispatchEvent(evt);", 1.758 + contentScriptWhen: "end", 1.759 + onClick: function() { 1.760 + onClickCalled = true; 1.761 + this.panel.show(); 1.762 + }, 1.763 + panel: Panel({ 1.764 + contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>", 1.765 + onShow: function() { 1.766 + assert.ok( 1.767 + onClickCalled, 1.768 + "onClick called on click for widget with both panel and onClick"); 1.769 + widget3.destroy(); 1.770 + loader.unload(); 1.771 + done(); 1.772 + } 1.773 + }) 1.774 + }); 1.775 +}; 1.776 + 1.777 +exports.testWidgetWithPanelInMenuPanel = function(assert, done) { 1.778 + const { CustomizableUI } = Cu.import("resource:///modules/CustomizableUI.jsm", {}); 1.779 + let { loader } = LoaderWithHookedConsole(module); 1.780 + const widgets = loader.require("sdk/widget"); 1.781 + const { Panel } = loader.require("sdk/panel"); 1.782 + 1.783 + let widget1 = widgets.Widget({ 1.784 + id: "panel1", 1.785 + label: "panel widget 1", 1.786 + content: "<div id='me'>foo</div>", 1.787 + contentScript: "new " + function() { 1.788 + self.port.on('click', () => { 1.789 + let evt = new MouseEvent('click', {button: 0}); 1.790 + document.body.dispatchEvent(evt); 1.791 + }); 1.792 + }, 1.793 + contentScriptWhen: "end", 1.794 + panel: Panel({ 1.795 + contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>", 1.796 + onShow: function() { 1.797 + let { document } = getMostRecentBrowserWindow(); 1.798 + let { anchorNode } = document.getElementById('mainPopupSet').lastChild; 1.799 + let panelButtonNode = document.getElementById("PanelUI-menu-button"); 1.800 + 1.801 + assert.strictEqual(anchorNode, panelButtonNode, 1.802 + 'the panel is anchored to the panel menu button instead of widget'); 1.803 + 1.804 + widget1.destroy(); 1.805 + loader.unload(); 1.806 + done(); 1.807 + } 1.808 + }) 1.809 + }); 1.810 + 1.811 + let widgetId = "widget:" + jetpackID + "-" + widget1.id; 1.812 + 1.813 + CustomizableUI.addListener({ 1.814 + onWidgetAdded: function(id) { 1.815 + if (id !== widgetId) return; 1.816 + 1.817 + let { document, PanelUI } = getMostRecentBrowserWindow(); 1.818 + 1.819 + PanelUI.panel.addEventListener('popupshowing', function onshow({type}) { 1.820 + this.removeEventListener(type, onshow); 1.821 + widget1.port.emit('click'); 1.822 + }); 1.823 + 1.824 + document.getElementById("PanelUI-menu-button").click() 1.825 + } 1.826 + }); 1.827 + 1.828 + CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL); 1.829 +}; 1.830 + 1.831 +exports.testWidgetMessaging = function testWidgetMessaging(assert, done) { 1.832 + let { loader } = LoaderWithHookedConsole(module); 1.833 + const widgets = loader.require("sdk/widget"); 1.834 + 1.835 + let origMessage = "foo"; 1.836 + let widget = widgets.Widget({ 1.837 + id: "widget-messaging", 1.838 + label: "foo", 1.839 + content: "<bar>baz</bar>", 1.840 + contentScriptWhen: "end", 1.841 + contentScript: "self.on('message', function(data) { self.postMessage(data); }); self.postMessage('ready');", 1.842 + onMessage: function(message) { 1.843 + if (message == "ready") 1.844 + widget.postMessage(origMessage); 1.845 + else { 1.846 + assert.equal(origMessage, message); 1.847 + widget.destroy(); 1.848 + loader.unload(); 1.849 + done(); 1.850 + } 1.851 + } 1.852 + }); 1.853 +}; 1.854 + 1.855 +exports.testWidgetViews = function testWidgetViews(assert, done) { 1.856 + let { loader } = LoaderWithHookedConsole(module); 1.857 + const widgets = loader.require("sdk/widget"); 1.858 + 1.859 + let widget = widgets.Widget({ 1.860 + id: "widget-views", 1.861 + label: "foo", 1.862 + content: "<bar>baz</bar>", 1.863 + contentScriptWhen: "ready", 1.864 + contentScript: "self.on('message', function(data) self.postMessage(data)); self.postMessage('ready')", 1.865 + onAttach: function(view) { 1.866 + assert.pass("WidgetView created"); 1.867 + view.on("message", function () { 1.868 + assert.pass("Got message in WidgetView"); 1.869 + widget.destroy(); 1.870 + }); 1.871 + view.on("detach", function () { 1.872 + assert.pass("WidgetView destroyed"); 1.873 + loader.unload(); 1.874 + done(); 1.875 + }); 1.876 + } 1.877 + }); 1.878 +}; 1.879 + 1.880 +exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(assert, done) { 1.881 + let { loader } = LoaderWithHookedConsole(module); 1.882 + const widgets = loader.require("sdk/widget"); 1.883 + const { browserWindows } = loader.require("sdk/windows"); 1.884 + 1.885 + let view = null; 1.886 + let widget = widgets.Widget({ 1.887 + id: "widget-view-ui-events", 1.888 + label: "foo", 1.889 + content: "<div id='me'>foo</div>", 1.890 + contentScript: "var evt = new MouseEvent('click', {button: 0});" + 1.891 + "document.getElementById('me').dispatchEvent(evt);", 1.892 + contentScriptWhen: "ready", 1.893 + onAttach: function(attachView) { 1.894 + view = attachView; 1.895 + assert.pass("Got attach event"); 1.896 + }, 1.897 + onClick: function (eventView) { 1.898 + assert.equal(view, eventView, 1.899 + "event first argument is equal to the WidgetView"); 1.900 + let view2 = widget.getView(browserWindows.activeWindow); 1.901 + assert.equal(view, view2, 1.902 + "widget.getView return the same WidgetView"); 1.903 + widget.destroy(); 1.904 + loader.unload(); 1.905 + done(); 1.906 + } 1.907 + }); 1.908 +}; 1.909 + 1.910 +exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(assert, done) { 1.911 + let { loader } = LoaderWithHookedConsole(module); 1.912 + const widgets = loader.require("sdk/widget"); 1.913 + 1.914 + let widget = widgets.Widget({ 1.915 + id: "widget-view-custom-events", 1.916 + label: "foo", 1.917 + content: "<div id='me'>foo</div>", 1.918 + contentScript: "self.port.emit('event', 'ok');", 1.919 + contentScriptWhen: "ready", 1.920 + onAttach: function(view) { 1.921 + view.port.on("event", function (data) { 1.922 + assert.equal(data, "ok", 1.923 + "event argument is valid on WidgetView"); 1.924 + }); 1.925 + }, 1.926 + }); 1.927 + widget.port.on("event", function (data) { 1.928 + assert.equal(data, "ok", "event argument is valid on Widget"); 1.929 + widget.destroy(); 1.930 + loader.unload(); 1.931 + done(); 1.932 + }); 1.933 +}; 1.934 + 1.935 +exports.testWidgetViewsTooltip = function testWidgetViewsTooltip(assert, done) { 1.936 + let { loader } = LoaderWithHookedConsole(module); 1.937 + const widgets = loader.require("sdk/widget"); 1.938 + const { browserWindows } = loader.require("sdk/windows"); 1.939 + 1.940 + let widget = new widgets.Widget({ 1.941 + id: "widget-views-tooltip", 1.942 + label: "foo", 1.943 + content: "foo" 1.944 + }); 1.945 + let view = widget.getView(browserWindows.activeWindow); 1.946 + widget.tooltip = null; 1.947 + assert.equal(view.tooltip, "foo", 1.948 + "view tooltip defaults to base widget label"); 1.949 + assert.equal(widget.tooltip, "foo", 1.950 + "tooltip defaults to base widget label"); 1.951 + widget.destroy(); 1.952 + loader.unload(); 1.953 + done(); 1.954 +}; 1.955 + 1.956 +exports.testWidgetMove = function testWidgetMove(assert, done) { 1.957 + let { loader } = LoaderWithHookedConsole(module); 1.958 + const widgets = loader.require("sdk/widget"); 1.959 + 1.960 + let browserWindow = getMostRecentBrowserWindow(); 1.961 + let doc = browserWindow.document; 1.962 + 1.963 + let label = "unique-widget-label"; 1.964 + let origMessage = "message after node move"; 1.965 + let gotFirstReady = false; 1.966 + 1.967 + let widget = widgets.Widget({ 1.968 + id: "widget-move", 1.969 + label: label, 1.970 + content: "<bar>baz</bar>", 1.971 + contentScriptWhen: "ready", 1.972 + contentScript: "self.on('message', function(data) { self.postMessage(data); }); self.postMessage('ready');", 1.973 + onMessage: function(message) { 1.974 + if (message == "ready") { 1.975 + if (!gotFirstReady) { 1.976 + assert.pass("Got first ready event"); 1.977 + let widgetNode = doc.querySelector('toolbaritem[label="' + label + '"]'); 1.978 + let parent = widgetNode.parentNode; 1.979 + parent.insertBefore(widgetNode, parent.firstChild); 1.980 + gotFirstReady = true; 1.981 + } 1.982 + else { 1.983 + assert.pass("Got second ready event"); 1.984 + widget.postMessage(origMessage); 1.985 + } 1.986 + } 1.987 + else { 1.988 + assert.equal(origMessage, message, "Got message after node move"); 1.989 + widget.destroy(); 1.990 + loader.unload(); 1.991 + done(); 1.992 + } 1.993 + } 1.994 + }); 1.995 +}; 1.996 + 1.997 +/* 1.998 +The bug is exhibited when a widget with HTML content has it's content 1.999 +changed to new HTML content with a pound in it. Because the src of HTML 1.1000 +content is converted to a data URI, the underlying iframe doesn't 1.1001 +consider the content change a navigation change, so doesn't load 1.1002 +the new content. 1.1003 +*/ 1.1004 +exports.testWidgetWithPound = function testWidgetWithPound(assert, done) { 1.1005 + let { loader } = LoaderWithHookedConsole(module); 1.1006 + const widgets = loader.require("sdk/widget"); 1.1007 + 1.1008 + function getWidgetContent(widget) { 1.1009 + let browserWindow = getMostRecentBrowserWindow(); 1.1010 + let doc = browserWindow.document; 1.1011 + let widgetNode = doc.querySelector('toolbaritem[label="' + widget.label + '"]'); 1.1012 + assert.ok(widgetNode, 'found widget node in the front-end'); 1.1013 + return widgetNode.firstChild.contentDocument.body.innerHTML; 1.1014 + } 1.1015 + 1.1016 + let count = 0; 1.1017 + let widget = widgets.Widget({ 1.1018 + id: "1", 1.1019 + label: "foo", 1.1020 + content: "foo", 1.1021 + contentScript: "window.addEventListener('load', self.postMessage, false);", 1.1022 + onMessage: function() { 1.1023 + count++; 1.1024 + if (count == 1) { 1.1025 + widget.content = "foo#"; 1.1026 + } 1.1027 + else { 1.1028 + assert.equal(getWidgetContent(widget), "foo#", "content updated to pound?"); 1.1029 + widget.destroy(); 1.1030 + loader.unload(); 1.1031 + done(); 1.1032 + } 1.1033 + } 1.1034 + }); 1.1035 +}; 1.1036 + 1.1037 +exports.testContentScriptOptionsOption = function(assert, done) { 1.1038 + let { loader } = LoaderWithHookedConsole(module); 1.1039 + const { Widget } = loader.require("sdk/widget"); 1.1040 + 1.1041 + let widget = Widget({ 1.1042 + id: "widget-script-options", 1.1043 + label: "fooz", 1.1044 + content: "fooz", 1.1045 + contentScript: "self.postMessage( [typeof self.options.d, self.options] );", 1.1046 + contentScriptWhen: "end", 1.1047 + contentScriptOptions: {a: true, b: [1,2,3], c: "string", d: function(){ return 'test'}}, 1.1048 + onMessage: function(msg) { 1.1049 + assert.equal( msg[0], 'undefined', 'functions are stripped from contentScriptOptions' ); 1.1050 + assert.equal( typeof msg[1], 'object', 'object as contentScriptOptions' ); 1.1051 + assert.equal( msg[1].a, true, 'boolean in contentScriptOptions' ); 1.1052 + assert.equal( msg[1].b.join(), '1,2,3', 'array and numbers in contentScriptOptions' ); 1.1053 + assert.equal( msg[1].c, 'string', 'string in contentScriptOptions' ); 1.1054 + widget.destroy(); 1.1055 + loader.unload(); 1.1056 + done(); 1.1057 + } 1.1058 + }); 1.1059 +}; 1.1060 + 1.1061 +exports.testOnAttachWithoutContentScript = function(assert, done) { 1.1062 + let { loader } = LoaderWithHookedConsole(module); 1.1063 + const { Widget } = loader.require("sdk/widget"); 1.1064 + 1.1065 + let widget = Widget({ 1.1066 + id: "onAttachNoCS", 1.1067 + label: "onAttachNoCS", 1.1068 + content: "onAttachNoCS", 1.1069 + onAttach: function (view) { 1.1070 + assert.pass("received attach event"); 1.1071 + widget.destroy(); 1.1072 + loader.unload(); 1.1073 + done(); 1.1074 + } 1.1075 + }); 1.1076 +}; 1.1077 + 1.1078 +exports.testPostMessageOnAttach = function(assert, done) { 1.1079 + let { loader } = LoaderWithHookedConsole(module); 1.1080 + const { Widget } = loader.require("sdk/widget"); 1.1081 + 1.1082 + let widget = Widget({ 1.1083 + id: "onAttach", 1.1084 + label: "onAttach", 1.1085 + content: "onAttach", 1.1086 + // 1) Send a message immediatly after `attach` event 1.1087 + onAttach: function (view) { 1.1088 + view.postMessage("ok"); 1.1089 + }, 1.1090 + // 2) Listen to it and forward it back to the widget 1.1091 + contentScript: "self.on('message', self.postMessage);", 1.1092 + // 3) Listen to this forwarded message 1.1093 + onMessage: function (msg) { 1.1094 + assert.equal( msg, "ok", "postMessage works on `attach` event"); 1.1095 + widget.destroy(); 1.1096 + loader.unload(); 1.1097 + done(); 1.1098 + } 1.1099 + }); 1.1100 +}; 1.1101 + 1.1102 +exports.testPostMessageOnLocationChange = function(assert, done) { 1.1103 + let { loader } = LoaderWithHookedConsole(module); 1.1104 + const { Widget } = loader.require("sdk/widget"); 1.1105 + 1.1106 + let attachEventCount = 0; 1.1107 + let messagesCount = 0; 1.1108 + let widget = Widget({ 1.1109 + id: "onLocationChange", 1.1110 + label: "onLocationChange", 1.1111 + content: "onLocationChange", 1.1112 + contentScript: "new " + function ContentScriptScope() { 1.1113 + // Emit an event when content script is applied in order to know when 1.1114 + // the first document is loaded so that we can load the 2nd one 1.1115 + self.postMessage("ready"); 1.1116 + // And forward any incoming message back to the widget to see if 1.1117 + // messaging is working on 2nd document 1.1118 + self.on("message", self.postMessage); 1.1119 + }, 1.1120 + onMessage: function (msg) { 1.1121 + messagesCount++; 1.1122 + if (messagesCount == 1) { 1.1123 + assert.equal(msg, "ready", "First document is loaded"); 1.1124 + widget.content = "location changed"; 1.1125 + } 1.1126 + else if (messagesCount == 2) { 1.1127 + assert.equal(msg, "ready", "Second document is loaded"); 1.1128 + widget.postMessage("ok"); 1.1129 + } 1.1130 + else if (messagesCount == 3) { 1.1131 + assert.equal(msg, "ok", 1.1132 + "We receive the message sent to the 2nd document"); 1.1133 + widget.destroy(); 1.1134 + loader.unload(); 1.1135 + done(); 1.1136 + } 1.1137 + } 1.1138 + }); 1.1139 +}; 1.1140 + 1.1141 +exports.testSVGWidget = function(assert, done) { 1.1142 + let { loader } = LoaderWithHookedConsole(module); 1.1143 + const { Widget } = loader.require("sdk/widget"); 1.1144 + 1.1145 + // use of capital SVG here is intended, that was failing.. 1.1146 + let SVG_URL = fixtures.url("mofo_logo.SVG"); 1.1147 + 1.1148 + let widget = Widget({ 1.1149 + id: "mozilla-svg-logo", 1.1150 + label: "moz foundation logo", 1.1151 + contentURL: SVG_URL, 1.1152 + contentScript: "self.postMessage({count: window.document.images.length, src: window.document.images[0].src});", 1.1153 + onMessage: function(data) { 1.1154 + widget.destroy(); 1.1155 + assert.equal(data.count, 1, 'only one image'); 1.1156 + assert.equal(data.src, SVG_URL, 'only one image'); 1.1157 + loader.unload(); 1.1158 + done(); 1.1159 + } 1.1160 + }); 1.1161 +}; 1.1162 + 1.1163 +exports.testReinsertion = function(assert, done) { 1.1164 + let { loader } = LoaderWithHookedConsole(module); 1.1165 + const { Widget } = loader.require("sdk/widget"); 1.1166 + const WIDGETID = "test-reinsertion"; 1.1167 + let browserWindow = getMostRecentBrowserWindow(); 1.1168 + 1.1169 + let widget = Widget({ 1.1170 + id: "test-reinsertion", 1.1171 + label: "test reinsertion", 1.1172 + content: "Test", 1.1173 + }); 1.1174 + let realWidgetId = "widget:" + jetpackID + "-" + WIDGETID; 1.1175 + // Remove the widget: 1.1176 + 1.1177 + browserWindow.CustomizableUI.removeWidgetFromArea(realWidgetId); 1.1178 + 1.1179 + openNewWindowTab("about:blank", { inNewWindow: true, onLoad: function(e) { 1.1180 + assert.equal(e.target.defaultView.document.getElementById(realWidgetId), null); 1.1181 + close(e.target.defaultView).then(_ => { 1.1182 + loader.unload(); 1.1183 + done(); 1.1184 + }); 1.1185 + }}); 1.1186 +}; 1.1187 + 1.1188 +exports.testWideWidget = function testWideWidget(assert) { 1.1189 + let { loader } = LoaderWithHookedConsole(module); 1.1190 + const widgets = loader.require("sdk/widget"); 1.1191 + const { document, CustomizableUI, gCustomizeMode, setTimeout } = getMostRecentBrowserWindow(); 1.1192 + 1.1193 + let wideWidget = widgets.Widget({ 1.1194 + id: "my-wide-widget", 1.1195 + label: "wide-wdgt", 1.1196 + content: "foo", 1.1197 + width: 200 1.1198 + }); 1.1199 + 1.1200 + let widget = widgets.Widget({ 1.1201 + id: "my-regular-widget", 1.1202 + label: "reg-wdgt", 1.1203 + content: "foo" 1.1204 + }); 1.1205 + 1.1206 + let wideWidgetNode = document.querySelector("toolbaritem[label=wide-wdgt]"); 1.1207 + let widgetNode = document.querySelector("toolbaritem[label=reg-wdgt]"); 1.1208 + 1.1209 + assert.equal(wideWidgetNode, null, 1.1210 + "Wide Widget are not added to UI"); 1.1211 + 1.1212 + assert.notEqual(widgetNode, null, 1.1213 + "regular size widget are in the UI"); 1.1214 +}; 1.1215 + 1.1216 +require("sdk/test").run(exports);