addon-sdk/source/test/test-ui-toggle-button.js

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

mercurial