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 | * <code><pre> |
77 | * var e1 = driver.findElement(webdriver.By.id('foo')); |
78 | * var e2 = driver.findElement({id: 'foo'}); |
79 | * </pre></code> |
80 | * |
81 | * <p>Care should be taken when using JavaScript minifiers (such as the |
82 | * Closure compiler), as locator hashes will always be parsed using |
83 | * the un-obfuscated properties listed below. |
84 | * |
85 | * @typedef {( |
86 | * {className: string}| |
87 | * {css: string}| |
88 | * {id: string}| |
89 | * {js: string}| |
90 | * {linkText: string}| |
91 | * {name: string}| |
92 | * {partialLinkText: string}| |
93 | * {tagName: string}| |
94 | * {xpath: string})} |
95 | */ |
96 | webdriver.By.Hash; |
97 | |
98 | |
99 | /** |
100 | * Locates elements that have a specific class name. The returned locator |
101 | * is equivalent to searching for elements with the CSS selector ".clazz". |
102 | * |
103 | * @param {string} className The class name to search for. |
104 | * @return {!webdriver.Locator} The new locator. |
105 | * @see http://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes |
106 | * @see http://www.w3.org/TR/CSS2/selector.html#class-html |
107 | */ |
108 | webdriver.By.className = webdriver.Locator.factory_('class name'); |
109 | |
110 | |
111 | /** |
112 | * Locates elements using a CSS selector. For browsers that do not support |
113 | * CSS selectors, WebDriver implementations may return an |
114 | * {@link bot.Error.State.INVALID_SELECTOR invalid selector} error. An |
115 | * implementation may, however, emulate the CSS selector API. |
116 | * |
117 | * @param {string} selector The CSS selector to use. |
118 | * @return {!webdriver.Locator} The new locator. |
119 | * @see http://www.w3.org/TR/CSS2/selector.html |
120 | */ |
121 | webdriver.By.css = webdriver.Locator.factory_('css selector'); |
122 | |
123 | |
124 | /** |
125 | * Locates an element by its ID. |
126 | * |
127 | * @param {string} id The ID to search for. |
128 | * @return {!webdriver.Locator} The new locator. |
129 | */ |
130 | webdriver.By.id = webdriver.Locator.factory_('id'); |
131 | |
132 | |
133 | /** |
134 | * Locates link elements whose {@link webdriver.WebElement#getText visible |
135 | * text} matches the given string. |
136 | * |
137 | * @param {string} text The link text to search for. |
138 | * @return {!webdriver.Locator} The new locator. |
139 | */ |
140 | webdriver.By.linkText = webdriver.Locator.factory_('link text'); |
141 | |
142 | |
143 | /** |
144 | * Locates an elements by evaluating a |
145 | * {@link webdriver.WebDriver#executeScript JavaScript expression}. |
146 | * The result of this expression must be an element or list of elements. |
147 | * |
148 | * @param {!(string|Function)} script The script to execute. |
149 | * @param {...*} var_args The arguments to pass to the script. |
150 | * @return {function(!webdriver.WebDriver): !webdriver.promise.Promise} A new, |
151 | * JavaScript-based locator function. |
152 | */ |
153 | webdriver.By.js = function(script, var_args) { |
154 | var args = goog.array.slice(arguments, 0); |
155 | return function(driver) { |
156 | return driver.executeScript.apply(driver, args); |
157 | }; |
158 | }; |
159 | |
160 | |
161 | /** |
162 | * Locates elements whose {@code name} attribute has the given value. |
163 | * |
164 | * @param {string} name The name attribute to search for. |
165 | * @return {!webdriver.Locator} The new locator. |
166 | */ |
167 | webdriver.By.name = webdriver.Locator.factory_('name'); |
168 | |
169 | |
170 | /** |
171 | * Locates link elements whose {@link webdriver.WebElement#getText visible |
172 | * text} contains the given substring. |
173 | * |
174 | * @param {string} text The substring to check for in a link's visible text. |
175 | * @return {!webdriver.Locator} The new locator. |
176 | */ |
177 | webdriver.By.partialLinkText = webdriver.Locator.factory_( |
178 | 'partial link text'); |
179 | |
180 | |
181 | /** |
182 | * Locates elements with a given tag name. The returned locator is |
183 | * equivalent to using the {@code getElementsByTagName} DOM function. |
184 | * |
185 | * @param {string} text The substring to check for in a link's visible text. |
186 | * @return {!webdriver.Locator} The new locator. |
187 | * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html |
188 | */ |
189 | webdriver.By.tagName = webdriver.Locator.factory_('tag name'); |
190 | |
191 | |
192 | /** |
193 | * Locates elements matching a XPath selector. Care should be taken when |
194 | * using an XPath selector with a {@link webdriver.WebElement} as WebDriver |
195 | * will respect the context in the specified in the selector. For example, |
196 | * given the selector {@code "//div"}, WebDriver will search from the |
197 | * document root regardless of whether the locator was used with a |
198 | * WebElement. |
199 | * |
200 | * @param {string} xpath The XPath selector to use. |
201 | * @return {!webdriver.Locator} The new locator. |
202 | * @see http://www.w3.org/TR/xpath/ |
203 | */ |
204 | webdriver.By.xpath = webdriver.Locator.factory_('xpath'); |
205 | |
206 | |
207 | /** |
208 | * Maps {@link webdriver.By.Hash} keys to the appropriate factory function. |
209 | * @type {!Object.<string, function(string): !(Function|webdriver.Locator)>} |
210 | * @const |
211 | */ |
212 | webdriver.Locator.Strategy = { |
213 | 'className': webdriver.By.className, |
214 | 'css': webdriver.By.css, |
215 | 'id': webdriver.By.id, |
216 | 'js': webdriver.By.js, |
217 | 'linkText': webdriver.By.linkText, |
218 | 'name': webdriver.By.name, |
219 | 'partialLinkText': webdriver.By.partialLinkText, |
220 | 'tagName': webdriver.By.tagName, |
221 | 'xpath': webdriver.By.xpath |
222 | }; |
223 | |
224 | |
225 | /** |
226 | * Verifies that a {@code value} is a valid locator to use for searching for |
227 | * elements on the page. |
228 | * |
229 | * @param {*} value The value to check is a valid locator. |
230 | * @return {!(webdriver.Locator|Function)} A valid locator object or function. |
231 | * @throws {TypeError} If the given value is an invalid locator. |
232 | */ |
233 | webdriver.Locator.checkLocator = function(value) { |
234 | if (goog.isFunction(value) || value instanceof webdriver.Locator) { |
235 | return value; |
236 | } |
237 | for (var key in value) { |
238 | if (value.hasOwnProperty(key) && |
239 | webdriver.Locator.Strategy.hasOwnProperty(key)) { |
240 | return webdriver.Locator.Strategy[key](value[key]); |
241 | } |
242 | } |
243 | throw new TypeError('Invalid locator'); |
244 | }; |
245 | |
246 | |
247 | |
248 | /** @override */ |
249 | webdriver.Locator.prototype.toString = function() { |
250 | return 'By.' + this.using.replace(/ ([a-z])/g, function(all, match) { |
251 | return match.toUpperCase(); |
252 | }) + '(' + goog.string.quote(this.value) + ')'; |
253 | }; |