lib/webdriver/locators.js

1// Copyright 2011 Software Freedom Conservancy. 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
15/**
16 * @fileoverview Factory methods for the supported locator strategies.
17 */
18
19goog.provide('webdriver.By');
20goog.provide('webdriver.Locator');
21goog.provide('webdriver.Locator.Strategy');
22
23goog.require('goog.array');
24goog.require('goog.object');
25goog.require('goog.string');
26
27
28
29/**
30 * An element locator.
31 * @param {string} using The type of strategy to use for this locator.
32 * @param {string} value The search target of this locator.
33 * @constructor
34 */
35webdriver.Locator = function(using, value) {
36
37 /**
38 * The search strategy to use when searching for an element.
39 * @type {string}
40 */
41 this.using = using;
42
43 /**
44 * The search target for this locator.
45 * @type {string}
46 */
47 this.value = value;
48};
49
50
51/**
52 * Creates a factory function for a {@link webdriver.Locator}.
53 * @param {string} type The type of locator for the factory.
54 * @return {function(string): !webdriver.Locator} The new factory function.
55 * @private
56 */
57webdriver.Locator.factory_ = function(type) {
58 return function(value) {
59 return new webdriver.Locator(type, value);
60 };
61};
62
63
64/**
65 * A collection of factory functions for creating {@link webdriver.Locator}
66 * instances.
67 */
68webdriver.By = {};
69// Exported to the global scope for legacy reasons.
70goog.exportSymbol('By', webdriver.By);
71
72
73/**
74 * Short-hand expressions for the primary element locator strategies.
75 * For example the following two statements are equivalent:
76 *
77 * var e1 = driver.findElement(webdriver.By.id('foo'));
78 * var e2 = driver.findElement({id: 'foo'});
79 *
80 * Care should be taken when using JavaScript minifiers (such as the
81 * Closure compiler), as locator hashes will always be parsed using
82 * the un-obfuscated properties listed.
83 *
84 * @typedef {(
85 * {className: string}|
86 * {css: string}|
87 * {id: string}|
88 * {js: string}|
89 * {linkText: string}|
90 * {name: string}|
91 * {partialLinkText: string}|
92 * {tagName: string}|
93 * {xpath: string})}
94 */
95webdriver.By.Hash;
96
97
98/**
99 * Locates elements that have a specific class name. The returned locator
100 * is equivalent to searching for elements with the CSS selector ".clazz".
101 *
102 * @param {string} className The class name to search for.
103 * @return {!webdriver.Locator} The new locator.
104 * @see http://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes
105 * @see http://www.w3.org/TR/CSS2/selector.html#class-html
106 */
107webdriver.By.className = webdriver.Locator.factory_('class name');
108
109
110/**
111 * Locates elements using a CSS selector. For browsers that do not support
112 * CSS selectors, WebDriver implementations may return an
113 * {@linkplain bot.Error.State.INVALID_SELECTOR invalid selector} error. An
114 * implementation may, however, emulate the CSS selector API.
115 *
116 * @param {string} selector The CSS selector to use.
117 * @return {!webdriver.Locator} The new locator.
118 * @see http://www.w3.org/TR/CSS2/selector.html
119 */
120webdriver.By.css = webdriver.Locator.factory_('css selector');
121
122
123/**
124 * Locates an element by its ID.
125 *
126 * @param {string} id The ID to search for.
127 * @return {!webdriver.Locator} The new locator.
128 */
129webdriver.By.id = webdriver.Locator.factory_('id');
130
131
132/**
133 * Locates link elements whose {@linkplain webdriver.WebElement#getText visible
134 * text} matches the given string.
135 *
136 * @param {string} text The link text to search for.
137 * @return {!webdriver.Locator} The new locator.
138 */
139webdriver.By.linkText = webdriver.Locator.factory_('link text');
140
141
142/**
143 * Locates an elements by evaluating a
144 * {@linkplain webdriver.WebDriver#executeScript JavaScript expression}.
145 * The result of this expression must be an element or list of elements.
146 *
147 * @param {!(string|Function)} script The script to execute.
148 * @param {...*} var_args The arguments to pass to the script.
149 * @return {function(!webdriver.WebDriver): !webdriver.promise.Promise} A new,
150 * JavaScript-based locator function.
151 */
152webdriver.By.js = function(script, var_args) {
153 var args = goog.array.slice(arguments, 0);
154 return function(driver) {
155 return driver.executeScript.apply(driver, args);
156 };
157};
158
159
160/**
161 * Locates elements whose {@code name} attribute has the given value.
162 *
163 * @param {string} name The name attribute to search for.
164 * @return {!webdriver.Locator} The new locator.
165 */
166webdriver.By.name = webdriver.Locator.factory_('name');
167
168
169/**
170 * Locates link elements whose {@linkplain webdriver.WebElement#getText visible
171 * text} contains the given substring.
172 *
173 * @param {string} text The substring to check for in a link's visible text.
174 * @return {!webdriver.Locator} The new locator.
175 */
176webdriver.By.partialLinkText = webdriver.Locator.factory_(
177 'partial link text');
178
179
180/**
181 * Locates elements with a given tag name. The returned locator is
182 * equivalent to using the
183 * [getElementsByTagName](https://developer.mozilla.org/en-US/docs/Web/API/Element.getElementsByTagName)
184 * DOM function.
185 *
186 * @param {string} text The substring to check for in a link's visible text.
187 * @return {!webdriver.Locator} The new locator.
188 * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html
189 */
190webdriver.By.tagName = webdriver.Locator.factory_('tag name');
191
192
193/**
194 * Locates elements matching a XPath selector. Care should be taken when
195 * using an XPath selector with a {@link webdriver.WebElement} as WebDriver
196 * will respect the context in the specified in the selector. For example,
197 * given the selector {@code "//div"}, WebDriver will search from the
198 * document root regardless of whether the locator was used with a
199 * WebElement.
200 *
201 * @param {string} xpath The XPath selector to use.
202 * @return {!webdriver.Locator} The new locator.
203 * @see http://www.w3.org/TR/xpath/
204 */
205webdriver.By.xpath = webdriver.Locator.factory_('xpath');
206
207
208/**
209 * Maps {@link webdriver.By.Hash} keys to the appropriate factory function.
210 * @type {!Object.<string, function(string): !(Function|webdriver.Locator)>}
211 * @const
212 */
213webdriver.Locator.Strategy = {
214 'className': webdriver.By.className,
215 'css': webdriver.By.css,
216 'id': webdriver.By.id,
217 'js': webdriver.By.js,
218 'linkText': webdriver.By.linkText,
219 'name': webdriver.By.name,
220 'partialLinkText': webdriver.By.partialLinkText,
221 'tagName': webdriver.By.tagName,
222 'xpath': webdriver.By.xpath
223};
224
225
226/**
227 * Verifies that a {@code value} is a valid locator to use for searching for
228 * elements on the page.
229 *
230 * @param {*} value The value to check is a valid locator.
231 * @return {!(webdriver.Locator|Function)} A valid locator object or function.
232 * @throws {TypeError} If the given value is an invalid locator.
233 */
234webdriver.Locator.checkLocator = function(value) {
235 if (goog.isFunction(value) || value instanceof webdriver.Locator) {
236 return value;
237 }
238 for (var key in value) {
239 if (value.hasOwnProperty(key) &&
240 webdriver.Locator.Strategy.hasOwnProperty(key)) {
241 return webdriver.Locator.Strategy[key](value[key]);
242 }
243 }
244 throw new TypeError('Invalid locator');
245};
246
247
248
249/** @override */
250webdriver.Locator.prototype.toString = function() {
251 return 'By.' + this.using.replace(/ ([a-z])/g, function(all, match) {
252 return match.toUpperCase();
253 }) + '(' + goog.string.quote(this.value) + ')';
254};