rainux-selenium-webdriver 0.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
+ };