| // Copyright 2010 The Closure Library Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS-IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| goog.provide('goog.ui.SelectTest'); |
| goog.setTestOnly('goog.ui.SelectTest'); |
| |
| goog.require('goog.a11y.aria'); |
| goog.require('goog.a11y.aria.Role'); |
| goog.require('goog.a11y.aria.State'); |
| goog.require('goog.dom'); |
| goog.require('goog.events'); |
| goog.require('goog.testing.jsunit'); |
| goog.require('goog.testing.recordFunction'); |
| goog.require('goog.ui.Component'); |
| goog.require('goog.ui.CustomButtonRenderer'); |
| goog.require('goog.ui.Menu'); |
| goog.require('goog.ui.MenuItem'); |
| goog.require('goog.ui.Select'); |
| goog.require('goog.ui.Separator'); |
| |
| var defaultCaption = 'initial caption'; |
| var sandboxEl; |
| var select; |
| |
| function setUp() { |
| sandboxEl = goog.dom.getElement('sandbox'); |
| select = new goog.ui.Select(defaultCaption); |
| } |
| |
| function tearDown() { |
| select.dispose(); |
| goog.dom.removeChildren(sandboxEl); |
| } |
| |
| |
| /** |
| * Checks that the default caption passed in the constructor and in the setter |
| * is returned by getDefaultCaption, and acts as a default caption, i.e. is |
| * shown as a caption when no items are selected. |
| */ |
| function testDefaultCaption() { |
| select.render(sandboxEl); |
| var item1 = new goog.ui.MenuItem('item 1'); |
| select.addItem(item1); |
| select.addItem(new goog.ui.MenuItem('item 2')); |
| assertEquals(defaultCaption, select.getDefaultCaption()); |
| assertEquals(defaultCaption, select.getCaption()); |
| |
| var newCaption = 'new caption'; |
| select.setDefaultCaption(newCaption); |
| assertEquals(newCaption, select.getDefaultCaption()); |
| assertEquals(newCaption, select.getCaption()); |
| |
| select.setSelectedItem(item1); |
| assertNotEquals(newCaption, select.getCaption()); |
| |
| select.setSelectedItem(null); |
| assertEquals(newCaption, select.getCaption()); |
| } |
| |
| function testNoDefaultCaption() { |
| assertNull(new goog.ui.Select().getDefaultCaption()); |
| assertEquals('', new goog.ui.Select('').getDefaultCaption()); |
| } |
| |
| // Confirms that aria roles for select conform to spec: |
| // http://www.w3.org/TR/wai-aria/roles#listbox |
| // Basically the select should have a role of LISTBOX and all the items should |
| // have a role of OPTION. |
| function testAriaRoles() { |
| select.render(sandboxEl); |
| var item1 = new goog.ui.MenuItem('item 1'); |
| select.addItem(item1); |
| // Added a separator to make sure that the SETSIZE ignores the separator |
| // items. |
| var separator = new goog.ui.Separator(); |
| select.addItem(separator); |
| var item2 = new goog.ui.MenuItem('item 2'); |
| select.addItem(item2); |
| assertNotNull(select.getElement()); |
| assertNotNull(item1.getElement()); |
| assertNotNull(item2.getElement()); |
| assertEquals(goog.a11y.aria.Role.LISTBOX, |
| goog.a11y.aria.getRole(select.getElement())); |
| assertEquals(goog.a11y.aria.Role.OPTION, |
| goog.a11y.aria.getRole(item1.getElement())); |
| assertEquals(goog.a11y.aria.Role.OPTION, |
| goog.a11y.aria.getRole(item2.getElement())); |
| assertNotNull(goog.a11y.aria.getState(select.getElement(), |
| goog.a11y.aria.State.ACTIVEDESCENDANT)); |
| var contentElement = select.getRenderer(). |
| getContentElement(select.getElement()); |
| assertEquals('2', goog.a11y.aria.getState(contentElement, |
| goog.a11y.aria.State.SETSIZE)); |
| assertEquals('0', goog.a11y.aria.getState(contentElement, |
| goog.a11y.aria.State.POSINSET)); |
| } |
| |
| |
| /** |
| * Checks that the select control handles ACTION events from its items. |
| */ |
| function testHandlesItemActions() { |
| select.render(sandboxEl); |
| var item1 = new goog.ui.MenuItem('item 1'); |
| var item2 = new goog.ui.MenuItem('item 2'); |
| select.addItem(item1); |
| select.addItem(item2); |
| |
| item1.dispatchEvent(goog.ui.Component.EventType.ACTION); |
| assertEquals(item1, select.getSelectedItem()); |
| assertEquals(item1.getCaption(), select.getCaption()); |
| |
| item2.dispatchEvent(goog.ui.Component.EventType.ACTION); |
| assertEquals(item2, select.getSelectedItem()); |
| assertEquals(item2.getCaption(), select.getCaption()); |
| } |
| |
| |
| /** |
| * Tests goog.ui.Select.prototype.setValue. |
| */ |
| function testSetValue() { |
| select.render(sandboxEl); |
| var item1 = new goog.ui.MenuItem('item 1', 1); |
| var item2 = new goog.ui.MenuItem('item 2', 2); |
| select.addItem(item1); |
| select.addItem(item2); |
| |
| select.setValue(1); |
| assertEquals(item1, select.getSelectedItem()); |
| |
| select.setValue(2); |
| assertEquals(item2, select.getSelectedItem()); |
| |
| select.setValue(3); |
| assertNull(select.getSelectedItem()); |
| } |
| |
| |
| /** |
| * Checks that the current selection is cleared when the selected item is |
| * removed. |
| */ |
| function testSelectionIsClearedWhenSelectedItemIsRemoved() { |
| select.render(sandboxEl); |
| var item1 = new goog.ui.MenuItem('item 1'); |
| select.addItem(item1); |
| select.addItem(new goog.ui.MenuItem('item 2')); |
| |
| select.setSelectedItem(item1); |
| select.removeItem(item1); |
| assertNull(select.getSelectedItem()); |
| } |
| |
| |
| /** |
| * Check that the select control is subscribed to its selection model events |
| * after being added, removed and added back again into the document. |
| */ |
| function testExitAndEnterDocument() { |
| var component = new goog.ui.Component(); |
| component.render(sandboxEl); |
| |
| var item1 = new goog.ui.MenuItem('item 1'); |
| var item2 = new goog.ui.MenuItem('item 2'); |
| var item3 = new goog.ui.MenuItem('item 3'); |
| |
| select.addItem(item1); |
| select.addItem(item2); |
| select.addItem(item3); |
| |
| component.addChild(select, true); |
| item2.dispatchEvent(goog.ui.Component.EventType.ACTION); |
| assertEquals(item2.getCaption(), select.getCaption()); |
| |
| component.removeChild(select, true); |
| item1.dispatchEvent(goog.ui.Component.EventType.ACTION); |
| assertEquals(item2.getCaption(), select.getCaption()); |
| |
| component.addChild(select, true); |
| item3.dispatchEvent(goog.ui.Component.EventType.ACTION); |
| assertEquals(item3.getCaption(), select.getCaption()); |
| } |
| |
| function testSelectEventFiresForProgrammaticChange() { |
| select.render(); |
| var item1 = new goog.ui.MenuItem('item 1'); |
| var item2 = new goog.ui.MenuItem('item 2'); |
| select.addItem(item1); |
| select.addItem(item2); |
| |
| var recordingHandler = new goog.testing.recordFunction(); |
| goog.events.listen( |
| select, goog.ui.Component.EventType.CHANGE, recordingHandler); |
| |
| select.setSelectedItem(item2); |
| assertEquals('Selecting new item should fire CHANGE event.', |
| 1, recordingHandler.getCallCount()); |
| |
| select.setSelectedItem(item2); |
| assertEquals('Selecting the same item should not fire CHANGE event.', |
| 1, recordingHandler.getCallCount()); |
| |
| select.setSelectedIndex(0); |
| assertEquals('Selecting new item should fire CHANGE event.', |
| 2, recordingHandler.getCallCount()); |
| |
| select.setSelectedIndex(0); |
| assertEquals('Selecting the same item should not fire CHANGE event.', |
| 2, recordingHandler.getCallCount()); |
| } |
| |
| function testSelectEventFiresForUserInitiatedAction() { |
| select.render(); |
| var item1 = new goog.ui.MenuItem('item 1'); |
| var item2 = new goog.ui.MenuItem('item 2'); |
| select.addItem(item1); |
| select.addItem(item2); |
| |
| var recordingHandler = new goog.testing.recordFunction(); |
| goog.events.listen( |
| select, goog.ui.Component.EventType.CHANGE, recordingHandler); |
| |
| select.setOpen(true); |
| |
| item2.dispatchEvent(goog.ui.Component.EventType.ACTION); |
| assertEquals('Selecting new item should fire CHANGE event.', |
| 1, recordingHandler.getCallCount()); |
| assertFalse(select.isOpen()); |
| |
| select.setOpen(true); |
| |
| item2.dispatchEvent(goog.ui.Component.EventType.ACTION); |
| assertEquals('Selecting the same item should not fire CHANGE event.', |
| 1, recordingHandler.getCallCount()); |
| assertFalse(select.isOpen()); |
| } |
| |
| |
| /** |
| * Checks that if an item is selected before decorate is called, the selection |
| * is preserved after decorate. |
| */ |
| function testSetSelectedItemBeforeRender() { |
| select.addItem(new goog.ui.MenuItem('item 1')); |
| select.addItem(new goog.ui.MenuItem('item 2')); |
| var item3 = new goog.ui.MenuItem('item 3'); |
| select.addItem(item3); |
| select.setSelectedItem(item3); |
| assertEquals(2, select.getSelectedIndex()); |
| |
| select.decorate(sandboxEl); |
| assertEquals(2, select.getSelectedIndex()); |
| } |
| |
| |
| /** |
| * Checks that if a value is set before decorate is called, the value is |
| * preserved after decorate. |
| */ |
| function testSetValueBeforeRender() { |
| select.addItem(new goog.ui.MenuItem('item 1', 1)); |
| select.addItem(new goog.ui.MenuItem('item 2', 2)); |
| select.setValue(2); |
| assertEquals(2, select.getValue()); |
| |
| select.decorate(sandboxEl); |
| assertEquals(2, select.getValue()); |
| } |
| |
| |
| function testUpdateCaption_aria() { |
| select.render(sandboxEl); |
| |
| // Verify default state. |
| assertEquals(defaultCaption, select.getCaption()); |
| assertFalse( |
| !!goog.a11y.aria.getLabel( |
| select.getRenderer().getContentElement(select.getElement()))); |
| |
| // Add and select an item with aria-label. |
| var item1 = new goog.ui.MenuItem(); |
| select.addItem(item1); |
| item1.getElement().setAttribute('aria-label', 'item1'); |
| select.setSelectedIndex(0); |
| assertEquals( |
| 'item1', |
| goog.a11y.aria.getLabel( |
| select.getRenderer().getContentElement(select.getElement()))); |
| |
| // Add and select an item without a label. |
| var item2 = new goog.ui.MenuItem(); |
| select.addItem(item2); |
| select.setSelectedIndex(1); |
| assertFalse( |
| !!goog.a11y.aria.getLabel( |
| select.getRenderer().getContentElement(select.getElement()))); |
| } |
| |
| function testDisposeWhenInnerHTMLHasBeenClearedInIE10() { |
| assertNotThrows(function() { |
| var customSelect = new goog.ui.Select(null /* label */, new goog.ui.Menu(), |
| new goog.ui.CustomButtonRenderer()); |
| customSelect.render(sandboxEl); |
| |
| // In IE10 setting the innerHTML of a node invalidates the parent child |
| // relation of all its child nodes (unlike removeNode). |
| sandboxEl.innerHTML = ''; |
| |
| // goog.ui.Select's disposeInternal trigger's goog.ui.Component's |
| // disposeInternal, which triggers goog.ui.MenuButton's exitDocument, |
| // which closes the associated menu and updates the activeDescendent. |
| // In the case of a CustomMenuButton the contentElement is referenced by |
| // element.firstChild.firstChild, an invalid relation in IE 10. |
| customSelect.dispose(); |
| }); |
| } |