| /** |
| Copyright 2011 WebDriver committers |
| Copyright 2011 Google Inc. |
| |
| 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. |
| */ |
| |
| /** |
| * @fileoverview Functions for handling HTML SELECT elements. |
| */ |
| |
| goog.provide('core.select'); |
| goog.provide('core.select.option'); |
| |
| goog.require('bot.action'); |
| goog.require('bot.dom'); |
| goog.require('core.Error'); |
| goog.require('core.locators'); |
| goog.require('core.patternMatcher'); |
| |
| |
| |
| /** |
| * @typedef {{findOption: function(!Element):!Element, |
| * assertSelected: function(!Element)}} |
| */ |
| core.select.option.Locator; |
| |
| |
| /** |
| * Create a locator for finding OPTION elements by the selected index. |
| * |
| * @param {string} index The index to use to find an OPTION element. |
| * @return {core.select.option.Locator} The created option locator; |
| */ |
| core.select.option.createIndexLocator_ = function(index) { |
| var toUse = Number(index); |
| |
| if (isNaN(toUse) || toUse < 0) { |
| throw new core.Error("Illegal Index: " + index); |
| } |
| |
| return { |
| findOption: function(element) { |
| if (element.options.length <= toUse) { |
| throw new core.Error( |
| 'Index out of range. Only ' + element.options.length + ' options available'); |
| } |
| return element.options[toUse]; |
| }, |
| |
| assertSelected: function(element) { |
| if (toUse != element.selectedIndex) { |
| throw new core.Error('Selected index (' + element.selectedIndex + |
| ') does not match expected index: ' + toUse); |
| } |
| } |
| }; |
| }; |
| |
| |
| /** |
| * OptionLocator for options identified by their labels. |
| */ |
| core.select.option.createTextLocator_ = function(text) { |
| var matches = core.patternMatcher.against(text); |
| |
| return { |
| findOption: function(element) { |
| for (var i = 0; i < element.options.length; i++) { |
| if (matches(element.options[i].text)) { |
| return element.options[i]; |
| } |
| } |
| throw new core.Error("Option with label '" + text + "' not found"); |
| }, |
| |
| assertSelected: function(element) { |
| var selectedText = element.options[element.selectedIndex].text; |
| if (!matches(selectedText)) { |
| throw new core.Error("Expected text (" + text + ") did not match: " + selectedText); |
| } |
| } |
| }; |
| }; |
| |
| |
| /** |
| * OptionLocator for options identified by their values. |
| */ |
| core.select.option.createValueLocator_ = function(value) { |
| var matcher = core.patternMatcher.against(value); |
| |
| return { |
| findOption: function(element) { |
| for (var i = 0; i < element.options.length; i++) { |
| if (matcher(element.options[i].value)) { |
| return element.options[i]; |
| } |
| } |
| throw new core.Error("Option with value '" + value + "' not found"); |
| }, |
| |
| assertSelected: function(element) { |
| var selectedValue = element.options[element.selectedIndex].value; |
| if (!matcher(selectedValue)) { |
| throw new core.Error("Expected value (" + value + ") did not match: " + selectedValue); |
| } |
| } |
| }; |
| }; |
| |
| |
| /** |
| * OptionLocator for options identified by their id. |
| */ |
| core.select.option.createIdLocator_ = function(id) { |
| var matches = core.patternMatcher.against(id); |
| |
| return { |
| findOption: function(element) { |
| for (var i = 0; i < element.options.length; i++) { |
| if (matches(element.options[i].id)) { |
| return element.options[i]; |
| } |
| } |
| throw new core.Error("Option with id '" + id + "' not found"); |
| }, |
| |
| assertSelected: function(element) { |
| var selectedId = element.options[element.selectedIndex].id; |
| if (!matches(selectedId)) { |
| throw new core.Error("Expected id (" + id + ") did not match: " + selectedId); |
| } |
| } |
| }; |
| }; |
| |
| |
| /** |
| * Option location strategies. |
| * |
| * @const |
| * @type {Object.<string, function(string) : core.select.option.Locator>} |
| */ |
| core.select.option.Locators_ = { |
| 'id': core.select.option.createIdLocator_, |
| 'index': core.select.option.createIndexLocator_, |
| 'label': core.select.option.createTextLocator_, |
| 'text': core.select.option.createTextLocator_, |
| 'value': core.select.option.createValueLocator_ |
| }; |
| |
| /** |
| * Find the correct option locator from a text locator. |
| * |
| * @param {string} optionLocator The option locator as text. |
| * @return {!core.select.option.Locator} An option locator |
| */ |
| core.select.option.getOptionLocator_ = function(optionLocator) { |
| var locatorType = 'label'; |
| var locatorValue = optionLocator; |
| // If there is a locator prefix, use the specified strategy |
| var result = optionLocator.match(/^([a-zA-Z]+)=(.*)/); |
| if (result) { |
| locatorType = result[1]; |
| locatorValue = result[2]; |
| } |
| |
| var locator = core.select.option.Locators_[locatorType]; |
| if (locator) { |
| return locator(locatorValue); |
| } |
| throw new core.Error("Unknown option locator type: " + locatorType); |
| }; |
| |
| |
| /** |
| * @param {string | !Element} locator Locator for a SELECT element. |
| * @return {!Element} The located SELECT element. |
| */ |
| core.select.findSelect = function(locator) { |
| var element = goog.isString(locator) ? core.locators.findElement(locator) : locator; |
| |
| if (goog.isDef(element['options'])) { |
| return element; |
| } |
| |
| throw new core.Error("Specified element is not a Select (has no options)"); |
| }; |
| |
| |
| core.select.option.findOption = function(selectLocator, optionLocator) { |
| var select = core.select.findSelect(selectLocator); |
| var option = core.select.option.getOptionLocator_(optionLocator); |
| |
| return option.findOption(select); |
| }; |
| |
| |
| core.select.findSelectedOptionProperties_ = function(locator, property) { |
| var element = core.select.findSelect(locator); |
| |
| var selectedOptions = []; |
| |
| for (var i = 0; i < element.options.length; i++) { |
| if (element.options[i].selected) { |
| var propVal = element.options[i][property]; |
| selectedOptions.push(propVal); |
| } |
| } |
| |
| if (selectedOptions.length == 0) { |
| throw new core.Error("No option selected"); |
| } |
| |
| return selectedOptions; |
| }; |
| |
| |
| core.select.findSelectedOptionProperty_ = function(locator, property) { |
| var selectedOptions = core.select.findSelectedOptionProperties_(locator, property); |
| |
| if (selectedOptions.length > 1) { |
| throw new core.Error("More than one selected option!"); |
| } |
| |
| return selectedOptions[0]; |
| }; |
| |
| |
| /** |
| * @param {string | !Element} locator an identifying for a SELECT element. |
| * @return {boolean} Whether an some option has been selected. |
| */ |
| core.select.isSomethingSelected = function(locator) { |
| var element = core.select.findSelect(locator); |
| |
| for (var i = 0; i < element.options.length; i++) { |
| if (element.options[i].selected) { |
| return true; |
| } |
| } |
| return false; |
| }; |
| |
| |
| /** |
| * @param {string | Element} locator an identifying for a SELECT element. |
| * @return {string} The visible text of the selected option. |
| */ |
| core.select.getSelectedText = function(locator) { |
| // TODO(simon): This doesn't match "bot.dom.getVisibleText" |
| return core.select.findSelectedOptionProperty_(locator, "text"); |
| }; |
| |
| |
| core.select.setSelected = function(locator, optionLocator) { |
| var select = core.select.findSelect(locator); |
| var foo = core.select.option.getOptionLocator_(optionLocator); |
| var option = foo.findOption(select); |
| |
| if (!bot.dom.isSelected(option)) { |
| bot.action.click(option); |
| } |
| }; |