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/. */
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');
20 const openBrowserWindow = partial(open, null, {features: {toolbar: true}});
21 const openPrivateBrowserWindow = partial(open, null,
22 {features: {toolbar: true, private: true}});
24 function getWidget(buttonId, window = getMostRecentBrowserWindow()) {
25 const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
26 const { AREA_NAVBAR } = CustomizableUI;
28 let widgets = CustomizableUI.getWidgetIdsInArea(AREA_NAVBAR).
29 filter((id) => id.startsWith('toggle-button--') && id.endsWith(buttonId));
31 if (widgets.length === 0)
32 throw new Error('Widget with id `' + id +'` not found.');
34 if (widgets.length > 1)
35 throw new Error('Unexpected number of widgets: ' + widgets.length)
37 return CustomizableUI.getWidget(widgets[0]).forWindow(window);
40 exports['test basic constructor validation'] = function(assert) {
41 let loader = Loader(module);
42 let { ToggleButton } = loader.require('sdk/ui');
45 () => ToggleButton({}),
47 'throws on no option given');
51 () => ToggleButton({ id: 'my-button', icon: './icon.png'}),
52 /^The option "label"/,
53 'throws on no label given');
57 () => ToggleButton({ label: 'my button', icon: './icon.png' }),
59 'throws on no id given');
63 () => ToggleButton({ id: 'my-button', label: 'my button' }),
65 'throws on no icon given');
70 () => ToggleButton({ id: 'my-button', label: '', icon: './icon.png' }),
71 /^The option "label"/,
72 'throws on no valid label given');
76 () => ToggleButton({ id: 'my button', label: 'my button', icon: './icon.png' }),
78 'throws on no valid id given');
82 () => ToggleButton({ id: '', label: 'my button', icon: './icon.png' }),
84 'throws on no valid id given');
88 () => ToggleButton({ id: 'my-button', label: 'my button', icon: 'http://www.mozilla.org/favicon.ico'}),
90 'throws on no valid icon given');
92 // Test wrong icon: no absolute URI to local resource, neither relative './'
94 () => ToggleButton({ id: 'my-button', label: 'my button', icon: 'icon.png'}),
96 'throws on no valid icon given');
98 // Test wrong icon: no absolute URI to local resource, neither relative './'
100 () => ToggleButton({ id: 'my-button', label: 'my button', icon: 'foo and bar'}),
101 /^The option "icon"/,
102 'throws on no valid icon given');
104 // Test wrong icon: '../' is not allowed
106 () => ToggleButton({ id: 'my-button', label: 'my button', icon: '../icon.png'}),
107 /^The option "icon"/,
108 'throws on no valid icon given');
110 // Test wrong checked
113 id: 'my-button', label: 'my button', icon: './icon.png', checked: 'yes'}),
114 /^The option "checked"/,
115 'throws on no valid checked value given');
120 exports['test button added'] = function(assert) {
121 let loader = Loader(module);
122 let { ToggleButton } = loader.require('sdk/ui');
124 let button = ToggleButton({
131 assert.equal(button.checked, false,
132 'checked is set to default `false` value');
134 assert.equal(button.disabled, false,
135 'disabled is set to default `false` value');
137 let { node } = getWidget(button.id);
139 assert.ok(!!node, 'The button is in the navbar');
141 assert.equal(button.label, node.getAttribute('label'),
144 assert.equal(button.label, node.getAttribute('tooltiptext'),
147 assert.equal(data.url(button.icon.substr(2)), node.getAttribute('image'),
153 exports['test button added with resource URI'] = function(assert) {
154 let loader = Loader(module);
155 let { ToggleButton } = loader.require('sdk/ui');
157 let button = ToggleButton({
160 icon: data.url('icon.png')
163 assert.equal(button.icon, data.url('icon.png'),
166 let { node } = getWidget(button.id);
168 assert.equal(button.icon, node.getAttribute('image'),
169 'icon on node is set');
174 exports['test button duplicate id'] = function(assert) {
175 let loader = Loader(module);
176 let { ToggleButton } = loader.require('sdk/ui');
178 let button = ToggleButton({
184 assert.throws(() => {
185 let doppelganger = ToggleButton({
192 'No duplicates allowed');
197 exports['test button multiple destroy'] = function(assert) {
198 let loader = Loader(module);
199 let { ToggleButton } = loader.require('sdk/ui');
201 let button = ToggleButton({
211 assert.pass('multiple destroy doesn\'t matter');
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');
223 CustomizableUI.addListener({
224 onWidgetDestroyed: function(id) {
225 if (id === widgetId) {
226 CustomizableUI.removeListener(this);
228 assert.pass('button properly removed');
235 let button = ToggleButton({
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;
248 exports['test button global state updated'] = function(assert) {
249 let loader = Loader(module);
250 let { ToggleButton } = loader.require('sdk/ui');
252 let button = ToggleButton({
258 // Tried to use `getWidgetIdsInArea` but seems undefined, not sure if it
259 // was removed or it's not in the UX build yet
261 let { node, id: widgetId } = getWidget(button.id);
263 // check read-only properties
265 assert.throws(() => button.id = 'another-id',
266 /^setting a property that has only a getter/,
267 'id cannot be set at runtime');
269 assert.equal(button.id, 'my-button-4',
271 assert.equal(node.id, widgetId,
272 'node id is unchanged');
274 // check writable properties
276 button.label = 'New label';
277 assert.equal(button.label, 'New label',
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');
284 button.icon = './new-icon.png';
285 assert.equal(button.icon, './new-icon.png',
287 assert.equal(node.getAttribute('image'), data.url('new-icon.png'),
288 'node image is updated');
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');
296 // TODO: test validation on update
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');
305 let button = ToggleButton({
311 // read the button's state
312 let state = button.state(button);
314 assert.equal(state.label, 'my button',
316 assert.equal(state.icon, './icon.png',
318 assert.equal(state.disabled, false,
319 'disabled is correct');
321 // set the new button's state
322 button.state(button, {
324 icon: './new-icon.png',
328 assert.equal(button.label, 'New label',
330 assert.equal(button.icon, './new-icon.png',
332 assert.equal(button.disabled, true,
333 'disabled is updated');
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');
342 let button = ToggleButton({
348 let nodes = [getWidget(button.id).node];
350 openBrowserWindow().then(window => {
351 nodes.push(getWidget(button.id, window).node);
353 button.label = 'New label';
354 button.icon = './new-icon.png';
355 button.disabled = true;
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');
363 assert.equal(button.icon, './new-icon.png',
365 assert.equal(node.getAttribute('image'), data.url('new-icon.png'),
366 'node image is updated');
368 assert.equal(button.disabled, true,
369 'disabled is updated');
370 assert.equal(node.getAttribute('disabled'), 'true',
371 'node disabled is updated');
378 then(done, assert.fail);
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');
386 let button = ToggleButton({
392 let mainWindow = browserWindows.activeWindow;
393 let nodes = [getWidget(button.id).node];
395 openBrowserWindow().then(focus).then(window => {
396 nodes.push(getWidget(button.id, window).node);
398 let { activeWindow } = browserWindows;
400 button.state(activeWindow, {
402 icon: './new-icon.png',
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');
415 let state = button.state(mainWindow);
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');
424 let state = button.state(activeWindow);
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');
433 // change the global state, only the windows without a state are affected
435 button.label = 'A good label';
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');
444 // delete the window state will inherits the global state again
446 button.state(activeWindow, null);
448 assert.equal(button.state(activeWindow).label, 'A good label',
449 'active window label inherited');
451 // check the nodes properties
453 let state = button.state(mainWindow);
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');
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');
466 let state = button.state(activeWindow);
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');
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');
482 then(done, assert.fail);
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');
492 let button = ToggleButton({
498 let mainTab = tabs.activeTab;
499 let node = getWidget(button.id).node;
503 onActivate: function onActivate(tab) {
504 tab.removeListener('activate', onActivate);
506 let { activeWindow } = browserWindows;
508 button.state(activeWindow, {
509 label: 'Window label',
510 icon: './window-icon.png'
513 // set previous active tab state
514 button.state(mainTab, {
516 icon: './tab-icon.png',
519 // set current active tab state
521 icon: './another-tab-icon.png',
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');
535 let state = button.state(mainTab);
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');
544 let state = button.state(tab);
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');
553 // change the global state
554 button.icon = './good-icon.png';
556 // delete the tab state
557 button.state(tab, null);
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');
566 // delete the window state
567 button.state(activeWindow, null);
569 assert.equal(button.state(tab).icon, './good-icon.png',
570 'tab icon inherited from global');
572 // check the node properties
574 let state = button.state(tabs.activeTab);
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');
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
589 let state = button.state(mainTab);
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');
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');
621 let button = ToggleButton({
625 onClick: ({label}) => labels.push(label)
628 let mainWindow = browserWindows.activeWindow;
629 let chromeWindow = getMostRecentBrowserWindow();
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' });
638 focus(chromeWindow).then(() => {
641 assert.deepEqual(labels, ['bar', 'foo'],
642 'button click works');
646 then(done, assert.fail);
648 }).then(null, assert.fail);
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');
656 // Test remote icon set
662 '16': 'http://www.mozilla.org/favicon.ico'
665 /^The option "icon"/,
666 'throws on no valid icon given');
668 let button = ToggleButton({
673 '16': './icon16.png',
674 '32': './icon32.png',
679 let { node, id: widgetId } = getWidget(button.id);
680 let { devicePixelRatio } = node.ownerDocument.defaultView;
682 let size = 16 * devicePixelRatio;
684 assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)),
685 'the icon is set properly in navbar');
687 let size = 32 * devicePixelRatio;
689 CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL);
691 assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)),
692 'the icon is set properly in panel');
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
699 CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR);
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');
709 // Test remote icon set
715 '16': 'http://www.mozilla.org/favicon.ico'
718 /^The option "icon"/,
719 'throws on no valid icon given');
721 let button = ToggleButton({
729 let { node, id: widgetId } = getWidget(button.id);
731 assert.equal(node.getAttribute('image'), data.url(button.icon['5'].substr(2)),
732 'the icon is set properly in navbar');
734 CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL);
736 assert.equal(node.getAttribute('image'), data.url(button.icon['5'].substr(2)),
737 'the icon is set properly in panel');
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
744 CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR);
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');
754 let button = ToggleButton({
760 let state = button.state(button);
763 () => button.state(button, { icon: 'http://www.mozilla.org/favicon.ico' }),
764 /^The option "icon"/,
765 'throws on remote icon given');
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');
776 let button = ToggleButton({
782 openPrivateBrowserWindow().then(window => {
783 assert.ok(isPrivate(window),
784 'the new window is private');
786 let { node } = getWidget(button.id, window);
788 assert.ok(!node || node.style.display === 'none',
789 'the button is not added / is not visible on private window');
795 then(done, assert.fail)
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');
804 let button = ToggleButton({
810 let state = button.state(button);
811 let windowState = button.state(browserWindows.activeWindow);
812 let tabState = button.state(tabs.activeTab);
814 assert.deepEqual(windowState, state,
815 'window state has the same properties of button state');
817 assert.deepEqual(tabState, state,
818 'tab state has the same properties of button state');
820 assert.notEqual(windowState, state,
821 'window state is not the same object of button state');
823 assert.notEqual(tabState, state,
824 'tab state is not the same object of button state');
826 assert.deepEqual(button.state(button), state,
827 'button state has the same content of previous button state');
829 assert.deepEqual(button.state(browserWindows.activeWindow), windowState,
830 'window state has the same content of previous window state');
832 assert.deepEqual(button.state(tabs.activeTab), tabState,
833 'tab state has the same content of previous tab state');
835 assert.notEqual(button.state(button), state,
836 'button state is not the same object of previous button state');
838 assert.notEqual(button.state(browserWindows.activeWindow), windowState,
839 'window state is not the same object of previous window state');
841 assert.notEqual(button.state(tabs.activeTab), tabState,
842 'tab state is not the same object of previous tab state');
847 exports['test button icon object is a snapshot'] = function(assert) {
848 let loader = Loader(module);
849 let { ToggleButton } = loader.require('sdk/ui');
855 let button = ToggleButton({
861 assert.deepEqual(button.icon, icon,
862 'button.icon has the same properties of the object set in the constructor');
864 assert.notEqual(button.icon, icon,
865 'button.icon is not the same object of the object set in the constructor');
868 () => button.icon[16] = './bar.png',
870 'properties of button.icon are ready-only'
873 let newIcon = {'16': './bar.png'};
874 button.icon = newIcon;
876 assert.deepEqual(button.icon, newIcon,
877 'button.icon has the same properties of the object set');
879 assert.notEqual(button.icon, newIcon,
880 'button.icon is not the same object of the object set');
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');
891 let button = ToggleButton({
895 onClick: () => assert.fail('onClick should not be called')
901 () => button.click(),
902 /^The state cannot be set or get/,
903 'button.click() not executed');
907 /^The state cannot be set or get/,
908 'button.label cannot be get after destroy');
911 () => button.label = 'my label',
912 /^The state cannot be set or get/,
913 'button.label cannot be set after destroy');
917 button.state(browserWindows.activeWindow, {
918 label: 'window label'
921 /^The state cannot be set or get/,
922 'window state label cannot be set after destroy');
925 () => button.state(browserWindows.activeWindow).label,
926 /^The state cannot be set or get/,
927 'window state label cannot be get after destroy');
931 button.state(activeTab, {
935 /^The state cannot be set or get/,
936 'tab state label cannot be set after destroy');
939 () => button.state(activeTab).label,
940 /^The state cannot be set or get/,
941 'window state label cannot se get after destroy');
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');
953 let button = ToggleButton({
958 onClick: ({label}) => events.push('clicked:' + label),
959 onChange: state => events.push('changed:' + state.label + ':' + state.checked)
962 let { node } = getWidget(button.id);
964 assert.equal(node.getAttribute('type'), 'checkbox',
965 'node type is properly set');
967 let mainWindow = browserWindows.activeWindow;
968 let chromeWindow = getMostRecentBrowserWindow();
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' });
978 focus(chromeWindow).then(() => {
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'
986 'button change events works');
990 then(done, assert.fail);
992 }).then(null, assert.fail);
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');
1001 let button = ToggleButton({
1007 let mainWindow = browserWindows.activeWindow;
1008 let mainTab = tabs.activeTab;
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`.');
1021 onActivate: function onActivate(tab) {
1022 tab.removeListener('activate', onActivate);
1024 assert.notEqual(mainTab, tab,
1025 'the current tab is not the same.');
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`.');
1036 openBrowserWindow().then(focus).then(window => {
1037 let { activeWindow } = browserWindows;
1038 let { activeTab } = activeWindow.tabs;
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`.');
1045 assert.equal(button.state(activeWindow).checked, false,
1046 'window state, checked is `false`.');
1050 then(loader.unload).
1051 then(done, assert.fail);
1054 then(null, assert.fail);
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');
1065 let button = ToggleButton({
1071 let mainWindow = browserWindows.activeWindow;
1072 let { activeTab } = mainWindow.tabs;
1074 button.state(mainWindow, { icon: './new-icon.png' });
1075 button.state(activeTab, { label: 'foo'})
1077 assert.equal(button.state(mainWindow).label, 'my button',
1078 'label property for window state, properly derived from global state');
1080 assert.equal(button.state(activeTab).icon, './new-icon.png',
1081 'icon property for tab state, properly derived from window state');
1085 button.label = 'bar';
1087 assert.equal(button.state(mainWindow).label, 'bar',
1088 'label property for window state, properly derived from global state');
1090 button.state(mainWindow, null);
1092 assert.equal(button.state(activeTab).icon, './icon.png',
1093 'icon property for tab state, properly derived from window state');
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');
1105 let b1 = ToggleButton({
1109 onChange: ({checked}) => checked && panel.show()
1112 let b2 = ToggleButton({
1116 onChange: ({checked}) => checked && panel.show({position: b2})
1123 let { document } = getMostRecentBrowserWindow();
1124 let b1Node = document.getElementById(identify(b1));
1125 let b2Node = document.getElementById(identify(b2));
1126 let panelNode = getActiveView(panel);
1128 panel.once('show', () => {
1129 assert.ok(b1.state('window').checked,
1130 'button is checked');
1132 assert.equal(panelNode.getAttribute('type'), 'arrow',
1133 'the panel is a arrow type');
1135 assert.strictEqual(b1Node, panelNode.anchorNode,
1136 'the panel is anchored properly to the button given in costructor');
1140 panel.once('show', () => {
1141 assert.ok(b2.state('window').checked,
1142 'button is checked');
1144 assert.equal(panelNode.getAttribute('type'), 'arrow',
1145 'the panel is a arrow type');
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');
1163 require('sdk/test').run(exports);