addon-sdk/source/test/test-ui-toggle-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.

     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';
     6 module.metadata = {
     7   'engines': {
     8     'Firefox': '> 28'
     9   }
    10 };
    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);
    38 };
    40 exports['test basic constructor validation'] = function(assert) {
    41   let loader = Loader(module);
    42   let { ToggleButton } = loader.require('sdk/ui');
    44   assert.throws(
    45     () => ToggleButton({}),
    46     /^The option/,
    47     'throws on no option given');
    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');
    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');
    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');
    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');
    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');
    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');
    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');
    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');
    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');
   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');
   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');
   117   loader.unload();
   118 };
   120 exports['test button added'] = function(assert) {
   121   let loader = Loader(module);
   122   let { ToggleButton } = loader.require('sdk/ui');
   124   let button = ToggleButton({
   125     id: 'my-button-1',
   126     label: 'my button',
   127     icon: './icon.png'
   128   });
   130   // check defaults
   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'),
   142     'label is set');
   144   assert.equal(button.label, node.getAttribute('tooltiptext'),
   145     'tooltip is set');
   147   assert.equal(data.url(button.icon.substr(2)), node.getAttribute('image'),
   148     'icon is set');
   150   loader.unload();
   151 }
   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({
   158     id: 'my-button-1',
   159     label: 'my button',
   160     icon: data.url('icon.png')
   161   });
   163   assert.equal(button.icon, data.url('icon.png'),
   164     'icon is set');
   166   let { node } = getWidget(button.id);
   168   assert.equal(button.icon, node.getAttribute('image'),
   169     'icon on node is set');
   171   loader.unload();
   172 }
   174 exports['test button duplicate id'] = function(assert) {
   175   let loader = Loader(module);
   176   let { ToggleButton } = loader.require('sdk/ui');
   178   let button = ToggleButton({
   179     id: 'my-button-2',
   180     label: 'my button',
   181     icon: './icon.png'
   182   });
   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');
   194   loader.unload();
   195 }
   197 exports['test button multiple destroy'] = function(assert) {
   198   let loader = Loader(module);
   199   let { ToggleButton } = loader.require('sdk/ui');
   201   let button = ToggleButton({
   202     id: 'my-button-2',
   203     label: 'my button',
   204     icon: './icon.png'
   205   });
   207   button.destroy();
   208   button.destroy();
   209   button.destroy();
   211   assert.pass('multiple destroy doesn\'t matter');
   213   loader.unload();
   214 }
   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');
   221   let widgetId;
   223   CustomizableUI.addListener({
   224     onWidgetDestroyed: function(id) {
   225       if (id === widgetId) {
   226         CustomizableUI.removeListener(this);
   228         assert.pass('button properly removed');
   229         loader.unload();
   230         done();
   231       }
   232     }
   233   });
   235   let button = ToggleButton({
   236     id: 'my-button-3',
   237     label: 'my button',
   238     icon: './icon.png'
   239   });
   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;
   245   button.destroy();
   246 };
   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({
   253     id: 'my-button-4',
   254     label: 'my button',
   255     icon: './icon.png'
   256   });
   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',
   270     'id is unchanged');
   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',
   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');
   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');
   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
   298   loader.unload();
   299 }
   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({
   306     id: 'my-button-16',
   307     label: 'my button',
   308     icon: './icon.png'
   309   });
   311   // read the button's state
   312   let state = button.state(button);
   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');
   321   // set the new button's state
   322   button.state(button, {
   323     label: 'New label',
   324     icon: './new-icon.png',
   325     disabled: true
   326   });
   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');
   335   loader.unload();
   336 };
   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({
   343     id: 'my-button-5',
   344     label: 'my button',
   345     icon: './icon.png'
   346   });
   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',
   364         'icon is updated');
   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');
   372     };
   374     return window;
   375   }).
   376   then(close).
   377   then(loader.unload).
   378   then(done, assert.fail);
   379 };
   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({
   387     id: 'my-button-6',
   388     label: 'my button',
   389     icon: './icon.png'
   390   });
   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, {
   401       label: 'New label',
   402       icon: './new-icon.png',
   403       disabled: true
   404     });
   406     // check the states
   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
   452     let node = nodes[0];
   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');
   465     let node = nodes[1];
   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');
   478     return window;
   479   }).
   480   then(close).
   481   then(loader.unload).
   482   then(done, assert.fail);
   483 };
   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({
   493     id: 'my-button-7',
   494     label: 'my button',
   495     icon: './icon.png'
   496   });
   498   let mainTab = tabs.activeTab;
   499   let node = getWidget(button.id).node;
   501   tabs.open({
   502     url: 'about:blank',
   503     onActivate: function onActivate(tab) {
   504       tab.removeListener('activate', onActivate);
   506       let { activeWindow } = browserWindows;
   507       // set window state
   508       button.state(activeWindow, {
   509         label: 'Window label',
   510         icon: './window-icon.png'
   511       });
   513       // set previous active tab state
   514       button.state(mainTab, {
   515         label: 'Tab label',
   516         icon: './tab-icon.png',
   517       });
   519       // set current active tab state
   520       button.state(tab, {
   521         icon: './another-tab-icon.png',
   522         disabled: true
   523       });
   525       // check the states
   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
   588           setTimeout(() => {
   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');
   600             tab.close(() => {
   601               loader.unload();
   602               done();
   603             });
   604           }, 500);
   605         });
   607         mainTab.activate();
   608       });
   609     }
   610   });
   612 };
   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');
   619   let labels = [];
   621   let button = ToggleButton({
   622     id: 'my-button-8',
   623     label: 'my button',
   624     icon: './icon.png',
   625     onClick: ({label}) => labels.push(label)
   626   });
   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' });
   636     button.click();
   638     focus(chromeWindow).then(() => {
   639       button.click();
   641       assert.deepEqual(labels, ['bar', 'foo'],
   642         'button click works');
   644       close(window).
   645         then(loader.unload).
   646         then(done, assert.fail);
   647     });
   648   }).then(null, assert.fail);
   649 }
   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
   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');
   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   });
   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
   698   // persist.
   699   CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR);
   701   loader.unload();
   702 }
   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
   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');
   721   let button = ToggleButton({
   722     id: 'my-button-11',
   723     label: 'my button',
   724     icon: {
   725       '5': './icon5.png'
   726     }
   727   });
   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
   743   // persist.
   744   CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR);
   746   loader.unload();
   747 }
   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({
   755     id: 'my-button-12',
   756     label: 'my button',
   757     icon: './icon.png'
   758   })
   760   let state = button.state(button);
   762   assert.throws(
   763     () => button.state(button, { icon: 'http://www.mozilla.org/favicon.ico' }),
   764     /^The option "icon"/,
   765     'throws on remote icon given');
   767   loader.unload();
   768 };
   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({
   777     id: 'my-button-13',
   778     label: 'my button',
   779     icon: './icon.png'
   780   });
   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');
   791     return window;
   792   }).
   793   then(close).
   794   then(loader.unload).
   795   then(done, assert.fail)
   796 }
   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({
   805     id: 'my-button-14',
   806     label: 'my button',
   807     icon: './icon.png'
   808   });
   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');
   844   loader.unload();
   845 }
   847 exports['test button icon object is a snapshot'] = function(assert) {
   848   let loader = Loader(module);
   849   let { ToggleButton } = loader.require('sdk/ui');
   851   let icon = {
   852     '16': './foo.png'
   853   };
   855   let button = ToggleButton({
   856     id: 'my-button-17',
   857     label: 'my button',
   858     icon: icon
   859   });
   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');
   867   assert.throws(
   868     () => button.icon[16] = './bar.png',
   869     /16 is read-only/,
   870     'properties of button.icon are ready-only'
   871   );
   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');
   882   loader.unload();
   883 }
   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({
   892     id: 'my-button-15',
   893     label: 'my button',
   894     icon: './icon.png',
   895     onClick: () => assert.fail('onClick should not be called')
   896   });
   898   button.destroy();
   900   assert.throws(
   901     () => button.click(),
   902     /^The state cannot be set or get/,
   903     'button.click() not executed');
   905   assert.throws(
   906     () => button.label,
   907     /^The state cannot be set or get/,
   908     'button.label cannot be get after destroy');
   910   assert.throws(
   911     () => button.label = 'my label',
   912     /^The state cannot be set or get/,
   913     'button.label cannot be set after destroy');
   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');
   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');
   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');
   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');
   943   loader.unload();
   944 };
   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');
   951   let events = [];
   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   });
   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' });
   975     button.click();
   976     button.click();
   978     focus(chromeWindow).then(() => {
   979       button.click();
   980       button.click();
   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');
   988       close(window).
   989         then(loader.unload).
   990         then(done, assert.fail);
   991     })
   992   }).then(null, assert.fail);
   993 }
   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({
  1002     id: 'my-button-20',
  1003     label: 'my button',
  1004     icon: './icon.png'
  1005   });
  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`.');
  1017   button.click();
  1019   tabs.open({
  1020     url: 'about:blank',
  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`.');
  1048         tab.close(()=> {
  1049           close(window).
  1050             then(loader.unload).
  1051             then(done, assert.fail);
  1052         })
  1053       }).
  1054       then(null, assert.fail);
  1056   });
  1058 };
  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({
  1066     id: 'my-button-21',
  1067     label: 'my button',
  1068     icon: './icon.png'
  1069   });
  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');
  1083   button.click();
  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');
  1095   loader.unload();
  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({
  1106     id: 'my-button-22',
  1107     label: 'my button',
  1108     icon: './icon.png',
  1109     onChange: ({checked}) => checked && panel.show()
  1110   });
  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   });
  1119   let panel = Panel({
  1120     position: b1
  1121   });
  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');
  1138     panel.hide();
  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');
  1152       loader.unload();
  1154       done();
  1155     });
  1157     b2.click();
  1158   });
  1160   b1.click();
  1163 require('sdk/test').run(exports);

mercurial