# 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 |
19 | goog.provide('webdriver.By');
20 | goog.provide('webdriver.Locator');
21 | goog.provide('webdriver.Locator.Strategy');
22 |
23 | goog.require('goog.array');
24 | goog.require('goog.object');
25 | goog.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 | */
35 | webdriver.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 | */
57 | webdriver.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 | */
68 | webdriver.By = {};
69 | // Exported to the global scope for legacy reasons.
70 | goog.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 | */
95 | webdriver.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 | */
107 | webdriver.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 | */
120 | webdriver.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 | */
129 | webdriver.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 | */
139 | webdriver.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 | */
152 | webdriver.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 | */
166 | webdriver.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 | */
176 | webdriver.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 | */
190 | webdriver.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 | */
205 | webdriver.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 | */
213 | webdriver.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 | */
234 | webdriver.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 */
250 | webdriver.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 | };