rainux-selenium-webdriver 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/COPYING +204 -0
  2. data/chrome/prebuilt/Win32/Release/npchromedriver.dll +0 -0
  3. data/chrome/prebuilt/x64/Release/npchromedriver.dll +0 -0
  4. data/chrome/src/extension/background.html +9 -0
  5. data/chrome/src/extension/background.js +995 -0
  6. data/chrome/src/extension/content_script.js +1321 -0
  7. data/chrome/src/extension/icons/busy.png +0 -0
  8. data/chrome/src/extension/icons/free.png +0 -0
  9. data/chrome/src/extension/manifest-nonwin.json +19 -0
  10. data/chrome/src/extension/manifest-win.json +20 -0
  11. data/chrome/src/extension/utils.js +231 -0
  12. data/chrome/src/rb/lib/selenium/webdriver/chrome.rb +8 -0
  13. data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +358 -0
  14. data/chrome/src/rb/lib/selenium/webdriver/chrome/command_executor.rb +124 -0
  15. data/chrome/src/rb/lib/selenium/webdriver/chrome/launcher.rb +135 -0
  16. data/common/src/js/abstractcommandprocessor.js +134 -0
  17. data/common/src/js/asserts.js +296 -0
  18. data/common/src/js/by.js +149 -0
  19. data/common/src/js/command.js +304 -0
  20. data/common/src/js/context.js +58 -0
  21. data/common/src/js/core/Blank.html +7 -0
  22. data/common/src/js/core/InjectedRemoteRunner.html +8 -0
  23. data/common/src/js/core/RemoteRunner.html +101 -0
  24. data/common/src/js/core/SeleniumLog.html +109 -0
  25. data/common/src/js/core/TestPrompt.html +145 -0
  26. data/common/src/js/core/TestRunner-splash.html +55 -0
  27. data/common/src/js/core/TestRunner.html +165 -0
  28. data/common/src/js/core/icons/all.png +0 -0
  29. data/common/src/js/core/icons/continue.png +0 -0
  30. data/common/src/js/core/icons/continue_disabled.png +0 -0
  31. data/common/src/js/core/icons/pause.png +0 -0
  32. data/common/src/js/core/icons/pause_disabled.png +0 -0
  33. data/common/src/js/core/icons/selected.png +0 -0
  34. data/common/src/js/core/icons/step.png +0 -0
  35. data/common/src/js/core/icons/step_disabled.png +0 -0
  36. data/common/src/js/core/lib/cssQuery/cssQuery-p.js +6 -0
  37. data/common/src/js/core/lib/cssQuery/src/cssQuery-level2.js +142 -0
  38. data/common/src/js/core/lib/cssQuery/src/cssQuery-level3.js +150 -0
  39. data/common/src/js/core/lib/cssQuery/src/cssQuery-standard.js +53 -0
  40. data/common/src/js/core/lib/cssQuery/src/cssQuery.js +356 -0
  41. data/common/src/js/core/lib/prototype.js +2006 -0
  42. data/common/src/js/core/lib/scriptaculous/builder.js +101 -0
  43. data/common/src/js/core/lib/scriptaculous/controls.js +815 -0
  44. data/common/src/js/core/lib/scriptaculous/dragdrop.js +915 -0
  45. data/common/src/js/core/lib/scriptaculous/effects.js +958 -0
  46. data/common/src/js/core/lib/scriptaculous/scriptaculous.js +47 -0
  47. data/common/src/js/core/lib/scriptaculous/slider.js +283 -0
  48. data/common/src/js/core/lib/scriptaculous/unittest.js +383 -0
  49. data/common/src/js/core/lib/snapsie.js +91 -0
  50. data/common/src/js/core/scripts/find_matching_child.js +69 -0
  51. data/common/src/js/core/scripts/htmlutils.js +8716 -0
  52. data/common/src/js/core/scripts/injection.html +72 -0
  53. data/common/src/js/core/scripts/selenium-api.js +3291 -0
  54. data/common/src/js/core/scripts/selenium-browserbot.js +2457 -0
  55. data/common/src/js/core/scripts/selenium-browserdetect.js +153 -0
  56. data/common/src/js/core/scripts/selenium-commandhandlers.js +379 -0
  57. data/common/src/js/core/scripts/selenium-executionloop.js +175 -0
  58. data/common/src/js/core/scripts/selenium-logging.js +148 -0
  59. data/common/src/js/core/scripts/selenium-remoterunner.js +695 -0
  60. data/common/src/js/core/scripts/selenium-testrunner.js +1362 -0
  61. data/common/src/js/core/scripts/selenium-version.js +5 -0
  62. data/common/src/js/core/scripts/ui-doc.html +808 -0
  63. data/common/src/js/core/scripts/ui-element.js +1644 -0
  64. data/common/src/js/core/scripts/ui-map-sample.js +979 -0
  65. data/common/src/js/core/scripts/user-extensions.js +3 -0
  66. data/common/src/js/core/scripts/user-extensions.js.sample +75 -0
  67. data/common/src/js/core/scripts/xmlextras.js +153 -0
  68. data/common/src/js/core/selenium-logo.png +0 -0
  69. data/common/src/js/core/selenium-test.css +43 -0
  70. data/common/src/js/core/selenium.css +316 -0
  71. data/common/src/js/core/xpath/dom.js +566 -0
  72. data/common/src/js/core/xpath/javascript-xpath-0.1.11.js +2816 -0
  73. data/common/src/js/core/xpath/util.js +549 -0
  74. data/common/src/js/core/xpath/xmltoken.js +149 -0
  75. data/common/src/js/core/xpath/xpath.js +2481 -0
  76. data/common/src/js/extension/README +2 -0
  77. data/common/src/js/extension/dommessenger.js +152 -0
  78. data/common/src/js/factory.js +55 -0
  79. data/common/src/js/future.js +141 -0
  80. data/common/src/js/jsunit.js +40 -0
  81. data/common/src/js/jsunit/app/css/jsUnitStyle.css +50 -0
  82. data/common/src/js/jsunit/app/css/readme +10 -0
  83. data/common/src/js/jsunit/app/emptyPage.html +11 -0
  84. data/common/src/js/jsunit/app/jsUnitCore.js +534 -0
  85. data/common/src/js/jsunit/app/jsUnitMockTimeout.js +81 -0
  86. data/common/src/js/jsunit/app/jsUnitTestManager.js +705 -0
  87. data/common/src/js/jsunit/app/jsUnitTestSuite.js +44 -0
  88. data/common/src/js/jsunit/app/jsUnitTracer.js +102 -0
  89. data/common/src/js/jsunit/app/jsUnitVersionCheck.js +59 -0
  90. data/common/src/js/jsunit/app/main-counts-errors.html +12 -0
  91. data/common/src/js/jsunit/app/main-counts-failures.html +13 -0
  92. data/common/src/js/jsunit/app/main-counts-runs.html +13 -0
  93. data/common/src/js/jsunit/app/main-counts.html +21 -0
  94. data/common/src/js/jsunit/app/main-data.html +178 -0
  95. data/common/src/js/jsunit/app/main-errors.html +23 -0
  96. data/common/src/js/jsunit/app/main-frame.html +19 -0
  97. data/common/src/js/jsunit/app/main-loader.html +45 -0
  98. data/common/src/js/jsunit/app/main-progress.html +25 -0
  99. data/common/src/js/jsunit/app/main-results.html +67 -0
  100. data/common/src/js/jsunit/app/main-status.html +13 -0
  101. data/common/src/js/jsunit/app/testContainer.html +16 -0
  102. data/common/src/js/jsunit/app/testContainerController.html +77 -0
  103. data/common/src/js/jsunit/app/xbDebug.js +306 -0
  104. data/common/src/js/jsunit/changelog.txt +60 -0
  105. data/common/src/js/jsunit/css/jsUnitStyle.css +83 -0
  106. data/common/src/js/jsunit/images/green.gif +0 -0
  107. data/common/src/js/jsunit/images/logo_jsunit.gif +0 -0
  108. data/common/src/js/jsunit/images/powerby-transparent.gif +0 -0
  109. data/common/src/js/jsunit/images/red.gif +0 -0
  110. data/common/src/js/jsunit/licenses/JDOM_license.txt +56 -0
  111. data/common/src/js/jsunit/licenses/Jetty_license.html +213 -0
  112. data/common/src/js/jsunit/licenses/MPL-1.1.txt +470 -0
  113. data/common/src/js/jsunit/licenses/gpl-2.txt +340 -0
  114. data/common/src/js/jsunit/licenses/index.html +141 -0
  115. data/common/src/js/jsunit/licenses/lgpl-2.1.txt +504 -0
  116. data/common/src/js/jsunit/licenses/mpl-tri-license-c.txt +35 -0
  117. data/common/src/js/jsunit/licenses/mpl-tri-license-html.txt +35 -0
  118. data/common/src/js/jsunit/readme.txt +19 -0
  119. data/common/src/js/jsunit/testRunner.html +167 -0
  120. data/common/src/js/jsunit/version.txt +1 -0
  121. data/common/src/js/key.js +117 -0
  122. data/common/src/js/localcommandprocessor.js +185 -0
  123. data/common/src/js/testcase.js +217 -0
  124. data/common/src/js/timing.js +89 -0
  125. data/common/src/js/webdriver.js +890 -0
  126. data/common/src/js/webelement.js +485 -0
  127. data/common/src/rb/README +30 -0
  128. data/common/src/rb/lib/selenium-webdriver.rb +1 -0
  129. data/common/src/rb/lib/selenium/webdriver.rb +67 -0
  130. data/common/src/rb/lib/selenium/webdriver/bridge_helper.rb +91 -0
  131. data/common/src/rb/lib/selenium/webdriver/child_process.rb +180 -0
  132. data/common/src/rb/lib/selenium/webdriver/core_ext/dir.rb +41 -0
  133. data/common/src/rb/lib/selenium/webdriver/driver.rb +252 -0
  134. data/common/src/rb/lib/selenium/webdriver/driver_extensions/takes_screenshot.rb +24 -0
  135. data/common/src/rb/lib/selenium/webdriver/element.rb +262 -0
  136. data/common/src/rb/lib/selenium/webdriver/error.rb +67 -0
  137. data/common/src/rb/lib/selenium/webdriver/find.rb +89 -0
  138. data/common/src/rb/lib/selenium/webdriver/keys.rb +84 -0
  139. data/common/src/rb/lib/selenium/webdriver/navigation.rb +27 -0
  140. data/common/src/rb/lib/selenium/webdriver/options.rb +50 -0
  141. data/common/src/rb/lib/selenium/webdriver/platform.rb +86 -0
  142. data/common/src/rb/lib/selenium/webdriver/target_locator.rb +70 -0
  143. data/firefox/prebuilt/Win32/Release/webdriver-firefox.dll +0 -0
  144. data/firefox/prebuilt/linux/Release/libwebdriver-firefox.so +0 -0
  145. data/firefox/prebuilt/linux/Release/x_ignore_nofocus.so +0 -0
  146. data/firefox/prebuilt/linux64/Release/libwebdriver-firefox.so +0 -0
  147. data/firefox/prebuilt/linux64/Release/x_ignore_nofocus.so +0 -0
  148. data/firefox/prebuilt/nsICommandProcessor.xpt +0 -0
  149. data/firefox/prebuilt/nsINativeEvents.xpt +0 -0
  150. data/firefox/prebuilt/nsIResponseHandler.xpt +0 -0
  151. data/firefox/src/extension/chrome.manifest +3 -0
  152. data/firefox/src/extension/components/badCertListener.js +294 -0
  153. data/firefox/src/extension/components/context.js +37 -0
  154. data/firefox/src/extension/components/driver-component.js +127 -0
  155. data/firefox/src/extension/components/firefoxDriver.js +810 -0
  156. data/firefox/src/extension/components/json2.js +273 -0
  157. data/firefox/src/extension/components/keytest.html +554 -0
  158. data/firefox/src/extension/components/nsCommandProcessor.js +643 -0
  159. data/firefox/src/extension/components/promptService.js +208 -0
  160. data/firefox/src/extension/components/screenshooter.js +81 -0
  161. data/firefox/src/extension/components/socketListener.js +185 -0
  162. data/firefox/src/extension/components/utils.js +1263 -0
  163. data/firefox/src/extension/components/webLoadingListener.js +57 -0
  164. data/firefox/src/extension/components/webdriverserver.js +106 -0
  165. data/firefox/src/extension/components/wrappedElement.js +683 -0
  166. data/firefox/src/extension/content/fxdriver.xul +30 -0
  167. data/firefox/src/extension/content/server.js +95 -0
  168. data/firefox/src/extension/idl/nsICommandProcessor.idl +38 -0
  169. data/firefox/src/extension/idl/nsIResponseHandler.idl +34 -0
  170. data/firefox/src/extension/install.rdf +29 -0
  171. data/firefox/src/rb/lib/selenium/webdriver/firefox.rb +31 -0
  172. data/firefox/src/rb/lib/selenium/webdriver/firefox/binary.rb +107 -0
  173. data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +484 -0
  174. data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +90 -0
  175. data/firefox/src/rb/lib/selenium/webdriver/firefox/launcher.rb +155 -0
  176. data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +233 -0
  177. data/firefox/src/rb/lib/selenium/webdriver/firefox/profiles_ini.rb +59 -0
  178. data/firefox/src/rb/lib/selenium/webdriver/firefox/util.rb +23 -0
  179. data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
  180. data/jobbie/prebuilt/x64/Release/InternetExplorerDriver.dll +0 -0
  181. data/jobbie/src/rb/lib/selenium/webdriver/ie.rb +14 -0
  182. data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +565 -0
  183. data/jobbie/src/rb/lib/selenium/webdriver/ie/lib.rb +99 -0
  184. data/jobbie/src/rb/lib/selenium/webdriver/ie/util.rb +147 -0
  185. data/remote/client/src/rb/lib/selenium/webdriver/remote.rb +16 -0
  186. data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +408 -0
  187. data/remote/client/src/rb/lib/selenium/webdriver/remote/capabilities.rb +105 -0
  188. data/remote/client/src/rb/lib/selenium/webdriver/remote/commands.rb +53 -0
  189. data/remote/client/src/rb/lib/selenium/webdriver/remote/default_http_client.rb +71 -0
  190. data/remote/client/src/rb/lib/selenium/webdriver/remote/response.rb +49 -0
  191. data/remote/client/src/rb/lib/selenium/webdriver/remote/server_error.rb +32 -0
  192. metadata +303 -0
