/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict'; module.metadata = { 'engines': { 'Firefox': '> 28' } }; const { Cu } = require('chrome'); const { Loader } = require('sdk/test/loader'); const { data } = require('sdk/self'); const { open, focus, close } = require('sdk/window/helpers'); const { setTimeout } = require('sdk/timers'); const { getMostRecentBrowserWindow } = require('sdk/window/utils'); const { partial } = require('sdk/lang/functional'); const openBrowserWindow = partial(open, null, {features: {toolbar: true}}); const openPrivateBrowserWindow = partial(open, null, {features: {toolbar: true, private: true}}); function getWidget(buttonId, window = getMostRecentBrowserWindow()) { const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {}); const { AREA_NAVBAR } = CustomizableUI; let widgets = CustomizableUI.getWidgetIdsInArea(AREA_NAVBAR). filter((id) => id.startsWith('button--') && id.endsWith(buttonId)); if (widgets.length === 0) throw new Error('Widget with id `' + id +'` not found.'); if (widgets.length > 1) throw new Error('Unexpected number of widgets: ' + widgets.length) return CustomizableUI.getWidget(widgets[0]).forWindow(window); }; exports['test basic constructor validation'] = function(assert) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); assert.throws( () => ToggleButton({}), /^The option/, 'throws on no option given'); // Test no label assert.throws( () => ToggleButton({ id: 'my-button', icon: './icon.png'}), /^The option "label"/, 'throws on no label given'); // Test no id assert.throws( () => ToggleButton({ label: 'my button', icon: './icon.png' }), /^The option "id"/, 'throws on no id given'); // Test no icon assert.throws( () => ToggleButton({ id: 'my-button', label: 'my button' }), /^The option "icon"/, 'throws on no icon given'); // Test empty label assert.throws( () => ToggleButton({ id: 'my-button', label: '', icon: './icon.png' }), /^The option "label"/, 'throws on no valid label given'); // Test invalid id assert.throws( () => ToggleButton({ id: 'my button', label: 'my button', icon: './icon.png' }), /^The option "id"/, 'throws on no valid id given'); // Test empty id assert.throws( () => ToggleButton({ id: '', label: 'my button', icon: './icon.png' }), /^The option "id"/, 'throws on no valid id given'); // Test remote icon assert.throws( () => ToggleButton({ id: 'my-button', label: 'my button', icon: 'http://www.mozilla.org/favicon.ico'}), /^The option "icon"/, 'throws on no valid icon given'); // Test wrong icon: no absolute URI to local resource, neither relative './' assert.throws( () => ToggleButton({ id: 'my-button', label: 'my button', icon: 'icon.png'}), /^The option "icon"/, 'throws on no valid icon given'); // Test wrong icon: no absolute URI to local resource, neither relative './' assert.throws( () => ToggleButton({ id: 'my-button', label: 'my button', icon: 'foo and bar'}), /^The option "icon"/, 'throws on no valid icon given'); // Test wrong icon: '../' is not allowed assert.throws( () => ToggleButton({ id: 'my-button', label: 'my button', icon: '../icon.png'}), /^The option "icon"/, 'throws on no valid icon given'); // Test wrong checked assert.throws( () => ToggleButton({ id: 'my-button', label: 'my button', icon: './icon.png', checked: 'yes'}), /^The option "checked"/, 'throws on no valid checked value given'); loader.unload(); }; exports['test button added'] = function(assert) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let button = ToggleButton({ id: 'my-button-1', label: 'my button', icon: './icon.png' }); // check defaults assert.equal(button.checked, false, 'checked is set to default `false` value'); assert.equal(button.disabled, false, 'disabled is set to default `false` value'); let { node } = getWidget(button.id); assert.ok(!!node, 'The button is in the navbar'); assert.equal(button.label, node.getAttribute('label'), 'label is set'); assert.equal(button.label, node.getAttribute('tooltiptext'), 'tooltip is set'); assert.equal(data.url(button.icon.substr(2)), node.getAttribute('image'), 'icon is set'); loader.unload(); } exports['test button added with resource URI'] = function(assert) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let button = ToggleButton({ id: 'my-button-1', label: 'my button', icon: data.url('icon.png') }); assert.equal(button.icon, data.url('icon.png'), 'icon is set'); let { node } = getWidget(button.id); assert.equal(button.icon, node.getAttribute('image'), 'icon on node is set'); loader.unload(); } exports['test button duplicate id'] = function(assert) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let button = ToggleButton({ id: 'my-button-2', label: 'my button', icon: './icon.png' }); assert.throws(() => { let doppelganger = ToggleButton({ id: 'my-button-2', label: 'my button', icon: './icon.png' }); }, /^The ID/, 'No duplicates allowed'); loader.unload(); } exports['test button multiple destroy'] = function(assert) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let button = ToggleButton({ id: 'my-button-2', label: 'my button', icon: './icon.png' }); button.destroy(); button.destroy(); button.destroy(); assert.pass('multiple destroy doesn\'t matter'); loader.unload(); } exports['test button removed on dispose'] = function(assert, done) { const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {}); let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let widgetId; CustomizableUI.addListener({ onWidgetDestroyed: function(id) { if (id === widgetId) { CustomizableUI.removeListener(this); assert.pass('button properly removed'); loader.unload(); done(); } } }); let button = ToggleButton({ id: 'my-button-3', label: 'my button', icon: './icon.png' }); // Tried to use `getWidgetIdsInArea` but seems undefined, not sure if it // was removed or it's not in the UX build yet widgetId = getWidget(button.id).id; button.destroy(); }; exports['test button global state updated'] = function(assert) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let button = ToggleButton({ id: 'my-button-4', label: 'my button', icon: './icon.png' }); // Tried to use `getWidgetIdsInArea` but seems undefined, not sure if it // was removed or it's not in the UX build yet let { node, id: widgetId } = getWidget(button.id); // check read-only properties assert.throws(() => button.id = 'another-id', /^setting a property that has only a getter/, 'id cannot be set at runtime'); assert.equal(button.id, 'my-button-4', 'id is unchanged'); assert.equal(node.id, widgetId, 'node id is unchanged'); // check writable properties button.label = 'New label'; assert.equal(button.label, 'New label', 'label is updated'); assert.equal(node.getAttribute('label'), 'New label', 'node label is updated'); assert.equal(node.getAttribute('tooltiptext'), 'New label', 'node tooltip is updated'); button.icon = './new-icon.png'; assert.equal(button.icon, './new-icon.png', 'icon is updated'); assert.equal(node.getAttribute('image'), data.url('new-icon.png'), 'node image is updated'); button.disabled = true; assert.equal(button.disabled, true, 'disabled is updated'); assert.equal(node.getAttribute('disabled'), 'true', 'node disabled is updated'); // TODO: test validation on update loader.unload(); } exports['test button global state updated on multiple windows'] = function(assert, done) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let button = ToggleButton({ id: 'my-button-5', label: 'my button', icon: './icon.png' }); let nodes = [getWidget(button.id).node]; openBrowserWindow().then(window => { nodes.push(getWidget(button.id, window).node); button.label = 'New label'; button.icon = './new-icon.png'; button.disabled = true; for (let node of nodes) { assert.equal(node.getAttribute('label'), 'New label', 'node label is updated'); assert.equal(node.getAttribute('tooltiptext'), 'New label', 'node tooltip is updated'); assert.equal(button.icon, './new-icon.png', 'icon is updated'); assert.equal(node.getAttribute('image'), data.url('new-icon.png'), 'node image is updated'); assert.equal(button.disabled, true, 'disabled is updated'); assert.equal(node.getAttribute('disabled'), 'true', 'node disabled is updated'); }; return window; }). then(close). then(loader.unload). then(done, assert.fail); }; exports['test button window state'] = function(assert, done) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let { browserWindows } = loader.require('sdk/windows'); let button = ToggleButton({ id: 'my-button-6', label: 'my button', icon: './icon.png' }); let mainWindow = browserWindows.activeWindow; let nodes = [getWidget(button.id).node]; openBrowserWindow().then(focus).then(window => { nodes.push(getWidget(button.id, window).node); let { activeWindow } = browserWindows; button.state(activeWindow, { label: 'New label', icon: './new-icon.png', disabled: true }); // check the states assert.equal(button.label, 'my button', 'global label unchanged'); assert.equal(button.icon, './icon.png', 'global icon unchanged'); assert.equal(button.disabled, false, 'global disabled unchanged'); let state = button.state(mainWindow); assert.equal(state.label, 'my button', 'previous window label unchanged'); assert.equal(state.icon, './icon.png', 'previous window icon unchanged'); assert.equal(state.disabled, false, 'previous window disabled unchanged'); let state = button.state(activeWindow); assert.equal(state.label, 'New label', 'active window label updated'); assert.equal(state.icon, './new-icon.png', 'active window icon updated'); assert.equal(state.disabled, true, 'active disabled updated'); // change the global state, only the windows without a state are affected button.label = 'A good label'; assert.equal(button.label, 'A good label', 'global label updated'); assert.equal(button.state(mainWindow).label, 'A good label', 'previous window label updated'); assert.equal(button.state(activeWindow).label, 'New label', 'active window label unchanged'); // delete the window state will inherits the global state again button.state(activeWindow, null); assert.equal(button.state(activeWindow).label, 'A good label', 'active window label inherited'); // check the nodes properties let node = nodes[0]; let state = button.state(mainWindow); assert.equal(node.getAttribute('label'), state.label, 'node label is correct'); assert.equal(node.getAttribute('tooltiptext'), state.label, 'node tooltip is correct'); assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)), 'node image is correct'); assert.equal(node.hasAttribute('disabled'), state.disabled, 'disabled is correct'); let node = nodes[1]; let state = button.state(activeWindow); assert.equal(node.getAttribute('label'), state.label, 'node label is correct'); assert.equal(node.getAttribute('tooltiptext'), state.label, 'node tooltip is correct'); assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)), 'node image is correct'); assert.equal(node.hasAttribute('disabled'), state.disabled, 'disabled is correct'); return window; }). then(close). then(loader.unload). then(done, assert.fail); }; exports['test button tab state'] = function(assert, done) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let { browserWindows } = loader.require('sdk/windows'); let tabs = loader.require('sdk/tabs'); let button = ToggleButton({ id: 'my-button-7', label: 'my button', icon: './icon.png' }); let mainTab = tabs.activeTab; let node = getWidget(button.id).node; tabs.open({ url: 'about:blank', onActivate: function onActivate(tab) { tab.removeListener('activate', onActivate); let { activeWindow } = browserWindows; // set window state button.state(activeWindow, { label: 'Window label', icon: './window-icon.png' }); // set previous active tab state button.state(mainTab, { label: 'Tab label', icon: './tab-icon.png', }); // set current active tab state button.state(tab, { icon: './another-tab-icon.png', disabled: true }); // check the states Cu.schedulePreciseGC(() => { assert.equal(button.label, 'my button', 'global label unchanged'); assert.equal(button.icon, './icon.png', 'global icon unchanged'); assert.equal(button.disabled, false, 'global disabled unchanged'); let state = button.state(mainTab); assert.equal(state.label, 'Tab label', 'previous tab label updated'); assert.equal(state.icon, './tab-icon.png', 'previous tab icon updated'); assert.equal(state.disabled, false, 'previous tab disabled unchanged'); let state = button.state(tab); assert.equal(state.label, 'Window label', 'active tab inherited from window state'); assert.equal(state.icon, './another-tab-icon.png', 'active tab icon updated'); assert.equal(state.disabled, true, 'active disabled updated'); // change the global state button.icon = './good-icon.png'; // delete the tab state button.state(tab, null); assert.equal(button.icon, './good-icon.png', 'global icon updated'); assert.equal(button.state(mainTab).icon, './tab-icon.png', 'previous tab icon unchanged'); assert.equal(button.state(tab).icon, './window-icon.png', 'tab icon inherited from window'); // delete the window state button.state(activeWindow, null); assert.equal(button.state(tab).icon, './good-icon.png', 'tab icon inherited from global'); // check the node properties let state = button.state(tabs.activeTab); assert.equal(node.getAttribute('label'), state.label, 'node label is correct'); assert.equal(node.getAttribute('tooltiptext'), state.label, 'node tooltip is correct'); assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)), 'node image is correct'); assert.equal(node.hasAttribute('disabled'), state.disabled, 'disabled is correct'); tabs.once('activate', () => { // This is made in order to avoid to check the node before it // is updated, need a better check setTimeout(() => { let state = button.state(mainTab); assert.equal(node.getAttribute('label'), state.label, 'node label is correct'); assert.equal(node.getAttribute('tooltiptext'), state.label, 'node tooltip is correct'); assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)), 'node image is correct'); assert.equal(node.hasAttribute('disabled'), state.disabled, 'disabled is correct'); tab.close(() => { loader.unload(); done(); }); }, 500); }); mainTab.activate(); }); } }); }; exports['test button click'] = function(assert, done) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let { browserWindows } = loader.require('sdk/windows'); let labels = []; let button = ToggleButton({ id: 'my-button-8', label: 'my button', icon: './icon.png', onClick: ({label}) => labels.push(label) }); let mainWindow = browserWindows.activeWindow; let chromeWindow = getMostRecentBrowserWindow(); openBrowserWindow().then(focus).then(window => { button.state(mainWindow, { label: 'nothing' }); button.state(mainWindow.tabs.activeTab, { label: 'foo'}) button.state(browserWindows.activeWindow, { label: 'bar' }); button.click(); focus(chromeWindow).then(() => { button.click(); assert.deepEqual(labels, ['bar', 'foo'], 'button click works'); close(window). then(loader.unload). then(done, assert.fail); }); }).then(null, assert.fail); } exports['test button icon set'] = function(assert) { const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {}); let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); // Test remote icon set assert.throws( () => ToggleButton({ id: 'my-button-10', label: 'my button', icon: { '16': 'http://www.mozilla.org/favicon.ico' } }), /^The option "icon"/, 'throws on no valid icon given'); let button = ToggleButton({ id: 'my-button-11', label: 'my button', icon: { '5': './icon5.png', '16': './icon16.png', '32': './icon32.png', '64': './icon64.png' } }); let { node, id: widgetId } = getWidget(button.id); let { devicePixelRatio } = node.ownerDocument.defaultView; let size = 16 * devicePixelRatio; assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)), 'the icon is set properly in navbar'); let size = 32 * devicePixelRatio; CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL); assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)), 'the icon is set properly in panel'); // Using `loader.unload` without move back the button to the original area // raises an error in the CustomizableUI. This is doesn't happen if the // button is moved manually from navbar to panel. I believe it has to do // with `addWidgetToArea` method, because even with a `timeout` the issue // persist. CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR); loader.unload(); } exports['test button icon se with only one option'] = function(assert) { const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {}); let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); // Test remote icon set assert.throws( () => ToggleButton({ id: 'my-button-10', label: 'my button', icon: { '16': 'http://www.mozilla.org/favicon.ico' } }), /^The option "icon"/, 'throws on no valid icon given'); let button = ToggleButton({ id: 'my-button-11', label: 'my button', icon: { '5': './icon5.png' } }); let { node, id: widgetId } = getWidget(button.id); assert.equal(node.getAttribute('image'), data.url(button.icon['5'].substr(2)), 'the icon is set properly in navbar'); CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL); assert.equal(node.getAttribute('image'), data.url(button.icon['5'].substr(2)), 'the icon is set properly in panel'); // Using `loader.unload` without move back the button to the original area // raises an error in the CustomizableUI. This is doesn't happen if the // button is moved manually from navbar to panel. I believe it has to do // with `addWidgetToArea` method, because even with a `timeout` the issue // persist. CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR); loader.unload(); } exports['test button state validation'] = function(assert) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let { browserWindows } = loader.require('sdk/windows'); let button = ToggleButton({ id: 'my-button-12', label: 'my button', icon: './icon.png' }) let state = button.state(button); assert.throws( () => button.state(button, { icon: 'http://www.mozilla.org/favicon.ico' }), /^The option "icon"/, 'throws on remote icon given'); loader.unload(); }; exports['test button are not in private windows'] = function(assert, done) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let{ isPrivate } = loader.require('sdk/private-browsing'); let { browserWindows } = loader.require('sdk/windows'); let button = ToggleButton({ id: 'my-button-13', label: 'my button', icon: './icon.png' }); openPrivateBrowserWindow().then(window => { assert.ok(isPrivate(window), 'the new window is private'); let { node } = getWidget(button.id, window); assert.ok(!node || node.style.display === 'none', 'the button is not added / is not visible on private window'); return window; }). then(close). then(loader.unload). then(done, assert.fail) } exports['test button state are snapshot'] = function(assert) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let { browserWindows } = loader.require('sdk/windows'); let tabs = loader.require('sdk/tabs'); let button = ToggleButton({ id: 'my-button-14', label: 'my button', icon: './icon.png' }); let state = button.state(button); let windowState = button.state(browserWindows.activeWindow); let tabState = button.state(tabs.activeTab); assert.deepEqual(windowState, state, 'window state has the same properties of button state'); assert.deepEqual(tabState, state, 'tab state has the same properties of button state'); assert.notEqual(windowState, state, 'window state is not the same object of button state'); assert.notEqual(tabState, state, 'tab state is not the same object of button state'); assert.deepEqual(button.state(button), state, 'button state has the same content of previous button state'); assert.deepEqual(button.state(browserWindows.activeWindow), windowState, 'window state has the same content of previous window state'); assert.deepEqual(button.state(tabs.activeTab), tabState, 'tab state has the same content of previous tab state'); assert.notEqual(button.state(button), state, 'button state is not the same object of previous button state'); assert.notEqual(button.state(browserWindows.activeWindow), windowState, 'window state is not the same object of previous window state'); assert.notEqual(button.state(tabs.activeTab), tabState, 'tab state is not the same object of previous tab state'); loader.unload(); } exports['test button after destroy'] = function(assert) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let { browserWindows } = loader.require('sdk/windows'); let { activeTab } = loader.require('sdk/tabs'); let button = ToggleButton({ id: 'my-button-15', label: 'my button', icon: './icon.png', onClick: () => assert.fail('onClick should not be called') }); button.destroy(); assert.throws( () => button.click(), /^The state cannot be set or get/, 'button.click() not executed'); assert.throws( () => button.label, /^The state cannot be set or get/, 'button.label cannot be get after destroy'); assert.throws( () => button.label = 'my label', /^The state cannot be set or get/, 'button.label cannot be set after destroy'); assert.throws( () => { button.state(browserWindows.activeWindow, { label: 'window label' }); }, /^The state cannot be set or get/, 'window state label cannot be set after destroy'); assert.throws( () => button.state(browserWindows.activeWindow).label, /^The state cannot be set or get/, 'window state label cannot be get after destroy'); assert.throws( () => { button.state(activeTab, { label: 'tab label' }); }, /^The state cannot be set or get/, 'tab state label cannot be set after destroy'); assert.throws( () => button.state(activeTab).label, /^The state cannot be set or get/, 'window state label cannot se get after destroy'); loader.unload(); }; exports['test button checked'] = function(assert, done) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let { browserWindows } = loader.require('sdk/windows'); let events = []; let button = ToggleButton({ id: 'my-button-9', label: 'my button', icon: './icon.png', checked: true, onClick: ({label}) => events.push('clicked:' + label), onChange: state => events.push('changed:' + state.label + ':' + state.checked) }); let { node } = getWidget(button.id); assert.equal(node.getAttribute('type'), 'checkbox', 'node type is properly set'); let mainWindow = browserWindows.activeWindow; let chromeWindow = getMostRecentBrowserWindow(); openBrowserWindow().then(focus).then(window => { button.state(mainWindow, { label: 'nothing' }); button.state(mainWindow.tabs.activeTab, { label: 'foo'}) button.state(browserWindows.activeWindow, { label: 'bar' }); button.click(); button.click(); focus(chromeWindow).then(() => { button.click(); button.click(); assert.deepEqual(events, [ 'clicked:bar', 'changed:bar:false', 'clicked:bar', 'changed:bar:true', 'clicked:foo', 'changed:foo:false', 'clicked:foo', 'changed:foo:true' ], 'button change events works'); close(window). then(loader.unload). then(done, assert.fail); }) }).then(null, assert.fail); } exports['test button is checked on window level'] = function(assert, done) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let { browserWindows } = loader.require('sdk/windows'); let tabs = loader.require('sdk/tabs'); let button = ToggleButton({ id: 'my-button-20', label: 'my button', icon: './icon.png' }); let mainWindow = browserWindows.activeWindow; let mainTab = tabs.activeTab; assert.equal(button.checked, false, 'global state, checked is `false`.'); assert.equal(button.state(mainTab).checked, false, 'tab state, checked is `false`.'); assert.equal(button.state(mainWindow).checked, false, 'window state, checked is `false`.'); button.click(); tabs.open({ url: 'about:blank', onActivate: function onActivate(tab) { tab.removeListener('activate', onActivate); assert.notEqual(mainTab, tab, 'the current tab is not the same.'); assert.equal(button.checked, false, 'global state, checked is `false`.'); assert.equal(button.state(mainTab).checked, true, 'previous tab state, checked is `true`.'); assert.equal(button.state(tab).checked, true, 'current tab state, checked is `true`.'); assert.equal(button.state(mainWindow).checked, true, 'window state, checked is `true`.'); openBrowserWindow().then(focus).then(window => { let { activeWindow } = browserWindows; let { activeTab } = activeWindow.tabs; assert.equal(button.checked, false, 'global state, checked is `false`.'); assert.equal(button.state(activeTab).checked, false, 'tab state, checked is `false`.'); assert.equal(button.state(activeWindow).checked, false, 'window state, checked is `false`.'); tab.close(()=> { close(window). then(loader.unload). then(done, assert.fail); }) }). then(null, assert.fail); } }); }; exports['test button click do not messing up states'] = function(assert) { let loader = Loader(module); let { ToggleButton } = loader.require('sdk/ui'); let { browserWindows } = loader.require('sdk/windows'); let button = ToggleButton({ id: 'my-button-21', label: 'my button', icon: './icon.png' }); let mainWindow = browserWindows.activeWindow; let { activeTab } = mainWindow.tabs; button.state(mainWindow, { icon: './new-icon.png' }); button.state(activeTab, { label: 'foo'}) assert.equal(button.state(mainWindow).label, 'my button', 'label property for window state, properly derived from global state'); assert.equal(button.state(activeTab).icon, './new-icon.png', 'icon property for tab state, properly derived from window state'); button.click(); button.label = 'bar'; assert.equal(button.state(mainWindow).label, 'bar', 'label property for window state, properly derived from global state'); button.state(mainWindow, null); assert.equal(button.state(activeTab).icon, './icon.png', 'icon property for tab state, properly derived from window state'); loader.unload(); } // If the module doesn't support the app we're being run in, require() will // throw. In that case, remove all tests above from exports, and add one dummy // test that passes. try { require('sdk/ui/button/toggle'); } catch (err) { if (!/^Unsupported Application/.test(err.message)) throw err; module.exports = { 'test Unsupported Application': assert => assert.pass(err.message) } } require('sdk/test').run(exports);