addon-sdk/source/test/test-widget.js

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial