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.
- data/chrome/prebuilt/Win32/Release/npchromedriver.dll +0 -0
- data/chrome/prebuilt/x64/Release/npchromedriver.dll +0 -0
- data/chrome/src/extension/background.html +9 -0
- data/chrome/src/extension/background.js +933 -0
- data/chrome/src/extension/content_script.js +1286 -0
- data/chrome/src/extension/manifest-nonwin.json +15 -0
- data/chrome/src/extension/manifest-win.json +16 -0
- data/chrome/src/extension/toolstrip.html +28 -0
- data/chrome/src/extension/utils.js +196 -0
- data/chrome/src/rb/lib/selenium/webdriver/chrome.rb +8 -0
- data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +324 -0
- data/chrome/src/rb/lib/selenium/webdriver/chrome/command_executor.rb +70 -0
- data/chrome/src/rb/lib/selenium/webdriver/chrome/launcher.rb +119 -0
- data/common/src/js/abstractcommandprocessor.js +161 -0
- data/common/src/js/asserts.js +296 -0
- data/common/src/js/by.js +147 -0
- data/common/src/js/command.js +274 -0
- data/common/src/js/context.js +58 -0
- data/common/src/js/extension/README +2 -0
- data/common/src/js/extension/dommessenger.js +152 -0
- data/common/src/js/factory.js +55 -0
- data/common/src/js/future.js +118 -0
- data/common/src/js/key.js +117 -0
- data/common/src/js/localcommandprocessor.js +181 -0
- data/common/src/js/logging.js +249 -0
- data/common/src/js/testrunner.js +605 -0
- data/common/src/js/timing.js +89 -0
- data/common/src/js/wait.js +199 -0
- data/common/src/js/webdriver.js +853 -0
- data/common/src/js/webelement.js +683 -0
- data/common/src/rb/lib/selenium-webdriver.rb +1 -0
- data/common/src/rb/lib/selenium/webdriver.rb +52 -0
- data/common/src/rb/lib/selenium/webdriver/bridge_helper.rb +88 -0
- data/common/src/rb/lib/selenium/webdriver/child_process.rb +85 -0
- data/common/src/rb/lib/selenium/webdriver/core_ext/dir.rb +41 -0
- data/common/src/rb/lib/selenium/webdriver/driver.rb +128 -0
- data/common/src/rb/lib/selenium/webdriver/element.rb +126 -0
- data/common/src/rb/lib/selenium/webdriver/error.rb +68 -0
- data/common/src/rb/lib/selenium/webdriver/find.rb +69 -0
- data/common/src/rb/lib/selenium/webdriver/navigation.rb +23 -0
- data/common/src/rb/lib/selenium/webdriver/options.rb +50 -0
- data/common/src/rb/lib/selenium/webdriver/platform.rb +82 -0
- data/common/src/rb/lib/selenium/webdriver/target_locator.rb +23 -0
- data/firefox/prebuilt/nsICommandProcessor.xpt +0 -0
- data/firefox/prebuilt/nsINativeEvents.xpt +0 -0
- data/firefox/prebuilt/nsIResponseHandler.xpt +0 -0
- data/firefox/src/extension/chrome.manifest +3 -0
- data/firefox/src/extension/components/context.js +37 -0
- data/firefox/src/extension/components/driver-component.js +127 -0
- data/firefox/src/extension/components/firefoxDriver.js +706 -0
- data/firefox/src/extension/components/json2.js +273 -0
- data/firefox/src/extension/components/keytest.html +554 -0
- data/firefox/src/extension/components/nsCommandProcessor.js +586 -0
- data/firefox/src/extension/components/screenshooter.js +70 -0
- data/firefox/src/extension/components/socketListener.js +185 -0
- data/firefox/src/extension/components/utils.js +1200 -0
- data/firefox/src/extension/components/webLoadingListener.js +57 -0
- data/firefox/src/extension/components/webdriverserver.js +101 -0
- data/firefox/src/extension/components/wrappedElement.js +609 -0
- data/firefox/src/extension/content/fxdriver.xul +30 -0
- data/firefox/src/extension/content/server.js +95 -0
- data/firefox/src/extension/idl/nsICommandProcessor.idl +38 -0
- data/firefox/src/extension/idl/nsIResponseHandler.idl +34 -0
- data/firefox/src/extension/install.rdf +29 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox.rb +21 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/binary.rb +86 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +426 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +82 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/launcher.rb +132 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +174 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/profiles_ini.rb +60 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/util.rb +23 -0
- data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
- data/jobbie/prebuilt/x64/Release/InternetExplorerDriver.dll +0 -0
- data/jobbie/src/rb/lib/selenium/webdriver/ie.rb +14 -0
- data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +552 -0
- data/jobbie/src/rb/lib/selenium/webdriver/ie/lib.rb +94 -0
- data/jobbie/src/rb/lib/selenium/webdriver/ie/util.rb +147 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote.rb +16 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +374 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/capabilities.rb +105 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/commands.rb +53 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/default_http_client.rb +71 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/response.rb +43 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/server_error.rb +32 -0
- 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
|
+
};
|