# lib/webdriver/locators.js

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