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
data/COPYING ADDED
@@ -0,0 +1,204 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright 2007-2009 Google Inc.
191
+ Copyright 2007-2009 WebDriver committers
192
+
193
+ Licensed under the Apache License, Version 2.0 (the "License");
194
+ you may not use this file except in compliance with the License.
195
+ You may obtain a copy of the License at
196
+
197
+ http://www.apache.org/licenses/LICENSE-2.0
198
+
199
+ Unless required by applicable law or agreed to in writing, software
200
+ distributed under the License is distributed on an "AS IS" BASIS,
201
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
202
+ See the License for the specific language governing permissions and
203
+ limitations under the License.
204
+
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head>
3
+ <title>WebDriver</title>
4
+ <script type="text/javascript" src="background.js"></script>
5
+ </head>
6
+ <body>
7
+ <p><embed type="application/x-chromedriver" /></p>
8
+ </body>
9
+ </html>
@@ -0,0 +1,995 @@
1
+ /** @namespace */
2
+ ChromeDriver = {};
3
+
4
+
5
+ /**
6
+ * Array of all information about currently loaded tabs (where a WebDriver
7
+ * window is probably a tab)
8
+ * Entries of form:
9
+ * {Int tabId, String windowName, Port mainPort, Boolean isFrameset, FrameData[] frames}
10
+ * FrameData ::= {[Int frameId], String frameName, Port framePort, FrameData[]}
11
+ * frameId can be undefined, if it has not yet been looked up, but should be
12
+ * added once it is known
13
+ * @type {Array.<Object>} TODO(jmleyba): Type info
14
+ */
15
+ ChromeDriver.tabs = [];
16
+
17
+
18
+ /**
19
+ * Port to the currently active frame (or tab, if the current page is not a
20
+ * frameset).
21
+ * @type {?Port}
22
+ */
23
+ ChromeDriver.activePort = null;
24
+
25
+
26
+ /**
27
+ * ID of the currently active tab.
28
+ * @type {?string}
29
+ */
30
+ ChromeDriver.activeTabId = null;
31
+
32
+
33
+ /**
34
+ * Whether we should switch to the next tab which opens. Should be set if the
35
+ * last active tab was closed.
36
+ * @type {boolean}
37
+ */
38
+ ChromeDriver.doFocusOnNextOpenedTab = true;
39
+
40
+
41
+ /**
42
+ * Place to temporarily store the URL currently being loaded, so that we can
43
+ * retry if needed, because opening a URL is an async callback.
44
+ * @type {?string}
45
+ */
46
+ ChromeDriver.urlBeingLoaded = null;
47
+
48
+
49
+ /**
50
+ * URL we believe we're currently on.
51
+ * @type {?string}
52
+ */
53
+ ChromeDriver.currentUrl = null;
54
+
55
+
56
+ /**
57
+ * Whether we are loading a new URL that difers from the current URL only in
58
+ * fragment.
59
+ * @type {boolean}
60
+ */
61
+ ChromeDriver.isGettingUrlButOnlyChangingByFragment = false;
62
+
63
+
64
+ /**
65
+ * Whether we are currently executing a {@code ChromeDriver#close()}, and
66
+ * accordingly should send a success response when the tab closes.
67
+ * @type {boolean}
68
+ */
69
+ ChromeDriver.isClosingTab = false;
70
+
71
+
72
+ /**
73
+ * Whether we have sent a response to the {currently, most recently loading
74
+ * page.
75
+ * @type {boolean}
76
+ */
77
+ ChromeDriver.hasSentResponseToThisPageLoading = false;
78
+
79
+
80
+ /**
81
+ * Whether we believe a page is open to which we have no content script.
82
+ * @type {boolean}
83
+ */
84
+ ChromeDriver.hasNoConnectionToPage = true;
85
+
86
+
87
+ /**
88
+ * Stores the remaining frames to traverse when switching frames.
89
+ * @type {Array.<string>}
90
+ */
91
+ ChromeDriver.restOfCurrentFramePath = [];
92
+
93
+
94
+ /**
95
+ * Port to the frameset or main content page we currently have loaded, so that
96
+ * we can probe it for information about its frames.
97
+ * @type {?Port}
98
+ */
99
+ ChromeDriver.portToUseForFrameLookups = null;
100
+
101
+
102
+ /**
103
+ * The last request we sent that has not been answered, so that if we change
104
+ * page between sending a request and receiving a response, we can re-send it to
105
+ * the newly loaded page.
106
+ * @type {*} TODO(jmleyba)
107
+ */
108
+ ChromeDriver.lastRequestToBeSentWhichHasntBeenAnsweredYet = null;
109
+
110
+
111
+ /**
112
+ * Whether the plugin has the OS-specific window handle for the active tab. This
113
+ * is called HWND rather than window handle to avoid confusion with the other
114
+ * use of window handle to mean 'name of window'.
115
+ * @type {boolean}
116
+ */
117
+ ChromeDriver.hasHwnd = false;
118
+
119
+
120
+ /**
121
+ * THe last XMLHttpRequest we made (used for communication with test language
122
+ * bindings).
123
+ * @type {?XMLHttpRequest}
124
+ */
125
+ ChromeDriver.xmlHttpRequest = null;
126
+
127
+ /**
128
+ * URL to ping for commands.
129
+ * @type {string}
130
+ */
131
+ ChromeDriver.xmlHttpRequestUrl = null;
132
+
133
+
134
+ /**
135
+ * @type {number}
136
+ */
137
+ ChromeDriver.requestSequenceNumber = 0;
138
+
139
+
140
+ /**
141
+ * @type {number}
142
+ */
143
+ ChromeDriver.lastReceivedSequenceNumber = -2;
144
+
145
+
146
+ /**
147
+ * @type {number}
148
+ */
149
+ ChromeDriver.getUrlRequestSequenceNumber = 0;
150
+
151
+
152
+ /**
153
+ * Prefix prepended to the hopefully unique javascript window name, in hopes of
154
+ * further removing conflict.
155
+ * @type {string}
156
+ */
157
+ ChromeDriver.windowHandlePrefix = '__webdriver_chromedriver_windowhandle';
158
+
159
+
160
+ /**
161
+ * Whether we will not execute any commands because we are already executing
162
+ * one.
163
+ * @type {boolean}
164
+ */
165
+ ChromeDriver.isBlockedWaitingForResponse = false;
166
+
167
+ /**
168
+ * It's possible that the page has completed loading,
169
+ * but the content script has not yet fired.
170
+ * In this case, to not report that there is no page,
171
+ * when we are just too fast, we wait up to this amount of time.
172
+ * @type {number} unit: milliseconds
173
+ */
174
+ ChromeDriver.timeoutUntilGiveUpOnContentScriptLoading = 5000;
175
+
176
+ /**
177
+ * How long we are currently waiting for the content script to load
178
+ * after loading the page
179
+ * @type {number} unit: milliseconds
180
+ */
181
+ ChromeDriver.currentlyWaitingUntilGiveUpOnContentScriptLoading;
182
+
183
+ //Set ChromeDriver.currentlyWaitingUntilGiveUpOnContentScriptLoading;
184
+ resetCurrentlyWaitingOnContentScriptTime();
185
+
186
+ /**
187
+ * How long we wait between poling whether we have a content script,
188
+ * when loading a new page, up until
189
+ * ChromeDriver.timeoutUntilGiveUpOnContentScriptLoading
190
+ * @type {number} unit: milliseconds
191
+ */
192
+ ChromeDriver.waitForContentScriptIncrement = 100;
193
+
194
+ chrome.extension.onConnect.addListener(function(port) {
195
+ if (ChromeDriver.xmlHttpRequestUrl == null) {
196
+ //This is the first content script, so is from the URL we need to connect to
197
+ ChromeDriver.xmlHttpRequestUrl = port.tab.url;
198
+ //Tell the ChromeCommandExecutor that we are here
199
+ sendResponseByXHR("", false);
200
+ return;
201
+ } else if (port.tab.url.indexOf(ChromeDriver.xmlHttpRequestUrl) == 0) {
202
+ //We have reloaded the xmlHttpRequest page. Ignore the connection.
203
+ return;
204
+ }
205
+
206
+ console.log("Connected to " + port.name);
207
+ // Note: The frameset port *always* connects before any frame port. After
208
+ // that, the order is in page loading time
209
+ ChromeDriver.hasNoConnectionToPage = false;
210
+ var foundTab = false;
211
+ for (var tab in ChromeDriver.tabs) {
212
+ if (ChromeDriver.tabs[tab].tabId == port.tab.id) {
213
+ //We must be a new [i]frame in the page, because when a page closes, it is
214
+ // removed from ChromeDriver.tabs
215
+ //TODO(danielwh): Work out WHICH page it's a sub-frame of (I don't look
216
+ // forward to this)
217
+ ChromeDriver.tabs[tab].frames.push({
218
+ frameName: port.name,
219
+ framePort: port,
220
+ frames: []
221
+ });
222
+ //Loaded a frame. Pushed it to the array. We don't know which page it's
223
+ // a sub-frame of, in the case of nested frames, if they have the same
224
+ // names. It would be nice to think people didn't use frames, let alone
225
+ // several layers of nesting of frames with the same name, but if it turns
226
+ // out to be a problem... Well, we'll see.
227
+ foundTab = true;
228
+ break;
229
+ }
230
+ }
231
+ if (!foundTab) {
232
+ //New tab!
233
+ //We don't know if it's a frameset yet, so we leave that as undefined
234
+ ChromeDriver.tabs.push({
235
+ tabId: port.tab.id,
236
+ windowName: ChromeDriver.windowHandlePrefix + "_" + port.tab.id,
237
+ mainPort: port,
238
+ frames: []
239
+ });
240
+ }
241
+
242
+ if (ChromeDriver.doFocusOnNextOpenedTab) {
243
+ ChromeDriver.activePort = port;
244
+ setActiveTabDetails(port.tab);
245
+ //Re-parse the last request we sent if we didn't get a response,
246
+ //because we ain't seeing a response any time soon
247
+
248
+ if (ChromeDriver.lastRequestToBeSentWhichHasntBeenAnsweredYet != null) {
249
+ if (ChromeDriver.urlBeingLoaded != null) {
250
+ ChromeDriver.lastRequestToBeSentWhichHasntBeenAnsweredYet = null;
251
+ } else {
252
+ ChromeDriver.isBlockedWaitingForResponse = false;
253
+ console.log("Re-trying request which was sent but not answered");
254
+ parseRequest(ChromeDriver.lastRequestToBeSentWhichHasntBeenAnsweredYet);
255
+ }
256
+ }
257
+ }
258
+
259
+ if (ChromeDriver.urlBeingLoaded != null) {
260
+ //This was the result of a getUrl. Need to issue a response
261
+ sendEmptyResponseWhenTabIsLoaded(port.tab);
262
+ }
263
+ port.onMessage.addListener(parsePortMessage);
264
+ port.onDisconnect.addListener(function disconnectPort(port) {
265
+ console.log("Disconnected from " + port.name);
266
+ var remainingTabs = [];
267
+ for (var tab in ChromeDriver.tabs) {
268
+ if (ChromeDriver.tabs[tab].tabId == port.tab.id) {
269
+ if (ChromeDriver.tabs[tab].mainPort == port) {
270
+ //This main tab is being closed.
271
+ //Don't include it in the new version of ChromeDriver.tabs.
272
+ //Any subframes will also disconnect,
273
+ //but their tabId won't be present in the array,
274
+ //so they will be ignored.
275
+ continue;
276
+ } else {
277
+ //This is a subFrame being ditched
278
+ var remainingFrames = [];
279
+ for (var frame in ChromeDriver.tabs[tab].frames) {
280
+ if (ChromeDriver.tabs[tab].frames[frame].framePort == port) {
281
+ continue;
282
+ }
283
+ remainingFrames.push(ChromeDriver.tabs[tab].frames[frame]);
284
+ }
285
+ ChromeDriver.tabs[tab].frames = remainingFrames;
286
+ }
287
+ }
288
+ remainingTabs.push(ChromeDriver.tabs[tab]);
289
+ }
290
+ ChromeDriver.tabs = remainingTabs;
291
+ if (ChromeDriver.tabs.length == 0 || ChromeDriver.activePort == null ||
292
+ ChromeDriver.activePort.tab.id == port.tab.id) {
293
+ //If it is the active tab, perhaps we have followed a link,
294
+ //so we should focus on it.
295
+ //We have nothing better to focus on, anyway.
296
+ resetActiveTabDetails();
297
+ }
298
+ if (ChromeDriver.isClosingTab) {
299
+ //We are actively closing the tab, and expect a response to this
300
+ sendResponseToParsedRequest({statusCode: 0}, false)
301
+ ChromeDriver.isClosingTab = false;
302
+ if (ChromeDriver.tabs.length == 0) {
303
+ chrome.windows.getAll({}, function(windows) {
304
+ for (var window in windows) {
305
+ chrome.windows.remove(windows[window].id);
306
+ }
307
+ });
308
+ }
309
+ }
310
+ });
311
+ });
312
+
313
+ /**
314
+ * Sends the passed argument as the result of a command
315
+ * @param result object encapsulating result to send
316
+ * @param wait whether we expect this command to possibly make changes
317
+ * we need to wait for (e.g. adding elements, opening windows) - if so,
318
+ * we wait until we think these effects are done
319
+ */
320
+ function sendResponseByXHR(result, wait) {
321
+ console.log("Sending result by XHR: " + JSON.stringify(result));
322
+ if (ChromeDriver.xmlHttpRequest != null) {
323
+ ChromeDriver.xmlHttpRequest.abort();
324
+ }
325
+ ChromeDriver.xmlHttpRequest = new XMLHttpRequest();
326
+ ChromeDriver.xmlHttpRequest.onreadystatechange =
327
+ handleXmlHttpRequestReadyStateChange;
328
+ ChromeDriver.xmlHttpRequest.open(
329
+ "POST", ChromeDriver.xmlHttpRequestUrl, true);
330
+ ChromeDriver.xmlHttpRequest.setRequestHeader(
331
+ "Content-type", "application/json");
332
+ //Default to waiting for page changes, just in case
333
+ //TODO(danielwh): Iterate over tabs checking their status
334
+ if (wait === undefined || wait == null || wait) {
335
+ setTimeout(sendResult, 600, [result]);
336
+ } else {
337
+ sendResult(result);
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Actually sends the result by XHR
343
+ * Should only EVER be called by sendResponseByXHR,
344
+ * as it ignores things like setting up XHR and blocking,
345
+ * and just forces the sending over an assumed open XHR
346
+ * @param result String to send
347
+ */
348
+ function sendResult(result) {
349
+ //TODO(danielwh): Iterate over tabs checking their status
350
+ ChromeDriver.xmlHttpRequest.send(result + "\nEOResponse\n");
351
+ console.log("Sent result by XHR: " + JSON.stringify(result));
352
+ }
353
+
354
+ /**
355
+ * Sends the response to a request, which has been parsed by parseRequest
356
+ * Should be used only from within parseRequest (or methods called from it),
357
+ * because it adheres to the blocking semantics of parseRequest
358
+ */
359
+ function sendResponseToParsedRequest(toSend, wait) {
360
+ if (!ChromeDriver.isBlockedWaitingForResponse) {
361
+ console.log("Tried to send a response (" + toSend +
362
+ ") when not waiting for one. Dropping response.");
363
+ return;
364
+ }
365
+ ChromeDriver.isBlockedWaitingForResponse = false;
366
+ ChromeDriver.lastRequestToBeSentWhichHasntBeenAnsweredYet = null;
367
+ console.log("SENDING RESPOND TO PARSED REQUEST");
368
+ sendResponseByXHR(JSON.stringify(toSend), wait);
369
+ setExtensionBusyIndicator(false);
370
+ }
371
+
372
+ /**
373
+ * When we receive a request, dispatches parseRequest to execute it
374
+ */
375
+ function handleXmlHttpRequestReadyStateChange() {
376
+ if (this.readyState == 4) {
377
+ if (this.status != 200) {
378
+ console.log("Request state was 4 but status: " + this.status +
379
+ ". responseText: " + this.responseText);
380
+ } else {
381
+ console.log("GOT XHR RESPONSE: " + this.responseText);
382
+ var request = JSON.parse(this.responseText);
383
+ if (request.request == "quit") {
384
+ //We're only allowed to send a response if we're blocked waiting for one, so pretend
385
+ console.log("SENDING QUIT XHR");
386
+ sendResponseByXHR(JSON.stringify({statusCode: 0}), false);
387
+ } else {
388
+ console.log("Got request to execute from XHR: " + this.responseText);
389
+ parseRequest(request);
390
+ }
391
+ }
392
+ }
393
+ }
394
+
395
+ /**
396
+ * Parses a request received from the ChromeCommandExecutor and either sends the
397
+ * response, or sends a message to the content script with a command to execute
398
+ * @param request object encapsulating the request (e.g.
399
+ * {request: url, url: "http://www.google.co.uk"})
400
+ */
401
+ function parseRequest(request) {
402
+ if (ChromeDriver.isBlockedWaitingForResponse) {
403
+ console.log("Already sent a request which hasn't been replied to yet. " +
404
+ "Not parsing any more.");
405
+ return;
406
+ }
407
+ ChromeDriver.isBlockedWaitingForResponse = true;
408
+ setExtensionBusyIndicator(true);
409
+
410
+ switch (request.request) {
411
+ case "get":
412
+ getUrl(request.url);
413
+ break;
414
+ case "close":
415
+ //Doesn't re-focus the ChromeDriver.activePort on any tab.
416
+ chrome.tabs.remove(ChromeDriver.activeTabId);
417
+ ChromeDriver.isClosingTab = true;
418
+ break;
419
+ case "getCurrentWindowHandle":
420
+ if (ChromeDriver.activePort == null) {
421
+ // console.log("No active port right now.");
422
+ // Fine. Find the active tab.
423
+ // TODO(simon): This is lame and error prone
424
+ var len = ChromeDriver.tabs.length;
425
+ for (var i = 0; i < len; i++) {
426
+ if (ChromeDriver.tabs[i].selected) {
427
+ sendResponseToParsedRequest({statusCode: 0, value: ChromeDriver.tabs[i].windowName}, false);
428
+ }
429
+ }
430
+
431
+ // Hohoho. The first argument to tabs.getSelected is optional, but must be set.
432
+ chrome.windows.getCurrent(function(win) {
433
+ chrome.tabs.getSelected(win.id, function(tab) {
434
+ var len = ChromeDriver.tabs.length;
435
+ for (var i = 0; i < len; i++) {
436
+ if (ChromeDriver.tabs[i].tabId == tab.id) {
437
+ sendResponseToParsedRequest({statusCode: 0, value: ChromeDriver.tabs[i].windowName}, false);
438
+ return;
439
+ }
440
+ }
441
+ });
442
+ });
443
+ } else {
444
+ // Wow. I can't see this being error prone in the slightest
445
+ var handle = ChromeDriver.windowHandlePrefix + "_" + ChromeDriver.activePort.sender.tab.id;
446
+ sendResponseToParsedRequest({statusCode: 0, value: handle}, false);
447
+ };
448
+ break;
449
+ case "getWindowHandles":
450
+ sendResponseToParsedRequest(getWindowHandles(), false);
451
+ break;
452
+ case "switchToDefaultContent":
453
+ switchToDefaultContent();
454
+ break;
455
+ case "switchToFrameByIndex":
456
+ switchToFrame(null, request.index);
457
+ break;
458
+ case "switchToFrameByName":
459
+ switchToFrame(request.name, null);
460
+ break;
461
+ case "switchToWindow":
462
+ ChromeDriver.hasHwnd = false;
463
+ if (request.windowName !== undefined) {
464
+ setActivePortByWindowName(request.windowName);
465
+ } else {
466
+ sendResponseToParsedRequest({
467
+ statusCode: 3,
468
+ value: {
469
+ message: 'Window to switch to was not given'
470
+ }
471
+ }, false);
472
+ }
473
+ break;
474
+ case "screenshot":
475
+ getScreenshot();
476
+ break;
477
+ case "clickElement":
478
+ case "hoverOverElement":
479
+ // Falling through, as native events are handled the same
480
+ case "sendKeysToElement":
481
+ if (typeof(request.keys) == "object" && request.keys.length !== undefined) {
482
+ request.keys = request.keys.join("");
483
+ }
484
+ sendMessageOnActivePortAndAlsoKeepTrackOfIt(
485
+ wrapInjectEmbedIfNecessary(request));
486
+ break;
487
+ case "getCurrentUrl":
488
+ case "getTitle":
489
+ if (hasNoPage()) {
490
+ console.log("Not got a page, but asked for string, so sending empty string");
491
+ sendResponseToParsedRequest({statusCode: 0, value: ''});
492
+ break;
493
+ }
494
+ // Falling through, as if we do have a page, we want to treat this like a
495
+ // normal request
496
+ case "findElement":
497
+ case "findChildElement":
498
+ if (hasNoPage()) {
499
+ console.log("Not got a page, but asked for element, so throwing NoSuchElementException");
500
+ sendResponseToParsedRequest({statusCode: 7, value: {message: 'Was not on a page, so could not find elements'}});
501
+ break;
502
+ }
503
+ // Falling through, as if we do have a page, we want to treat this like a
504
+ // normal request
505
+ case "findElements":
506
+ case "findChildElements":
507
+ if (hasNoPage()) {
508
+ console.log("Not got a page, but asked for elements, so returning no elements");
509
+ sendResponseToParsedRequest({statusCode: 0, value: []});
510
+ break;
511
+ }
512
+ // Falling through, as if we do have a page, we want to treat this like a
513
+ // normal request
514
+ case "deleteAllCookies":
515
+ case "deleteCookie":
516
+ if (hasNoPage()) {
517
+ console.log("Not got a page, but asked to delete cookies, so returning ok");
518
+ sendResponseToParsedRequest({statusCode: 0});
519
+ break;
520
+ }
521
+ // Falling through, as if we do have a page, we want to treat this like a
522
+ // normal request
523
+ case "executeScript":
524
+ if (hasNoPage()) {
525
+ console.log("Not got a page, but asked to execute script, so sending error 17");
526
+ sendResponseToParsedRequest({statusCode: 17, value: {message: 'Was not on a page, so could not execute javascript'}});
527
+ break;
528
+ }
529
+ // Falling through, as if we do have a page, we want to treat this like a
530
+ // normal request
531
+ default:
532
+ var sequenceNumber = ChromeDriver.requestSequenceNumber;
533
+ ChromeDriver.requestSequenceNumber++;
534
+ sendMessageOnActivePortAndAlsoKeepTrackOfIt({
535
+ request: request,
536
+ sequenceNumber: sequenceNumber
537
+ });
538
+ break;
539
+ }
540
+ }
541
+
542
+ function getScreenshot() {
543
+ chrome.tabs.captureVisibleTab(null, getScreenshotResult);
544
+ }
545
+
546
+ function getScreenshotResult(snapshotDataUrl) {
547
+ var index = snapshotDataUrl.indexOf('base64,');
548
+ if (index == -1) {
549
+ sendResponseToParsedRequest({statusCode: 99}, false);
550
+ return;
551
+ }
552
+ var base64 = snapshotDataUrl.substring(index + 'base64,'.length);
553
+ sendResponseToParsedRequest({statusCode: 0, value: base64}, false);
554
+ }
555
+
556
+ function sendMessageOnActivePortAndAlsoKeepTrackOfIt(message) {
557
+ ChromeDriver.lastRequestToBeSentWhichHasntBeenAnsweredYet = message.request;
558
+ try {
559
+ ChromeDriver.activePort.postMessage(message);
560
+ } catch (e) {
561
+ console.log("Tried to send request without an active port. " +
562
+ "Request will retry when connected, but will hang until then.");
563
+ }
564
+ }
565
+
566
+ /**
567
+ * Parse messages coming in on the port (responses from the content script).
568
+ * @param message JSON message of format:
569
+ * {response: "some command",
570
+ * value: {statusCode: STATUS_CODE
571
+ * [, optional params]}}
572
+ */
573
+ function parsePortMessage(message) {
574
+ console.log(
575
+ "Received response from content script: " + JSON.stringify(message));
576
+ if (!message || !message.response || !message.response.value ||
577
+ message.response.value.statusCode === undefined ||
578
+ message.response.value.statusCode === null ||
579
+ message.sequenceNumber === undefined || message.sequenceNumber < ChromeDriver.lastReceivedSequenceNumber) {
580
+ // Should only ever happen if we sent a bad request,
581
+ // or the content script is broken
582
+ console.log("Got invalid response from the content script.");
583
+ return;
584
+ }
585
+ var toSend = {statusCode: 12};
586
+ ChromeDriver.lastRequestToBeSentWhichHasntBeenAnsweredYet = null;
587
+ switch (message.response.value.statusCode) {
588
+ // Error codes are loosely based on native exception codes, see
589
+ // common/src/cpp/webdriver-interactions/errorcodes.h
590
+ case 0:
591
+ case 2: //org.openqa.selenium.WebDriverException [Cookies]
592
+ case 3: //org.openqa.selenium.NoSuchWindowException
593
+ case 7: //org.openqa.selenium.NoSuchElementException
594
+ case 8: //org.openqa.selenium.NoSuchFrameException
595
+ case 9: //java.lang.UnsupportedOperationException [Unknown command]
596
+ case 10: //org.openqa.selenium.StaleElementReferenceException
597
+ case 11: //org.openqa.selenium.ElementNotVisibleException
598
+ case 12: //java.lang.UnsupportedOperationException [Invalid element state ]
599
+ case 13: //org.openqa.selenium.WebDriverException [Unhandled error]
600
+ case 17: //org.openqa.selenium.WebDriverException [Bad javascript]
601
+ case 19: //org.openqa.selenium.XPathLookupException
602
+ case 99: //org.openqa.selenium.WebDriverException [Native event]
603
+ toSend = {statusCode: message.response.value.statusCode, value: null};
604
+ if (message.response.value !== undefined && message.response.value !== null &&
605
+ message.response.value.value !== undefined) {
606
+ toSend.value = message.response.value.value;
607
+ }
608
+ sendResponseToParsedRequest(toSend, message.response.wait);
609
+ break;
610
+ case "no-op":
611
+ //Some special operation which isn't sending HTTP
612
+ switch (message.response.response) {
613
+ case "clickElement":
614
+ try {
615
+ if (document.embeds[0].clickAt(message.response.value.x, message.response.value.y)) {
616
+ sendResponseToParsedRequest({statusCode: 0}, true);
617
+ } else {
618
+ sendResponseToParsedRequest({statusCode: 99}, true);
619
+ }
620
+ } catch(e) {
621
+ console.log("Error natively clicking. Trying non-native.");
622
+ ChromeDriver.isBlockedWaitingForResponse = false;
623
+ parseRequest({
624
+ request: 'nonNativeClickElement',
625
+ elementId: message.response.value.elementId
626
+ });
627
+ }
628
+ break;
629
+ case "hoverElement":
630
+ try {
631
+ var points = message.response.value;
632
+ if (document.embeds[0].mouseMoveTo(15, points.oldX, points.oldY, points.newX, points.newY)) {
633
+ sendResponseToParsedRequest({statusCode: 0}, true);
634
+ } else {
635
+ sendResponseToParsedRequest({statusCode: 99}, true);
636
+ }
637
+ } catch(e) {
638
+ sendResponseToParsedRequest({statusCode: 99}, true);
639
+ }
640
+ break;
641
+ case "sendKeysToElement":
642
+ try {
643
+ if (document.embeds[0].sendKeys(message.response.value.keys)) {
644
+ sendResponseToParsedRequest({statusCode: 0}, true);
645
+ } else {
646
+ sendResponseToParsedRequest({statusCode: 99}, true);
647
+ }
648
+ } catch(e) {
649
+ console.log("Error natively sending keys. Trying non-native.");
650
+ ChromeDriver.isBlockedWaitingForResponse = false;
651
+ parseRequest({
652
+ request: 'sendElementNonNativeKeys',
653
+ elementId: message.response.value.elementId,
654
+ keys: message.response.value.keys
655
+ });
656
+ }
657
+ break;
658
+ case "sniffForMetaRedirects":
659
+ if (!message.response.value.value &&
660
+ !ChromeDriver.hasSentResponseToThisPageLoading) {
661
+ ChromeDriver.urlBeingLoaded = null;
662
+ ChromeDriver.hasSentResponseToThisPageLoading = true;
663
+ switchToDefaultContent();
664
+ }
665
+ break;
666
+ case "newTabInformation":
667
+ var response = message.response.value;
668
+ for (var tab in ChromeDriver.tabs) {
669
+ //RACE CONDITION!!!
670
+ //This call should happen before another content script
671
+ //connects and returns this value,
672
+ //but if it doesn't, we may get mismatched information
673
+ if (ChromeDriver.tabs[tab].isFrameset === undefined) {
674
+ ChromeDriver.tabs[tab].isFrameset = response.isFrameset;
675
+ return;
676
+ } else {
677
+ for (var frame in ChromeDriver.tabs[tab].frames) {
678
+ var theFrame = ChromeDriver.tabs[tab].frames[frame];
679
+ if (theFrame.isFrameset === undefined) {
680
+ theFrame.isFrameset = response.isFrameset;
681
+ return;
682
+ }
683
+ }
684
+ }
685
+ }
686
+ break;
687
+ case "getFrameNameFromIndex":
688
+ var newName = message.response.value.name;
689
+ if (ChromeDriver.restOfCurrentFramePath.length != 0) {
690
+ newName += "." + ChromeDriver.restOfCurrentFramePath.join(".");
691
+ }
692
+ switchToFrameByName(newName);
693
+ break;
694
+ }
695
+ break;
696
+ }
697
+ }
698
+
699
+ /**
700
+ * If the plugin doesn't currently have an HWND for this page,
701
+ * we need to get one by injecting an embed
702
+ */
703
+ function wrapInjectEmbedIfNecessary(requestObject) {
704
+ if (ChromeDriver.hasHwnd) {
705
+ var sequenceNumber = ChromeDriver.requestSequenceNumber;
706
+ ChromeDriver.requestSequenceNumber++;
707
+ return {
708
+ sequenceNumber: sequenceNumber,
709
+ request: requestObject
710
+ };
711
+ } else {
712
+ var wrappedObject = {
713
+ sequenceNumber: ChromeDriver.requestSequenceNumber,
714
+ request: {
715
+ request: "injectEmbed",
716
+ followup: {
717
+ sequenceNumber: ChromeDriver.requestSequenceNumber + 1,
718
+ request: requestObject
719
+ }
720
+ }
721
+ };
722
+ ChromeDriver.requestSequenceNumber += 2;
723
+ return wrappedObject;
724
+ }
725
+ }
726
+
727
+ /**
728
+ * Gets all current window handles
729
+ * @return an array containing all of the current window handles
730
+ */
731
+ function getWindowHandles() {
732
+ var windowHandles = [];
733
+ for (var tab in ChromeDriver.tabs) {
734
+ windowHandles.push(ChromeDriver.tabs[tab].windowName);
735
+ }
736
+ return {statusCode: 0, value: windowHandles}
737
+ }
738
+
739
+ function resetActiveTabDetails() {
740
+ ChromeDriver.activePort = null;
741
+ ChromeDriver.hasHwnd = false;
742
+ ChromeDriver.activeTabId = null;
743
+ ChromeDriver.doFocusOnNextOpenedTab = true;
744
+ ChromeDriver.hasSentResponseToThisPageLoading = false;
745
+ ChromeDriver.portToUseForFrameLookups = null;
746
+ ChromeDriver.currentUrl = null;
747
+ resetCurrentlyWaitingOnContentScriptTime();
748
+ }
749
+
750
+ function setActiveTabDetails(tab) {
751
+ ChromeDriver.activeTabId = tab.id;
752
+ ChromeDriver.activeWindowId = tab.windowId;
753
+ ChromeDriver.doFocusOnNextOpenedTab = false;
754
+ ChromeDriver.currentUrl = tab.url;
755
+ resetCurrentlyWaitingOnContentScriptTime();
756
+ }
757
+
758
+ function switchToDefaultContent() {
759
+ ChromeDriver.hasHwnd = false;
760
+ for (var tab in ChromeDriver.tabs) {
761
+ if (ChromeDriver.tabs[tab].tabId == ChromeDriver.activeTabId) {
762
+ if (ChromeDriver.tabs[tab].isFrameset) {
763
+ ChromeDriver.isBlockedWaitingForResponse = false;
764
+ parseRequest({request: 'switchToFrameByIndex', index: 0});
765
+ } else {
766
+ ChromeDriver.activePort = ChromeDriver.tabs[tab].mainPort;
767
+ sendResponseToParsedRequest({statusCode: 0}, false);
768
+ }
769
+ return;
770
+ }
771
+ }
772
+ }
773
+
774
+ function switchToFrame(name, index) {
775
+ ChromeDriver.hasHwnd = false;
776
+ for (var tab in ChromeDriver.tabs) {
777
+ if (ChromeDriver.tabs[tab].tabId == ChromeDriver.activeTabId) {
778
+ ChromeDriver.portToUseForFrameLookups = ChromeDriver.tabs[tab].mainPort;
779
+ break;
780
+ }
781
+ }
782
+ if (name !== undefined && name !== null) {
783
+ switchToFrameByName(name);
784
+ } else if (index !== undefined && index !== null) {
785
+ getFrameNameFromIndex(index);
786
+ } else {
787
+ sendResponseToParsedRequest({
788
+ statusCode: 9,
789
+ value: {
790
+ message: "Switching frames other than by name or id is unsupported"
791
+ }
792
+ });
793
+ }
794
+ }
795
+
796
+ function switchToFrameByName(name) {
797
+ var names = name.split(".");
798
+
799
+ for (var tab in ChromeDriver.tabs) {
800
+ if (ChromeDriver.tabs[tab].tabId == ChromeDriver.activeTabId) {
801
+ var frame;
802
+ for (frame in ChromeDriver.tabs[tab].frames) {
803
+ // Maybe name was a fully qualified name, which perhaps just happened to
804
+ // include .s
805
+ if (ChromeDriver.tabs[tab].frames[frame].frameName == name) {
806
+ ChromeDriver.activePort =
807
+ ChromeDriver.tabs[tab].frames[frame].framePort;
808
+ ChromeDriver.restOfCurrentFramePath = [];
809
+ sendResponseToParsedRequest({statusCode: 0}, false);
810
+ return;
811
+ }
812
+ }
813
+ for (frame in ChromeDriver.tabs[tab].frames) {
814
+ // Maybe we're looking for a child, see if this is the parent of it
815
+ if (ChromeDriver.tabs[tab].frames[frame].frameName == names[0]) {
816
+ ChromeDriver.activePort =
817
+ ChromeDriver.tabs[tab].frames[frame].framePort;
818
+ ChromeDriver.portToUseForFrameLookups = ChromeDriver.activePort;
819
+ names.shift();
820
+ ChromeDriver.restOfCurrentFramePath = names;
821
+ if (names.length == 0) {
822
+ sendResponseToParsedRequest({statusCode: 0}, false);
823
+ return;
824
+ } else {
825
+ switchToFrameByName(names.join("."));
826
+ return;
827
+ }
828
+ }
829
+ }
830
+ }
831
+ }
832
+
833
+ //Maybe the "name" was actually an index? Let's find out...
834
+ var index = null;
835
+ try {
836
+ index = parseInt(names[0]);
837
+ } catch (e) {
838
+ }
839
+ if (!isNaN(index)) {
840
+ names.shift();
841
+ ChromeDriver.restOfCurrentFramePath = names;
842
+ getFrameNameFromIndex(index);
843
+ return;
844
+ }
845
+
846
+ ChromeDriver.isBlockedWaitingForResponse = false;
847
+ parseRequest({request: 'switchToNamedIFrameIfOneExists', name: name});
848
+ }
849
+
850
+ function getFrameNameFromIndex(index) {
851
+ var message = {
852
+ request: {
853
+ request: "getFrameNameFromIndex",
854
+ index: index
855
+ },
856
+ sequenceNumber: ChromeDriver.requestSequenceNumber
857
+ };
858
+ ChromeDriver.requestSequenceNumber++;
859
+ ChromeDriver.portToUseForFrameLookups.postMessage(message);
860
+ }
861
+
862
+ /**
863
+ * Closes the current tab if it exists, and opens a new one, in which it
864
+ * gets the URL passed
865
+ * @param url the URL to load
866
+ */
867
+ function getUrl(url) {
868
+ ChromeDriver.urlBeingLoaded = url;
869
+ var tempActiveTagId = ChromeDriver.activeTabId;
870
+ if (url.indexOf("#") > -1 && ChromeDriver.currentUrl != null &&
871
+ ChromeDriver.currentUrl.split("#")[0] == url.split("#")[0]) {
872
+ ChromeDriver.isGettingUrlButOnlyChangingByFragment = true;
873
+ } else {
874
+ resetActiveTabDetails();
875
+ }
876
+ ChromeDriver.currentUrl = url;
877
+ if (tempActiveTagId == null) {
878
+ chrome.tabs.create({url: url, selected: true}, getUrlCallback);
879
+ } else {
880
+ ChromeDriver.activeTabId = tempActiveTagId;
881
+ if (ChromeDriver.isGettingUrlButOnlyChangingByFragment) {
882
+ chrome.tabs.update(ChromeDriver.activeTabId, {url: url, selected: true},
883
+ getUrlCallback);
884
+ } else {
885
+ // we need to create the new tab before deleting the old one
886
+ // in order to avoid hanging on OS X
887
+ var oldId = ChromeDriver.activeTabId;
888
+ resetActiveTabDetails();
889
+ chrome.tabs.create({url: url, selected: true}, getUrlCallback);
890
+ chrome.tabs.remove(oldId);
891
+ }
892
+ }
893
+ }
894
+
895
+ function getUrlCallback(tab) {
896
+ if (chrome.extension.lastError) {
897
+ // An error probably arose because Chrome didn't have a window yet
898
+ // (see crbug.com 19846)
899
+ // If we retry, we *should* be fine. Unless something really bad is
900
+ // happening, in which case we will probably hang indefinitely trying to
901
+ // reload the same URL
902
+ getUrl(ChromeDriver.urlBeingLoaded);
903
+ return;
904
+ }
905
+ if (tab == null) {
906
+ //chrome.tabs.update's callback doesn't pass a Tab argument,
907
+ //so we need to populate it ourselves
908
+ chrome.tabs.get(ChromeDriver.activeTabId, getUrlCallback);
909
+ return;
910
+ }
911
+ if (tab.status != "complete") {
912
+ // Use the helper calback so that we actually get updated version of the tab
913
+ // we're getting
914
+ setTimeout("getUrlCallbackById(" + tab.id + ")", 10);
915
+ } else {
916
+ ChromeDriver.getUrlRequestSequenceNumber++;
917
+ if (ChromeDriver.activePort == null) {
918
+ if (ChromeDriver.currentlyWaitingUntilGiveUpOnContentScriptLoading <= 0) {
919
+ ChromeDriver.hasNoConnectionToPage = true;
920
+ sendEmptyResponseWhenTabIsLoaded(tab);
921
+ } else {
922
+ ChromeDriver.currentlyWaitingUntilGiveUpOnContentScriptLoading -=
923
+ ChromeDriver.waitForContentScriptIncrement;
924
+ setTimeout("getUrlCallbackById(" + tab.id + ")", ChromeDriver.waitForContentScriptIncrement);
925
+ return;
926
+ }
927
+ }
928
+ setActiveTabDetails(tab);
929
+ }
930
+ if (ChromeDriver.isGettingUrlButOnlyChangingByFragment) {
931
+ ChromeDriver.urlBeingLoaded = null;
932
+ resetCurrentlyWaitingOnContentScriptTime();
933
+ sendResponseToParsedRequest({statusCode: 0}, false);
934
+ ChromeDriver.isGettingUrlButOnlyChangingByFragment = false;
935
+ }
936
+ }
937
+
938
+ function getUrlCallbackById(tabId) {
939
+ chrome.tabs.get(tabId, getUrlCallback);
940
+ }
941
+
942
+ function sendEmptyResponseWhenTabIsLoaded(tab) {
943
+ if (tab.status == "complete") {
944
+ if (ChromeDriver.activePort) {
945
+ ChromeDriver.isBlockedWaitingForResponse = false;
946
+ parseRequest({request: 'sniffForMetaRedirects'});
947
+ } else {
948
+ if (!ChromeDriver.hasSentResponseToThisPageLoading) {
949
+ ChromeDriver.urlBeingLoaded = null;
950
+ sendResponseToParsedRequest({statusCode: 0}, false);
951
+ }
952
+ }
953
+ } else {
954
+ chrome.tabs.get(tab.id, sendEmptyResponseWhenTabIsLoaded);
955
+ }
956
+ }
957
+
958
+
959
+ function setExtensionBusyIndicator(busy) {
960
+ if (busy) {
961
+ chrome.browserAction.setIcon({path: "icons/busy.png"})
962
+ } else {
963
+ chrome.browserAction.setIcon({path: "icons/free.png"})
964
+ }
965
+ }
966
+
967
+ function setActivePortByWindowName(handle) {
968
+ for (var tab in ChromeDriver.tabs) {
969
+ if (ChromeDriver.tabs[tab].windowName == handle ||
970
+ ChromeDriver.tabs[tab].mainPort.name == handle ||
971
+ ChromeDriver.tabs[tab].tabId.toString() == handle) {
972
+ ChromeDriver.activePort = ChromeDriver.tabs[tab].mainPort;
973
+ chrome.tabs.get(ChromeDriver.tabs[tab].tabId, setActiveTabDetails);
974
+ chrome.tabs.update(ChromeDriver.tabs[tab].tabId, {selected: true});
975
+ sendResponseToParsedRequest({statusCode: 0}, false);
976
+ return;
977
+ }
978
+ }
979
+ sendResponseToParsedRequest({statusCode: 3, value: {message: 'Could not find window to switch to by handle: ' + handle}}, false);
980
+ }
981
+
982
+
983
+ /**
984
+ * @return {boolean} Whether there is currently no active page.
985
+ */
986
+ function hasNoPage() {
987
+ return ChromeDriver.hasNoConnectionToPage ||
988
+ ChromeDriver.activePort == null ||
989
+ ChromeDriver.activeTabId == null;
990
+ }
991
+
992
+ function resetCurrentlyWaitingOnContentScriptTime() {
993
+ ChromeDriver.currentlyWaitingUntilGiveUpOnContentScriptLoading =
994
+ ChromeDriver.timeoutUntilGiveUpOnContentScriptLoading;
995
+ }