selenium-webdriver 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/chrome/prebuilt/Win32/Release/npchromedriver.dll +0 -0
  2. data/chrome/prebuilt/x64/Release/npchromedriver.dll +0 -0
  3. data/chrome/src/extension/background.html +9 -0
  4. data/chrome/src/extension/background.js +933 -0
  5. data/chrome/src/extension/content_script.js +1286 -0
  6. data/chrome/src/extension/manifest-nonwin.json +15 -0
  7. data/chrome/src/extension/manifest-win.json +16 -0
  8. data/chrome/src/extension/toolstrip.html +28 -0
  9. data/chrome/src/extension/utils.js +196 -0
  10. data/chrome/src/rb/lib/selenium/webdriver/chrome.rb +8 -0
  11. data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +324 -0
  12. data/chrome/src/rb/lib/selenium/webdriver/chrome/command_executor.rb +70 -0
  13. data/chrome/src/rb/lib/selenium/webdriver/chrome/launcher.rb +119 -0
  14. data/common/src/js/abstractcommandprocessor.js +161 -0
  15. data/common/src/js/asserts.js +296 -0
  16. data/common/src/js/by.js +147 -0
  17. data/common/src/js/command.js +274 -0
  18. data/common/src/js/context.js +58 -0
  19. data/common/src/js/extension/README +2 -0
  20. data/common/src/js/extension/dommessenger.js +152 -0
  21. data/common/src/js/factory.js +55 -0
  22. data/common/src/js/future.js +118 -0
  23. data/common/src/js/key.js +117 -0
  24. data/common/src/js/localcommandprocessor.js +181 -0
  25. data/common/src/js/logging.js +249 -0
  26. data/common/src/js/testrunner.js +605 -0
  27. data/common/src/js/timing.js +89 -0
  28. data/common/src/js/wait.js +199 -0
  29. data/common/src/js/webdriver.js +853 -0
  30. data/common/src/js/webelement.js +683 -0
  31. data/common/src/rb/lib/selenium-webdriver.rb +1 -0
  32. data/common/src/rb/lib/selenium/webdriver.rb +52 -0
  33. data/common/src/rb/lib/selenium/webdriver/bridge_helper.rb +88 -0
  34. data/common/src/rb/lib/selenium/webdriver/child_process.rb +85 -0
  35. data/common/src/rb/lib/selenium/webdriver/core_ext/dir.rb +41 -0
  36. data/common/src/rb/lib/selenium/webdriver/driver.rb +128 -0
  37. data/common/src/rb/lib/selenium/webdriver/element.rb +126 -0
  38. data/common/src/rb/lib/selenium/webdriver/error.rb +68 -0
  39. data/common/src/rb/lib/selenium/webdriver/find.rb +69 -0
  40. data/common/src/rb/lib/selenium/webdriver/navigation.rb +23 -0
  41. data/common/src/rb/lib/selenium/webdriver/options.rb +50 -0
  42. data/common/src/rb/lib/selenium/webdriver/platform.rb +82 -0
  43. data/common/src/rb/lib/selenium/webdriver/target_locator.rb +23 -0
  44. data/firefox/prebuilt/nsICommandProcessor.xpt +0 -0
  45. data/firefox/prebuilt/nsINativeEvents.xpt +0 -0
  46. data/firefox/prebuilt/nsIResponseHandler.xpt +0 -0
  47. data/firefox/src/extension/chrome.manifest +3 -0
  48. data/firefox/src/extension/components/context.js +37 -0
  49. data/firefox/src/extension/components/driver-component.js +127 -0
  50. data/firefox/src/extension/components/firefoxDriver.js +706 -0
  51. data/firefox/src/extension/components/json2.js +273 -0
  52. data/firefox/src/extension/components/keytest.html +554 -0
  53. data/firefox/src/extension/components/nsCommandProcessor.js +586 -0
  54. data/firefox/src/extension/components/screenshooter.js +70 -0
  55. data/firefox/src/extension/components/socketListener.js +185 -0
  56. data/firefox/src/extension/components/utils.js +1200 -0
  57. data/firefox/src/extension/components/webLoadingListener.js +57 -0
  58. data/firefox/src/extension/components/webdriverserver.js +101 -0
  59. data/firefox/src/extension/components/wrappedElement.js +609 -0
  60. data/firefox/src/extension/content/fxdriver.xul +30 -0
  61. data/firefox/src/extension/content/server.js +95 -0
  62. data/firefox/src/extension/idl/nsICommandProcessor.idl +38 -0
  63. data/firefox/src/extension/idl/nsIResponseHandler.idl +34 -0
  64. data/firefox/src/extension/install.rdf +29 -0
  65. data/firefox/src/rb/lib/selenium/webdriver/firefox.rb +21 -0
  66. data/firefox/src/rb/lib/selenium/webdriver/firefox/binary.rb +86 -0
  67. data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +426 -0
  68. data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +82 -0
  69. data/firefox/src/rb/lib/selenium/webdriver/firefox/launcher.rb +132 -0
  70. data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +174 -0
  71. data/firefox/src/rb/lib/selenium/webdriver/firefox/profiles_ini.rb +60 -0
  72. data/firefox/src/rb/lib/selenium/webdriver/firefox/util.rb +23 -0
  73. data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
  74. data/jobbie/prebuilt/x64/Release/InternetExplorerDriver.dll +0 -0
  75. data/jobbie/src/rb/lib/selenium/webdriver/ie.rb +14 -0
  76. data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +552 -0
  77. data/jobbie/src/rb/lib/selenium/webdriver/ie/lib.rb +94 -0
  78. data/jobbie/src/rb/lib/selenium/webdriver/ie/util.rb +147 -0
  79. data/remote/client/src/rb/lib/selenium/webdriver/remote.rb +16 -0
  80. data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +374 -0
  81. data/remote/client/src/rb/lib/selenium/webdriver/remote/capabilities.rb +105 -0
  82. data/remote/client/src/rb/lib/selenium/webdriver/remote/commands.rb +53 -0
  83. data/remote/client/src/rb/lib/selenium/webdriver/remote/default_http_client.rb +71 -0
  84. data/remote/client/src/rb/lib/selenium/webdriver/remote/response.rb +43 -0
  85. data/remote/client/src/rb/lib/selenium/webdriver/remote/server_error.rb +32 -0
  86. metadata +182 -0
