select_test.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. // Copyright 2010 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.ui.SelectTest');
  15. goog.setTestOnly('goog.ui.SelectTest');
  16. goog.require('goog.a11y.aria');
  17. goog.require('goog.a11y.aria.Role');
  18. goog.require('goog.a11y.aria.State');
  19. goog.require('goog.dom');
  20. goog.require('goog.events');
  21. goog.require('goog.testing.jsunit');
  22. goog.require('goog.testing.recordFunction');
  23. goog.require('goog.ui.Component');
  24. goog.require('goog.ui.CustomButtonRenderer');
  25. goog.require('goog.ui.Menu');
  26. goog.require('goog.ui.MenuItem');
  27. goog.require('goog.ui.Select');
  28. goog.require('goog.ui.Separator');
  29. var defaultCaption = 'initial caption';
  30. var sandboxEl;
  31. var select;
  32. function setUp() {
  33. sandboxEl = goog.dom.getElement('sandbox');
  34. select = new goog.ui.Select(defaultCaption);
  35. }
  36. function tearDown() {
  37. select.dispose();
  38. goog.dom.removeChildren(sandboxEl);
  39. }
  40. /**
  41. * Checks that the default caption passed in the constructor and in the setter
  42. * is returned by getDefaultCaption, and acts as a default caption, i.e. is
  43. * shown as a caption when no items are selected.
  44. */
  45. function testDefaultCaption() {
  46. select.render(sandboxEl);
  47. var item1 = new goog.ui.MenuItem('item 1');
  48. select.addItem(item1);
  49. select.addItem(new goog.ui.MenuItem('item 2'));
  50. assertEquals(defaultCaption, select.getDefaultCaption());
  51. assertEquals(defaultCaption, select.getCaption());
  52. var newCaption = 'new caption';
  53. select.setDefaultCaption(newCaption);
  54. assertEquals(newCaption, select.getDefaultCaption());
  55. assertEquals(newCaption, select.getCaption());
  56. select.setSelectedItem(item1);
  57. assertNotEquals(newCaption, select.getCaption());
  58. select.setSelectedItem(null);
  59. assertEquals(newCaption, select.getCaption());
  60. }
  61. function testNoDefaultCaption() {
  62. assertNull(new goog.ui.Select().getDefaultCaption());
  63. assertEquals('', new goog.ui.Select('').getDefaultCaption());
  64. }
  65. // Confirms that aria roles for select conform to spec:
  66. // http://www.w3.org/TR/wai-aria/roles#listbox
  67. // Basically the select should have a role of LISTBOX and all the items should
  68. // have a role of OPTION.
  69. function testAriaRoles() {
  70. select.render(sandboxEl);
  71. var item1 = new goog.ui.MenuItem('item 1');
  72. select.addItem(item1);
  73. // Added a separator to make sure that the SETSIZE ignores the separator
  74. // items.
  75. var separator = new goog.ui.Separator();
  76. select.addItem(separator);
  77. var item2 = new goog.ui.MenuItem('item 2');
  78. select.addItem(item2);
  79. assertNotNull(select.getElement());
  80. assertNotNull(item1.getElement());
  81. assertNotNull(item2.getElement());
  82. assertEquals(
  83. goog.a11y.aria.Role.LISTBOX, goog.a11y.aria.getRole(select.getElement()));
  84. assertEquals(
  85. goog.a11y.aria.Role.OPTION, goog.a11y.aria.getRole(item1.getElement()));
  86. assertEquals(
  87. goog.a11y.aria.Role.OPTION, goog.a11y.aria.getRole(item2.getElement()));
  88. assertNotNull(
  89. goog.a11y.aria.getState(
  90. select.getElement(), goog.a11y.aria.State.ACTIVEDESCENDANT));
  91. var contentElement =
  92. select.getRenderer().getContentElement(select.getElement());
  93. assertEquals(
  94. '2',
  95. goog.a11y.aria.getState(contentElement, goog.a11y.aria.State.SETSIZE));
  96. assertEquals(
  97. '0',
  98. goog.a11y.aria.getState(contentElement, goog.a11y.aria.State.POSINSET));
  99. select.setSelectedItem(item1);
  100. assertEquals(
  101. '1',
  102. goog.a11y.aria.getState(contentElement, goog.a11y.aria.State.POSINSET));
  103. select.setSelectedItem(item2);
  104. assertEquals(
  105. '2',
  106. goog.a11y.aria.getState(contentElement, goog.a11y.aria.State.POSINSET));
  107. }
  108. /**
  109. * Checks that the select control handles ACTION events from its items.
  110. */
  111. function testHandlesItemActions() {
  112. select.render(sandboxEl);
  113. var item1 = new goog.ui.MenuItem('item 1');
  114. var item2 = new goog.ui.MenuItem('item 2');
  115. select.addItem(item1);
  116. select.addItem(item2);
  117. item1.dispatchEvent(goog.ui.Component.EventType.ACTION);
  118. assertEquals(item1, select.getSelectedItem());
  119. assertEquals(item1.getCaption(), select.getCaption());
  120. item2.dispatchEvent(goog.ui.Component.EventType.ACTION);
  121. assertEquals(item2, select.getSelectedItem());
  122. assertEquals(item2.getCaption(), select.getCaption());
  123. }
  124. /**
  125. * Tests goog.ui.Select.prototype.setValue.
  126. */
  127. function testSetValue() {
  128. select.render(sandboxEl);
  129. var item1 = new goog.ui.MenuItem('item 1', 1);
  130. var item2 = new goog.ui.MenuItem('item 2', 2);
  131. select.addItem(item1);
  132. select.addItem(item2);
  133. select.setValue(1);
  134. assertEquals(item1, select.getSelectedItem());
  135. select.setValue(2);
  136. assertEquals(item2, select.getSelectedItem());
  137. select.setValue(3);
  138. assertNull(select.getSelectedItem());
  139. }
  140. /**
  141. * Checks that the current selection is cleared when the selected item is
  142. * removed.
  143. */
  144. function testSelectionIsClearedWhenSelectedItemIsRemoved() {
  145. select.render(sandboxEl);
  146. var item1 = new goog.ui.MenuItem('item 1');
  147. select.addItem(item1);
  148. select.addItem(new goog.ui.MenuItem('item 2'));
  149. select.setSelectedItem(item1);
  150. select.removeItem(item1);
  151. assertNull(select.getSelectedItem());
  152. }
  153. /**
  154. * Check that the select control is subscribed to its selection model events
  155. * after being added, removed and added back again into the document.
  156. */
  157. function testExitAndEnterDocument() {
  158. var component = new goog.ui.Component();
  159. component.render(sandboxEl);
  160. var item1 = new goog.ui.MenuItem('item 1');
  161. var item2 = new goog.ui.MenuItem('item 2');
  162. var item3 = new goog.ui.MenuItem('item 3');
  163. select.addItem(item1);
  164. select.addItem(item2);
  165. select.addItem(item3);
  166. component.addChild(select, true);
  167. item2.dispatchEvent(goog.ui.Component.EventType.ACTION);
  168. assertEquals(item2.getCaption(), select.getCaption());
  169. component.removeChild(select, true);
  170. item1.dispatchEvent(goog.ui.Component.EventType.ACTION);
  171. assertEquals(item2.getCaption(), select.getCaption());
  172. component.addChild(select, true);
  173. item3.dispatchEvent(goog.ui.Component.EventType.ACTION);
  174. assertEquals(item3.getCaption(), select.getCaption());
  175. }
  176. function testSelectEventFiresForProgrammaticChange() {
  177. select.render();
  178. var item1 = new goog.ui.MenuItem('item 1');
  179. var item2 = new goog.ui.MenuItem('item 2');
  180. select.addItem(item1);
  181. select.addItem(item2);
  182. var recordingHandler = new goog.testing.recordFunction();
  183. goog.events.listen(
  184. select, goog.ui.Component.EventType.CHANGE, recordingHandler);
  185. select.setSelectedItem(item2);
  186. assertEquals(
  187. 'Selecting new item should fire CHANGE event.', 1,
  188. recordingHandler.getCallCount());
  189. select.setSelectedItem(item2);
  190. assertEquals(
  191. 'Selecting the same item should not fire CHANGE event.', 1,
  192. recordingHandler.getCallCount());
  193. select.setSelectedIndex(0);
  194. assertEquals(
  195. 'Selecting new item should fire CHANGE event.', 2,
  196. recordingHandler.getCallCount());
  197. select.setSelectedIndex(0);
  198. assertEquals(
  199. 'Selecting the same item should not fire CHANGE event.', 2,
  200. recordingHandler.getCallCount());
  201. }
  202. function testSelectEventFiresForUserInitiatedAction() {
  203. select.render();
  204. var item1 = new goog.ui.MenuItem('item 1');
  205. var item2 = new goog.ui.MenuItem('item 2');
  206. select.addItem(item1);
  207. select.addItem(item2);
  208. var recordingHandler = new goog.testing.recordFunction();
  209. goog.events.listen(
  210. select, goog.ui.Component.EventType.CHANGE, recordingHandler);
  211. select.setOpen(true);
  212. item2.dispatchEvent(goog.ui.Component.EventType.ACTION);
  213. assertEquals(
  214. 'Selecting new item should fire CHANGE event.', 1,
  215. recordingHandler.getCallCount());
  216. assertFalse(select.isOpen());
  217. select.setOpen(true);
  218. item2.dispatchEvent(goog.ui.Component.EventType.ACTION);
  219. assertEquals(
  220. 'Selecting the same item should not fire CHANGE event.', 1,
  221. recordingHandler.getCallCount());
  222. assertFalse(select.isOpen());
  223. }
  224. /**
  225. * Checks that if an item is selected before decorate is called, the selection
  226. * is preserved after decorate.
  227. */
  228. function testSetSelectedItemBeforeRender() {
  229. select.addItem(new goog.ui.MenuItem('item 1'));
  230. select.addItem(new goog.ui.MenuItem('item 2'));
  231. var item3 = new goog.ui.MenuItem('item 3');
  232. select.addItem(item3);
  233. select.setSelectedItem(item3);
  234. assertEquals(2, select.getSelectedIndex());
  235. select.decorate(sandboxEl);
  236. assertEquals(2, select.getSelectedIndex());
  237. }
  238. /**
  239. * Checks that if a value is set before decorate is called, the value is
  240. * preserved after decorate.
  241. */
  242. function testSetValueBeforeRender() {
  243. select.addItem(new goog.ui.MenuItem('item 1', 1));
  244. select.addItem(new goog.ui.MenuItem('item 2', 2));
  245. select.setValue(2);
  246. assertEquals(2, select.getValue());
  247. select.decorate(sandboxEl);
  248. assertEquals(2, select.getValue());
  249. }
  250. function testUpdateCaption_aria() {
  251. select.render(sandboxEl);
  252. // Verify default state.
  253. assertEquals(defaultCaption, select.getCaption());
  254. assertFalse(
  255. !!goog.a11y.aria.getLabel(
  256. select.getRenderer().getContentElement(select.getElement())));
  257. // Add and select an item with aria-label.
  258. var item1 = new goog.ui.MenuItem();
  259. select.addItem(item1);
  260. item1.getElement().setAttribute('aria-label', 'item1');
  261. select.setSelectedIndex(0);
  262. assertEquals(
  263. 'item1',
  264. goog.a11y.aria.getLabel(
  265. select.getRenderer().getContentElement(select.getElement())));
  266. // Add and select an item without a label.
  267. var item2 = new goog.ui.MenuItem();
  268. select.addItem(item2);
  269. select.setSelectedIndex(1);
  270. assertFalse(
  271. !!goog.a11y.aria.getLabel(
  272. select.getRenderer().getContentElement(select.getElement())));
  273. }
  274. function testDisposeWhenInnerHTMLHasBeenClearedInIE10() {
  275. assertNotThrows(function() {
  276. var customSelect = new goog.ui.Select(
  277. null /* label */, new goog.ui.Menu(),
  278. new goog.ui.CustomButtonRenderer());
  279. customSelect.render(sandboxEl);
  280. // In IE10 setting the innerHTML of a node invalidates the parent child
  281. // relation of all its child nodes (unlike removeNode).
  282. goog.dom.removeChildren(sandboxEl);
  283. // goog.ui.Select's disposeInternal trigger's goog.ui.Component's
  284. // disposeInternal, which triggers goog.ui.MenuButton's exitDocument,
  285. // which closes the associated menu and updates the activeDescendent.
  286. // In the case of a CustomMenuButton the contentElement is referenced by
  287. // element.firstChild.firstChild, an invalid relation in IE 10.
  288. customSelect.dispose();
  289. });
  290. }