addon-sdk/source/test/test-ui-action-button.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': '> 28'
michael@0 9 }
michael@0 10 };
michael@0 11
michael@0 12 const { Cu } = require('chrome');
michael@0 13 const { Loader } = require('sdk/test/loader');
michael@0 14 const { data } = require('sdk/self');
michael@0 15 const { open, focus, close } = require('sdk/window/helpers');
michael@0 16 const { setTimeout } = require('sdk/timers');
michael@0 17 const { getMostRecentBrowserWindow } = require('sdk/window/utils');
michael@0 18 const { partial } = require('sdk/lang/functional');
michael@0 19
michael@0 20 const openBrowserWindow = partial(open, null, {features: {toolbar: true}});
michael@0 21 const openPrivateBrowserWindow = partial(open, null,
michael@0 22 {features: {toolbar: true, private: true}});
michael@0 23
michael@0 24 function getWidget(buttonId, window = getMostRecentBrowserWindow()) {
michael@0 25 const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
michael@0 26 const { AREA_NAVBAR } = CustomizableUI;
michael@0 27
michael@0 28 let widgets = CustomizableUI.getWidgetIdsInArea(AREA_NAVBAR).
michael@0 29 filter((id) => id.startsWith('action-button--') && id.endsWith(buttonId));
michael@0 30
michael@0 31 if (widgets.length === 0)
michael@0 32 throw new Error('Widget with id `' + id +'` not found.');
michael@0 33
michael@0 34 if (widgets.length > 1)
michael@0 35 throw new Error('Unexpected number of widgets: ' + widgets.length)
michael@0 36
michael@0 37 return CustomizableUI.getWidget(widgets[0]).forWindow(window);
michael@0 38 };
michael@0 39
michael@0 40 exports['test basic constructor validation'] = function(assert) {
michael@0 41 let loader = Loader(module);
michael@0 42 let { ActionButton } = loader.require('sdk/ui');
michael@0 43
michael@0 44 assert.throws(
michael@0 45 () => ActionButton({}),
michael@0 46 /^The option/,
michael@0 47 'throws on no option given');
michael@0 48
michael@0 49 // Test no label
michael@0 50 assert.throws(
michael@0 51 () => ActionButton({ id: 'my-button', icon: './icon.png'}),
michael@0 52 /^The option "label"/,
michael@0 53 'throws on no label given');
michael@0 54
michael@0 55 // Test no id
michael@0 56 assert.throws(
michael@0 57 () => ActionButton({ label: 'my button', icon: './icon.png' }),
michael@0 58 /^The option "id"/,
michael@0 59 'throws on no id given');
michael@0 60
michael@0 61 // Test no icon
michael@0 62 assert.throws(
michael@0 63 () => ActionButton({ id: 'my-button', label: 'my button' }),
michael@0 64 /^The option "icon"/,
michael@0 65 'throws on no icon given');
michael@0 66
michael@0 67
michael@0 68 // Test empty label
michael@0 69 assert.throws(
michael@0 70 () => ActionButton({ id: 'my-button', label: '', icon: './icon.png' }),
michael@0 71 /^The option "label"/,
michael@0 72 'throws on no valid label given');
michael@0 73
michael@0 74 // Test invalid id
michael@0 75 assert.throws(
michael@0 76 () => ActionButton({ id: 'my button', label: 'my button', icon: './icon.png' }),
michael@0 77 /^The option "id"/,
michael@0 78 'throws on no valid id given');
michael@0 79
michael@0 80 // Test empty id
michael@0 81 assert.throws(
michael@0 82 () => ActionButton({ id: '', label: 'my button', icon: './icon.png' }),
michael@0 83 /^The option "id"/,
michael@0 84 'throws on no valid id given');
michael@0 85
michael@0 86 // Test remote icon
michael@0 87 assert.throws(
michael@0 88 () => ActionButton({ id: 'my-button', label: 'my button', icon: 'http://www.mozilla.org/favicon.ico'}),
michael@0 89 /^The option "icon"/,
michael@0 90 'throws on no valid icon given');
michael@0 91
michael@0 92 // Test wrong icon: no absolute URI to local resource, neither relative './'
michael@0 93 assert.throws(
michael@0 94 () => ActionButton({ id: 'my-button', label: 'my button', icon: 'icon.png'}),
michael@0 95 /^The option "icon"/,
michael@0 96 'throws on no valid icon given');
michael@0 97
michael@0 98 // Test wrong icon: no absolute URI to local resource, neither relative './'
michael@0 99 assert.throws(
michael@0 100 () => ActionButton({ id: 'my-button', label: 'my button', icon: 'foo and bar'}),
michael@0 101 /^The option "icon"/,
michael@0 102 'throws on no valid icon given');
michael@0 103
michael@0 104 // Test wrong icon: '../' is not allowed
michael@0 105 assert.throws(
michael@0 106 () => ActionButton({ id: 'my-button', label: 'my button', icon: '../icon.png'}),
michael@0 107 /^The option "icon"/,
michael@0 108 'throws on no valid icon given');
michael@0 109
michael@0 110 loader.unload();
michael@0 111 };
michael@0 112
michael@0 113 exports['test button added'] = function(assert) {
michael@0 114 let loader = Loader(module);
michael@0 115 let { ActionButton } = loader.require('sdk/ui');
michael@0 116
michael@0 117 let button = ActionButton({
michael@0 118 id: 'my-button-1',
michael@0 119 label: 'my button',
michael@0 120 icon: './icon.png'
michael@0 121 });
michael@0 122
michael@0 123 // check defaults
michael@0 124 assert.equal(button.disabled, false,
michael@0 125 'disabled is set to default `false` value');
michael@0 126
michael@0 127 let { node } = getWidget(button.id);
michael@0 128
michael@0 129 assert.ok(!!node, 'The button is in the navbar');
michael@0 130
michael@0 131 assert.equal(button.label, node.getAttribute('label'),
michael@0 132 'label is set');
michael@0 133
michael@0 134 assert.equal(button.label, node.getAttribute('tooltiptext'),
michael@0 135 'tooltip is set');
michael@0 136
michael@0 137 assert.equal(data.url(button.icon.substr(2)), node.getAttribute('image'),
michael@0 138 'icon is set');
michael@0 139
michael@0 140 loader.unload();
michael@0 141 }
michael@0 142
michael@0 143 exports['test button added with resource URI'] = function(assert) {
michael@0 144 let loader = Loader(module);
michael@0 145 let { ActionButton } = loader.require('sdk/ui');
michael@0 146
michael@0 147 let button = ActionButton({
michael@0 148 id: 'my-button-1',
michael@0 149 label: 'my button',
michael@0 150 icon: data.url('icon.png')
michael@0 151 });
michael@0 152
michael@0 153 assert.equal(button.icon, data.url('icon.png'),
michael@0 154 'icon is set');
michael@0 155
michael@0 156 let { node } = getWidget(button.id);
michael@0 157
michael@0 158 assert.equal(button.icon, node.getAttribute('image'),
michael@0 159 'icon on node is set');
michael@0 160
michael@0 161 loader.unload();
michael@0 162 }
michael@0 163
michael@0 164 exports['test button duplicate id'] = function(assert) {
michael@0 165 let loader = Loader(module);
michael@0 166 let { ActionButton } = loader.require('sdk/ui');
michael@0 167
michael@0 168 let button = ActionButton({
michael@0 169 id: 'my-button-2',
michael@0 170 label: 'my button',
michael@0 171 icon: './icon.png'
michael@0 172 });
michael@0 173
michael@0 174 assert.throws(() => {
michael@0 175 let doppelganger = ActionButton({
michael@0 176 id: 'my-button-2',
michael@0 177 label: 'my button',
michael@0 178 icon: './icon.png'
michael@0 179 });
michael@0 180 },
michael@0 181 /^The ID/,
michael@0 182 'No duplicates allowed');
michael@0 183
michael@0 184 loader.unload();
michael@0 185 }
michael@0 186
michael@0 187 exports['test button multiple destroy'] = function(assert) {
michael@0 188 let loader = Loader(module);
michael@0 189 let { ActionButton } = loader.require('sdk/ui');
michael@0 190
michael@0 191 let button = ActionButton({
michael@0 192 id: 'my-button-2',
michael@0 193 label: 'my button',
michael@0 194 icon: './icon.png'
michael@0 195 });
michael@0 196
michael@0 197 button.destroy();
michael@0 198 button.destroy();
michael@0 199 button.destroy();
michael@0 200
michael@0 201 assert.pass('multiple destroy doesn\'t matter');
michael@0 202
michael@0 203 loader.unload();
michael@0 204 }
michael@0 205
michael@0 206 exports['test button removed on dispose'] = function(assert, done) {
michael@0 207 const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
michael@0 208 let loader = Loader(module);
michael@0 209 let { ActionButton } = loader.require('sdk/ui');
michael@0 210
michael@0 211 let widgetId;
michael@0 212
michael@0 213 CustomizableUI.addListener({
michael@0 214 onWidgetDestroyed: function(id) {
michael@0 215 if (id === widgetId) {
michael@0 216 CustomizableUI.removeListener(this);
michael@0 217
michael@0 218 assert.pass('button properly removed');
michael@0 219 loader.unload();
michael@0 220 done();
michael@0 221 }
michael@0 222 }
michael@0 223 });
michael@0 224
michael@0 225 let button = ActionButton({
michael@0 226 id: 'my-button-3',
michael@0 227 label: 'my button',
michael@0 228 icon: './icon.png'
michael@0 229 });
michael@0 230
michael@0 231 // Tried to use `getWidgetIdsInArea` but seems undefined, not sure if it
michael@0 232 // was removed or it's not in the UX build yet
michael@0 233 widgetId = getWidget(button.id).id;
michael@0 234
michael@0 235 button.destroy();
michael@0 236 };
michael@0 237
michael@0 238 exports['test button global state updated'] = function(assert) {
michael@0 239 let loader = Loader(module);
michael@0 240 let { ActionButton } = loader.require('sdk/ui');
michael@0 241
michael@0 242 let button = ActionButton({
michael@0 243 id: 'my-button-4',
michael@0 244 label: 'my button',
michael@0 245 icon: './icon.png'
michael@0 246 });
michael@0 247
michael@0 248 // Tried to use `getWidgetIdsInArea` but seems undefined, not sure if it
michael@0 249 // was removed or it's not in the UX build yet
michael@0 250
michael@0 251 let { node, id: widgetId } = getWidget(button.id);
michael@0 252
michael@0 253 // check read-only properties
michael@0 254
michael@0 255 assert.throws(() => button.id = 'another-id',
michael@0 256 /^setting a property that has only a getter/,
michael@0 257 'id cannot be set at runtime');
michael@0 258
michael@0 259 assert.equal(button.id, 'my-button-4',
michael@0 260 'id is unchanged');
michael@0 261 assert.equal(node.id, widgetId,
michael@0 262 'node id is unchanged');
michael@0 263
michael@0 264 // check writable properties
michael@0 265
michael@0 266 button.label = 'New label';
michael@0 267 assert.equal(button.label, 'New label',
michael@0 268 'label is updated');
michael@0 269 assert.equal(node.getAttribute('label'), 'New label',
michael@0 270 'node label is updated');
michael@0 271 assert.equal(node.getAttribute('tooltiptext'), 'New label',
michael@0 272 'node tooltip is updated');
michael@0 273
michael@0 274 button.icon = './new-icon.png';
michael@0 275 assert.equal(button.icon, './new-icon.png',
michael@0 276 'icon is updated');
michael@0 277 assert.equal(node.getAttribute('image'), data.url('new-icon.png'),
michael@0 278 'node image is updated');
michael@0 279
michael@0 280 button.disabled = true;
michael@0 281 assert.equal(button.disabled, true,
michael@0 282 'disabled is updated');
michael@0 283 assert.equal(node.getAttribute('disabled'), 'true',
michael@0 284 'node disabled is updated');
michael@0 285
michael@0 286 // TODO: test validation on update
michael@0 287
michael@0 288 loader.unload();
michael@0 289 }
michael@0 290
michael@0 291 exports['test button global state set and get with state method'] = function(assert) {
michael@0 292 let loader = Loader(module);
michael@0 293 let { ActionButton } = loader.require('sdk/ui');
michael@0 294
michael@0 295 let button = ActionButton({
michael@0 296 id: 'my-button-16',
michael@0 297 label: 'my button',
michael@0 298 icon: './icon.png'
michael@0 299 });
michael@0 300
michael@0 301 // read the button's state
michael@0 302 let state = button.state(button);
michael@0 303
michael@0 304 assert.equal(state.label, 'my button',
michael@0 305 'label is correct');
michael@0 306 assert.equal(state.icon, './icon.png',
michael@0 307 'icon is correct');
michael@0 308 assert.equal(state.disabled, false,
michael@0 309 'disabled is correct');
michael@0 310
michael@0 311 // set the new button's state
michael@0 312 button.state(button, {
michael@0 313 label: 'New label',
michael@0 314 icon: './new-icon.png',
michael@0 315 disabled: true
michael@0 316 });
michael@0 317
michael@0 318 assert.equal(button.label, 'New label',
michael@0 319 'label is updated');
michael@0 320 assert.equal(button.icon, './new-icon.png',
michael@0 321 'icon is updated');
michael@0 322 assert.equal(button.disabled, true,
michael@0 323 'disabled is updated');
michael@0 324
michael@0 325 loader.unload();
michael@0 326 }
michael@0 327
michael@0 328 exports['test button global state updated on multiple windows'] = function(assert, done) {
michael@0 329 let loader = Loader(module);
michael@0 330 let { ActionButton } = loader.require('sdk/ui');
michael@0 331
michael@0 332 let button = ActionButton({
michael@0 333 id: 'my-button-5',
michael@0 334 label: 'my button',
michael@0 335 icon: './icon.png'
michael@0 336 });
michael@0 337
michael@0 338 let nodes = [getWidget(button.id).node];
michael@0 339
michael@0 340 openBrowserWindow().then(window => {
michael@0 341 nodes.push(getWidget(button.id, window).node);
michael@0 342
michael@0 343 button.label = 'New label';
michael@0 344 button.icon = './new-icon.png';
michael@0 345 button.disabled = true;
michael@0 346
michael@0 347 for (let node of nodes) {
michael@0 348 assert.equal(node.getAttribute('label'), 'New label',
michael@0 349 'node label is updated');
michael@0 350 assert.equal(node.getAttribute('tooltiptext'), 'New label',
michael@0 351 'node tooltip is updated');
michael@0 352
michael@0 353 assert.equal(button.icon, './new-icon.png',
michael@0 354 'icon is updated');
michael@0 355 assert.equal(node.getAttribute('image'), data.url('new-icon.png'),
michael@0 356 'node image is updated');
michael@0 357
michael@0 358 assert.equal(button.disabled, true,
michael@0 359 'disabled is updated');
michael@0 360 assert.equal(node.getAttribute('disabled'), 'true',
michael@0 361 'node disabled is updated');
michael@0 362 };
michael@0 363
michael@0 364 return window;
michael@0 365 }).
michael@0 366 then(close).
michael@0 367 then(loader.unload).
michael@0 368 then(done, assert.fail);
michael@0 369 };
michael@0 370
michael@0 371 exports['test button window state'] = function(assert, done) {
michael@0 372 let loader = Loader(module);
michael@0 373 let { ActionButton } = loader.require('sdk/ui');
michael@0 374 let { browserWindows } = loader.require('sdk/windows');
michael@0 375
michael@0 376 let button = ActionButton({
michael@0 377 id: 'my-button-6',
michael@0 378 label: 'my button',
michael@0 379 icon: './icon.png'
michael@0 380 });
michael@0 381
michael@0 382 let mainWindow = browserWindows.activeWindow;
michael@0 383 let nodes = [getWidget(button.id).node];
michael@0 384
michael@0 385 openBrowserWindow().then(focus).then(window => {
michael@0 386 nodes.push(getWidget(button.id, window).node);
michael@0 387
michael@0 388 let { activeWindow } = browserWindows;
michael@0 389
michael@0 390 button.state(activeWindow, {
michael@0 391 label: 'New label',
michael@0 392 icon: './new-icon.png',
michael@0 393 disabled: true
michael@0 394 });
michael@0 395
michael@0 396 // check the states
michael@0 397
michael@0 398 assert.equal(button.label, 'my button',
michael@0 399 'global label unchanged');
michael@0 400 assert.equal(button.icon, './icon.png',
michael@0 401 'global icon unchanged');
michael@0 402 assert.equal(button.disabled, false,
michael@0 403 'global disabled unchanged');
michael@0 404
michael@0 405 let state = button.state(mainWindow);
michael@0 406
michael@0 407 assert.equal(state.label, 'my button',
michael@0 408 'previous window label unchanged');
michael@0 409 assert.equal(state.icon, './icon.png',
michael@0 410 'previous window icon unchanged');
michael@0 411 assert.equal(state.disabled, false,
michael@0 412 'previous window disabled unchanged');
michael@0 413
michael@0 414 let state = button.state(activeWindow);
michael@0 415
michael@0 416 assert.equal(state.label, 'New label',
michael@0 417 'active window label updated');
michael@0 418 assert.equal(state.icon, './new-icon.png',
michael@0 419 'active window icon updated');
michael@0 420 assert.equal(state.disabled, true,
michael@0 421 'active disabled updated');
michael@0 422
michael@0 423 // change the global state, only the windows without a state are affected
michael@0 424
michael@0 425 button.label = 'A good label';
michael@0 426
michael@0 427 assert.equal(button.label, 'A good label',
michael@0 428 'global label updated');
michael@0 429 assert.equal(button.state(mainWindow).label, 'A good label',
michael@0 430 'previous window label updated');
michael@0 431 assert.equal(button.state(activeWindow).label, 'New label',
michael@0 432 'active window label unchanged');
michael@0 433
michael@0 434 // delete the window state will inherits the global state again
michael@0 435
michael@0 436 button.state(activeWindow, null);
michael@0 437
michael@0 438 assert.equal(button.state(activeWindow).label, 'A good label',
michael@0 439 'active window label inherited');
michael@0 440
michael@0 441 // check the nodes properties
michael@0 442 let node = nodes[0];
michael@0 443 let state = button.state(mainWindow);
michael@0 444
michael@0 445 assert.equal(node.getAttribute('label'), state.label,
michael@0 446 'node label is correct');
michael@0 447 assert.equal(node.getAttribute('tooltiptext'), state.label,
michael@0 448 'node tooltip is correct');
michael@0 449
michael@0 450 assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
michael@0 451 'node image is correct');
michael@0 452 assert.equal(node.hasAttribute('disabled'), state.disabled,
michael@0 453 'disabled is correct');
michael@0 454
michael@0 455 let node = nodes[1];
michael@0 456 let state = button.state(activeWindow);
michael@0 457
michael@0 458 assert.equal(node.getAttribute('label'), state.label,
michael@0 459 'node label is correct');
michael@0 460 assert.equal(node.getAttribute('tooltiptext'), state.label,
michael@0 461 'node tooltip is correct');
michael@0 462
michael@0 463 assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
michael@0 464 'node image is correct');
michael@0 465 assert.equal(node.hasAttribute('disabled'), state.disabled,
michael@0 466 'disabled is correct');
michael@0 467
michael@0 468 return window;
michael@0 469 }).
michael@0 470 then(close).
michael@0 471 then(loader.unload).
michael@0 472 then(done, assert.fail);
michael@0 473 };
michael@0 474
michael@0 475
michael@0 476 exports['test button tab state'] = function(assert, done) {
michael@0 477 let loader = Loader(module);
michael@0 478 let { ActionButton } = loader.require('sdk/ui');
michael@0 479 let { browserWindows } = loader.require('sdk/windows');
michael@0 480 let tabs = loader.require('sdk/tabs');
michael@0 481
michael@0 482 let button = ActionButton({
michael@0 483 id: 'my-button-7',
michael@0 484 label: 'my button',
michael@0 485 icon: './icon.png'
michael@0 486 });
michael@0 487
michael@0 488 let mainTab = tabs.activeTab;
michael@0 489 let node = getWidget(button.id).node;
michael@0 490
michael@0 491 tabs.open({
michael@0 492 url: 'about:blank',
michael@0 493 onActivate: function onActivate(tab) {
michael@0 494 tab.removeListener('activate', onActivate);
michael@0 495
michael@0 496 let { activeWindow } = browserWindows;
michael@0 497 // set window state
michael@0 498 button.state(activeWindow, {
michael@0 499 label: 'Window label',
michael@0 500 icon: './window-icon.png'
michael@0 501 });
michael@0 502
michael@0 503 // set previous active tab state
michael@0 504 button.state(mainTab, {
michael@0 505 label: 'Tab label',
michael@0 506 icon: './tab-icon.png',
michael@0 507 });
michael@0 508
michael@0 509 // set current active tab state
michael@0 510 button.state(tab, {
michael@0 511 icon: './another-tab-icon.png',
michael@0 512 disabled: true
michael@0 513 });
michael@0 514
michael@0 515 // check the states
michael@0 516
michael@0 517 Cu.schedulePreciseGC(() => {
michael@0 518 assert.equal(button.label, 'my button',
michael@0 519 'global label unchanged');
michael@0 520 assert.equal(button.icon, './icon.png',
michael@0 521 'global icon unchanged');
michael@0 522 assert.equal(button.disabled, false,
michael@0 523 'global disabled unchanged');
michael@0 524
michael@0 525 let state = button.state(mainTab);
michael@0 526
michael@0 527 assert.equal(state.label, 'Tab label',
michael@0 528 'previous tab label updated');
michael@0 529 assert.equal(state.icon, './tab-icon.png',
michael@0 530 'previous tab icon updated');
michael@0 531 assert.equal(state.disabled, false,
michael@0 532 'previous tab disabled unchanged');
michael@0 533
michael@0 534 let state = button.state(tab);
michael@0 535
michael@0 536 assert.equal(state.label, 'Window label',
michael@0 537 'active tab inherited from window state');
michael@0 538 assert.equal(state.icon, './another-tab-icon.png',
michael@0 539 'active tab icon updated');
michael@0 540 assert.equal(state.disabled, true,
michael@0 541 'active disabled updated');
michael@0 542
michael@0 543 // change the global state
michael@0 544 button.icon = './good-icon.png';
michael@0 545
michael@0 546 // delete the tab state
michael@0 547 button.state(tab, null);
michael@0 548
michael@0 549 assert.equal(button.icon, './good-icon.png',
michael@0 550 'global icon updated');
michael@0 551 assert.equal(button.state(mainTab).icon, './tab-icon.png',
michael@0 552 'previous tab icon unchanged');
michael@0 553 assert.equal(button.state(tab).icon, './window-icon.png',
michael@0 554 'tab icon inherited from window');
michael@0 555
michael@0 556 // delete the window state
michael@0 557 button.state(activeWindow, null);
michael@0 558
michael@0 559 assert.equal(button.state(tab).icon, './good-icon.png',
michael@0 560 'tab icon inherited from global');
michael@0 561
michael@0 562 // check the node properties
michael@0 563
michael@0 564 let state = button.state(tabs.activeTab);
michael@0 565
michael@0 566 assert.equal(node.getAttribute('label'), state.label,
michael@0 567 'node label is correct');
michael@0 568 assert.equal(node.getAttribute('tooltiptext'), state.label,
michael@0 569 'node tooltip is correct');
michael@0 570 assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
michael@0 571 'node image is correct');
michael@0 572 assert.equal(node.hasAttribute('disabled'), state.disabled,
michael@0 573 'disabled is correct');
michael@0 574
michael@0 575 tabs.once('activate', () => {
michael@0 576 // This is made in order to avoid to check the node before it
michael@0 577 // is updated, need a better check
michael@0 578 setTimeout(() => {
michael@0 579 let state = button.state(mainTab);
michael@0 580
michael@0 581 assert.equal(node.getAttribute('label'), state.label,
michael@0 582 'node label is correct');
michael@0 583 assert.equal(node.getAttribute('tooltiptext'), state.label,
michael@0 584 'node tooltip is correct');
michael@0 585 assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
michael@0 586 'node image is correct');
michael@0 587 assert.equal(node.hasAttribute('disabled'), state.disabled,
michael@0 588 'disabled is correct');
michael@0 589
michael@0 590 tab.close(() => {
michael@0 591 loader.unload();
michael@0 592 done();
michael@0 593 });
michael@0 594 }, 500);
michael@0 595 });
michael@0 596
michael@0 597 mainTab.activate();
michael@0 598 });
michael@0 599 }
michael@0 600 });
michael@0 601
michael@0 602 };
michael@0 603
michael@0 604 exports['test button click'] = function(assert, done) {
michael@0 605 let loader = Loader(module);
michael@0 606 let { ActionButton } = loader.require('sdk/ui');
michael@0 607 let { browserWindows } = loader.require('sdk/windows');
michael@0 608
michael@0 609 let labels = [];
michael@0 610
michael@0 611 let button = ActionButton({
michael@0 612 id: 'my-button-8',
michael@0 613 label: 'my button',
michael@0 614 icon: './icon.png',
michael@0 615 onClick: ({label}) => labels.push(label)
michael@0 616 });
michael@0 617
michael@0 618 let mainWindow = browserWindows.activeWindow;
michael@0 619 let chromeWindow = getMostRecentBrowserWindow();
michael@0 620
michael@0 621 openBrowserWindow().then(focus).then(window => {
michael@0 622 button.state(mainWindow, { label: 'nothing' });
michael@0 623 button.state(mainWindow.tabs.activeTab, { label: 'foo'})
michael@0 624 button.state(browserWindows.activeWindow, { label: 'bar' });
michael@0 625
michael@0 626 button.click();
michael@0 627
michael@0 628 focus(chromeWindow).then(() => {
michael@0 629 button.click();
michael@0 630
michael@0 631 assert.deepEqual(labels, ['bar', 'foo'],
michael@0 632 'button click works');
michael@0 633
michael@0 634 close(window).
michael@0 635 then(loader.unload).
michael@0 636 then(done, assert.fail);
michael@0 637 });
michael@0 638 }).then(null, assert.fail);
michael@0 639
michael@0 640 }
michael@0 641
michael@0 642 exports['test button icon set'] = function(assert) {
michael@0 643 const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
michael@0 644 let loader = Loader(module);
michael@0 645 let { ActionButton } = loader.require('sdk/ui');
michael@0 646
michael@0 647 // Test remote icon set
michael@0 648 assert.throws(
michael@0 649 () => ActionButton({
michael@0 650 id: 'my-button-10',
michael@0 651 label: 'my button',
michael@0 652 icon: {
michael@0 653 '16': 'http://www.mozilla.org/favicon.ico'
michael@0 654 }
michael@0 655 }),
michael@0 656 /^The option "icon"/,
michael@0 657 'throws on no valid icon given');
michael@0 658
michael@0 659 let button = ActionButton({
michael@0 660 id: 'my-button-11',
michael@0 661 label: 'my button',
michael@0 662 icon: {
michael@0 663 '5': './icon5.png',
michael@0 664 '16': './icon16.png',
michael@0 665 '32': './icon32.png',
michael@0 666 '64': './icon64.png'
michael@0 667 }
michael@0 668 });
michael@0 669
michael@0 670 let { node, id: widgetId } = getWidget(button.id);
michael@0 671 let { devicePixelRatio } = node.ownerDocument.defaultView;
michael@0 672
michael@0 673 let size = 16 * devicePixelRatio;
michael@0 674
michael@0 675 assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)),
michael@0 676 'the icon is set properly in navbar');
michael@0 677
michael@0 678 let size = 32 * devicePixelRatio;
michael@0 679
michael@0 680 CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL);
michael@0 681
michael@0 682 assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)),
michael@0 683 'the icon is set properly in panel');
michael@0 684
michael@0 685 // Using `loader.unload` without move back the button to the original area
michael@0 686 // raises an error in the CustomizableUI. This is doesn't happen if the
michael@0 687 // button is moved manually from navbar to panel. I believe it has to do
michael@0 688 // with `addWidgetToArea` method, because even with a `timeout` the issue
michael@0 689 // persist.
michael@0 690 CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR);
michael@0 691
michael@0 692 loader.unload();
michael@0 693 }
michael@0 694
michael@0 695 exports['test button icon se with only one option'] = function(assert) {
michael@0 696 const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
michael@0 697 let loader = Loader(module);
michael@0 698 let { ActionButton } = loader.require('sdk/ui');
michael@0 699
michael@0 700 // Test remote icon set
michael@0 701 assert.throws(
michael@0 702 () => ActionButton({
michael@0 703 id: 'my-button-10',
michael@0 704 label: 'my button',
michael@0 705 icon: {
michael@0 706 '16': 'http://www.mozilla.org/favicon.ico'
michael@0 707 }
michael@0 708 }),
michael@0 709 /^The option "icon"/,
michael@0 710 'throws on no valid icon given');
michael@0 711
michael@0 712 let button = ActionButton({
michael@0 713 id: 'my-button-11',
michael@0 714 label: 'my button',
michael@0 715 icon: {
michael@0 716 '5': './icon5.png'
michael@0 717 }
michael@0 718 });
michael@0 719
michael@0 720 let { node, id: widgetId } = getWidget(button.id);
michael@0 721
michael@0 722 assert.equal(node.getAttribute('image'), data.url(button.icon['5'].substr(2)),
michael@0 723 'the icon is set properly in navbar');
michael@0 724
michael@0 725 CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL);
michael@0 726
michael@0 727 assert.equal(node.getAttribute('image'), data.url(button.icon['5'].substr(2)),
michael@0 728 'the icon is set properly in panel');
michael@0 729
michael@0 730 // Using `loader.unload` without move back the button to the original area
michael@0 731 // raises an error in the CustomizableUI. This is doesn't happen if the
michael@0 732 // button is moved manually from navbar to panel. I believe it has to do
michael@0 733 // with `addWidgetToArea` method, because even with a `timeout` the issue
michael@0 734 // persist.
michael@0 735 CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR);
michael@0 736
michael@0 737 loader.unload();
michael@0 738 }
michael@0 739
michael@0 740 exports['test button state validation'] = function(assert) {
michael@0 741 let loader = Loader(module);
michael@0 742 let { ActionButton } = loader.require('sdk/ui');
michael@0 743 let { browserWindows } = loader.require('sdk/windows');
michael@0 744
michael@0 745 let button = ActionButton({
michael@0 746 id: 'my-button-12',
michael@0 747 label: 'my button',
michael@0 748 icon: './icon.png'
michael@0 749 })
michael@0 750
michael@0 751 let state = button.state(button);
michael@0 752
michael@0 753 assert.throws(
michael@0 754 () => button.state(button, { icon: 'http://www.mozilla.org/favicon.ico' }),
michael@0 755 /^The option "icon"/,
michael@0 756 'throws on remote icon given');
michael@0 757
michael@0 758 loader.unload();
michael@0 759 };
michael@0 760
michael@0 761 exports['test button are not in private windows'] = function(assert, done) {
michael@0 762 let loader = Loader(module);
michael@0 763 let { ActionButton } = loader.require('sdk/ui');
michael@0 764 let{ isPrivate } = loader.require('sdk/private-browsing');
michael@0 765 let { browserWindows } = loader.require('sdk/windows');
michael@0 766
michael@0 767 let button = ActionButton({
michael@0 768 id: 'my-button-13',
michael@0 769 label: 'my button',
michael@0 770 icon: './icon.png'
michael@0 771 });
michael@0 772
michael@0 773 openPrivateBrowserWindow().then(window => {
michael@0 774 assert.ok(isPrivate(window),
michael@0 775 'the new window is private');
michael@0 776
michael@0 777 let { node } = getWidget(button.id, window);
michael@0 778
michael@0 779 assert.ok(!node || node.style.display === 'none',
michael@0 780 'the button is not added / is not visible on private window');
michael@0 781
michael@0 782 return window;
michael@0 783 }).
michael@0 784 then(close).
michael@0 785 then(loader.unload).
michael@0 786 then(done, assert.fail)
michael@0 787 }
michael@0 788
michael@0 789 exports['test button state are snapshot'] = function(assert) {
michael@0 790 let loader = Loader(module);
michael@0 791 let { ActionButton } = loader.require('sdk/ui');
michael@0 792 let { browserWindows } = loader.require('sdk/windows');
michael@0 793 let tabs = loader.require('sdk/tabs');
michael@0 794
michael@0 795 let button = ActionButton({
michael@0 796 id: 'my-button-14',
michael@0 797 label: 'my button',
michael@0 798 icon: './icon.png'
michael@0 799 });
michael@0 800
michael@0 801 let state = button.state(button);
michael@0 802 let windowState = button.state(browserWindows.activeWindow);
michael@0 803 let tabState = button.state(tabs.activeTab);
michael@0 804
michael@0 805 assert.deepEqual(windowState, state,
michael@0 806 'window state has the same properties of button state');
michael@0 807
michael@0 808 assert.deepEqual(tabState, state,
michael@0 809 'tab state has the same properties of button state');
michael@0 810
michael@0 811 assert.notEqual(windowState, state,
michael@0 812 'window state is not the same object of button state');
michael@0 813
michael@0 814 assert.notEqual(tabState, state,
michael@0 815 'tab state is not the same object of button state');
michael@0 816
michael@0 817 assert.deepEqual(button.state(button), state,
michael@0 818 'button state has the same content of previous button state');
michael@0 819
michael@0 820 assert.deepEqual(button.state(browserWindows.activeWindow), windowState,
michael@0 821 'window state has the same content of previous window state');
michael@0 822
michael@0 823 assert.deepEqual(button.state(tabs.activeTab), tabState,
michael@0 824 'tab state has the same content of previous tab state');
michael@0 825
michael@0 826 assert.notEqual(button.state(button), state,
michael@0 827 'button state is not the same object of previous button state');
michael@0 828
michael@0 829 assert.notEqual(button.state(browserWindows.activeWindow), windowState,
michael@0 830 'window state is not the same object of previous window state');
michael@0 831
michael@0 832 assert.notEqual(button.state(tabs.activeTab), tabState,
michael@0 833 'tab state is not the same object of previous tab state');
michael@0 834
michael@0 835 loader.unload();
michael@0 836 }
michael@0 837
michael@0 838 exports['test button icon object is a snapshot'] = function(assert) {
michael@0 839 let loader = Loader(module);
michael@0 840 let { ActionButton } = loader.require('sdk/ui');
michael@0 841
michael@0 842 let icon = {
michael@0 843 '16': './foo.png'
michael@0 844 };
michael@0 845
michael@0 846 let button = ActionButton({
michael@0 847 id: 'my-button-17',
michael@0 848 label: 'my button',
michael@0 849 icon: icon
michael@0 850 });
michael@0 851
michael@0 852 assert.deepEqual(button.icon, icon,
michael@0 853 'button.icon has the same properties of the object set in the constructor');
michael@0 854
michael@0 855 assert.notEqual(button.icon, icon,
michael@0 856 'button.icon is not the same object of the object set in the constructor');
michael@0 857
michael@0 858 assert.throws(
michael@0 859 () => button.icon[16] = './bar.png',
michael@0 860 /16 is read-only/,
michael@0 861 'properties of button.icon are ready-only'
michael@0 862 );
michael@0 863
michael@0 864 let newIcon = {'16': './bar.png'};
michael@0 865 button.icon = newIcon;
michael@0 866
michael@0 867 assert.deepEqual(button.icon, newIcon,
michael@0 868 'button.icon has the same properties of the object set');
michael@0 869
michael@0 870 assert.notEqual(button.icon, newIcon,
michael@0 871 'button.icon is not the same object of the object set');
michael@0 872
michael@0 873 loader.unload();
michael@0 874 }
michael@0 875
michael@0 876 exports['test button after destroy'] = function(assert) {
michael@0 877 let loader = Loader(module);
michael@0 878 let { ActionButton } = loader.require('sdk/ui');
michael@0 879 let { browserWindows } = loader.require('sdk/windows');
michael@0 880 let { activeTab } = loader.require('sdk/tabs');
michael@0 881
michael@0 882 let button = ActionButton({
michael@0 883 id: 'my-button-15',
michael@0 884 label: 'my button',
michael@0 885 icon: './icon.png',
michael@0 886 onClick: () => assert.fail('onClick should not be called')
michael@0 887 });
michael@0 888
michael@0 889 button.destroy();
michael@0 890
michael@0 891 assert.throws(
michael@0 892 () => button.click(),
michael@0 893 /^The state cannot be set or get/,
michael@0 894 'button.click() not executed');
michael@0 895
michael@0 896 assert.throws(
michael@0 897 () => button.label,
michael@0 898 /^The state cannot be set or get/,
michael@0 899 'button.label cannot be get after destroy');
michael@0 900
michael@0 901 assert.throws(
michael@0 902 () => button.label = 'my label',
michael@0 903 /^The state cannot be set or get/,
michael@0 904 'button.label cannot be set after destroy');
michael@0 905
michael@0 906 assert.throws(
michael@0 907 () => {
michael@0 908 button.state(browserWindows.activeWindow, {
michael@0 909 label: 'window label'
michael@0 910 });
michael@0 911 },
michael@0 912 /^The state cannot be set or get/,
michael@0 913 'window state label cannot be set after destroy');
michael@0 914
michael@0 915 assert.throws(
michael@0 916 () => button.state(browserWindows.activeWindow).label,
michael@0 917 /^The state cannot be set or get/,
michael@0 918 'window state label cannot be get after destroy');
michael@0 919
michael@0 920 assert.throws(
michael@0 921 () => {
michael@0 922 button.state(activeTab, {
michael@0 923 label: 'tab label'
michael@0 924 });
michael@0 925 },
michael@0 926 /^The state cannot be set or get/,
michael@0 927 'tab state label cannot be set after destroy');
michael@0 928
michael@0 929 assert.throws(
michael@0 930 () => button.state(activeTab).label,
michael@0 931 /^The state cannot be set or get/,
michael@0 932 'window state label cannot se get after destroy');
michael@0 933
michael@0 934 loader.unload();
michael@0 935 };
michael@0 936
michael@0 937 require('sdk/test').run(exports);

mercurial