@@ -0,0 +1,683 @@
1
+ /** @license
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ 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, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+
18
+ /**
19
+ * @fileoverview A class for working with elements on the page under test.
20
+ * @author jmleyba@gmail.com (Jason Leyba)
21
+ */
22
+
23
+ goog.provide('webdriver.WebElement');
24
+
25
+ goog.require('goog.array');
26
+ goog.require('goog.math.Coordinate');
27
+ goog.require('goog.math.Size');
28
+ goog.require('webdriver.By.Locator');
29
+ goog.require('webdriver.By.Strategy');
30
+ goog.require('webdriver.Command');
31
+ goog.require('webdriver.CommandName');
32
+ goog.require('webdriver.Future');
33
+
34
+
35
+ /**
36
+ * Represents a DOM element. WebElements can be found by searching from the
37
+ * document root using a {@code webdriver.WebDriver}, or by searhcing under
38
+ * another {@code webdriver.WebElement}:
39
+ *
40
+ * driver.get('http://www.google.com');
41
+ * var searchForm = driver.findElement({tagName: 'form'});
42
+ * var searchBox = searchForm.findElement({name: 'q'});
43
+ * searchBox.sendKeys('webdriver');
44
+ *
45
+ * @param {webdriver.WebDriver} driver The WebDriver instance that will
46
+ * actually execute commands.
47
+ * @constructor
48
+ */
49
+ webdriver.WebElement = function(driver) {
50
+
51
+ /**
52
+ * The WebDriver instance to issue commands to.
53
+ * @type {webdriver.WebDriver}
54
+ * @private
55
+ */
56
+ this.driver_ = driver;
57
+
58
+ /**
59
+ * The UUID used by WebDriver to identify this element on the page. The ID is
60
+ * wrapped in a webdriver.Future instance so it can be determined
61
+ * asynchronously.
62
+ * @type {webdriver.Future}
63
+ * @private
64
+ */
65
+ this.elementId_ = new webdriver.Future(this.driver_);
66
+ };
67
+
68
+
69
+ /**
70
+ * Regular expression for a UUID.
71
+ * @type {RegExp}
72
+ * @static
73
+ */
74
+ webdriver.WebElement.UUID_REGEX =
75
+ /^{[\da-z]{8}-[\da-z]{4}-[\da-z]{4}-[\da-z]{4}-[\da-z]{12}}$/i;
76
+
77
+
78
+ /**
79
+ * Adds a command to the given {@code webdriver.WebDriver} instance to find an
80
+ * element on the page.
81
+ * @param {webdriver.WebDriver} driver The driver to perform the search with.
82
+ * @param {webdriver.By.Locator|{*: string}} locator The locator to use for
83
+ * finding the element, or a short-hand object that can be converted into a
84
+ * locator.
85
+ * @return {webdriver.WebElement} A WebElement that can be used to issue
86
+ * commands on the found element. The element's ID will be set
87
+ * asynchronously once the driver successfully finds the element.
88
+ * @see webdriver.By.Locator.createFromObj
89
+ */
90
+ webdriver.WebElement.findElement = function(driver, locator) {
91
+ var webElement = new webdriver.WebElement(driver);
92
+ locator = webdriver.By.Locator.checkLocator(locator);
93
+ var command = new webdriver.Command(webdriver.CommandName.FIND_ELEMENT).
94
+ setParameters(locator.type, locator.target).
95
+ setSuccessCallback(function(response) {
96
+ webElement.getId().setValue(response.value);
97
+ });
98
+ driver.addCommand(command);
99
+ return webElement;
100
+ };
101
+
102
+
103
+ /**
104
+ * Adds a command to the given {@code webdriver.WebDriver} instance to test if
105
+ * an element is present on the page.
106
+ * @param {webdriver.WebDriver} driver The driver to perform the search with.
107
+ * @param {webdriver.By.Locator|{*: string}} locator The locator to use for
108
+ * finding the element, or a short-hand object that can be converted into a
109
+ * locator.
110
+ * @return {webdriver.Future} A future whose value will be set when the driver
111
+ * completes the search; value will be {@code true} if the element was
112
+ * found, false otherwise.
113
+ * @see webdriver.By.Locator.createFromObj
114
+ */
115
+ webdriver.WebElement.isElementPresent = function(driver, locator) {
116
+ var isPresent = new webdriver.Future(driver);
117
+ var callback = function(response) {
118
+ // If returns without an error, element is present.
119
+ isPresent.setValue(response.value = !response.isFailure);
120
+ // Go ahead and clear the error.
121
+ response.isFailure = false;
122
+ };
123
+ locator = webdriver.By.Locator.checkLocator(locator);
124
+ var command = new webdriver.Command(webdriver.CommandName.FIND_ELEMENT).
125
+ setParameters(locator.type, locator.target).
126
+ setSuccessCallback(callback).
127
+ setFailureCallback(callback);
128
+ driver.addCommand(command);
129
+ return isPresent;
130
+ };
131
+
132
+
133
+ /**
134
+ * Adds a command to the given {@code webdriver.WebDriver} instance to find
135
+ * multiple elements on the page.
136
+ * @param {webdriver.WebDriver} driver The driver to perform the search with.
137
+ * @param {webdriver.By.Locator|{*: string}} locator The locator to use for
138
+ * finding the element, or a short-hand object that can be converted into a
139
+ * locator.
140
+ * @see webdriver.By.Locator.createFromObj
141
+ */
142
+ webdriver.WebElement.findElements = function(driver, locator) {
143
+ locator = webdriver.By.Locator.checkLocator(locator);
144
+ var command = new webdriver.Command(webdriver.CommandName.FIND_ELEMENTS).
145
+ setParameters(locator.type, locator.target).
146
+ setSuccessCallback(function(response) {
147
+ var ids = response.value.split(',');
148
+ var elements = [];
149
+ for (var i = 0, id; id = ids[i]; i++) {
150
+ if (id) {
151
+ var element = new webdriver.WebElement(driver);
152
+ element.getId().setValue(id);
153
+ elements.push(element);
154
+ }
155
+ }
156
+ response.value = elements;
157
+ });
158
+ driver.addCommand(command);
159
+ };
160
+
161
+
162
+ /**
163
+ * Adds a command to determine if an element is present under this element in
164
+ * the DOM tree.
165
+ * @param {webdriver.By.Locator|{*: string}} locator The locator to use for
166
+ * finding the element, or a short-hand object that can be converted into a
167
+ * locator.
168
+ * @return {webdriver.Future} A future whose value will be set when the driver
169
+ * completes the search; value will be {@code true} if the element was
170
+ * found, false otherwise.
171
+ * @see webdriver.By.Locator.createFromObj
172
+ */
173
+ webdriver.WebElement.prototype.isElementPresent = function(locator) {
174
+ var isPresent = new webdriver.Future(this.driver_);
175
+ var callback = function(response) {
176
+ // If returns without an error, element is present.
177
+ isPresent.setValue(response.value = !response.isFailure);
178
+ // Go ahead and clear the error (if any).
179
+ response.isFailure = false;
180
+ };
181
+ locator = webdriver.By.Locator.checkLocator(locator);
182
+ var command = new webdriver.Command(webdriver.CommandName.FIND_CHILD_ELEMENT).
183
+ setParameters({
184
+ 'id': this.getId(),
185
+ 'using': locator.type,
186
+ 'value': locator.target
187
+ }).
188
+ setSuccessCallback(callback).
189
+ setFailureCallback(callback);
190
+ this.driver_.addCommand(command);
191
+ return isPresent;
192
+ };
193
+
194
+
195
+ /**
196
+ * Adds a command to search for a single element on the page, restricting the
197
+ * search to the descendants of the element represented by this instance.
198
+ * @param {webdriver.By.Locator|{*: string}} locator The locator to use for
199
+ * finding the element, or a short-hand object that can be converted into a
200
+ * locator.
201
+ * @return {webdriver.WebElement} A WebElement that can be used to issue
202
+ * commands on the found element. The element's ID will be set
203
+ * asynchronously once the element is successfully located.
204
+ * @see webdriver.By.Locator.createFromObj
205
+ */
206
+ webdriver.WebElement.prototype.findElement = function(locator) {
207
+ var webElement = new webdriver.WebElement(this.driver_);
208
+ locator = webdriver.By.Locator.checkLocator(locator);
209
+ var command = new webdriver.Command(webdriver.CommandName.FIND_CHILD_ELEMENT).
210
+ setParameters({
211
+ 'id': this.getId(),
212
+ 'using': locator.type,
213
+ 'value': locator.target
214
+ }).
215
+ setSuccessCallback(function(response) {
216
+ webElement.getId().setValue(response.value);
217
+ });
218
+ this.driver_.addCommand(command);
219
+ return webElement;
220
+ };
221
+
222
+
223
+ /**
224
+ * Adds a command to search for multiple elements on the page, restricting the
225
+ * search to the descendants of hte element represented by this instance.
226
+ * @param {webdriver.By.Locator|{*: string}} locator The locator to use for
227
+ * finding the element, or a short-hand object that can be converted into a
228
+ * locator.
229
+ * @see webdriver.By.Locator.createFromObj
230
+ */
231
+ webdriver.WebElement.prototype.findElements = function(locator) {
232
+ locator = webdriver.By.Locator.checkLocator(locator);
233
+ var command =
234
+ new webdriver.Command(webdriver.CommandName.FIND_CHILD_ELEMENTS).
235
+ setParameters({
236
+ 'id': this.getId(),
237
+ 'using': locator.type,
238
+ 'value': locator.target
239
+ }).
240
+ setSuccessCallback(function(response) {
241
+ var ids = response.value.split(',');
242
+ var elements = [];
243
+ for (var i = 0, id; id = ids[i]; i++) {
244
+ if (id) {
245
+ var element = new webdriver.WebElement(this.driver_);
246
+ element.getId().setValue(id);
247
+ elements.push(element);
248
+ }
249
+ }
250
+ response.value = elements;
251
+ }, this);
252
+ this.driver_.addCommand(command);
253
+ };
254
+
255
+
256
+ /**
257
+ * @return {webdriver.WebDriver} The driver that this element delegates commands
258
+ * to.
259
+ */
260
+ webdriver.WebElement.prototype.getDriver = function() {
261
+ return this.driver_;
262
+ };
263
+
264
+
265
+ /**
266
+ * @return {webdriver.Futur} The UUID of this element wrapped in a Future.
267
+ */
268
+ webdriver.WebElement.prototype.getId = function() {
269
+ return this.elementId_;
270
+ };
271
+
272
+
273
+ /**
274
+ * Creates a new {@code webdriver.Command} against the element represented by
275
+ * this instance.
276
+ * @param {string} name The name of the command to create.
277
+ * @return {webdriver.Command} The new command.
278
+ * @private
279
+ */
280
+ webdriver.WebElement.prototype.createCommand_ = function(name) {
281
+ return new webdriver.Command(name, this);
282
+ };
283
+
284
+
285
+ /**
286
+ * Adds a command to click on this element.
287
+ */
288
+ webdriver.WebElement.prototype.click = function() {
289
+ var command = this.createCommand_(webdriver.CommandName.CLICK);
290
+ this.driver_.addCommand(command);
291
+ };
292
+
293
+
294
+ /**
295
+ * Types a sequence on the DOM element represented by this instance.
296
+ * <p/>
297
+ * Modifier keys (SHIFT, CONTROL, ALT, META) are stateful; once a modifier is
298
+ * processed in the keysequence, that key state is toggled until one of the
299
+ * following occurs:
300
+ * <ul>
301
+ * <li>The modifier key is encountered again in the sequence. At this point the
302
+ * state of the key is toggled (along with the appropriate keyup/down events).
303
+ * </li>
304
+ * <li>The {@code webdriver.Key.NULL} key is encountered in the sequence. When
305
+ * this key is encountered, all modifier keys current in the down state are
306
+ * released (with accompanying keyup events). The NULL key can be used to
307
+ * simulate common keyboard shortcuts:
308
+ * <code>
309
+ * element.sendKeys("text was",
310
+ * webdriver.Key.CONTROL, "a", webdriver.Key.NULL,
311
+ * "now text is");
312
+ * // Alternatively:
313
+ * element.sendKeys("text was",
314
+ * webdriver.Key.chord(webdriver.Key.CONTROL, "a"),
315
+ * "now text is");
316
+ * </code></li>
317
+ * <li>The end of the keysequence is encountered. When there are no more keys
318
+ * to type, all depressed modifier keys are released (with accompanying keyup
319
+ * events).
320
+ * </li>
321
+ * </ul>
322
+ * If a certain character can only be generated by using the shift key, such as
323
+ * uppercase characters or certain punctuation marks, the shift key will be
324
+ * applied for that individual key. If the shift key was not depressed before
325
+ * typing that key, it will be released after typing the key. If the shift key
326
+ * was already depressed, the extra event will not be generated. For example:
327
+ * <code>
328
+ * // Expect shift down/up for each character.
329
+ * element.sendKeys("ABC");
330
+ * // Shift is already depressed, so it will not be pushed again for each
331
+ * // character.
332
+ * element.sendKeys(webdriver.Key.SHIFT, "ABC");
333
+ * </code>
334
+ * <p/>
335
+ * <strong>Note:</strong> On browsers where native keyboard events are not yet
336
+ * supported (e.g. Firefox on OS X), key events will be synthesized. Special
337
+ * punctionation keys will be synthesized according to a standard QWERTY English
338
+ * keyboard layout.
339
+ * @param {string|webdriver.Future} var_args The strings to type. All arguments
340
+ * will be joined into a single sequence (var_args is permitted for
341
+ * convenience).
342
+ */
343
+ webdriver.WebElement.prototype.sendKeys = function(var_args) {
344
+ var command = this.createCommand_(webdriver.CommandName.SEND_KEYS);
345
+ command.setParameters.apply(command, arguments);
346
+ this.driver_.addCommand(command);
347
+ };
348
+
349
+ /**
350
+ * Queries for the tag/node name of this element.
351
+ */
352
+ webdriver.WebElement.prototype.getTagName = function() {
353
+ var name = new webdriver.Future(this.driver_);
354
+ var command = this.createCommand_(webdriver.CommandName.GET_TAG_NAME).
355
+ setSuccessCallback(name.setValueFromResponse, name);
356
+ this.driver_.addCommand(command);
357
+ return name;
358
+ };
359
+
360
+
361
+ /**
362
+ * Queries for the computed style of the element represented by this instance.
363
+ * If the element inherits the named style from its parent, the parent will be
364
+ * queried for its value. Where possible, color values will be converted to
365
+ * their hex representation (#00ff00 instead of rgb(0, 255, 0)).
366
+ * <em>Warning:</em> the value returned will be as the browser interprets it, so
367
+ * it may be tricky to form a proper assertion.
368
+ * @param {string} cssStyleProperty The name of the CSS style property to look
369
+ * up.
370
+ * @return {webdriver.Future<string>} The computed style property wrapped in a
371
+ * Future.
372
+ */
373
+ webdriver.WebElement.prototype.getComputedStyle = function(cssStyleProperty) {
374
+ var value = new webdriver.Future(this.driver_);
375
+ var command = this.createCommand_(webdriver.CommandName.GET_VALUE_OF_CSS_PROPERTY).
376
+ setParameters(cssStyleProperty).
377
+ setSuccessCallback(value.setValueFromResponse, value);
378
+ this.driver_.addCommand(command);
379
+ return value;
380
+ };
381
+
382
+
383
+ /**
384
+ * Queries for the specified attribute.
385
+ * @param {string} attributeName The name of the attribute to query.
386
+ */
387
+ webdriver.WebElement.prototype.getAttribute = function(attributeName) {
388
+ var value = new webdriver.Future(this.driver_);
389
+ var command = this.createCommand_(webdriver.CommandName.GET_ATTRIBUTE).
390
+ setParameters(attributeName).
391
+ setSuccessCallback(value.setValueFromResponse, value).
392
+ // If there is an error b/c the attribute was not found, set value to null
393
+ setFailureCallback(function(response) {
394
+ // TODO(jmleyba): This error message needs to be consistent for all
395
+ // drivers.
396
+ if (response.value == 'No match') {
397
+ response.isFailure = false;
398
+ response.value = null;
399
+ value.setValue(null);
400
+ }
401
+ });
402
+ this.driver_.addCommand(command);
403
+ return value;
404
+ };
405
+
406
+
407
+ /**
408
+ * @return {webdriver.Future} The value attribute for the element represented by
409
+ * this instance.
410
+ */
411
+ webdriver.WebElement.prototype.getValue = function() {
412
+ var value = new webdriver.Future(this.driver_);
413
+ var command = this.createCommand_(webdriver.CommandName.GET_VALUE).
414
+ setSuccessCallback(value.setValueFromResponse, value);
415
+ this.driver_.addCommand(command);
416
+ return value;
417
+ };
418
+
419
+
420
+ /**
421
+ * @return {webdriver.Future} The innerText of this element, without any leading
422
+ * or trailing whitespace.
423
+ */
424
+ webdriver.WebElement.prototype.getText = function() {
425
+ var text = new webdriver.Future(this.driver_);
426
+ var command = this.createCommand_(webdriver.CommandName.GET_TEXT).
427
+ setSuccessCallback(text.setValueFromResponse, text);
428
+ this.driver_.addCommand(command);
429
+ return text;
430
+ };
431
+
432
+
433
+ /**
434
+ * Selects this element.
435
+ */
436
+ webdriver.WebElement.prototype.setSelected = function() {
437
+ var command = this.createCommand_(webdriver.CommandName.SET_SELECTED);
438
+ this.driver_.addCommand(command);
439
+ };
440
+
441
+
442
+ /**
443
+ * @return {webdriver.Future} The size of this element.
444
+ */
445
+ webdriver.WebElement.prototype.getSize = function() {
446
+ var size = new webdriver.Future(this.driver_);
447
+ var command = this.createCommand_(webdriver.CommandName.GET_SIZE).
448
+ setSuccessCallback(function(response) {
449
+ var wh = response.value.replace(/\s/g, '').split(',');
450
+ response.value = new goog.math.Size(wh[0], wh[1]);
451
+ size.setValue(response.value);
452
+ });
453
+ this.driver_.addCommand(command);
454
+ return size;
455
+ };
456
+
457
+
458
+ /**
459
+ * Parses a response of the form "$x $y" into a {@code goog.math.Coordinate}
460
+ * object.
461
+ * @param {webdriver.Future} future The Future to store the parsed result in.
462
+ * @param {webdriver.Response} response The response to parse.
463
+ * @private
464
+ */
465
+ webdriver.WebElement.createCoordinatesFromResponse_ = function(future,
466
+ response) {
467
+ var xy = response.value.replace(/\s/g, '').split(',');
468
+ response.value = new goog.math.Coordinate(xy[0], xy[1]);
469
+ future.setValue(response.value);
470
+ };
471
+
472
+
473
+ /**
474
+ * @return {webdriver.Future} The location of this element.
475
+ */
476
+ webdriver.WebElement.prototype.getLocation = function() {
477
+ var currentLocation = new webdriver.Future(this.driver_);
478
+ var command = this.createCommand_(webdriver.CommandName.GET_LOCATION).
479
+ setSuccessCallback(
480
+ goog.bind(webdriver.WebElement.createCoordinatesFromResponse_, null,
481
+ currentLocation));
482
+ this.driver_.addCommand(command);
483
+ return currentLocation;
484
+ };
485
+
486
+
487
+ /**
488
+ * @param {webdriver.Future} newLocation Future to store the new location in
489
+ * when the command is complete.
490
+ * @param {number} x Horizontal distance to drag this element.
491
+ * @param {number} y Vertical distanct to drag this element.
492
+ * @param opt_addToFront
493
+ * @private
494
+ */
495
+ webdriver.WebElement.prototype.addDragAndDropCommand_ = function(
496
+ newLocation, x, y, opt_addToFront) {
497
+ var command = this.createCommand_(webdriver.CommandName.DRAG_ELEMENT).
498
+ setParameters(x, y).
499
+ setSuccessCallback(
500
+ goog.bind(webdriver.WebElement.createCoordinatesFromResponse_, null,
501
+ newLocation));
502
+ this.driver_.addCommand(command, opt_addToFront);
503
+ };
504
+
505
+
506
+ /**
507
+ * Drags this element by the given offset.
508
+ * @param {number} x The horizontal amount, in pixels, to drag this element.
509
+ * @param {number} y The vertical amount, in pixels, to drag this element.
510
+ * @return {webdriver.Future} The new location of the element.
511
+ */
512
+ webdriver.WebElement.prototype.dragAndDropBy = function(x, y) {
513
+ var newLocation = new webdriver.Future(this.driver_);
514
+ this.addDragAndDropCommand_(newLocation, x, y);
515
+ return newLocation;
516
+ };
517
+
518
+
519
+ /**
520
+ * Drags this element to the location of another {@code webElement}. After this
521
+ * command executes, this element's upper-left hand corner should be the same
522
+ * location as the upper-left hand corner of the given {@code webElement}.
523
+ * @param {webdriver.WebElement} webElement The element to drag this element to.
524
+ * @return {webdriver.Future} This element's new location.
525
+ */
526
+ webdriver.WebElement.prototype.dragAndDropTo = function(webElement) {
527
+ if (this.driver_ != webElement.driver_) {
528
+ throw new Error(
529
+ 'WebElements created by different drivers cannot coordinate');
530
+ }
531
+
532
+ var toLocation = webElement.getLocation();
533
+ var thisLocation = this.getLocation();
534
+ var newLocation = new webdriver.Future(this.driver_);
535
+ this.driver_.callFunction(goog.bind(function() {
536
+ var delta = goog.math.Coordinate.difference(
537
+ toLocation.getValue(), thisLocation.getValue());
538
+ this.addDragAndDropCommand_(newLocation, delta.x, delta.y, true);
539
+ }, this));
540
+ return newLocation;
541
+ };
542
+
543
+
544
+ /**
545
+ * @return {boolean} Whether the DOM element represented by this instance is
546
+ * enabled, as dictated by the {@code disabled} attribute.
547
+ */
548
+ webdriver.WebElement.prototype.isEnabled = function() {
549
+ var futureValue = new webdriver.Future(this.driver_);
550
+ var command = this.createCommand_(webdriver.CommandName.GET_ATTRIBUTE).
551
+ setParameters('disabled').
552
+ setSuccessCallback(function(response) {
553
+ response.value = !!!response.value;
554
+ futureValue.setValue(response.value);
555
+ });
556
+ this.driver_.addCommand(command);
557
+ return futureValue;
558
+ };
559
+
560
+
561
+ /**
562
+ * Determines if this element is checked or selected; will generate an error if
563
+ * the DOM element represented by this instance is not an OPTION or checkbox
564
+ * INPUT element.
565
+ * @return {webdriver.Future} Whether this instance is currently checked or
566
+ * selected.
567
+ * @private
568
+ */
569
+ webdriver.WebElement.prototype.isCheckedOrSelected_ = function(opt_future,
570
+ opt_addToFront) {
571
+ var value = opt_future || new webdriver.Future(this.driver_);
572
+ var command = this.createCommand_(webdriver.CommandName.GET_TAG_NAME).
573
+ setSuccessCallback(function(response) {
574
+ var attribute = response.value == 'input' ? 'checked' : 'selected';
575
+ var getAttrCommand =
576
+ this.createCommand_(webdriver.CommandName.GET_ATTRIBUTE).
577
+ setParameters(attribute).
578
+ setSuccessCallback(function(response) {
579
+ response.value = !!response.value;
580
+ value.setValue(response.value);
581
+ });
582
+ this.driver_.addCommand(getAttrCommand, true);
583
+ }, this);
584
+ this.driver_.addCommand(command, opt_addToFront);
585
+ return value;
586
+ };
587
+
588
+
589
+ /**
590
+ * @return {webdriver.Future} Whether this element is selected.
591
+ */
592
+ webdriver.WebElement.prototype.isSelected = function() {
593
+ return this.isCheckedOrSelected_();
594
+ };
595
+
596
+
597
+ /**
598
+ * @return {webdriver.Future} Whether this element is checked.
599
+ */
600
+ webdriver.WebElement.prototype.isChecked = function() {
601
+ return this.isCheckedOrSelected_();
602
+ };
603
+
604
+
605
+ /**
606
+ * Toggles the checked/selected state of this element; will generate an error if
607
+ * the DOM element represented by this instance is not an OPTION or checkbox
608
+ * input element.
609
+ * @return {webdriver.Future} The new checked/selected state of this element.
610
+ */
611
+ webdriver.WebElement.prototype.toggle = function() {
612
+ var toggleResult = new webdriver.Future(this.driver_);
613
+ var command = this.createCommand_(webdriver.CommandName.TOGGLE).
614
+ setSuccessCallback(function() {
615
+ this.isCheckedOrSelected_(toggleResult, true);
616
+ }, this);
617
+ this.driver_.addCommand(command);
618
+ return toggleResult;
619
+ };
620
+
621
+
622
+ /**
623
+ * If this current element is a form, or an element within a form, then this
624
+ * will that form.
625
+ */
626
+ webdriver.WebElement.prototype.submit = function() {
627
+ this.driver_.addCommand(
628
+ this.createCommand_(webdriver.CommandName.SUBMIT));
629
+ };
630
+
631
+
632
+ /**
633
+ * If this instance represents a text INPUT element, or a TEXTAREA element, this
634
+ * will clear its {@code value}.
635
+ */
636
+ webdriver.WebElement.prototype.clear = function() {
637
+ this.driver_.addCommand(
638
+ this.createCommand_(webdriver.CommandName.CLEAR));
639
+ };
640
+
641
+
642
+ /**
643
+ * @return {webdriver.Future} Whether this element is currently displayed.
644
+ */
645
+ webdriver.WebElement.prototype.isDisplayed = function() {
646
+ var futureValue = new webdriver.Future(this.driver_);
647
+ var command = this.createCommand_(webdriver.CommandName.IS_DISPLAYED).
648
+ setSuccessCallback(function(response) {
649
+ // TODO(jmleyba): FF extension should not be returning a string here...
650
+ if (goog.isString(response.value)) {
651
+ futureValue.setValue(response.value == 'true');
652
+ } else {
653
+ futureValue.setValue(response.value);
654
+ }
655
+ });
656
+ this.driver_.addCommand(command);
657
+ return futureValue;
658
+ };
659
+
660
+
661
+ /**
662
+ * @return {webdriver.Future} The outer HTML of this element.
663
+ */
664
+ webdriver.WebElement.prototype.getOuterHtml = function() {
665
+ return this.driver_.executeScript(
666
+ ['var element = arguments[0];',
667
+ 'if ("outerHTML" in element) {',
668
+ ' return element.outerHTML;',
669
+ '} else {',
670
+ ' var div = document.createElement("div");',
671
+ ' div.appendChild(element.cloneNode(true));',
672
+ ' return div.innerHTML;',
673
+ '}'].join(''), this);
674
+ };
675
+
676
+
677
+ /**
678
+ * @return {webdriver.Future} The inner HTML of this element.
679
+ */
680
+ webdriver.WebElement.prototype.getInnerHtml = function() {
681
+ return this.driver_.executeScript('return arguments[0].innerHTML', this);
682
+ };
683
+