test-ui-action-button.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. 'use strict';
  5. module.metadata = {
  6. 'engines': {
  7. 'Firefox': '> 28'
  8. }
  9. };
  10. const { Cu } = require('chrome');
  11. const { Loader } = require('sdk/test/loader');
  12. const { data } = require('sdk/self');
  13. const { open, focus, close } = require('sdk/window/helpers');
  14. const { setTimeout } = require('sdk/timers');
  15. const { getMostRecentBrowserWindow } = require('sdk/window/utils');
  16. const { partial } = require('sdk/lang/functional');
  17. const openBrowserWindow = partial(open, null, {features: {toolbar: true}});
  18. const openPrivateBrowserWindow = partial(open, null,
  19. {features: {toolbar: true, private: true}});
  20. function getWidget(buttonId, window = getMostRecentBrowserWindow()) {
  21. const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
  22. const { AREA_NAVBAR } = CustomizableUI;
  23. let widgets = CustomizableUI.getWidgetIdsInArea(AREA_NAVBAR).
  24. filter((id) => id.startsWith('button--') && id.endsWith(buttonId));
  25. if (widgets.length === 0)
  26. throw new Error('Widget with id `' + id +'` not found.');
  27. if (widgets.length > 1)
  28. throw new Error('Unexpected number of widgets: ' + widgets.length)
  29. return CustomizableUI.getWidget(widgets[0]).forWindow(window);
  30. };
  31. exports['test basic constructor validation'] = function(assert) {
  32. let loader = Loader(module);
  33. let { ActionButton } = loader.require('sdk/ui');
  34. assert.throws(
  35. () => ActionButton({}),
  36. /^The option/,
  37. 'throws on no option given');
  38. // Test no label
  39. assert.throws(
  40. () => ActionButton({ id: 'my-button', icon: './icon.png'}),
  41. /^The option "label"/,
  42. 'throws on no label given');
  43. // Test no id
  44. assert.throws(
  45. () => ActionButton({ label: 'my button', icon: './icon.png' }),
  46. /^The option "id"/,
  47. 'throws on no id given');
  48. // Test no icon
  49. assert.throws(
  50. () => ActionButton({ id: 'my-button', label: 'my button' }),
  51. /^The option "icon"/,
  52. 'throws on no icon given');
  53. // Test empty label
  54. assert.throws(
  55. () => ActionButton({ id: 'my-button', label: '', icon: './icon.png' }),
  56. /^The option "label"/,
  57. 'throws on no valid label given');
  58. // Test invalid id
  59. assert.throws(
  60. () => ActionButton({ id: 'my button', label: 'my button', icon: './icon.png' }),
  61. /^The option "id"/,
  62. 'throws on no valid id given');
  63. // Test empty id
  64. assert.throws(
  65. () => ActionButton({ id: '', label: 'my button', icon: './icon.png' }),
  66. /^The option "id"/,
  67. 'throws on no valid id given');
  68. // Test remote icon
  69. assert.throws(
  70. () => ActionButton({ id: 'my-button', label: 'my button', icon: 'http://www.mozilla.org/favicon.ico'}),
  71. /^The option "icon"/,
  72. 'throws on no valid icon given');
  73. // Test wrong icon: no absolute URI to local resource, neither relative './'
  74. assert.throws(
  75. () => ActionButton({ id: 'my-button', label: 'my button', icon: 'icon.png'}),
  76. /^The option "icon"/,
  77. 'throws on no valid icon given');
  78. // Test wrong icon: no absolute URI to local resource, neither relative './'
  79. assert.throws(
  80. () => ActionButton({ id: 'my-button', label: 'my button', icon: 'foo and bar'}),
  81. /^The option "icon"/,
  82. 'throws on no valid icon given');
  83. // Test wrong icon: '../' is not allowed
  84. assert.throws(
  85. () => ActionButton({ id: 'my-button', label: 'my button', icon: '../icon.png'}),
  86. /^The option "icon"/,
  87. 'throws on no valid icon given');
  88. loader.unload();
  89. };
  90. exports['test button added'] = function(assert) {
  91. let loader = Loader(module);
  92. let { ActionButton } = loader.require('sdk/ui');
  93. let button = ActionButton({
  94. id: 'my-button-1',
  95. label: 'my button',
  96. icon: './icon.png'
  97. });
  98. // check defaults
  99. assert.equal(button.disabled, false,
  100. 'disabled is set to default `false` value');
  101. let { node } = getWidget(button.id);
  102. assert.ok(!!node, 'The button is in the navbar');
  103. assert.equal(button.label, node.getAttribute('label'),
  104. 'label is set');
  105. assert.equal(button.label, node.getAttribute('tooltiptext'),
  106. 'tooltip is set');
  107. assert.equal(data.url(button.icon.substr(2)), node.getAttribute('image'),
  108. 'icon is set');
  109. loader.unload();
  110. }
  111. exports['test button added with resource URI'] = function(assert) {
  112. let loader = Loader(module);
  113. let { ActionButton } = loader.require('sdk/ui');
  114. let button = ActionButton({
  115. id: 'my-button-1',
  116. label: 'my button',
  117. icon: data.url('icon.png')
  118. });
  119. assert.equal(button.icon, data.url('icon.png'),
  120. 'icon is set');
  121. let { node } = getWidget(button.id);
  122. assert.equal(button.icon, node.getAttribute('image'),
  123. 'icon on node is set');
  124. loader.unload();
  125. }
  126. exports['test button duplicate id'] = function(assert) {
  127. let loader = Loader(module);
  128. let { ActionButton } = loader.require('sdk/ui');
  129. let button = ActionButton({
  130. id: 'my-button-2',
  131. label: 'my button',
  132. icon: './icon.png'
  133. });
  134. assert.throws(() => {
  135. let doppelganger = ActionButton({
  136. id: 'my-button-2',
  137. label: 'my button',
  138. icon: './icon.png'
  139. });
  140. },
  141. /^The ID/,
  142. 'No duplicates allowed');
  143. loader.unload();
  144. }
  145. exports['test button multiple destroy'] = function(assert) {
  146. let loader = Loader(module);
  147. let { ActionButton } = loader.require('sdk/ui');
  148. let button = ActionButton({
  149. id: 'my-button-2',
  150. label: 'my button',
  151. icon: './icon.png'
  152. });
  153. button.destroy();
  154. button.destroy();
  155. button.destroy();
  156. assert.pass('multiple destroy doesn\'t matter');
  157. loader.unload();
  158. }
  159. exports['test button removed on dispose'] = function(assert, done) {
  160. const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
  161. let loader = Loader(module);
  162. let { ActionButton } = loader.require('sdk/ui');
  163. let widgetId;
  164. CustomizableUI.addListener({
  165. onWidgetDestroyed: function(id) {
  166. if (id === widgetId) {
  167. CustomizableUI.removeListener(this);
  168. assert.pass('button properly removed');
  169. loader.unload();
  170. done();
  171. }
  172. }
  173. });
  174. let button = ActionButton({
  175. id: 'my-button-3',
  176. label: 'my button',
  177. icon: './icon.png'
  178. });
  179. // Tried to use `getWidgetIdsInArea` but seems undefined, not sure if it
  180. // was removed or it's not in the UX build yet
  181. widgetId = getWidget(button.id).id;
  182. button.destroy();
  183. };
  184. exports['test button global state updated'] = function(assert) {
  185. let loader = Loader(module);
  186. let { ActionButton } = loader.require('sdk/ui');
  187. let button = ActionButton({
  188. id: 'my-button-4',
  189. label: 'my button',
  190. icon: './icon.png'
  191. });
  192. // Tried to use `getWidgetIdsInArea` but seems undefined, not sure if it
  193. // was removed or it's not in the UX build yet
  194. let { node, id: widgetId } = getWidget(button.id);
  195. // check read-only properties
  196. assert.throws(() => button.id = 'another-id',
  197. /^setting a property that has only a getter/,
  198. 'id cannot be set at runtime');
  199. assert.equal(button.id, 'my-button-4',
  200. 'id is unchanged');
  201. assert.equal(node.id, widgetId,
  202. 'node id is unchanged');
  203. // check writable properties
  204. button.label = 'New label';
  205. assert.equal(button.label, 'New label',
  206. 'label is updated');
  207. assert.equal(node.getAttribute('label'), 'New label',
  208. 'node label is updated');
  209. assert.equal(node.getAttribute('tooltiptext'), 'New label',
  210. 'node tooltip is updated');
  211. button.icon = './new-icon.png';
  212. assert.equal(button.icon, './new-icon.png',
  213. 'icon is updated');
  214. assert.equal(node.getAttribute('image'), data.url('new-icon.png'),
  215. 'node image is updated');
  216. button.disabled = true;
  217. assert.equal(button.disabled, true,
  218. 'disabled is updated');
  219. assert.equal(node.getAttribute('disabled'), 'true',
  220. 'node disabled is updated');
  221. // TODO: test validation on update
  222. loader.unload();
  223. }
  224. exports['test button global state updated on multiple windows'] = function(assert, done) {
  225. let loader = Loader(module);
  226. let { ActionButton } = loader.require('sdk/ui');
  227. let button = ActionButton({
  228. id: 'my-button-5',
  229. label: 'my button',
  230. icon: './icon.png'
  231. });
  232. let nodes = [getWidget(button.id).node];
  233. openBrowserWindow().then(window => {
  234. nodes.push(getWidget(button.id, window).node);
  235. button.label = 'New label';
  236. button.icon = './new-icon.png';
  237. button.disabled = true;
  238. for (let node of nodes) {
  239. assert.equal(node.getAttribute('label'), 'New label',
  240. 'node label is updated');
  241. assert.equal(node.getAttribute('tooltiptext'), 'New label',
  242. 'node tooltip is updated');
  243. assert.equal(button.icon, './new-icon.png',
  244. 'icon is updated');
  245. assert.equal(node.getAttribute('image'), data.url('new-icon.png'),
  246. 'node image is updated');
  247. assert.equal(button.disabled, true,
  248. 'disabled is updated');
  249. assert.equal(node.getAttribute('disabled'), 'true',
  250. 'node disabled is updated');
  251. };
  252. return window;
  253. }).
  254. then(close).
  255. then(loader.unload).
  256. then(done, assert.fail);
  257. };
  258. exports['test button window state'] = function(assert, done) {
  259. let loader = Loader(module);
  260. let { ActionButton } = loader.require('sdk/ui');
  261. let { browserWindows } = loader.require('sdk/windows');
  262. let button = ActionButton({
  263. id: 'my-button-6',
  264. label: 'my button',
  265. icon: './icon.png'
  266. });
  267. let mainWindow = browserWindows.activeWindow;
  268. let nodes = [getWidget(button.id).node];
  269. openBrowserWindow().then(focus).then(window => {
  270. nodes.push(getWidget(button.id, window).node);
  271. let { activeWindow } = browserWindows;
  272. button.state(activeWindow, {
  273. label: 'New label',
  274. icon: './new-icon.png',
  275. disabled: true
  276. });
  277. // check the states
  278. assert.equal(button.label, 'my button',
  279. 'global label unchanged');
  280. assert.equal(button.icon, './icon.png',
  281. 'global icon unchanged');
  282. assert.equal(button.disabled, false,
  283. 'global disabled unchanged');
  284. let state = button.state(mainWindow);
  285. assert.equal(state.label, 'my button',
  286. 'previous window label unchanged');
  287. assert.equal(state.icon, './icon.png',
  288. 'previous window icon unchanged');
  289. assert.equal(state.disabled, false,
  290. 'previous window disabled unchanged');
  291. let state = button.state(activeWindow);
  292. assert.equal(state.label, 'New label',
  293. 'active window label updated');
  294. assert.equal(state.icon, './new-icon.png',
  295. 'active window icon updated');
  296. assert.equal(state.disabled, true,
  297. 'active disabled updated');
  298. // change the global state, only the windows without a state are affected
  299. button.label = 'A good label';
  300. assert.equal(button.label, 'A good label',
  301. 'global label updated');
  302. assert.equal(button.state(mainWindow).label, 'A good label',
  303. 'previous window label updated');
  304. assert.equal(button.state(activeWindow).label, 'New label',
  305. 'active window label unchanged');
  306. // delete the window state will inherits the global state again
  307. button.state(activeWindow, null);
  308. assert.equal(button.state(activeWindow).label, 'A good label',
  309. 'active window label inherited');
  310. // check the nodes properties
  311. let node = nodes[0];
  312. let state = button.state(mainWindow);
  313. assert.equal(node.getAttribute('label'), state.label,
  314. 'node label is correct');
  315. assert.equal(node.getAttribute('tooltiptext'), state.label,
  316. 'node tooltip is correct');
  317. assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
  318. 'node image is correct');
  319. assert.equal(node.hasAttribute('disabled'), state.disabled,
  320. 'disabled is correct');
  321. let node = nodes[1];
  322. let state = button.state(activeWindow);
  323. assert.equal(node.getAttribute('label'), state.label,
  324. 'node label is correct');
  325. assert.equal(node.getAttribute('tooltiptext'), state.label,
  326. 'node tooltip is correct');
  327. assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
  328. 'node image is correct');
  329. assert.equal(node.hasAttribute('disabled'), state.disabled,
  330. 'disabled is correct');
  331. return window;
  332. }).
  333. then(close).
  334. then(loader.unload).
  335. then(done, assert.fail);
  336. };
  337. exports['test button tab state'] = function(assert, done) {
  338. let loader = Loader(module);
  339. let { ActionButton } = loader.require('sdk/ui');
  340. let { browserWindows } = loader.require('sdk/windows');
  341. let tabs = loader.require('sdk/tabs');
  342. let button = ActionButton({
  343. id: 'my-button-7',
  344. label: 'my button',
  345. icon: './icon.png'
  346. });
  347. let mainTab = tabs.activeTab;
  348. let node = getWidget(button.id).node;
  349. tabs.open({
  350. url: 'about:blank',
  351. onActivate: function onActivate(tab) {
  352. tab.removeListener('activate', onActivate);
  353. let { activeWindow } = browserWindows;
  354. // set window state
  355. button.state(activeWindow, {
  356. label: 'Window label',
  357. icon: './window-icon.png'
  358. });
  359. // set previous active tab state
  360. button.state(mainTab, {
  361. label: 'Tab label',
  362. icon: './tab-icon.png',
  363. });
  364. // set current active tab state
  365. button.state(tab, {
  366. icon: './another-tab-icon.png',
  367. disabled: true
  368. });
  369. // check the states
  370. Cu.schedulePreciseGC(() => {
  371. assert.equal(button.label, 'my button',
  372. 'global label unchanged');
  373. assert.equal(button.icon, './icon.png',
  374. 'global icon unchanged');
  375. assert.equal(button.disabled, false,
  376. 'global disabled unchanged');
  377. let state = button.state(mainTab);
  378. assert.equal(state.label, 'Tab label',
  379. 'previous tab label updated');
  380. assert.equal(state.icon, './tab-icon.png',
  381. 'previous tab icon updated');
  382. assert.equal(state.disabled, false,
  383. 'previous tab disabled unchanged');
  384. let state = button.state(tab);
  385. assert.equal(state.label, 'Window label',
  386. 'active tab inherited from window state');
  387. assert.equal(state.icon, './another-tab-icon.png',
  388. 'active tab icon updated');
  389. assert.equal(state.disabled, true,
  390. 'active disabled updated');
  391. // change the global state
  392. button.icon = './good-icon.png';
  393. // delete the tab state
  394. button.state(tab, null);
  395. assert.equal(button.icon, './good-icon.png',
  396. 'global icon updated');
  397. assert.equal(button.state(mainTab).icon, './tab-icon.png',
  398. 'previous tab icon unchanged');
  399. assert.equal(button.state(tab).icon, './window-icon.png',
  400. 'tab icon inherited from window');
  401. // delete the window state
  402. button.state(activeWindow, null);
  403. assert.equal(button.state(tab).icon, './good-icon.png',
  404. 'tab icon inherited from global');
  405. // check the node properties
  406. let state = button.state(tabs.activeTab);
  407. assert.equal(node.getAttribute('label'), state.label,
  408. 'node label is correct');
  409. assert.equal(node.getAttribute('tooltiptext'), state.label,
  410. 'node tooltip is correct');
  411. assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
  412. 'node image is correct');
  413. assert.equal(node.hasAttribute('disabled'), state.disabled,
  414. 'disabled is correct');
  415. tabs.once('activate', () => {
  416. // This is made in order to avoid to check the node before it
  417. // is updated, need a better check
  418. setTimeout(() => {
  419. let state = button.state(mainTab);
  420. assert.equal(node.getAttribute('label'), state.label,
  421. 'node label is correct');
  422. assert.equal(node.getAttribute('tooltiptext'), state.label,
  423. 'node tooltip is correct');
  424. assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
  425. 'node image is correct');
  426. assert.equal(node.hasAttribute('disabled'), state.disabled,
  427. 'disabled is correct');
  428. tab.close(() => {
  429. loader.unload();
  430. done();
  431. });
  432. }, 500);
  433. });
  434. mainTab.activate();
  435. });
  436. }
  437. });
  438. };
  439. exports['test button click'] = function(assert, done) {
  440. let loader = Loader(module);
  441. let { ActionButton } = loader.require('sdk/ui');
  442. let { browserWindows } = loader.require('sdk/windows');
  443. let labels = [];
  444. let button = ActionButton({
  445. id: 'my-button-8',
  446. label: 'my button',
  447. icon: './icon.png',
  448. onClick: ({label}) => labels.push(label)
  449. });
  450. let mainWindow = browserWindows.activeWindow;
  451. let chromeWindow = getMostRecentBrowserWindow();
  452. openBrowserWindow().then(focus).then(window => {
  453. button.state(mainWindow, { label: 'nothing' });
  454. button.state(mainWindow.tabs.activeTab, { label: 'foo'})
  455. button.state(browserWindows.activeWindow, { label: 'bar' });
  456. button.click();
  457. focus(chromeWindow).then(() => {
  458. button.click();
  459. assert.deepEqual(labels, ['bar', 'foo'],
  460. 'button click works');
  461. close(window).
  462. then(loader.unload).
  463. then(done, assert.fail);
  464. });
  465. }).then(null, assert.fail);
  466. }
  467. exports['test button icon set'] = function(assert) {
  468. const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
  469. let loader = Loader(module);
  470. let { ActionButton } = loader.require('sdk/ui');
  471. // Test remote icon set
  472. assert.throws(
  473. () => ActionButton({
  474. id: 'my-button-10',
  475. label: 'my button',
  476. icon: {
  477. '16': 'http://www.mozilla.org/favicon.ico'
  478. }
  479. }),
  480. /^The option "icon"/,
  481. 'throws on no valid icon given');
  482. let button = ActionButton({
  483. id: 'my-button-11',
  484. label: 'my button',
  485. icon: {
  486. '5': './icon5.png',
  487. '16': './icon16.png',
  488. '32': './icon32.png',
  489. '64': './icon64.png'
  490. }
  491. });
  492. let { node, id: widgetId } = getWidget(button.id);
  493. let { devicePixelRatio } = node.ownerDocument.defaultView;
  494. let size = 16 * devicePixelRatio;
  495. assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)),
  496. 'the icon is set properly in navbar');
  497. let size = 32 * devicePixelRatio;
  498. CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL);
  499. assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)),
  500. 'the icon is set properly in panel');
  501. // Using `loader.unload` without move back the button to the original area
  502. // raises an error in the CustomizableUI. This is doesn't happen if the
  503. // button is moved manually from navbar to panel. I believe it has to do
  504. // with `addWidgetToArea` method, because even with a `timeout` the issue
  505. // persist.
  506. CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR);
  507. loader.unload();
  508. }
  509. exports['test button icon se with only one option'] = function(assert) {
  510. const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
  511. let loader = Loader(module);
  512. let { ActionButton } = loader.require('sdk/ui');
  513. // Test remote icon set
  514. assert.throws(
  515. () => ActionButton({
  516. id: 'my-button-10',
  517. label: 'my button',
  518. icon: {
  519. '16': 'http://www.mozilla.org/favicon.ico'
  520. }
  521. }),
  522. /^The option "icon"/,
  523. 'throws on no valid icon given');
  524. let button = ActionButton({
  525. id: 'my-button-11',
  526. label: 'my button',
  527. icon: {
  528. '5': './icon5.png'
  529. }
  530. });
  531. let { node, id: widgetId } = getWidget(button.id);
  532. assert.equal(node.getAttribute('image'), data.url(button.icon['5'].substr(2)),
  533. 'the icon is set properly in navbar');
  534. CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL);
  535. assert.equal(node.getAttribute('image'), data.url(button.icon['5'].substr(2)),
  536. 'the icon is set properly in panel');
  537. // Using `loader.unload` without move back the button to the original area
  538. // raises an error in the CustomizableUI. This is doesn't happen if the
  539. // button is moved manually from navbar to panel. I believe it has to do
  540. // with `addWidgetToArea` method, because even with a `timeout` the issue
  541. // persist.
  542. CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR);
  543. loader.unload();
  544. }
  545. exports['test button state validation'] = function(assert) {
  546. let loader = Loader(module);
  547. let { ActionButton } = loader.require('sdk/ui');
  548. let { browserWindows } = loader.require('sdk/windows');
  549. let button = ActionButton({
  550. id: 'my-button-12',
  551. label: 'my button',
  552. icon: './icon.png'
  553. })
  554. let state = button.state(button);
  555. assert.throws(
  556. () => button.state(button, { icon: 'http://www.mozilla.org/favicon.ico' }),
  557. /^The option "icon"/,
  558. 'throws on remote icon given');
  559. loader.unload();
  560. };
  561. exports['test button are not in private windows'] = function(assert, done) {
  562. let loader = Loader(module);
  563. let { ActionButton } = loader.require('sdk/ui');
  564. let{ isPrivate } = loader.require('sdk/private-browsing');
  565. let { browserWindows } = loader.require('sdk/windows');
  566. let button = ActionButton({
  567. id: 'my-button-13',
  568. label: 'my button',
  569. icon: './icon.png'
  570. });
  571. openPrivateBrowserWindow().then(window => {
  572. assert.ok(isPrivate(window),
  573. 'the new window is private');
  574. let { node } = getWidget(button.id, window);
  575. assert.ok(!node || node.style.display === 'none',
  576. 'the button is not added / is not visible on private window');
  577. return window;
  578. }).
  579. then(close).
  580. then(loader.unload).
  581. then(done, assert.fail)
  582. }
  583. exports['test button state are snapshot'] = function(assert) {
  584. let loader = Loader(module);
  585. let { ActionButton } = loader.require('sdk/ui');
  586. let { browserWindows } = loader.require('sdk/windows');
  587. let tabs = loader.require('sdk/tabs');
  588. let button = ActionButton({
  589. id: 'my-button-14',
  590. label: 'my button',
  591. icon: './icon.png'
  592. });
  593. let state = button.state(button);
  594. let windowState = button.state(browserWindows.activeWindow);
  595. let tabState = button.state(tabs.activeTab);
  596. assert.deepEqual(windowState, state,
  597. 'window state has the same properties of button state');
  598. assert.deepEqual(tabState, state,
  599. 'tab state has the same properties of button state');
  600. assert.notEqual(windowState, state,
  601. 'window state is not the same object of button state');
  602. assert.notEqual(tabState, state,
  603. 'tab state is not the same object of button state');
  604. assert.deepEqual(button.state(button), state,
  605. 'button state has the same content of previous button state');
  606. assert.deepEqual(button.state(browserWindows.activeWindow), windowState,
  607. 'window state has the same content of previous window state');
  608. assert.deepEqual(button.state(tabs.activeTab), tabState,
  609. 'tab state has the same content of previous tab state');
  610. assert.notEqual(button.state(button), state,
  611. 'button state is not the same object of previous button state');
  612. assert.notEqual(button.state(browserWindows.activeWindow), windowState,
  613. 'window state is not the same object of previous window state');
  614. assert.notEqual(button.state(tabs.activeTab), tabState,
  615. 'tab state is not the same object of previous tab state');
  616. loader.unload();
  617. }
  618. exports['test button after destroy'] = function(assert) {
  619. let loader = Loader(module);
  620. let { ActionButton } = loader.require('sdk/ui');
  621. let { browserWindows } = loader.require('sdk/windows');
  622. let { activeTab } = loader.require('sdk/tabs');
  623. let button = ActionButton({
  624. id: 'my-button-15',
  625. label: 'my button',
  626. icon: './icon.png',
  627. onClick: () => assert.fail('onClick should not be called')
  628. });
  629. button.destroy();
  630. assert.throws(
  631. () => button.click(),
  632. /^The state cannot be set or get/,
  633. 'button.click() not executed');
  634. assert.throws(
  635. () => button.label,
  636. /^The state cannot be set or get/,
  637. 'button.label cannot be get after destroy');
  638. assert.throws(
  639. () => button.label = 'my label',
  640. /^The state cannot be set or get/,
  641. 'button.label cannot be set after destroy');
  642. assert.throws(
  643. () => {
  644. button.state(browserWindows.activeWindow, {
  645. label: 'window label'
  646. });
  647. },
  648. /^The state cannot be set or get/,
  649. 'window state label cannot be set after destroy');
  650. assert.throws(
  651. () => button.state(browserWindows.activeWindow).label,
  652. /^The state cannot be set or get/,
  653. 'window state label cannot be get after destroy');
  654. assert.throws(
  655. () => {
  656. button.state(activeTab, {
  657. label: 'tab label'
  658. });
  659. },
  660. /^The state cannot be set or get/,
  661. 'tab state label cannot be set after destroy');
  662. assert.throws(
  663. () => button.state(activeTab).label,
  664. /^The state cannot be set or get/,
  665. 'window state label cannot se get after destroy');
  666. loader.unload();
  667. };
  668. // If the module doesn't support the app we're being run in, require() will
  669. // throw. In that case, remove all tests above from exports, and add one dummy
  670. // test that passes.
  671. try {
  672. require('sdk/ui/button/action');
  673. }
  674. catch (err) {
  675. if (!/^Unsupported Application/.test(err.message))
  676. throw err;
  677. module.exports = {
  678. 'test Unsupported Application': assert => assert.pass(err.message)
  679. }
  680. }
  681. require('sdk/test').run(exports);