/** @license Copyright 2007-2009 WebDriver committers Copyright 2007-2009 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 A class for working with elements on the page under test. * @author jmleyba@gmail.com (Jason Leyba) */ goog.provide('webdriver.WebElement'); goog.require('goog.array'); goog.require('webdriver.By.Locator'); goog.require('webdriver.By.Strategy'); goog.require('webdriver.CommandName'); goog.require('webdriver.Future'); /** * Represents a DOM element. WebElements can be found by searching from the * document root using a {@code webdriver.WebDriver}, or by searhcing under * another {@code webdriver.WebElement}: * * driver.get('http://www.google.com'); * var searchForm = driver.findElement({tagName: 'form'}); * var searchBox = searchForm.findElement({name: 'q'}); * searchBox.sendKeys('webdriver'); * * @param {webdriver.WebDriver} driver The WebDriver instance that will * actually execute commands. * @constructor */ webdriver.WebElement = function(driver) { /** * The WebDriver instance to issue commands to. * @type {webdriver.WebDriver} * @private */ this.driver_ = driver; /** * The UUID used by WebDriver to identify this element on the page. The ID is * wrapped in a webdriver.Future instance so it can be determined * asynchronously. * @type {webdriver.Future} * @private */ this.elementId_ = new webdriver.Future(this.driver_); }; /** * Adds a command to determine if an element is present under this element in * the DOM tree. * @param {webdriver.By.Locator|{*: string}} locator The locator to use for * finding the element, or a short-hand object that can be converted into a * locator. * @return {webdriver.Future} A future whose value will be set when the driver * completes the search; value will be {@code true} if the element was * found, false otherwise. * @see webdriver.By.Locator.createFromObj */ webdriver.WebElement.prototype.isElementPresent = function(locator) { locator = webdriver.By.Locator.checkLocator(locator); return this.driver_.callFunction(function() { var findCommand = this.driver_. addCommand(webdriver.CommandName.FIND_CHILD_ELEMENT). setParameters({ 'id': this.getId(), 'using': locator.type, 'value': locator.target }); var commandFailed = false; var key = goog.events.listenOnce(findCommand, webdriver.Command.ERROR_EVENT, function(e) { commandFailed = true; this.driver_.abortCommand(e.currentTarget); e.preventDefault(); e.stopPropagation(); return false; }, /*capture phase*/true, this); return this.driver_.callFunction(function() { goog.events.unlistenByKey(key); return !commandFailed; }); }, this); }; /** * Adds a command to search for a single element on the page, restricting the * search to the descendants of the element represented by this instance. * @param {webdriver.By.Locator|{*: string}} locator The locator to use for * finding the element, or a short-hand object that can be converted into a * locator. * @return {webdriver.WebElement} A WebElement that can be used to issue * commands on the found element. The element's ID will be set * asynchronously once the element is successfully located. * @see webdriver.By.Locator.createFromObj */ webdriver.WebElement.prototype.findElement = function(locator) { var webElement = new webdriver.WebElement(this.driver_); locator = webdriver.By.Locator.checkLocator(locator); var command = this.driver_. addCommand(webdriver.CommandName.FIND_CHILD_ELEMENT). setParameters({ 'id': this.getId(), 'using': locator.type, 'value': locator.target }); webElement.getId().setValue(command.getFutureResult()); return webElement; }; /** * Adds a command to search for multiple elements on the page, restricting the * search to the descendants of hte element represented by this instance. * @param {webdriver.By.Locator|{*: string}} locator The locator to use for * finding the element, or a short-hand object that can be converted into a * locator. * @see webdriver.By.Locator.createFromObj */ webdriver.WebElement.prototype.findElements = function(locator) { locator = webdriver.By.Locator.checkLocator(locator); this.driver_.callFunction(function() { this.driver_.addCommand(webdriver.CommandName.FIND_CHILD_ELEMENTS). setParameters({ 'id': this.getId(), 'using': locator.type, 'value': locator.target }); return this.driver_.callFunction(function(ids) { var elements = []; for (var i = 0; i < ids.length; i++) { if (ids[i]) { var element = new webdriver.WebElement(this.driver_); element.getId().setValue(ids[i]); elements.push(element); } } return elements; }, this); }, this); }; /** * @return {webdriver.WebDriver} The driver that this element delegates commands * to. */ webdriver.WebElement.prototype.getDriver = function() { return this.driver_; }; /** * @return {webdriver.Futur} The UUID of this element wrapped in a Future. */ webdriver.WebElement.prototype.getId = function() { return this.elementId_; }; /** * Creates a new {@code webdriver.Command} against the element represented by * this instance. * @param {string} name The name of the command to create. * @return {webdriver.Command} The new command. * @private */ webdriver.WebElement.prototype.createCommand_ = function(name) { return this.driver_.addCommand(name, this); }; /** * Adds a command to click on this element. */ webdriver.WebElement.prototype.click = function() { this.createCommand_(webdriver.CommandName.CLICK); }; /** * Types a sequence on the DOM element represented by this instance. *
* Modifier keys (SHIFT, CONTROL, ALT, META) are stateful; once a modifier is * processed in the keysequence, that key state is toggled until one of the * following occurs: *
* element.sendKeys("text was",
* webdriver.Key.CONTROL, "a", webdriver.Key.NULL,
* "now text is");
* // Alternatively:
* element.sendKeys("text was",
* webdriver.Key.chord(webdriver.Key.CONTROL, "a"),
* "now text is");
*
* // Expect shift down/up for each character.
* element.sendKeys("ABC");
* // Shift is already depressed, so it will not be pushed again for each
* // character.
* element.sendKeys(webdriver.Key.SHIFT, "ABC");
*
*
* Note: On browsers where native keyboard events are not yet
* supported (e.g. Firefox on OS X), key events will be synthesized. Special
* punctionation keys will be synthesized according to a standard QWERTY English
* keyboard layout.
* @param {string|webdriver.Future} var_args The strings to type. All arguments
* will be joined into a single sequence (var_args is permitted for
* convenience).
*/
webdriver.WebElement.prototype.sendKeys = function(var_args) {
var command = this.createCommand_(webdriver.CommandName.SEND_KEYS);
command.setParameters.apply(command, arguments);
};
/**
* Queries for the tag/node name of this element.
*/
webdriver.WebElement.prototype.getTagName = function() {
return this.createCommand_(webdriver.CommandName.GET_TAG_NAME).
getFutureResult();
};
/**
* Queries for the computed style of the element represented by this instance.
* If the element inherits the named style from its parent, the parent will be
* queried for its value. Where possible, color values will be converted to
* their hex representation (#00ff00 instead of rgb(0, 255, 0)).
* Warning: the value returned will be as the browser interprets it, so
* it may be tricky to form a proper assertion.
* @param {string} cssStyleProperty The name of the CSS style property to look
* up.
* @return {webdriver.Future