@@ -0,0 +1,217 @@
1
+ /** @license
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+
18
+ /**
19
+ * @fileoverview A test case that uses the WebDriver Javascript API. Each phase
20
+ * of a test (setUp, test function, and tearDown) will be called with an
21
+ * instance of a {@code webdriver.WebDriver} that can be used to schedule
22
+ * commands for controlling the browser (e.g. clicking or typing on an
23
+ * element).
24
+ * <p>
25
+ * Unlike pure JavaScript test frameworks like Selenium, WebDriver controls the
26
+ * browser directly, allowing for more accurate simulation of user actions in a
27
+ * web application.
28
+ * <p>
29
+ * See below for a basic example of using WebDriver to test cut and paste in
30
+ * a contentEditable document.
31
+ * <pre>
32
+ * goog.require('goog.dom');
33
+ * goog.require('webdriver.asserts');
34
+ * goog.require('webdriver.jsunit');
35
+ *
36
+ * var richTextFrame;
37
+ *
38
+ * function setUp() {
39
+ * richTextFrame = goog.dom.$('rtframe');
40
+ * richTextFrame.contentWindow.document.designMode = 'on';
41
+ * richTextFrame.contentWindow.document.body.innerHTML = '';
42
+ * }
43
+ *
44
+ * function testCutAndPaste(driver) {
45
+ * driver.switchToFrame('rtframe');
46
+ * var body = driver.findElement({xpath: '//body'});
47
+ * body.sendKeys('abc', webdriver.Key.CONTROL, 'axvv');
48
+ * driver.callFunction(function() {
49
+ * assertEquals('abcabc',
50
+ * richTextFrame.contentWindow.document.body.innerHTML);
51
+ * });
52
+ * }
53
+ * </pre>
54
+ *
55
+ * @author jmleyba@gmail.com (Jason Leyba)
56
+ */
57
+
58
+ goog.provide('webdriver.TestCase');
59
+ goog.provide('webdriver.TestCase.Test');
60
+
61
+ goog.require('goog.events');
62
+ goog.require('goog.testing.TestCase');
63
+ goog.require('goog.testing.TestCase.Test');
64
+ goog.require('goog.testing.asserts');
65
+ goog.require('webdriver.Command');
66
+
67
+
68
+
69
+ /**
70
+ * A specialized test case for running jsunit tests with the WebDriver
71
+ * framework. Each phase of a test (setUp, test, and tearDown) will be given an
72
+ * instance of {@code webdriver.WebDriver} that can be used to schedule
73
+ * commands for controlling the browser.
74
+ * @param {string} name The name of the test case.
75
+ * @param {function(): webdriver.WebDriver} driverFactoryFn Factory function to
76
+ * use for creating {@code webdriver.WebDriver} instances for each test.
77
+ * @extends {goog.testing.TestCase}
78
+ * @constructor
79
+ */
80
+ webdriver.TestCase = function(name, driverFactoryFn) {
81
+ goog.testing.TestCase.call(this, name);
82
+
83
+ /**
84
+ * Factory function use for creating {@code webdriver.WebDriver}
85
+ * instances for each test.
86
+ * @type {function(): webdriver.WebDriver}
87
+ * @private
88
+ */
89
+ this.driverFactoryFn_ = driverFactoryFn;
90
+ };
91
+ goog.inherits(webdriver.TestCase, goog.testing.TestCase);
92
+
93
+
94
+ /** @override */
95
+ webdriver.TestCase.prototype.cycleTests = function() {
96
+ this.saveMessage('Start');
97
+ this.batchTime_ = this.now_();
98
+ this.startTest_();
99
+ };
100
+
101
+
102
+ /**
103
+ * Starts a test.
104
+ * @private
105
+ */
106
+ webdriver.TestCase.prototype.startTest_ = function() {
107
+ var test = this.next();
108
+ if (!test || !this.running) {
109
+ this.finalize(); // Tests are done.
110
+ return;
111
+ }
112
+
113
+ // TODO(jleyba): result_ should be exposed using a public accessor.
114
+ this.result_.runCount++;
115
+ this.log('Running test: ' + test.name);
116
+ goog.testing.TestCase.currentTestName = test.name;
117
+
118
+ var driver;
119
+ try {
120
+ driver = this.driverFactoryFn_();
121
+
122
+ // Attach an error handler to record each command failure as an error for
123
+ // the current test. After each error, the currently pending command and
124
+ // all of its subcommands so we can continue the test.
125
+ goog.events.listen(driver, webdriver.Command.ERROR_EVENT,
126
+ function(e) {
127
+ var failingCommand = (/** @type {webdriver.Command} */e.target);
128
+ if (!failingCommand.getResponse()) {
129
+ // This should never happen, but just in case.
130
+ test.errors.push('Unknown error');
131
+ } else {
132
+ test.errors.push(failingCommand.getResponse().getErrorMessage());
133
+ }
134
+ driver.abortCommand(null);
135
+ }, /*capture=*/false);
136
+
137
+ // TODO(jleyba): make this automatic upon creating an instance.
138
+ driver.newSession(true);
139
+
140
+ // If setup fails, we don't want to run the test function, so group setup
141
+ // and the test function together in a function command.
142
+ driver.callFunction(function() {
143
+ this.setUp(driver);
144
+ // Wrap the call to the actual test function in a function command. This
145
+ // will ensure all of the commands scheduled in setUp will executed before
146
+ // the test function is called.
147
+ driver.callFunction(function() {
148
+ test.ref.call(test.scope, driver);
149
+ });
150
+ }, this);
151
+
152
+ // Call tearDown once all setup and test commands have completed.
153
+ driver.callFunction(function() {
154
+ this.tearDown(driver);
155
+ }, this);
156
+
157
+ // Likewise, once tearDown is completely finished, finish the test.
158
+ driver.callFunction(function() {
159
+ this.finishTest_(test, driver);
160
+ }, this);
161
+ } catch (e) {
162
+ test.errors.push(e);
163
+ this.finishTest_(test, driver);
164
+ }
165
+ };
166
+
167
+ /**
168
+ * Completes a test.
169
+ * @param {webdriver.TestCase.Test} test The test to complete.
170
+ * @param {webdriver.WebDriver} driver The driver instance used by the test.
171
+ * @private
172
+ */
173
+ webdriver.TestCase.prototype.finishTest_ = function(test, driver) {
174
+ if (driver) {
175
+ driver.dispose();
176
+ }
177
+ goog.testing.TestCase.currentTestName = null;
178
+ var numErrors = test.errors.length;
179
+ if (numErrors) {
180
+ for (var i = 0; i < numErrors; i++) {
181
+ this.doError(test, test.errors[i]);
182
+ }
183
+ } else {
184
+ this.doSuccess(test);
185
+ }
186
+ this.startTest_(); // Start the next test.
187
+ };
188
+
189
+
190
+ /** @override */
191
+ webdriver.TestCase.prototype.createTestFromAutoDiscoveredFunction =
192
+ function(name, ref) {
193
+ return new webdriver.TestCase.Test(name, ref, goog.global);
194
+ };
195
+
196
+
197
+ /**
198
+ * Represents a single test function that will be run by a
199
+ * {@code webdriver.TestCase}.
200
+ * @param {string} name The test name.
201
+ * @param {function} ref Reference to the test function.
202
+ * @param {Object} opt_scope Optional scope that the test function should be
203
+ * called in.
204
+ * @constructor
205
+ * @extends {goog.testing.TestCase.Test}
206
+ */
207
+ webdriver.TestCase.Test = function(name, ref, opt_scope) {
208
+ goog.testing.TestCase.Test.call(this, name, ref, opt_scope);
209
+
210
+ /**
211
+ * The errors that occurred while running this test.
212
+ * @type {Array.<string|Error>}
213
+ */
214
+ this.errors = [];
215
+ };
216
+ goog.inherits(webdriver.TestCase.Test, goog.testing.TestCase.Test);
217
+
@@ -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,890 @@
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
+ goog.provide('webdriver.WebDriver.Speed');
26
+
27
+ goog.require('goog.debug.Logger');
28
+ goog.require('goog.events');
29
+ goog.require('goog.events.EventTarget');
30
+ goog.require('webdriver.By.Locator');
31
+ goog.require('webdriver.Command');
32
+ goog.require('webdriver.CommandName');
33
+ goog.require('webdriver.Context');
34
+ goog.require('webdriver.Response');
35
+ goog.require('webdriver.WebElement');
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 logger for this instance.
74
+ * @type {!goog.debug.Logger}
75
+ * @private
76
+ */
77
+ this.logger_ = goog.debug.Logger.getLogger('webdriver.WebDriver');
78
+
79
+ /**
80
+ * The command processor to use for executing commands.
81
+ * @type {Object}
82
+ * @private
83
+ */
84
+ this.commandProcessor_ = commandProcessor;
85
+
86
+ /**
87
+ * A stack of frames for queued commands. The list of commands at index 0
88
+ * are global commands. When the stack has more than 1 frame, the commands
89
+ * in the list at the top of the stack are the remaining subcommands for the
90
+ * command at the top of the {@code pendingCommands_} stack.
91
+ * @type {Array.<Array.<webdriver.Command>>}
92
+ * @private
93
+ */
94
+ this.queuedCommands_ = [[]];
95
+
96
+ /**
97
+ * A list of commands that are currently being executed. The command at index
98
+ * N+1 is a subcommand to the command at index N. It will always be the case
99
+ * that {@code queuedCommands_.length == pendingCommands_.length + 1;}.
100
+ * @type {Array.<webdriver.Command>}
101
+ * @private
102
+ */
103
+ this.pendingCommands_ = [];
104
+
105
+ /**
106
+ * Whether this instance is paused. When paused, commands can still be issued,
107
+ * but no commands will be executed.
108
+ * @type {boolean}
109
+ * @private
110
+ */
111
+ this.isPaused_ = false;
112
+
113
+ /**
114
+ * This instances current context (window and frame ID).
115
+ * @type {webdriver.Context}
116
+ * @private
117
+ */
118
+ this.context_ = new webdriver.Context();
119
+
120
+ /**
121
+ * This instance's current session ID. Set with the
122
+ * {@code webdriver.WebDriver.prototype.newSession} command.
123
+ * @type {?string}
124
+ * @private
125
+ */
126
+ this.sessionId_ = null;
127
+
128
+ /**
129
+ * Interval ID for the command processing loop.
130
+ * @type {number}
131
+ * @private
132
+ */
133
+ this.commandInterval_ = webdriver.timing.setInterval(
134
+ goog.bind(this.processCommands_, this),
135
+ webdriver.WebDriver.COMMAND_INTERVAL_LENGTH_);
136
+ };
137
+ goog.inherits(webdriver.WebDriver, goog.events.EventTarget);
138
+
139
+
140
+ /**
141
+ * The amount of time in milliseconds between ticks of the command processing
142
+ * interval.
143
+ * @type {number}
144
+ * @private
145
+ */
146
+ webdriver.WebDriver.COMMAND_INTERVAL_LENGTH_ = 10;
147
+
148
+
149
+ /**
150
+ * Enumeration of the events that may be dispatched by an instance of
151
+ * {@code webdriver.WebDriver}.
152
+ * @enum {string}
153
+ */
154
+ webdriver.WebDriver.EventType = {
155
+ ERROR: 'ERROR',
156
+ PAUSED: 'PAUSED',
157
+ RESUMED: 'RESUMED'
158
+ };
159
+
160
+
161
+ /**
162
+ * Enumeration of the supported mouse speeds.
163
+ * @enum {number}
164
+ * @see webdriver.WebDriver.prototype.setMouseSpeed
165
+ * @see webdriver.WebDriver.prototype.getMouseSpeed
166
+ */
167
+ webdriver.WebDriver.Speed = {
168
+ SLOW: 1,
169
+ MEDIUM: 10,
170
+ FAST: 100
171
+ };
172
+
173
+
174
+ /**
175
+ * @override
176
+ */
177
+ webdriver.WebDriver.prototype.disposeInternal = function() {
178
+ this.commandProcessor_.dispose();
179
+ webdriver.timing.clearInterval(this.commandInterval_);
180
+
181
+ goog.array.forEach(this.pendingCommands_, function(command) {
182
+ command.dispose();
183
+ });
184
+ goog.array.forEach(this.queuedCommands_, function(frame) {
185
+ goog.array.forEach(frame, function(command) {
186
+ command.dispose();
187
+ });
188
+ });
189
+
190
+ delete this.commandProcessor_;
191
+ delete this.pendingCommands_;
192
+ delete this.queuedCommands_;
193
+ delete this.isPaused_;
194
+ delete this.context_;
195
+ delete this.sessionLocked_;
196
+ delete this.sessionId_;
197
+ delete this.commandInterval_;
198
+
199
+ webdriver.WebDriver.superClass_.disposeInternal.call(this);
200
+ };
201
+
202
+
203
+ /**
204
+ * Queues a command to execute.
205
+ * @param {webdriver.CommandName} name The name of the command to execute.
206
+ * @param {webdriver.WebElement} opt_element The element that is the target
207
+ * of the new command.
208
+ * @return {webdriver.Command} The new command.
209
+ * @protected
210
+ */
211
+ webdriver.WebDriver.prototype.addCommand = function(name, opt_element) {
212
+ var command = new webdriver.Command(this, name, opt_element);
213
+ goog.array.peek(this.queuedCommands_).push(command);
214
+ return command;
215
+ };
216
+
217
+
218
+ /**
219
+ * @return {boolean} Whether this driver is idle (there are no pending
220
+ * commands).
221
+ */
222
+ webdriver.WebDriver.prototype.isIdle = function() {
223
+ if (this.isDisposed()) {
224
+ return true;
225
+ }
226
+
227
+ // If there is a finished command on the pending command queue, but it
228
+ // failed, then the failure hasn't been dealt with yet and the driver will
229
+ // not process any more commands, so we consider this idle.
230
+ var pendingCommand = goog.array.peek(this.pendingCommands_);
231
+ if (pendingCommand && pendingCommand.isFinished() &&
232
+ pendingCommand.getResponse().isFailure) {
233
+ return true;
234
+ }
235
+ return !pendingCommand && this.queuedCommands_.length == 1 &&
236
+ !this.queuedCommands_[0].length;
237
+ };
238
+
239
+
240
+ /**
241
+ * Aborts the specified command and all of its pending subcommands.
242
+ * @param {webdriver.Command|webdriver.WebDriver} command The command to abort.
243
+ * @return {number} The total number of commands aborted. A value of 0
244
+ * indicates that the given command was not a pending command.
245
+ */
246
+ webdriver.WebDriver.prototype.abortCommand = function(command) {
247
+ var index = (null == command || this == command) ? 0 :
248
+ goog.array.findIndexRight(this.pendingCommands_, function(cmd) {
249
+ return cmd == command;
250
+ });
251
+ if (index >= 0) {
252
+ var numAborted = this.pendingCommands_.length - index;
253
+ var totalNumAborted = numAborted;
254
+ for (var i = 0; i < numAborted; i++) {
255
+ this.pendingCommands_.pop().dispose();
256
+ goog.array.forEach(this.queuedCommands_.pop(), function(subCommand) {
257
+ totalNumAborted += 1;
258
+ subCommand.dispose();
259
+ });
260
+ }
261
+ return totalNumAborted;
262
+ }
263
+ return 0;
264
+ };
265
+
266
+
267
+ /**
268
+ * Immediately pauses the driver so it will not execute anymore commands until
269
+ * {@code #resume()} is called.
270
+ * Dispatches a {@code webdriver.WebDriver.EventType.PAUSED} event.
271
+ */
272
+ webdriver.WebDriver.prototype.pauseImmediately = function() {
273
+ this.isPaused_ = true;
274
+ this.logger_.fine('WebDriver paused');
275
+ this.dispatchEvent(webdriver.WebDriver.EventType.PAUSED);
276
+ };
277
+
278
+
279
+ /**
280
+ * Unpauses this driver so it can execute commands again. Dispatches a
281
+ * {@code webdriver.WebDriver.EventType.RESUMED} event.
282
+ */
283
+ webdriver.WebDriver.prototype.resume = function() {
284
+ this.isPaused_ = false;
285
+ this.logger_.fine('WebDriver resumed');
286
+ this.dispatchEvent(webdriver.WebDriver.EventType.RESUMED);
287
+ };
288
+
289
+
290
+ /**
291
+ * Event handler for whenever this driver is ready to execute a command.
292
+ * @private
293
+ */
294
+ webdriver.WebDriver.prototype.processCommands_ = function() {
295
+ var pendingCommand = goog.array.peek(this.pendingCommands_);
296
+ if (this.isPaused_ || (pendingCommand && !pendingCommand.isFinished())) {
297
+ return;
298
+ }
299
+
300
+ if (pendingCommand && pendingCommand.getResponse().isFailure) {
301
+ // Or should we be throwing this to be caught by window.onerror?
302
+ this.logger_.severe(
303
+ 'Unhandled command failure; halting command processing:\n' +
304
+ pendingCommand.getResponse().getErrorMessage());
305
+ return;
306
+ }
307
+
308
+ var currentFrame = goog.array.peek(this.queuedCommands_);
309
+ var nextCommand = currentFrame.shift();
310
+ while (!nextCommand && this.queuedCommands_.length > 1) {
311
+ this.queuedCommands_.pop();
312
+ this.pendingCommands_.pop();
313
+ currentFrame = goog.array.peek(this.queuedCommands_);
314
+ nextCommand = currentFrame.shift();
315
+ }
316
+
317
+ if (nextCommand) {
318
+ var parentTarget = goog.array.peek(this.pendingCommands_) || this;
319
+ nextCommand.setParentEventTarget(parentTarget);
320
+ this.pendingCommands_.push(nextCommand);
321
+ this.queuedCommands_.push([]);
322
+ this.commandProcessor_.execute(nextCommand);
323
+ }
324
+ };
325
+
326
+
327
+ /**
328
+ * @return {?string} This instance's current session ID or {@code null} if it
329
+ * does not have one yet.
330
+ */
331
+ webdriver.WebDriver.prototype.getSessionId = function() {
332
+ return this.sessionId_;
333
+ };
334
+
335
+
336
+ /**
337
+ * @return {webdriver.Context} This instance's current context.
338
+ */
339
+ webdriver.WebDriver.prototype.getContext = function() {
340
+ return this.context_;
341
+ };
342
+
343
+
344
+ /**
345
+ * Sets this driver's context.
346
+ * @param {webdriver.Context} context The new context.
347
+ */
348
+ webdriver.WebDriver.prototype.setContext = function(context) {
349
+ return this.context_ = context;
350
+ };
351
+
352
+
353
+ // ----------------------------------------------------------------------------
354
+ // Client command functions:
355
+ // ----------------------------------------------------------------------------
356
+
357
+ /**
358
+ * Adds an event handler to catch any {@code ERROR} events from the previous
359
+ * command. If the previous command generates an ERROR, that error will be
360
+ * suppressed and this instance will continue executing commands. If an error
361
+ * was not raised, a new {@code webdriver.WebDriver.EventType.ERROR} event will
362
+ * be dispatched for the unexpected behavior.
363
+ * @param {string} opt_errorMsg The message to include with the ERROR event if
364
+ * the expected error does not occur.
365
+ */
366
+ webdriver.WebDriver.prototype.catchExpectedError = function(opt_errorMsg,
367
+ opt_handlerFn) {
368
+ var currentFrame = goog.array.peek(this.queuedCommands_);
369
+ var previousCommand = goog.array.peek(currentFrame);
370
+ if (!previousCommand) {
371
+ throw new Error('No commands in the queue to expect an error from');
372
+ }
373
+
374
+ var failedCommand = null;
375
+ var key = goog.events.listenOnce(previousCommand,
376
+ webdriver.Command.ERROR_EVENT, function(e) {
377
+ failedCommand = e.target;
378
+ this.abortCommand(e.currentTarget);
379
+ e.preventDefault();
380
+ e.stopPropagation();
381
+ return false;
382
+ }, /*capture phase*/true, this);
383
+
384
+ this.callFunction(function() {
385
+ if (null == failedCommand) {
386
+ goog.events.unlistenByKey(key);
387
+ throw new Error(
388
+ (opt_errorMsg ? (opt_errorMsg + '\n') : '') +
389
+ 'Expected an error but none were raised.');
390
+ } else if (goog.isFunction(opt_handlerFn)) {
391
+ opt_handlerFn(failedCommand);
392
+ }
393
+ });
394
+ };
395
+
396
+
397
+ /**
398
+ * Queueus a command to call the given function if and only if the previous
399
+ * command fails. Since failed commands do not have a result, the function
400
+ * called will not be given the return value of the previous command.
401
+ * @param {function} fn The function to call if the previous command fails.
402
+ * @param {Object} opt_selfObj The object in whose scope to call the function.
403
+ * @param {*} var_args Any arguments to pass to the function.
404
+ */
405
+ webdriver.WebDriver.prototype.ifPreviousCommandFailsCall = function(
406
+ fn, opt_selfObj, var_args) {
407
+ var args = arguments;
408
+ var currentFrame = goog.array.peek(this.queuedCommands_);
409
+ var previousCommand = goog.array.peek(currentFrame);
410
+ if (!previousCommand) {
411
+ throw new Error('No commands in the queue to expect an error from');
412
+ }
413
+ var commandFailed = false;
414
+ var key = goog.events.listenOnce(previousCommand,
415
+ webdriver.Command.ERROR_EVENT, function(e) {
416
+ commandFailed = true;
417
+ this.abortCommand(e.currentTarget);
418
+ e.preventDefault();
419
+ e.stopPropagation();
420
+ return false;
421
+ }, /*capture phase*/true, this);
422
+ this.callFunction(function() {
423
+ goog.events.unlistenByKey(key);
424
+ if (commandFailed) {
425
+ return this.callFunction.apply(this, args);
426
+ }
427
+ }, this);
428
+ };
429
+
430
+
431
+ /**
432
+ * Adds a command to pause this driver so it will not execute anymore commands
433
+ * until {@code #resume()} is called. When this command executes, a
434
+ * {@code webdriver.WebDriver.EventType.PAUSED} event will be dispatched.
435
+ */
436
+ webdriver.WebDriver.prototype.pause = function() {
437
+ this.callFunction(goog.bind(this.pauseImmediately, this));
438
+ };
439
+
440
+
441
+ /**
442
+ * Has the driver temporarily halt command execution. This command does
443
+ * <em>not</em> result in a {@code webdriver.WebDriver.EventType.PAUSED} event.
444
+ * @param {number} ms The amount of time in milliseconds for the driver to
445
+ * sleep.
446
+ */
447
+ webdriver.WebDriver.prototype.sleep = function(ms) {
448
+ this.addCommand(webdriver.CommandName.SLEEP).setParameters(ms);
449
+ };
450
+
451
+
452
+ /**
453
+ * Inserts a function into the command queue for the driver to call. The
454
+ * function will be passed the last {@code webdriver.Response} retrieved from
455
+ * the command processor. The result of the function will be stored in a new
456
+ * {@code webdriver.Response} and passed to any subsequent function commands.
457
+ * @param {function} fn The function to call; should take a single
458
+ * {@code webdriver.Response} object.
459
+ * @return {webdriver.Future} The result of the function wrapped in a future.
460
+ */
461
+ webdriver.WebDriver.prototype.callFunction = function(fn, opt_selfObj,
462
+ var_args) {
463
+ var args = goog.array.slice(arguments, 2);
464
+ var frame = goog.array.peek(this.queuedCommands_);
465
+ var previousCommand = goog.array.peek(frame);
466
+ args.push(previousCommand ? previousCommand.getFutureResult() : null);
467
+ return this.addCommand(webdriver.CommandName.FUNCTION).
468
+ setParameters(fn, opt_selfObj, args).
469
+ getFutureResult();
470
+ };
471
+
472
+
473
+ /**
474
+ * Waits for a condition to be true before executing the next command. If the
475
+ * condition does not hold after the given {@code timeout}, an error will be
476
+ * raised.
477
+ * Example:
478
+ * <code>
479
+ * driver.get('http://www.google.com');
480
+ * var element = driver.findElement({name: 'q'});
481
+ * driver.wait(element.isDisplayed, 3000, element);
482
+ * </code>
483
+ * @param {function} conditionFn The function to evaluate.
484
+ * @param {number} timeout The maximum amount of time to wait, in milliseconds.
485
+ * @param {Object} opt_self (Optional) The object in whose context to execute
486
+ * the {@code conditionFn}.
487
+ * @param {boolean} opt_waitNot (Optional) Whether to wait for the inverse of
488
+ * the {@code conditionFn}.
489
+ */
490
+ webdriver.WebDriver.prototype.wait = function(conditionFn, timeout, opt_self,
491
+ opt_waitNot) {
492
+ conditionFn = goog.bind(conditionFn, opt_self);
493
+ var waitOnInverse = !!opt_waitNot;
494
+ var callFunction = goog.bind(this.callFunction, this);
495
+
496
+ function pollFunction(opt_startTime, opt_future) {
497
+ var startTime = opt_startTime || goog.now();
498
+
499
+ function checkValue(value) {
500
+ var pendingFuture = null;
501
+ if (value instanceof webdriver.Future) {
502
+ if (value.isSet()) {
503
+ value = value.getValue();
504
+ } else {
505
+ pendingFuture = value;
506
+ value = null;
507
+ }
508
+ }
509
+
510
+ var done = !pendingFuture && (waitOnInverse != !!value);
511
+ if (!done) {
512
+ var ellapsed = goog.now() - startTime;
513
+ if (ellapsed > timeout) {
514
+ throw Error('Wait timed out after ' + ellapsed + 'ms');
515
+ }
516
+ // If we pass the pending future in as is, the AbstractCommandProcessor
517
+ // will try to resolve it to its value. However, if we're scheduling
518
+ // this function, it's because the future has not been set yet, which
519
+ // will lead to an error. To avoid this, wrap up the pollFunction in an
520
+ // anonymous function so the AbstractCommandProcessor does not
521
+ // interfere.
522
+ callFunction(goog.bind(pollFunction, null, startTime, pendingFuture));
523
+ }
524
+ }
525
+
526
+ var result = opt_future || conditionFn();
527
+ checkValue(result);
528
+ }
529
+
530
+ this.addCommand(webdriver.CommandName.WAIT).
531
+ setParameters(pollFunction, null, [0, null]);
532
+ };
533
+
534
+
535
+ /**
536
+ * Waits for the inverse of a condition to be true before executing the next
537
+ * command. If the condition does not hold after the given {@code timeout}, an
538
+ * error will be raised. Example:
539
+ * <code>
540
+ * driver.get('http://www.google.com');
541
+ * var element = driver.findElement({name: 'q'});
542
+ * driver.waitNot(element.isDisplayed, 3000, element);
543
+ * </code>
544
+ * @param {function} conditionFn The function to evaluate.
545
+ * @param {number} timeout The maximum amount of time to wait, in milliseconds.
546
+ * @param {Object} opt_self (Optional) The object in whose context to execute
547
+ * the {@code conditionFn}.
548
+ */
549
+ webdriver.WebDriver.prototype.waitNot = function(conditionFn, timeout,
550
+ opt_self) {
551
+ this.wait(conditionFn, timeout, opt_self, true);
552
+ };
553
+
554
+
555
+ /**
556
+ * Request a new session ID.
557
+ */
558
+ webdriver.WebDriver.prototype.newSession = function() {
559
+ this.callFunction(function() {
560
+ this.addCommand(webdriver.CommandName.NEW_SESSION);
561
+ this.callFunction(function(value) {
562
+ this.sessionId_ = value;
563
+ }, this);
564
+ }, this);
565
+ };
566
+
567
+
568
+ /**
569
+ * Switch the focus of future commands for this driver to the window with the
570
+ * given name.
571
+ * @param {string|webdriver.Future} name The name of the window to transfer
572
+ * control to. Alternatively, the UUID of a window handle, returned by
573
+ * {@code #getWindowHandle()} or {@code #getAllWindowHandles()}.
574
+ */
575
+ webdriver.WebDriver.prototype.switchToWindow = function(name) {
576
+ this.callFunction(function() {
577
+ this.addCommand(webdriver.CommandName.SWITCH_TO_WINDOW).
578
+ setParameters(name);
579
+ this.callFunction(this.setContext, this);
580
+ }, this);
581
+ };
582
+
583
+
584
+ /**
585
+ * Switch the focus of future commands for this driver to the frame with the
586
+ * given name or ID. To select sub-frames, simply separate the frame names/IDs
587
+ * by dots. As an example, {@code 'main.child'} will select the frame with the
588
+ * name 'main' and hten its child 'child'. If a frame name is a number, then it
589
+ * will be treated as an index into the {@code window.frames} array of the
590
+ * current window.
591
+ * @param {string|number|webdriver.WebElement} frame Identifier for the frame
592
+ * to transfer control to.
593
+ */
594
+ webdriver.WebDriver.prototype.switchToFrame = function(frame) {
595
+ this.callFunction(function() {
596
+ var commandName = webdriver.CommandName.SWITCH_TO_FRAME;
597
+ var command;
598
+ if (goog.isString(frame) || goog.isNumber(frame)) {
599
+ command = this.addCommand(commandName).setParameters(frame);
600
+ } else {
601
+ command = this.addCommand(commandName, frame);
602
+ }
603
+ }, this);
604
+ };
605
+
606
+
607
+ /**
608
+ * Selects either the first frame on the page, or the main document when a page
609
+ * contains iframes.
610
+ */
611
+ webdriver.WebDriver.prototype.switchToDefaultContent = function() {
612
+ this.callFunction(function() {
613
+ this.addCommand(webdriver.CommandName.SWITCH_TO_DEFAULT_CONTENT).
614
+ setParameters(null);
615
+ }, this);
616
+ };
617
+
618
+
619
+ /**
620
+ * Retrieves the internal UUID handle for the current window.
621
+ * @return {webdriver.Future} The current handle wrapped in a Future.
622
+ */
623
+ webdriver.WebDriver.prototype.getWindowHandle = function() {
624
+ return this.addCommand(webdriver.CommandName.GET_CURRENT_WINDOW_HANDLE).
625
+ getFutureResult();
626
+ };
627
+
628
+
629
+ /**
630
+ * Retrieves the handles for all known windows.
631
+ */
632
+ webdriver.WebDriver.prototype.getAllWindowHandles = function() {
633
+ this.addCommand(webdriver.CommandName.GET_WINDOW_HANDLES);
634
+ };
635
+
636
+
637
+ /**
638
+ * Retrieves the HTML source of the current page.
639
+ * @return {webdriver.Future} The page source wrapped in a Future.
640
+ */
641
+ webdriver.WebDriver.prototype.getPageSource = function() {
642
+ return this.addCommand(webdriver.CommandName.GET_PAGE_SOURCE).
643
+ getFutureResult();
644
+ };
645
+
646
+
647
+ /**
648
+ * Closes the current window.
649
+ * <strong>WARNING: This command provides no protection against closing the
650
+ * script window (e.g. the window sending commands to the driver)</strong>
651
+ */
652
+ webdriver.WebDriver.prototype.close = function() {
653
+ this.addCommand(webdriver.CommandName.CLOSE);
654
+ };
655
+
656
+
657
+
658
+ /**
659
+ * Helper function for converting an argument to a script into a parameter
660
+ * object to send with the {@code webdriver.Command}.
661
+ * @param {*} arg The value to convert.
662
+ * @return {Object} A JSON object with "type" and "value" properties.
663
+ * @see {webdriver.WebDriver.prototype.executeScript}
664
+ * @private
665
+ */
666
+ webdriver.WebDriver.wrapScriptArgument_ = function(arg) {
667
+ var type, value;
668
+ if (arg instanceof webdriver.WebElement) {
669
+ type = 'ELEMENT';
670
+ value = arg.getId();
671
+ } else if (goog.isBoolean(arg) ||
672
+ goog.isNumber(arg) ||
673
+ goog.isString(arg)) {
674
+ type = goog.typeOf(arg).toUpperCase();
675
+ value = arg;
676
+ } else if (goog.isArray(arg)) {
677
+ type = goog.typeOf(arg).toUpperCase();
678
+ value = goog.array.map(arg, webdriver.WebDriver.wrapScriptArgument_);
679
+ } else {
680
+ throw new Error('Invalid script argument type: ' + goog.typeOf(arg));
681
+ }
682
+ return {'type': type, 'value': value};
683
+ };
684
+
685
+
686
+ /**
687
+ * Helper function for unwrapping an executeScript result.
688
+ * @param {{type:string,value:*}|Array.<{type:string,value:*}>} result The
689
+ * result to unwrap.
690
+ * @return {*} The unwrapped result.
691
+ * @private
692
+ */
693
+ webdriver.WebDriver.prototype.unwrapScriptResult_ = function(result) {
694
+ switch (result.type) {
695
+ case 'ELEMENT':
696
+ var element = new webdriver.WebElement(this);
697
+ element.getId().setValue(result.value);
698
+ return element;
699
+
700
+ case 'ARRAY':
701
+ return goog.array.map(result.value, goog.bind(
702
+ this.unwrapScriptResult_, this));
703
+
704
+ default:
705
+ return result.value;
706
+ }
707
+ };
708
+
709
+
710
+ /**
711
+ * Adds a command to execute a JavaScript snippet in the window of the page
712
+ * currently under test.
713
+ * @param {string} script The JavaScript snippet to execute.
714
+ * @param {*} var_args The arguments to pass to the script.
715
+ * @return {webdriver.Future} The result of the executed script, wrapped in a
716
+ * {@code webdriver.Future} instance.
717
+ */
718
+ webdriver.WebDriver.prototype.executeScript = function(script, var_args) {
719
+ var args = goog.array.map(
720
+ goog.array.slice(arguments, 1),
721
+ webdriver.WebDriver.wrapScriptArgument_);
722
+ return this.callFunction(function() {
723
+ this.addCommand(webdriver.CommandName.EXECUTE_SCRIPT).
724
+ setParameters(script, args);
725
+ return this.callFunction(function(prevResult) {
726
+ return this.unwrapScriptResult_(prevResult);
727
+ }, this);
728
+ }, this);
729
+ };
730
+
731
+
732
+ /**
733
+ * Adds a command to fetch the given URL.
734
+ * @param {goog.Uri|string} url The URL to fetch.
735
+ */
736
+ webdriver.WebDriver.prototype.get = function(url) {
737
+ this.callFunction(function() {
738
+ this.addCommand(webdriver.CommandName.GET).
739
+ setParameters(url.toString());
740
+ }, this);
741
+ };
742
+
743
+
744
+ /**
745
+ * Navigate backwards in the current browser window's history.
746
+ */
747
+ webdriver.WebDriver.prototype.back = function() {
748
+ this.addCommand(webdriver.CommandName.BACK);
749
+ };
750
+
751
+
752
+ /**
753
+ * Navigate forwards in the current browser window's history.
754
+ */
755
+ webdriver.WebDriver.prototype.forward = function() {
756
+ this.addCommand(webdriver.CommandName.FORWARD);
757
+ };
758
+
759
+
760
+ /**
761
+ * Refresh the current page.
762
+ */
763
+ webdriver.WebDriver.prototype.refresh = function() {
764
+ this.addCommand(webdriver.CommandName.REFRESH);
765
+ };
766
+
767
+
768
+ /**
769
+ * Retrieves the current window URL.
770
+ * @return {webdriver.Future} The current URL in a webdriver.Future.
771
+ */
772
+ webdriver.WebDriver.prototype.getCurrentUrl = function() {
773
+ return this.addCommand(webdriver.CommandName.GET_CURRENT_URL).
774
+ getFutureResult();
775
+ };
776
+
777
+
778
+ /**
779
+ * Retrieves the current page's title.
780
+ * @return {webdriver.Future} The current page title.
781
+ */
782
+ webdriver.WebDriver.prototype.getTitle = function() {
783
+ return this.addCommand(webdriver.CommandName.GET_TITLE).
784
+ getFutureResult();
785
+ };
786
+
787
+
788
+ /**
789
+ * Find an element on the current page. If the element cannot be found, an
790
+ * {@code webdriver.WebDriver.EventType.ERROR} event will be dispatched.
791
+ * @param {webdriver.By.Locator|object} by An object describing the locator
792
+ * strategy to use.
793
+ * @return {webdriver.WebElement} A WebElement wrapper that can be used to
794
+ * issue commands against the located element.
795
+ */
796
+ webdriver.WebDriver.prototype.findElement = function(by) {
797
+ var webElement = new webdriver.WebElement(this);
798
+ var locator = webdriver.By.Locator.checkLocator(by);
799
+ var command = this.addCommand(webdriver.CommandName.FIND_ELEMENT).
800
+ setParameters(locator.type, locator.target);
801
+ webElement.getId().setValue(command.getFutureResult());
802
+ return webElement;
803
+ };
804
+
805
+
806
+ /**
807
+ * Determine if an element is present on the page.
808
+ * @param {webdriver.By.Locator|{*: string}} by The locator to use for finding
809
+ * the element, or a short-hand object that can be converted into a locator.
810
+ * @return {webdriver.Future} Whether the element was present on the page. The
811
+ * return value is wrapped in a Future that will be defined when the driver
812
+ * completes the command.
813
+ * @see webdriver.By.Locator.createFromObj
814
+ */
815
+ webdriver.WebDriver.prototype.isElementPresent = function(by) {
816
+ var locator = webdriver.By.Locator.checkLocator(by);
817
+ return this.callFunction(function() {
818
+ var findCommand = this.addCommand(webdriver.CommandName.FIND_ELEMENT).
819
+ setParameters(locator.type, locator.target);
820
+ var commandFailed = false;
821
+ var key = goog.events.listenOnce(findCommand,
822
+ webdriver.Command.ERROR_EVENT, function(e) {
823
+ commandFailed = true;
824
+ this.abortCommand(e.currentTarget);
825
+ e.preventDefault();
826
+ e.stopPropagation();
827
+ return false;
828
+ }, /*capture phase*/true, this);
829
+ return this.callFunction(function() {
830
+ goog.events.unlistenByKey(key);
831
+ return !commandFailed;
832
+ });
833
+ }, this);
834
+ };
835
+
836
+
837
+
838
+ /**
839
+ * Search for multiple elements on the current page. The result of this
840
+ * operation can be accessed from the last saved {@code webdriver.Response}
841
+ * object:
842
+ * driver.findElements({xpath: '//div'});
843
+ * driver.callFunction(function(value) {
844
+ * value[0].click();
845
+ * value[1].click();
846
+ * // etc.
847
+ * });
848
+ * @param {webdriver.By.Locator|{*: string}} by The locator to use for finding
849
+ * the element, or a short-hand object that can be converted into a locator.
850
+ * @see webdriver.By.Locator.createFromObj
851
+ */
852
+ webdriver.WebDriver.prototype.findElements = function(by) {
853
+ var locator = webdriver.By.Locator.checkLocator(by);
854
+ return this.callFunction(function() {
855
+ this.addCommand(webdriver.CommandName.FIND_ELEMENTS).
856
+ setParameters(locator.type, locator.target);
857
+ return this.callFunction(function(ids) {
858
+ var elements = [];
859
+ for (var i = 0; i < ids.length; i++) {
860
+ if (ids[i]) {
861
+ var element = new webdriver.WebElement(this);
862
+ element.getId().setValue(ids[i]);
863
+ elements.push(element);
864
+ }
865
+ }
866
+ return elements;
867
+ }, this);
868
+ }, this);
869
+ };
870
+
871
+
872
+ /**
873
+ * Adjust the speed of the mouse for mouse related commands.
874
+ * @param {webdriver.WebDriver.Speed} speed The new speed setting.
875
+ */
876
+ webdriver.WebDriver.prototype.setMouseSpeed = function(speed) {
877
+ this.addCommand(webdriver.CommandName.SET_MOUSE_SPEED).
878
+ setParameters(speed);
879
+ };
880
+
881
+
882
+ /**
883
+ * Fetch the current mouse speed.
884
+ * @return {webdriver.Future} A Future whose value will be set by this driver
885
+ * when the query command completes.
886
+ */
887
+ webdriver.WebDriver.prototype.getMouseSpeed = function() {
888
+ return this.addCommand(webdriver.CommandName.GET_MOUSE_SPEED).
889
+ getFutureResult();
890
+ };