blob: 5f42d6cff8a59f795be3a5b95661108db3de9f9e [file] [log] [blame]
// 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();
});
}