selenium-webdriver 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,89 @@
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 Defines a namespace that implements the global timing
20
+ * functions: setTimeout, setInterval, clearTimeout, and clearInterval.
21
+ * Internally, this namespaces uses protected references to the real global
22
+ * functions so that users can override them without interfering with WebDriver
23
+ * functionality.
24
+ * @author jmleyba@gmail.com (Jason Leyba)
25
+ */
26
+
27
+ goog.provide('webdriver.timing');
28
+
29
+ goog.require('goog.userAgent');
30
+
31
+
32
+ webdriver.timing.protectedSetTimeout_ = goog.global['setTimeout'];
33
+ webdriver.timing.protectedSetInterval_ = goog.global['setInterval'];
34
+ webdriver.timing.protectedClearTimeout_ = goog.global['clearTimeout'];
35
+ webdriver.timing.protectedClearInterval_ = goog.global['clearInterval'];
36
+
37
+
38
+ /**
39
+ * Schedules a function to be executed after the given {@code delay}.
40
+ * @param {function} fn The function to call after {@code delay} milliseconds.
41
+ * @param {number} delay The number of milliseconds to delay executing the
42
+ * function by.
43
+ * @return {number} The timeout ID that can be used with {@code #clearTimeout}
44
+ * to cancel executing {@code fn}.
45
+ */
46
+ webdriver.timing.setTimeout = function(fn, delay) {
47
+ return goog.userAgent.IE ?
48
+ webdriver.timing.protectedSetTimeout_(fn, delay) :
49
+ webdriver.timing.protectedSetTimeout_.call(null, fn, delay);
50
+ };
51
+
52
+
53
+ /**
54
+ * Schedules a function to be executed every {@code interval} milliseconds.
55
+ * @param {function} fn The function to call every {@code delay} milliseconds.
56
+ * @param {number} interval The number of milliseconds to delay executing the
57
+ * function by.
58
+ * @return {number} The interval ID that can be used with {@code #clearInterval}
59
+ * to cancel this interval.
60
+ */
61
+ webdriver.timing.setInterval = function(fn, interval) {
62
+ return goog.userAgent.IE ?
63
+ webdriver.timing.protectedSetInterval_(fn, interval) :
64
+ webdriver.timing.protectedSetInterval_.call(goog.global, fn, interval);
65
+ };
66
+
67
+
68
+ /**
69
+ * Cancels a timeout scheduled with {@code #setTimeout()}.
70
+ * @param {number} timeoutId ID of the timeout to cancel as returned by
71
+ * {@code #setTimeout}. Passing an invalid ID results in a no-op.
72
+ */
73
+ webdriver.timing.clearTimeout = function(timeoutId) {
74
+ return goog.userAgent.IE ?
75
+ webdriver.timing.protectedClearTimeout_(timeoutId) :
76
+ webdriver.timing.protectedClearTimeout_.call(goog.global, timeoutId);
77
+ };
78
+
79
+
80
+ /**
81
+ * Cancels an interval scheduled with {@code #clearInterval()}.
82
+ * @param {number} intervalId ID of the interval to cancel as returned by
83
+ * {@code #setInterval}. Passing an invalid ID results in a no-op.
84
+ */
85
+ webdriver.timing.clearInterval = function(intervalId) {
86
+ return goog.userAgent.IE ?
87
+ webdriver.timing.protectedClearInterval_(timeoutId) :
88
+ webdriver.timing.protectedClearInterval_.call(goog.global, intervalId);
89
+ };
@@ -0,0 +1,199 @@
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 Defines a mechanism for blocking {@code webdriver.WebDriver}
20
+ * command execution on user-defined conditions.
21
+ * @author jmleyba@gmail.com (Jason Leyba)
22
+ */
23
+
24
+ goog.provide('webdriver.Wait');
25
+
26
+ goog.require('goog.events');
27
+ goog.require('webdriver.Future');
28
+ goog.require('webdriver.timing');
29
+
30
+
31
+ /**
32
+ * Controls polling a condition that a {@code webdriver.WebDriver} instance
33
+ * should block command execution on.
34
+ * @param {function} conditionFn The condition function that the driver will
35
+ * poll. The function should require no arguments and return a boolean or a
36
+ * {@code webdriver.Future} that will evaluate to a boolean.
37
+ * @param {number} timeout The amount of time to wait, in milliseconds, for the
38
+ * condition to hold.
39
+ * @constructor
40
+ * @private
41
+ */
42
+ webdriver.Wait = function(conditionFn, timeout) {
43
+
44
+ /**
45
+ * Function to call for evaluating the condition being waited on.
46
+ * @type {function: boolean}
47
+ * @private
48
+ */
49
+ this.conditionFn_ = conditionFn;
50
+
51
+ /**
52
+ * The maximum amount of time in milliseconds to wait for condition.
53
+ * @type {number}
54
+ * @private
55
+ */
56
+ this.timeout_ = timeout;
57
+
58
+ /**
59
+ * When the wait began. Set on the first call to {@code #start()}.
60
+ * @type {number}
61
+ * @private
62
+ */
63
+ this.started_ = 0;
64
+
65
+ /**
66
+ * ID of the timeout timer. Initialized on the first call to {@code #start()}.
67
+ * @type {number}
68
+ * @private
69
+ */
70
+ this.timeoutId_ = null;
71
+
72
+ /**
73
+ * ID of the interval timer. Initialized on the first call to
74
+ * {@code #start()}.
75
+ * @type {number}
76
+ * @private
77
+ */
78
+ this.pollingIntervalId_ = null;
79
+
80
+ /**
81
+ * Whether to wait on the inverse of the wait condition.
82
+ * @type {boolean}
83
+ * @private
84
+ */
85
+ this.waitOnInverse_ = false;
86
+ };
87
+
88
+
89
+ /**
90
+ * Set this instance to wait for the inverse of its condition.
91
+ * @param {boolean} wait Whether to wait for the inverse of the condition.
92
+ */
93
+ webdriver.Wait.prototype.waitOnInverse = function(wait) {
94
+ this.waitOnInverse_ = wait;
95
+ };
96
+
97
+
98
+ /**
99
+ * Starts the timer the and starts evaluating the condition.
100
+ * @param {function} callbackFn The function to call with the result. The
101
+ * function should take 3 arguments: a boolean for whether the wait timed
102
+ * out (will only be true on a timeout), the amount of time spent in the
103
+ * wait. The 3rd parameter will be an Error, if any, that caused the wait
104
+ * to abort early.
105
+ */
106
+ webdriver.Wait.prototype.start = function(callbackFn) {
107
+ if (!!!this.started_) {
108
+ this.started_ = goog.now();
109
+
110
+ var tickHandler = goog.bind(this.onTick_, this, callbackFn);
111
+ var timeoutHandler = goog.bind(this.onTimeout_, this, callbackFn);
112
+
113
+ this.pollingIntervalId_ = webdriver.timing.setInterval(tickHandler, 5);
114
+ this.timeoutId_ =
115
+ webdriver.timing.setTimeout(timeoutHandler, this.timeout_);
116
+
117
+ this.onTick_(callbackFn);
118
+ }
119
+ };
120
+
121
+
122
+ /**
123
+ * Callback for when the wait times out.
124
+ * @param {function} callbackFn The function to call with the result.
125
+ * @private
126
+ */
127
+ webdriver.Wait.prototype.onTimeout_ = function(callbackFn) {
128
+ webdriver.timing.clearInterval(this.pollingIntervalId_);
129
+ if (this.pendingFuture_) {
130
+ this.pendingFuture_.dispose();
131
+ }
132
+ callbackFn(true, goog.now() - this.started_);
133
+ };
134
+
135
+
136
+ /**
137
+ * Evaluates the wait condition and determines whether to abort the wait.
138
+ * @param {function} callbackFn The function to call with the result.
139
+ * @private
140
+ */
141
+ webdriver.Wait.prototype.onTick_ = function(callbackFn) {
142
+ if (this.pendingFuture_) {
143
+ return;
144
+ }
145
+
146
+ var elapsed = goog.now() - this.started_;
147
+ var value;
148
+ try {
149
+ value = this.conditionFn_();
150
+ if (value instanceof webdriver.Future) {
151
+ if (value.isSet() &&
152
+ this.checkValue_(value.getValue(), elapsed, callbackFn)) {
153
+ return;
154
+ }
155
+
156
+ this.pendingFuture_ = value;
157
+ goog.events.listenOnce(value, goog.events.EventType.CHANGE, function() {
158
+ this.pendingFuture_ = null;
159
+ this.checkValue_(value.getValue(), goog.now() - this.started_,
160
+ callbackFn);
161
+ }, false, this);
162
+
163
+ } else {
164
+ this.checkValue_(value, elapsed, callbackFn);
165
+ }
166
+
167
+ } catch (ex) {
168
+ webdriver.timing.clearInterval(this.pollingIntervalId_);
169
+ webdriver.timing.clearTimeout(this.timeoutId_);
170
+ if (this.pendingFuture_) {
171
+ this.pendingFuture_.dispose();
172
+ }
173
+ callbackFn(true, elapsed, ex);
174
+ }
175
+ };
176
+
177
+
178
+ /**
179
+ * Checks the value returned by the condition function.
180
+ * @param {boolean} value The result of the condition function.
181
+ * @param {number} elapsed The time elapsed since the wait started.
182
+ * @param {function} callbackFn The function to call with the result.
183
+ * @private
184
+ */
185
+ webdriver.Wait.prototype.checkValue_ = function(value, elapsed, callbackFn) {
186
+ value = !!value;
187
+ if (this.waitOnInverse_) {
188
+ value = !value;
189
+ }
190
+ if (value) {
191
+ webdriver.timing.clearInterval(this.pollingIntervalId_);
192
+ webdriver.timing.clearTimeout(this.timeoutId_);
193
+ if (this.pendingFuture_) {
194
+ this.pendingFuture_.dispose();
195
+ }
196
+ callbackFn(false, elapsed);
197
+ }
198
+ return value;
199
+ };
@@ -0,0 +1,853 @@
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 The heart of the WebDriver JavaScript API.
20
+ * @author jmleyba@gmail.com (Jason Leyba)
21
+ */
22
+
23
+ goog.provide('webdriver.WebDriver');
24
+ goog.provide('webdriver.WebDriver.EventType');
25
+
26
+ goog.require('goog.events');
27
+ goog.require('goog.events.EventTarget');
28
+ goog.require('webdriver.Command');
29
+ goog.require('webdriver.CommandName');
30
+ goog.require('webdriver.Context');
31
+ goog.require('webdriver.Future');
32
+ goog.require('webdriver.Response');
33
+ goog.require('webdriver.Wait');
34
+ goog.require('webdriver.WebElement');
35
+ goog.require('webdriver.logging');
36
+ goog.require('webdriver.timing');
37
+
38
+
39
+ /**
40
+ * The main interface for controlling a web browser. How the browser is
41
+ * controlled is dictated by the injected {@code commandProcessor}. The command
42
+ * processor may control the browser either through an extension or plugin, or
43
+ * by sending commands to a RemoteWebDriver server.
44
+ *
45
+ * Any WebDriver command that is expected to produce a return value will return
46
+ * a {@code webdriver.Future}. This Future can passed as an argument to another
47
+ * command, or an assertion function in the {@code webdriver.asserts} namespace.
48
+ * For example:
49
+ * driver.get('http://www.google.com');
50
+ * var futureTitle = driver.getTitle();
51
+ * assertThat(futureTitle, equals('Google Search'));
52
+ *
53
+ * The WebDriver will dispatch the following events:
54
+ * <ul>
55
+ * <li>webdriver.WebDriver.EventType.PAUSED - Command execution has been halted
56
+ * and no more commands will be processed until {@code #resume()} is called
57
+ * </li>
58
+ * <li>webdriver.WebDriver.EventType.RESUMED - The driver has resumed execution
59
+ * after being paused</li>
60
+ * <li>webdriver.WebDriver.EventType.ERROR - Dispatched whenever a WebDriver
61
+ * command fails</li>
62
+ * </ul>
63
+ *
64
+ * @param {Object} commandProcessor The command processor to use for executing
65
+ * individual {@code webdriver.Command}s.
66
+ * @constructor
67
+ * @extends {goog.events.EventTarget}
68
+ */
69
+ webdriver.WebDriver = function(commandProcessor) {
70
+ goog.events.EventTarget.call(this);
71
+
72
+ /**
73
+ * The command processor to use for executing commands.
74
+ * @type {Object}
75
+ * @private
76
+ */
77
+ this.commandProcessor_ = commandProcessor;
78
+
79
+ /**
80
+ * List of commands that have been sent to the command processor and are
81
+ * await results. This array should only ever have three sizes:
82
+ * 0: there are no pending commands with the command processor
83
+ * 1: a single command is pending with the command processor
84
+ * 2: a command within a wait condition is pending with the command
85
+ * processor
86
+ * @type {Array.<webdriver.Command>}
87
+ * @private
88
+ */
89
+ this.pendingCommands_ = [];
90
+
91
+ /**
92
+ * A stack of frames for managing batched command execution order.
93
+ * @type {Array.<Array.<webdriver.Command>>}
94
+ * @private
95
+ */
96
+ this.frames_ = [[]];
97
+
98
+ /**
99
+ * A list of commands that have been successfully completed since the last
100
+ * reset.
101
+ * @type {Array.<webdriver.Command>}
102
+ * @priate
103
+ */
104
+ this.commandHistory_ = [];
105
+
106
+ /**
107
+ * Whether this instance is paused. When paused, commands can still be issued,
108
+ * but no commands will be executed.
109
+ * @type {boolean}
110
+ * @private
111
+ */
112
+ this.isPaused_ = false;
113
+
114
+ /**
115
+ * This instances current context (window and frame ID).
116
+ * @type {webdriver.Context}
117
+ * @private
118
+ */
119
+ this.context_ = new webdriver.Context();
120
+
121
+ /**
122
+ * Whether this instance is locked into its current session. Once locked in,
123
+ * any further calls to {@code webdriver.WebDriver.prototype.newSession} will
124
+ * be ignored.
125
+ * @type {boolean}
126
+ * @private
127
+ */
128
+ this.sessionLocked_ = false;
129
+
130
+ /**
131
+ * This instance's current session ID. Set with the
132
+ * {@code webdriver.WebDriver.prototype.newSession} command.
133
+ * @type {?string}
134
+ * @private
135
+ */
136
+ this.sessionId_ = null;
137
+
138
+ /**
139
+ * Interval ID for the command processing loop.
140
+ * @type {number}
141
+ * @private
142
+ */
143
+ this.commandInterval_ = webdriver.timing.setInterval(
144
+ goog.bind(this.processCommands_, this),
145
+ webdriver.WebDriver.COMMAND_INTERVAL_LENGTH_);
146
+ };
147
+ goog.inherits(webdriver.WebDriver, goog.events.EventTarget);
148
+
149
+
150
+ /**
151
+ * The amount of time in milliseconds between ticks of the command processing
152
+ * interval.
153
+ * @type {number}
154
+ * @private
155
+ */
156
+ webdriver.WebDriver.COMMAND_INTERVAL_LENGTH_ = 10;
157
+
158
+
159
+ /**
160
+ * Enumeration of the events that may be dispatched by an instance of
161
+ * {@code webdriver.WebDriver}.
162
+ * @enum {string}
163
+ */
164
+ webdriver.WebDriver.EventType = {
165
+ ERROR: 'ERROR',
166
+ PAUSED: 'PAUSED',
167
+ RESUMED: 'RESUMED'
168
+ };
169
+
170
+
171
+ /**
172
+ * Enumeration of the supported mouse speeds.
173
+ * @enum {number}
174
+ * @see webdriver.WebDriver.prototype.setMouseSpeed
175
+ * @see webdriver.WebDriver.prototype.getMouseSpeed
176
+ */
177
+ webdriver.WebDriver.Speed = {
178
+ SLOW: 1,
179
+ MEDIUM: 10,
180
+ FAST: 100
181
+ };
182
+
183
+
184
+ /**
185
+ * @override
186
+ */
187
+ webdriver.WebDriver.prototype.dispose = function() {
188
+ this.commandProcessor_.dispose();
189
+ webdriver.timing.clearInterval(this.commandInterval_);
190
+
191
+ delete this.commandProcessor_;
192
+ delete this.pendingCommands_;
193
+ delete this.frames_;
194
+ delete this.commandHistory_;
195
+ delete this.isPaused_;
196
+ delete this.context_;
197
+ delete this.sessionLocked_;
198
+ delete this.sessionId_;
199
+ delete this.commandInterval_;
200
+
201
+ webdriver.WebDriver.superClass_.dispose.call(this);
202
+ };
203
+
204
+
205
+ /**
206
+ * Queues a command to execute.
207
+ * @param {webdriver.Command} command The command to execute.
208
+ * @param {boolean} opt_addToFront Whether to add the command to the front or
209
+ * back of the queue. Defaults to false.
210
+ * @protected
211
+ */
212
+ webdriver.WebDriver.prototype.addCommand = function(command, opt_addToFront) {
213
+ if (!(command instanceof webdriver.Command)) {
214
+ throw new Error(
215
+ 'IllegalArgument: command not an instanceof webdriver.Command');
216
+ }
217
+ var frame = goog.array.peek(this.frames_);
218
+ if (opt_addToFront) {
219
+ goog.array.insertAt(frame, command, 0);
220
+ } else {
221
+ frame.push(command);
222
+ }
223
+ };
224
+
225
+
226
+ /**
227
+ * @return {webdriver.Command} The command currently being executed or
228
+ * {@code undefined}.
229
+ */
230
+ webdriver.WebDriver.prototype.getPendingCommand = function() {
231
+ return goog.array.peek(this.pendingCommands_);
232
+ };
233
+
234
+
235
+ /**
236
+ * Aborts the pending command, if any. If the pending command is part of a
237
+ * {@code #wait()}, then the entire wait operation will be aborted.
238
+ */
239
+ webdriver.WebDriver.prototype.abortPendingCommand = function() {
240
+ goog.array.forEach(this.pendingCommands_, function(command) {
241
+ command.abort = true;
242
+ });
243
+ this.pendingCommands_ = [];
244
+ this.waitFrame_ = null;
245
+ };
246
+
247
+
248
+ /**
249
+ * Immediately pauses the driver so it will not execute anymore commands until
250
+ * {@code #resume()} is called.
251
+ * Dispatches a {@code webdriver.WebDriver.EventType.PAUSED} event.
252
+ */
253
+ webdriver.WebDriver.prototype.pauseImmediately = function() {
254
+ this.isPaused_ = true;
255
+ webdriver.logging.debug('Webdriver paused');
256
+ this.dispatchEvent(webdriver.WebDriver.EventType.PAUSED);
257
+ };
258
+
259
+
260
+ /**
261
+ * Unpauses this driver so it can execute commands again. Dispatches a
262
+ * {@code webdriver.WebDriver.EventType.RESUMED} event.
263
+ */
264
+ webdriver.WebDriver.prototype.resume = function() {
265
+ this.isPaused_ = false;
266
+ webdriver.logging.debug('Webdriver resumed');
267
+ this.dispatchEvent(webdriver.WebDriver.EventType.RESUMED);
268
+ };
269
+
270
+
271
+ /**
272
+ * Event handler for whenever this driver is ready to execute a command.
273
+ * @private
274
+ */
275
+ webdriver.WebDriver.prototype.processCommands_ = function() {
276
+ if (this.isPaused_) {
277
+ return;
278
+ }
279
+
280
+ var pendingCommand = this.getPendingCommand();
281
+ if (pendingCommand && webdriver.CommandName.WAIT != pendingCommand.name) {
282
+ return;
283
+ }
284
+
285
+ var currentFrame = goog.array.peek(this.frames_);
286
+ var nextCommand = currentFrame.shift();
287
+ if (nextCommand) {
288
+ this.pendingCommands_.push(nextCommand);
289
+ if (nextCommand.name == webdriver.CommandName.FUNCTION) {
290
+ this.frames_.push([]);
291
+ } else if (nextCommand.name == webdriver.CommandName.WAIT) {
292
+ this.waitFrame_ = [];
293
+ this.frames_.push(this.waitFrame_);
294
+ }
295
+
296
+ nextCommand.setCompleteCallback(this.onCommandComplete_, this);
297
+ this.commandProcessor_.execute(nextCommand, this.sessionId_, this.context_);
298
+ } else if (this.frames_.length > 1) {
299
+ if (currentFrame !== this.waitFrame_) {
300
+ this.frames_.pop();
301
+ }
302
+ }
303
+ };
304
+
305
+
306
+ /**
307
+ * Callback for when a pending {@code webdriver.Command} is finished.
308
+ * @private
309
+ */
310
+ webdriver.WebDriver.prototype.onCommandComplete_ = function(command) {
311
+ this.commandHistory_.push(command);
312
+ if (command.response.isFailure || command.response.errors.length) {
313
+ if (webdriver.CommandName.WAIT == command.name) {
314
+ // The wait terminated early. Abort all other commands issued inside the
315
+ // wait condition.
316
+ for (var i = 1; i < this.pendingCommands_.length; i++) {
317
+ this.pendingCommands_[i].abort = true;
318
+ }
319
+ this.pendingCommands_ = [this.pendingCommands_[0]];
320
+ }
321
+ this.dispatchEvent(webdriver.WebDriver.EventType.ERROR);
322
+ } else {
323
+ this.pendingCommands_.pop();
324
+ if (webdriver.CommandName.WAIT == command.name) {
325
+ this.waitFrame_ = null;
326
+ }
327
+ }
328
+ };
329
+
330
+
331
+
332
+ /**
333
+ * @return {?string} This instance's current session ID or {@code null} if it
334
+ * does not have one yet.
335
+ */
336
+ webdriver.WebDriver.prototype.getSessionId = function() {
337
+ return this.sessionId_;
338
+ };
339
+
340
+
341
+ /**
342
+ * @return {webdriver.Context} This instance's current context.
343
+ */
344
+ webdriver.WebDriver.prototype.getContext = function() {
345
+ return this.context_;
346
+ };
347
+
348
+
349
+ // ----------------------------------------------------------------------------
350
+ // Client command functions:
351
+ // ----------------------------------------------------------------------------
352
+
353
+ /**
354
+ * Adds an event handler to catch any {@code ERROR} events from the previous
355
+ * command. If the previous command generates an ERROR, that error will be
356
+ * suppressed and this instance will continue executing commands. If an error
357
+ * was not raised, a new {@code webdriver.WebDriver.EventType.ERROR} event will
358
+ * be dispatched for the unexpected behavior.
359
+ * @param {string} opt_errorMsg The message to include with the ERROR event if
360
+ * the expected error does not occur.
361
+ */
362
+ webdriver.WebDriver.prototype.catchExpectedError = function(opt_errorMsg,
363
+ opt_handlerFn) {
364
+ var currentFrame = goog.array.peek(this.frames_);
365
+ var previousCommand = currentFrame.pop();
366
+ if (!previousCommand) {
367
+ throw new Error('No commands in the queue to expect an error from');
368
+ }
369
+
370
+ var listener =
371
+ goog.events.getListener(this, webdriver.WebDriver.EventType.ERROR, true);
372
+ if (listener) {
373
+ throw new Error('IllegalState: Driver already has a registered ' +
374
+ 'expected error handler');
375
+ }
376
+
377
+ var caughtError = false;
378
+ var handleError = function(e) {
379
+ caughtError = true;
380
+ e.stopPropagation();
381
+ e.preventDefault();
382
+ if (goog.isFunction(opt_handlerFn)) {
383
+ opt_handlerFn(e.target.getPendingCommand());
384
+ }
385
+ goog.events.removeAll(
386
+ e.target, webdriver.WebDriver.EventType.ERROR, /*capture=*/true);
387
+
388
+ // Errors cause the pending command to hang. Go ahead and abort that command
389
+ // so we can proceed.
390
+ this.abortPendingCommand();
391
+ var frame = goog.array.peek(this.frames_);
392
+ while (frame !== currentFrame) {
393
+ this.frames_.pop();
394
+ frame = goog.array.peek(this.frames_);
395
+ }
396
+ return false;
397
+ };
398
+
399
+ // Surround the last command with two new commands. The first enables our
400
+ // error listener which cancels any errors. The second verifies that we
401
+ // caught an error. If not, it fails the test.
402
+ var catchExpected = new webdriver.Command(webdriver.CommandName.FUNCTION).
403
+ setParameters(goog.bind(function() {
404
+ goog.events.listenOnce(this, webdriver.WebDriver.EventType.ERROR,
405
+ handleError, /*capture=*/true);
406
+ }, this));
407
+
408
+ var cleanupCatch = new webdriver.Command(webdriver.CommandName.FUNCTION).
409
+ setParameters(goog.bind(function() {
410
+ // Need to unlisten for error events so the error below doesn't get
411
+ // blocked.
412
+ goog.events.unlisten(this, webdriver.WebDriver.EventType.ERROR,
413
+ handleError, /*capture=*/true);
414
+ if (!caughtError) {
415
+ throw new Error(
416
+ (opt_errorMsg ? (opt_errorMsg + '\n') : '') +
417
+ 'Expected an error but none were raised.');
418
+ }
419
+ }, this));
420
+
421
+ currentFrame.push(catchExpected);
422
+ currentFrame.push(previousCommand);
423
+ currentFrame.push(cleanupCatch);
424
+ };
425
+
426
+
427
+ /**
428
+ * Adds a command to pause this driver so it will not execute anymore commands
429
+ * until {@code #resume()} is called. When this command executes, a
430
+ * {@code webdriver.WebDriver.EventType.PAUSED} event will be dispatched.
431
+ */
432
+ webdriver.WebDriver.prototype.pause = function() {
433
+ this.callFunction(goog.bind(this.pauseImmediately, this));
434
+ };
435
+
436
+
437
+ /**
438
+ * Has the driver temporarily halt command execution. This command does
439
+ * <em>not</em> result in a {@code webdriver.WebDriver.EventType.PAUSED} event.
440
+ * @param {number} ms The amount of time in milliseconds for the driver to
441
+ * sleep.
442
+ */
443
+ webdriver.WebDriver.prototype.sleep = function(ms) {
444
+ this.addCommand(new webdriver.Command(webdriver.CommandName.SLEEP).
445
+ setParameters(ms));
446
+ };
447
+
448
+
449
+ /**
450
+ * Inserts a function into the command queue for the driver to call. The
451
+ * function will be passed the last {@code webdriver.Response} retrieved from
452
+ * the command processor. The result of the function will be stored in a new
453
+ * {@code webdriver.Response} and passed to any subsequent function commands.
454
+ * @param {function} fn The function to call; should take a single
455
+ * {@code webdriver.Response} object.
456
+ */
457
+ webdriver.WebDriver.prototype.callFunction = function(fn, opt_selfObj,
458
+ var_args) {
459
+ var args = goog.array.slice(arguments, 2);
460
+ var wrappedFunction = goog.bind(function() {
461
+ var lastCommand = goog.array.peek(this.commandHistory_);
462
+ args.push(lastCommand ? lastCommand.response :null);
463
+ fn.apply(opt_selfObj, args);
464
+ }, this);
465
+ this.addCommand(new webdriver.Command(webdriver.CommandName.FUNCTION).
466
+ setParameters(wrappedFunction));
467
+ };
468
+
469
+
470
+ /**
471
+ * Waits for a condition to be true before executing the next command. If the
472
+ * condition does not hold after the given {@code timeout}, an error will be
473
+ * raised. Only one wait may be performed at a time (e.g. no nesting).
474
+ * Example:
475
+ * <code>
476
+ * driver.get('http://www.google.com');
477
+ * var element = driver.findElement({name: 'q'});
478
+ * driver.wait(element.isDisplayed, 3000, element);
479
+ * </code>
480
+ * @param {function} conditionFn The function to evaluate.
481
+ * @param {number} timeout The maximum amount of time to wait, in milliseconds.
482
+ * @param {Object} opt_self (Optional) The object in whose context to execute
483
+ * the {@code conditionFn}.
484
+ * @throws If this driver is currently executing another wait command.
485
+ * @see webdriver.Wait
486
+ */
487
+ webdriver.WebDriver.prototype.wait = function(conditionFn, timeout, opt_self) {
488
+ if (this.pendingCommands_.length) {
489
+ var command = this.pendingCommands_[0];
490
+ if (webdriver.CommandName.WAIT == command.name) {
491
+ throw new Error('Nested waits are not supported');
492
+ }
493
+ }
494
+
495
+ if (opt_self) {
496
+ conditionFn = goog.bind(conditionFn, opt_self);
497
+ }
498
+ var waitOp = new webdriver.Wait(conditionFn, timeout);
499
+ this.addCommand(new webdriver.Command(webdriver.CommandName.WAIT).
500
+ setParameters(waitOp));
501
+ };
502
+
503
+
504
+ /**
505
+ * Waits for the inverse of a condition to be true before executing the next
506
+ * command. If the condition does not hold after the given {@code timeout}, an
507
+ * error will be raised. Example:
508
+ * <code>
509
+ * driver.get('http://www.google.com');
510
+ * var element = driver.findElement({name: 'q'});
511
+ * driver.waitNot(element.isDisplayed, 3000, element);
512
+ * </code>
513
+ * @param {function} conditionFn The function to evaluate.
514
+ * @param {number} timeout The maximum amount of time to wait, in milliseconds.
515
+ * @param {Object} opt_self (Optional) The object in whose context to execute
516
+ * the {@code conditionFn}.
517
+ * @see webdriver.Wait
518
+ */
519
+ webdriver.WebDriver.prototype.waitNot = function(conditionFn, timeout, opt_self,
520
+ opt_interval) {
521
+ if (opt_self) {
522
+ conditionFn = goog.bind(conditionFn, opt_self);
523
+ }
524
+ var waitOp = new webdriver.Wait(conditionFn, timeout);
525
+ waitOp.waitOnInverse(true);
526
+ this.addCommand(new webdriver.Command(webdriver.CommandName.WAIT).
527
+ setParameters(waitOp));
528
+ };
529
+
530
+
531
+ /**
532
+ * Request a new session ID. This is a no-op if this instance is already locked
533
+ * into a session.
534
+ * @param {boolean} lockSession Whether to lock this instance into the returned
535
+ * session. Once locked into a session, the driver cannot ask for a new
536
+ * session (a new instance must be created).
537
+ */
538
+ webdriver.WebDriver.prototype.newSession = function(lockSession) {
539
+ if (lockSession) {
540
+ this.addCommand(new webdriver.Command(webdriver.CommandName.NEW_SESSION).
541
+ setSuccessCallback(function(response) {
542
+ this.sessionLocked_ = lockSession;
543
+ this.sessionId_ = response.value;
544
+ this.context_ = response.context;
545
+ }, this));
546
+ } else {
547
+ webdriver.logging.warn(
548
+ 'Cannot start new session; driver is locked into current session');
549
+ }
550
+ };
551
+
552
+
553
+ /**
554
+ * Switch the focus of future commands for this driver to the window with the
555
+ * given name.
556
+ * @param {string|webdriver.Future} name The name of the window to transfer
557
+ * control to. Alternatively, the UUID of a window handle, returned by
558
+ * {@code #getWindowHandle()} or {@code #getAllWindowHandles()}.
559
+ */
560
+ webdriver.WebDriver.prototype.switchToWindow = function(name) {
561
+ this.addCommand(new webdriver.Command(webdriver.CommandName.SWITCH_TO_WINDOW).
562
+ setParameters(name).
563
+ setSuccessCallback(function(response) {
564
+ this.context_ = response.value;
565
+ }, this));
566
+ };
567
+
568
+
569
+ /**
570
+ * Switch the focus of future commands for this driver to the frame with the
571
+ * given name or ID. To select sub-frames, simply separate the frame names/IDs
572
+ * by dots. As an example, {@code 'main.child'} will select the frame with the
573
+ * name 'main' and hten its child 'child'. If a frame name is a number, then it
574
+ * will be treated as an index into the {@code window.frames} array of the
575
+ * current window.
576
+ * @param {string|number|webdriver.WebElement} frame Identifier for the frame
577
+ * to transfer control to.
578
+ */
579
+ webdriver.WebDriver.prototype.switchToFrame = function(frame) {
580
+ var commandName = webdriver.CommandName.SWITCH_TO_FRAME;
581
+ var command;
582
+ if (goog.isString(frame) || goog.isNumber(frame)) {
583
+ command = new webdriver.Command(commandName).setParameters(frame);
584
+ } else {
585
+ command = new webdriver.Command(commandName, frame);
586
+ }
587
+ this.addCommand(command.setSuccessCallback(function(response) {
588
+ this.context_ = response.context;
589
+ }, this));
590
+ };
591
+
592
+
593
+ /**
594
+ * Selects either the first frame on the page, or the main document when a page
595
+ * contains iframes.
596
+ */
597
+ webdriver.WebDriver.prototype.switchToDefaultContent = function() {
598
+ var command =
599
+ new webdriver.Command(webdriver.CommandName.SWITCH_TO_DEFAULT_CONTENT).
600
+ setParameters(null).
601
+ setSuccessCallback(function(response) {
602
+ this.context_ = response.context;
603
+ }, this);
604
+ this.addCommand(command);
605
+ };
606
+
607
+
608
+ /**
609
+ * Retrieves the internal UUID handle for the current window.
610
+ * @return {webdriver.Future} The current handle wrapped in a Future.
611
+ */
612
+ webdriver.WebDriver.prototype.getWindowHandle = function() {
613
+ var handle = new webdriver.Future(this);
614
+ var command =
615
+ new webdriver.Command(webdriver.CommandName.GET_CURRENT_WINDOW_HANDLE).
616
+ setSuccessCallback(handle.setValueFromResponse, handle);
617
+ this.addCommand(command);
618
+ return handle;
619
+ };
620
+
621
+
622
+ /**
623
+ * Retrieves the handles for all known windows.
624
+ */
625
+ webdriver.WebDriver.prototype.getAllWindowHandles = function() {
626
+ var command =
627
+ new webdriver.Command(webdriver.CommandName.GET_WINDOW_HANDLES).
628
+ setSuccessCallback(function(response) {
629
+ response.value = response.value.split(',');
630
+ });
631
+ this.addCommand(command);
632
+ };
633
+
634
+
635
+ /**
636
+ * Retrieves the HTML source of the current page.
637
+ * @return {webdriver.Future} The page source wrapped in a Future.
638
+ */
639
+ webdriver.WebDriver.prototype.getPageSource = function() {
640
+ var source = new webdriver.Future(this);
641
+ var command = new webdriver.Command(webdriver.CommandName.GET_PAGE_SOURCE).
642
+ setSuccessCallback(source.setValueFromResponse, source);
643
+ this.addCommand(command);
644
+ return source;
645
+ };
646
+
647
+
648
+ /**
649
+ * Closes the current window.
650
+ * <strong>WARNING: This command provides no protection against closing the
651
+ * script window (e.g. the window sending commands to the driver)</strong>
652
+ */
653
+ webdriver.WebDriver.prototype.close = function() {
654
+ this.addCommand(new webdriver.Command(webdriver.CommandName.CLOSE));
655
+ };
656
+
657
+
658
+
659
+ /**
660
+ * Helper function for converting an argument to a script into a parameter
661
+ * object to send with the {@code webdriver.Command}.
662
+ * @param {*} arg The value to convert.
663
+ * @return {Object} A JSON object with "type" and "value" properties.
664
+ * @see {webdriver.WebDriver.prototype.executeScript}
665
+ * @private
666
+ */
667
+ webdriver.WebDriver.mapToExecuteScriptArgument_ = function(arg) {
668
+ var type, value;
669
+ if (arg instanceof webdriver.WebElement) {
670
+ type = 'ELEMENT';
671
+ value = arg.getId();
672
+ } else if (goog.isBoolean(arg) ||
673
+ goog.isNumber(arg) ||
674
+ goog.isString(arg)) {
675
+ type = goog.typeOf(arg).toUpperCase();
676
+ value = arg;
677
+ } else {
678
+ throw new Error('Invalid script argument type: ' + goog.typeOf(arg));
679
+ }
680
+ return {'type': type, 'value': value};
681
+ };
682
+
683
+
684
+ /**
685
+ * Adds a command to execute a JavaScript snippet in the window of the page
686
+ * currently under test.
687
+ * @param {string} script The JavaScript snippet to execute.
688
+ * @param {*} var_args The arguments to pass to the script.
689
+ * @return {webdriver.Future} The result of the executed script, wrapped in a
690
+ * {@code webdriver.Future} instance.
691
+ */
692
+ webdriver.WebDriver.prototype.executeScript = function(script, var_args) {
693
+ var args = goog.array.map(
694
+ goog.array.slice(arguments, 1),
695
+ webdriver.WebDriver.mapToExecuteScriptArgument_);
696
+ var result = new webdriver.Future(this);
697
+ this.addCommand(new webdriver.Command(webdriver.CommandName.EXECUTE_SCRIPT).
698
+ setParameters(script, args).
699
+ setSuccessCallback(function(response) {
700
+ switch(response.extraData['resultType']) {
701
+ case 'NULL':
702
+ response.value = null;
703
+ break;
704
+
705
+ case 'ELEMENT':
706
+ var id = response.value;
707
+ response.value = new webdriver.WebElement(this);
708
+ response.value.getId().setValue(id);
709
+ break;
710
+
711
+ case 'OTHER': // Fall-through
712
+ default:
713
+ break;
714
+ }
715
+ result.setValue(response.value);
716
+ }, this));
717
+ return result;
718
+ };
719
+
720
+
721
+ /**
722
+ * Adds a command to fetch the given URL.
723
+ * @param {goog.Uri|string} url The URL to fetch.
724
+ */
725
+ webdriver.WebDriver.prototype.get = function(url) {
726
+ this.addCommand(new webdriver.Command(webdriver.CommandName.GET).
727
+ setParameters(url.toString()).
728
+ setSuccessCallback(function(response) {
729
+ this.context_ = response.context;
730
+ }, this));
731
+ };
732
+
733
+
734
+ /**
735
+ * Navigate backwards in the current browser window's history.
736
+ */
737
+ webdriver.WebDriver.prototype.back = function() {
738
+ this.addCommand(new webdriver.Command(webdriver.CommandName.BACK));
739
+ };
740
+
741
+
742
+ /**
743
+ * Navigate forwards in the current browser window's history.
744
+ */
745
+ webdriver.WebDriver.prototype.forward = function() {
746
+ this.addCommand(new webdriver.Command(webdriver.CommandName.FORWARD));
747
+ };
748
+
749
+
750
+ /**
751
+ * Refresh the current page.
752
+ */
753
+ webdriver.WebDriver.prototype.refresh = function() {
754
+ this.addCommand(new webdriver.Command(webdriver.CommandName.REFRESH));
755
+ };
756
+
757
+
758
+ /**
759
+ * Retrieves the current window URL.
760
+ * @return {webdriver.Future} The current URL in a webdriver.Future.
761
+ */
762
+ webdriver.WebDriver.prototype.getCurrentUrl = function() {
763
+ var url = new webdriver.Future(this);
764
+ this.addCommand(new webdriver.Command(webdriver.CommandName.GET_CURRENT_URL).
765
+ setSuccessCallback(url.setValueFromResponse, url));
766
+ return url;
767
+ };
768
+
769
+
770
+ /**
771
+ * Retrieves the current page's title.
772
+ * @return {webdriver.Future} The current page title.
773
+ */
774
+ webdriver.WebDriver.prototype.getTitle = function() {
775
+ var title = new webdriver.Future(this);
776
+ this.addCommand(new webdriver.Command(webdriver.CommandName.GET_TITLE).
777
+ setSuccessCallback(title.setValueFromResponse, title));
778
+ return title;
779
+ };
780
+
781
+
782
+ /**
783
+ * Find an element on the current page. If the element cannot be found, an
784
+ * {@code webdriver.WebDriver.EventType.ERROR} event will be dispatched.
785
+ * @param {webdriver.By.Locator|object} by An object describing the locator
786
+ * strategy to use.
787
+ * @return {webdriver.WebElement} A WebElement wrapper that can be used to
788
+ * issue commands against the located element.
789
+ */
790
+ webdriver.WebDriver.prototype.findElement = function(by) {
791
+ return webdriver.WebElement.findElement(this, by);
792
+ };
793
+
794
+
795
+ /**
796
+ * Determine if an element is present on the page.
797
+ * @param {webdriver.By.Locator|{*: string}} by The locator to use for finding
798
+ * the element, or a short-hand object that can be converted into a locator.
799
+ * @return {webdriver.Future} Whether the element was present on the page. The
800
+ * return value is wrapped in a Future that will be defined when the driver
801
+ * completes the command.
802
+ * @see webdriver.By.Locator.createFromObj
803
+ */
804
+ webdriver.WebDriver.prototype.isElementPresent = function(by) {
805
+ return webdriver.WebElement.isElementPresent(this, by);
806
+ };
807
+
808
+
809
+
810
+ /**
811
+ * Search for multiple elements on the current page. The result of this
812
+ * operation can be accessed from the last saved {@code webdriver.Response}
813
+ * object:
814
+ * driver.findElements({xpath: '//div'});
815
+ * driver.callFunction(function(response) {
816
+ * response.value[0].click();
817
+ * response.value[1].click();
818
+ * // etc.
819
+ * });
820
+ * @param {webdriver.By.Locator|{*: string}} by The locator to use for finding
821
+ * the element, or a short-hand object that can be converted into a locator.
822
+ * @see webdriver.By.Locator.createFromObj
823
+ */
824
+ webdriver.WebDriver.prototype.findElements = function(by) {
825
+ return webdriver.WebElement.findElements(this, by);
826
+ };
827
+
828
+
829
+ /**
830
+ * Adjust the speed of the mouse for mouse related commands.
831
+ * @param {webdriver.WebDriver.Speed} speed The new speed setting.
832
+ */
833
+ webdriver.WebDriver.prototype.setMouseSpeed = function(speed) {
834
+ this.addCommand(new webdriver.Command(webdriver.CommandName.SET_MOUSE_SPEED).
835
+ setParameters(speed));
836
+ };
837
+
838
+
839
+ /**
840
+ * Fetch the current mouse speed.
841
+ * @return {webdriver.Future} A Future whose value will be set by this driver
842
+ * when the query command completes.
843
+ */
844
+ webdriver.WebDriver.prototype.getMouseSpeed = function() {
845
+ var speed = new webdriver.Future(this);
846
+ this.addCommand(
847
+ new webdriver.Command(webdriver.CommandName.GET_MOUSE_SPEED).
848
+ setSuccessCallback(function(response) {
849
+ response.value = Number(response.value);
850
+ speed.setValue(response.value);
851
+ }));
852
+ return speed;
853
+ };