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,643 @@
1
+ /*
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+ Portions copyright 2007 ThoughtWorks, Inc
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ */
18
+
19
+ /**
20
+ * @fileOverview Contains a Javascript implementation for
21
+ * nsICommandProcessor.idl. The implemented XPCOM component is exposed to
22
+ * the content page as a global property so that it can be used from
23
+ * unpriviledged code.
24
+ */
25
+
26
+
27
+ /**
28
+ * When this component is loaded, load the necessary subscripts.
29
+ */
30
+ (function() {
31
+ var scripts = [
32
+ 'context.js',
33
+ 'utils.js'
34
+ ];
35
+
36
+ // Firefox 3.5+ has native JSON support; prefer that over our script from
37
+ // www.json.org, which may be slower.
38
+ var appInfo = Components.classes['@mozilla.org/xre/app-info;1'].
39
+ getService(Components.interfaces.nsIXULAppInfo);
40
+ var versionChecker = Components.classes['@mozilla.org/xpcom/version-comparator;1'].
41
+ getService(Components.interfaces.nsIVersionComparator);
42
+ if (versionChecker.compare(appInfo.version, '3.5') < 0) {
43
+ scripts.push('json2.js');
44
+ }
45
+
46
+ var fileProtocolHandler = Components.
47
+ classes['@mozilla.org/network/protocol;1?name=file'].
48
+ createInstance(Components.interfaces.nsIFileProtocolHandler);
49
+ var loader = Components.classes['@mozilla.org/moz/jssubscript-loader;1'].
50
+ createInstance(Components.interfaces.mozIJSSubScriptLoader);
51
+
52
+ for (var script in scripts) {
53
+ var file = __LOCATION__.parent.clone();
54
+ file.append(scripts[script]);
55
+
56
+ var fileName = fileProtocolHandler.getURLSpecFromFile(file);
57
+ loader.loadSubScript(fileName);
58
+ }
59
+ })();
60
+
61
+
62
+ /**
63
+ * Encapsulates the result of a command to the {@code nsCommandProcessor}.
64
+ * @param {Object} command JSON object describing the command to execute.
65
+ * @param {nsIResponseHandler} responseHandler The handler to send the response
66
+ * to.
67
+ * @constructor
68
+ */
69
+ var Response = function(command, responseHandler) {
70
+ this.statusBarLabel_ = null;
71
+ this.responseHandler_ = responseHandler;
72
+ this.json_ = {
73
+ commandName: command ? command.commandName : 'Unknown command',
74
+ isError: false,
75
+ response: '',
76
+ elementId: command.elementId,
77
+ context: command.context
78
+ };
79
+ };
80
+
81
+ Response.prototype = {
82
+
83
+ /**
84
+ * Updates the extension status label to indicate we are about to execute a
85
+ * command.
86
+ * @param {window} win The content window that the command will be executed on.
87
+ */
88
+ startCommand: function(win) {
89
+ this.statusBarLabel_ = win.document.getElementById("fxdriver-label");
90
+ if (this.statusBarLabel_) {
91
+ this.statusBarLabel_.style.color = "red";
92
+ }
93
+ },
94
+
95
+ /**
96
+ * Sends the encapsulated response to the registered callback.
97
+ */
98
+ send: function() {
99
+ if (this.responseSent_) {
100
+ // We shouldn't ever send the same response twice.
101
+ return;
102
+ }
103
+ // Indicate that we are no longer executing a command.
104
+ if (this.statusBarLabel_) {
105
+ this.statusBarLabel_.style.color = 'black';
106
+ }
107
+
108
+ this.context = this.context.toString();
109
+ this.responseHandler_.handleResponse(JSON.stringify(this.json_));
110
+
111
+ // Neuter ourselves
112
+ this.responseSent_ = true;
113
+ },
114
+
115
+ /**
116
+ * Helper function for reporting internal errors to the client.
117
+ * @param {Error} ex The internal error to report to the client.
118
+ */
119
+ reportError: function(ex) {
120
+ Utils.dump(ex);
121
+ this.response = 'Internal error: ' + JSON.stringify({
122
+ fileName : ex.fileName,
123
+ lineNumber : ex.lineNumber,
124
+ message : ex.message,
125
+ name : ex.name
126
+ });
127
+ this.isError = true;
128
+ this.send();
129
+ },
130
+
131
+ setField: function(name, value) { this.json_[name] = value; },
132
+ set commandName(name) { this.json_.commandName = name; },
133
+ get commandName() { return this.json_.commandName; },
134
+ set elementId(id) { this.json_.elementId = id; },
135
+ get elementId() { return this.json_.elementId; },
136
+ set isError(error) { this.json_.isError = error; },
137
+ get isError() { return this.json_.isError; },
138
+ set response(res) { this.json_.response = res; },
139
+ get response() { return this.json_.response; },
140
+ set context(c) { this.json_.context = c; },
141
+ get context() { return this.json_.context; }
142
+ };
143
+
144
+
145
+ /**
146
+ * Handles executing a command from the {@code CommandProcessor} once the window
147
+ * has fully loaded.
148
+ * @param {FirefoxDriver} driver The FirefoxDriver instance to execute the
149
+ * command with.
150
+ * @param {Object} command JSON object describing the command to execute.
151
+ * @param {Response} response The response object to send the command response
152
+ * in.
153
+ * @param {Number} opt_sleepDelay The amount of time to wait before attempting
154
+ * the command again if the window is not ready.
155
+ * @constructor
156
+ */
157
+ var DelayedCommand = function(driver, command, response, opt_sleepDelay) {
158
+ this.driver_ = driver;
159
+ this.command_ = command;
160
+ this.response_ = response;
161
+ this.onBlank_ = false;
162
+ this.sleepDelay_ = opt_sleepDelay || DelayedCommand.DEFAULT_SLEEP_DELAY;
163
+
164
+ var activeWindow =
165
+ response.context.frame || response.context.fxbrowser.contentWindow;
166
+ this.loadGroup_ = activeWindow.
167
+ QueryInterface(Components.interfaces.nsIInterfaceRequestor).
168
+ getInterface(Components.interfaces.nsIWebNavigation).
169
+ QueryInterface(Components.interfaces.nsIInterfaceRequestor).
170
+ getInterface(Components.interfaces.nsILoadGroup);
171
+ };
172
+
173
+
174
+ /**
175
+ * Default amount of time, in milliseconds, to wait before (re)attempting a
176
+ * {@code DelayedCommand}.
177
+ * @type {Number}
178
+ */
179
+ DelayedCommand.DEFAULT_SLEEP_DELAY = 100;
180
+
181
+
182
+ /**
183
+ * Executes the command after the specified delay.
184
+ * @param {Number} ms The delay in milliseconds.
185
+ */
186
+ DelayedCommand.prototype.execute = function(ms) {
187
+ var self = this;
188
+ this.driver_.window.setTimeout(function() {
189
+ self.executeInternal_();
190
+ }, ms);
191
+ };
192
+
193
+
194
+ /**
195
+ * @return {boolean} Whether this instance should delay execution of its
196
+ * command for a pending request in the current window's nsILoadGroup.
197
+ */
198
+ DelayedCommand.prototype.shouldDelayExecutionForPendingRequest_ = function() {
199
+ try {
200
+ if (this.loadGroup_.isPending()) {
201
+ var hasOnLoadBlocker = false;
202
+ var numPending = 0;
203
+ var requests = this.loadGroup_.requests;
204
+ while (requests.hasMoreElements()) {
205
+ var request =
206
+ requests.getNext().QueryInterface(Components.interfaces.nsIRequest);
207
+ if (request.isPending()) {
208
+ numPending += 1;
209
+ hasOnLoadBlocker = hasOnLoadBlocker ||
210
+ (request.name == 'about:document-onload-blocker');
211
+
212
+ if (numPending > 1) {
213
+ // More than one pending request, need to wait.
214
+ return true;
215
+ }
216
+ }
217
+ }
218
+
219
+ if (numPending && !hasOnLoadBlocker) {
220
+ Utils.dumpn('Ignoring pending about:document-onload-blocker request');
221
+ // If we only have one pending request and it is not a
222
+ // document-onload-blocker, we need to wait. We do not wait for
223
+ // document-onload-blocker requests since these are created when
224
+ // one of document.[open|write|writeln] is called. If document.close is
225
+ // never called, the document-onload-blocker request will not be
226
+ // completed.
227
+ return true;
228
+ }
229
+ }
230
+ } catch(e) {
231
+ Utils.dumpn('Problem while checking if we should delay execution: ' + e);
232
+ }
233
+
234
+ return false;
235
+ };
236
+
237
+
238
+ /**
239
+ * Attempts to execute the command. If the window is not ready for the command
240
+ * to execute, will set a timeout to try again.
241
+ * @private
242
+ */
243
+ DelayedCommand.prototype.executeInternal_ = function() {
244
+ if (this.shouldDelayExecutionForPendingRequest_()) {
245
+ return this.execute(this.sleepDelay_);
246
+ }
247
+
248
+ // Ugh! New windows open on "about:blank" before going to their
249
+ // destination URL. This check attempts to tell the difference between a
250
+ // newly opened window and someone actually wanting to do something on
251
+ // about:blank.
252
+ if (this.driver_.window.location == 'about:blank' && !this.onBlank_) {
253
+ this.onBlank_ = true;
254
+ return this.execute(this.sleepDelay_);
255
+ } else {
256
+ try {
257
+ this.response_.commandName = this.command_.commandName;
258
+ // TODO(simon): This is rampantly ugly, but allows an alert to kill the command
259
+ // TODO(simon): This is never cleared, but _should_ be okay, because send wipes itself
260
+ this.driver_.response_ = this.response_;
261
+
262
+ this.driver_[this.command_.commandName](
263
+ this.response_, this.command_.parameters);
264
+ } catch (e) {
265
+ // if (e instanceof StaleElementError) won't work here since
266
+ // StaleElementError is defined in the utils.js subscript which is
267
+ // loaded independently in this component and in the main driver
268
+ // component.
269
+ // TODO(jmleyba): Continue cleaning up the extension and replacing the
270
+ // subscripts with proper components.
271
+ if (e.isStaleElementError) {
272
+ this.response_.isError = true;
273
+ this.response_.response = 'element is obsolete';
274
+ this.response_.send();
275
+ } else {
276
+ Utils.dumpn(
277
+ 'Exception caught by driver: ' + this.command_.commandName +
278
+ '(' + this.command_.parameters + ')\n' + e);
279
+ this.response_.reportError(e);
280
+ }
281
+ }
282
+ }
283
+ };
284
+
285
+
286
+ /**
287
+ * Class for dispatching WebDriver requests. Handles window locating commands
288
+ * (e.g. switching, searching, etc.), all other commands are executed with the
289
+ * {@code FirefoxDriver} through reflection. Note this is a singleton class.
290
+ * @constructor
291
+ */
292
+ var nsCommandProcessor = function() {
293
+ this.wrappedJSObject = this;
294
+ this.wm = Components.classes['@mozilla.org/appshell/window-mediator;1'].
295
+ getService(Components.interfaces.nsIWindowMediator);
296
+ };
297
+
298
+ /**
299
+ * Flags for the {@code nsIClassInfo} interface.
300
+ * @type {Number}
301
+ */
302
+ nsCommandProcessor.prototype.flags =
303
+ Components.interfaces.nsIClassInfo.DOM_OBJECT;
304
+
305
+ /**
306
+ * Implementaiton language detail for the {@code nsIClassInfo} interface.
307
+ * @type {String}
308
+ */
309
+ nsCommandProcessor.prototype.implementationLanguage =
310
+ Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT;
311
+
312
+
313
+ /**
314
+ * Logs a message to the Console Service and then throws an error.
315
+ * @param {String} message The message to log.
316
+ * @throws {Components.results.NS_ERROR_FAILURE}
317
+ */
318
+ nsCommandProcessor.logError = function(message) {
319
+ // TODO(jleyba): This should log an error and not a generic message.
320
+ Utils.dumpn(message);
321
+ throw Components.results.NS_ERROR_FAILURE;
322
+ };
323
+
324
+
325
+ /**
326
+ * Processes a command request for the {@code FirefoxDriver}.
327
+ * @param {string} jsonCommandString The command to execute, specified in a
328
+ * JSON string.
329
+ * @param {nsIResponseHandler} responseHandler The callback to send the response
330
+ * to.
331
+ */
332
+ nsCommandProcessor.prototype.execute = function(jsonCommandString,
333
+ responseHandler) {
334
+ var command, response;
335
+ try {
336
+ command = JSON.parse(jsonCommandString);
337
+ } catch (ex) {
338
+ response = JSON.stringify({
339
+ 'isError': true,
340
+ 'value': 'Error parsing command: "' + jsonCommandString + '"'
341
+ });
342
+ responseHandler.handleResponse(response);
343
+ return;
344
+ }
345
+
346
+ command.context = Context.fromString(command.context);
347
+ response = new Response(command, responseHandler);
348
+
349
+ // These are used to locate a new driver, and so not having one is a fine
350
+ // thing to do
351
+ if (command.commandName == 'newSession' ||
352
+ command.commandName == 'switchToWindow' ||
353
+ command.commandName == 'getWindowHandles' ||
354
+ command.commandName == 'quit') {
355
+ return this[command.commandName](response, command.parameters);
356
+ }
357
+
358
+ var win, fxbrowser, driver;
359
+ var allWindows = this.wm.getEnumerator(null);
360
+ while (allWindows.hasMoreElements()) {
361
+ win = allWindows.getNext();
362
+ if (win["fxdriver"] && win.fxdriver.id == response.context.windowId) {
363
+ fxbrowser = win.getBrowser();
364
+ driver = win.fxdriver;
365
+ break;
366
+ }
367
+ }
368
+
369
+ if (!fxbrowser) {
370
+ response.isError = true;
371
+ response.response = 'Unable to find browser with id ' +
372
+ response.context.windowId;
373
+ return response.send();
374
+ }
375
+
376
+ if (!driver) {
377
+ response.isError = true;
378
+ response.response = 'Unable to find the driver for browser with id ' +
379
+ response.context.windowId;
380
+ return response.send();
381
+ }
382
+
383
+ if (typeof driver[command.commandName] != 'function') {
384
+ response.isError = true;
385
+ response.response = 'Unrecognised command: ' + command.commandName;
386
+ return response.send();
387
+ }
388
+
389
+ response.context.fxbrowser = fxbrowser;
390
+
391
+ // Determine whether or not we need to care about frames.
392
+ var frames = fxbrowser.contentWindow.frames;
393
+ if ("?" == response.context.frameId) {
394
+ if (frames && frames.length) {
395
+ if ("FRAME" == frames[0].frameElement.tagName) {
396
+ response.context.frameId = 0;
397
+ } else {
398
+ response.context.frameId = undefined;
399
+ }
400
+ } else {
401
+ response.context.frameId = undefined;
402
+ }
403
+ }
404
+
405
+ if (response.context.frameId !== undefined) {
406
+ response.context.frame = Utils.findFrame(
407
+ fxbrowser, response.context.frameId);
408
+ }
409
+
410
+ response.startCommand(win);
411
+ new DelayedCommand(driver, command, response).execute(0);
412
+ };
413
+
414
+
415
+
416
+ /**
417
+ * Changes the context of the caller to the window specified by the first
418
+ * element of the {@code windowId} array.
419
+ * @param {Response} response The response object to send the command response
420
+ * in.
421
+ * @param {Array.<*>} windowId The parameters sent with the original command.
422
+ * The first element in the array must be the ID of the window to switch to.
423
+ * Note all other command parameters are ignored.
424
+ * @param {number} opt_searchAttempt Which attempt this is at finding the
425
+ * window to switch to.
426
+ */
427
+ nsCommandProcessor.prototype.switchToWindow = function(response, windowId,
428
+ opt_searchAttempt) {
429
+ var lookFor = windowId[0];
430
+ var matches = function(win, lookFor) {
431
+ return !win.closed &&
432
+ (win.content && win.content.name == lookFor) ||
433
+ (win.top && win.top.fxdriver && win.top.fxdriver.id == lookFor);
434
+ };
435
+
436
+ var windowFound = this.searchWindows_('navigator:browser', function(win) {
437
+ if (matches(win, lookFor)) {
438
+ // Create a switch indicator file so the native events library
439
+ // will know a window switch is in progress and will indeed
440
+ // switch focus.
441
+ createSwitchFile("switch:" + win.fxdriver.id);
442
+
443
+ win.focus();
444
+ if (win.top.fxdriver) {
445
+ response.response = new Context(win.fxdriver.id).toString();
446
+ } else {
447
+ response.isError = true;
448
+ response.response = 'No driver found attached to top window!';
449
+ }
450
+ response.send();
451
+ // Found the desired window, stop the search.
452
+ return true;
453
+ }
454
+ });
455
+
456
+ // It is possible that the window won't be found on the first attempt. This is
457
+ // typically true for anchors with a target attribute set. This search could
458
+ // execute before the target window has finished loaded, meaning the content
459
+ // window won't have a name or FirefoxDriver instance yet (see matches above).
460
+ // If we don't find the window, set a timeout and try again.
461
+ if (!windowFound) {
462
+ // TODO(jmleyba): We should be sniffing the current windows to detect if
463
+ // one is still loading vs. a brute force "try again"
464
+ var searchAttempt = opt_searchAttempt || 0;
465
+ if (searchAttempt > 3) {
466
+ response.isError = true;
467
+ response.response = 'Unable to locate window "' + lookFor + '"';
468
+ response.send();
469
+ } else {
470
+ var self = this;
471
+ this.wm.getMostRecentWindow('navigator:browser').
472
+ setTimeout(function() {
473
+ self.switchToWindow(response, windowId, (searchAttempt + 1));
474
+ }, 500);
475
+ }
476
+ }
477
+ };
478
+
479
+
480
+ /**
481
+ * Retrieves a list of all known FirefoxDriver windows.
482
+ * @param {Response} response The response object to send the command response
483
+ * in.
484
+ */
485
+ nsCommandProcessor.prototype.getWindowHandles = function(response) {
486
+ var res = [];
487
+ this.searchWindows_('navigator:browser', function(win) {
488
+ if (win.top && win.top.fxdriver) {
489
+ res.push(win.top.fxdriver.id);
490
+ } else if (win.content) {
491
+ res.push(win.content.name);
492
+ }
493
+ });
494
+ response.response = res;
495
+ response.send();
496
+ };
497
+
498
+
499
+ /**
500
+ * Searches over a selection of windows, calling a visitor function on each
501
+ * window found in the search.
502
+ * @param {?string} search_criteria The category of windows to search or
503
+ * {@code null} to search all windows.
504
+ * @param {function} visitor_fn A visitor function to call with each window. The
505
+ * function may return true to indicate that the window search should abort
506
+ * early.
507
+ * @return {boolean} Whether the visitor function short circuited the search.
508
+ */
509
+ nsCommandProcessor.prototype.searchWindows_ = function(search_criteria,
510
+ visitor_fn) {
511
+ var allWindows = this.wm.getEnumerator(search_criteria);
512
+ while (allWindows.hasMoreElements()) {
513
+ var win = allWindows.getNext();
514
+ if (visitor_fn(win)) {
515
+ return true;
516
+ }
517
+ }
518
+ return false;
519
+ };
520
+
521
+
522
+ /**
523
+ * Locates the most recently used FirefoxDriver window.
524
+ * @param {Response} response The response object to send the command response
525
+ * in.
526
+ */
527
+ nsCommandProcessor.prototype.newSession = function(response) {
528
+ var win = this.wm.getMostRecentWindow("navigator:browser");
529
+ var driver = win.fxdriver;
530
+ if (!driver) {
531
+ response.isError = true;
532
+ response.response = 'No drivers associated with the window';
533
+ } else {
534
+ response.context = new Context(driver.id);
535
+ response.response = driver.id;
536
+ }
537
+ response.send();
538
+ };
539
+
540
+
541
+ /**
542
+ * Forcefully shuts down the Firefox application.
543
+ */
544
+ nsCommandProcessor.prototype.quit = function() {
545
+ // Create a switch file so the native events library will
546
+ // let all events through in case of a close.
547
+ createSwitchFile("close:<ALL>");
548
+ Components.classes['@mozilla.org/toolkit/app-startup;1'].
549
+ getService(Components.interfaces.nsIAppStartup).
550
+ quit(Components.interfaces.nsIAppStartup.eForceQuit);
551
+ };
552
+
553
+
554
+ nsCommandProcessor.prototype.getInterfaces = function(count) {
555
+ var ifaces = [
556
+ Components.interfaces.nsICommandProcessor,
557
+ Components.interfaces.nsISupports
558
+ ];
559
+ count.value = ifaces.length;
560
+ return ifaces;
561
+ };
562
+
563
+
564
+ nsCommandProcessor.prototype.QueryInterface = function (aIID) {
565
+ if (!aIID.equals(Components.interfaces.nsICommandProcessor) &&
566
+ !aIID.equals(Components.interfaces.nsISupports)) {
567
+ throw Components.results.NS_ERROR_NO_INTERFACE;
568
+ }
569
+ return this;
570
+ };
571
+
572
+
573
+ nsCommandProcessor.CLASS_ID =
574
+ Components.ID('{692e5117-a4a2-4b00-99f7-0685285b4db5}');
575
+ nsCommandProcessor.CLASS_NAME = 'Firefox WebDriver CommandProcessor';
576
+ nsCommandProcessor.CONTRACT_ID =
577
+ '@googlecode.com/webdriver/command-processor;1';
578
+
579
+
580
+ /**
581
+ * Factory object for obtaining a reference to the singleton instance of
582
+ * {@code CommandProcessor}.
583
+ */
584
+ nsCommandProcessor.Factory = {
585
+ instance_ : null,
586
+
587
+ createInstance: function(aOuter, aIID) {
588
+ if (aOuter != null) {
589
+ throw Components.results.NS_ERROR_NO_AGGREGATION;
590
+ }
591
+ if (!this.instance_) {
592
+ this.instance_ = new nsCommandProcessor();
593
+ }
594
+ return this.instance_.QueryInterface(aIID);
595
+ }
596
+ };
597
+
598
+
599
+ /**
600
+ * Module definition for registering this XPCOM component.
601
+ */
602
+ nsCommandProcessor.Module = {
603
+ firstTime_: true,
604
+
605
+ registerSelf: function(aCompMgr, aFileSpec, aLocation, aType) {
606
+ if (this.firstTime_) {
607
+ this.firstTime_ = false;
608
+ throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
609
+ }
610
+ aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar).
611
+ registerFactoryLocation(
612
+ nsCommandProcessor.CLASS_ID,
613
+ nsCommandProcessor.CLASS_NAME,
614
+ nsCommandProcessor.CONTRACT_ID,
615
+ aFileSpec, aLocation, aType);
616
+ },
617
+
618
+ unregisterSelf: function(aCompMgr, aLocation) {
619
+ aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar).
620
+ unregisterFactoryLocation(nsCommandProcessor.CLASS_ID, aLocation);
621
+ },
622
+
623
+ getClassObject: function(aCompMgr, aCID, aIID) {
624
+ if (!aIID.equals(Components.interfaces.nsIFactory)) {
625
+ throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
626
+ } else if (!aCID.equals(nsCommandProcessor.CLASS_ID)) {
627
+ throw Components.results.NS_ERROR_NO_INTERFACE;
628
+ }
629
+ return nsCommandProcessor.Factory;
630
+ },
631
+
632
+ canUnload: function() {
633
+ return true;
634
+ }
635
+ };
636
+
637
+
638
+ /**
639
+ * Module initialization.
640
+ */
641
+ function NSGetModule() {
642
+ return nsCommandProcessor.Module;
643
+ }