selenium-webdriver 2.53.4 → 3.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +363 -10
  3. data/LICENSE +1 -1
  4. data/README.md +2 -3
  5. data/lib/selenium-webdriver.rb +0 -2
  6. data/lib/selenium/server.rb +69 -70
  7. data/lib/selenium/webdriver.rb +32 -23
  8. data/lib/selenium/webdriver/atoms.rb +18 -0
  9. data/lib/selenium/webdriver/atoms/getAttribute.js +8 -0
  10. data/lib/selenium/webdriver/chrome.rb +8 -6
  11. data/lib/selenium/webdriver/chrome/driver.rb +112 -0
  12. data/lib/selenium/webdriver/chrome/options.rb +168 -0
  13. data/lib/selenium/webdriver/chrome/profile.rb +17 -17
  14. data/lib/selenium/webdriver/chrome/service.rb +22 -89
  15. data/lib/selenium/webdriver/common.rb +13 -6
  16. data/lib/selenium/webdriver/common/action_builder.rb +49 -57
  17. data/lib/selenium/webdriver/common/alert.rb +5 -15
  18. data/lib/selenium/webdriver/common/bridge_helper.rb +10 -17
  19. data/lib/selenium/webdriver/common/driver.rb +53 -68
  20. data/lib/selenium/webdriver/common/driver_extensions/{has_input_devices.rb → has_addons.rb} +13 -23
  21. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +4 -8
  22. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +4 -7
  23. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +0 -4
  24. data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +0 -4
  25. data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +1 -5
  26. data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +0 -5
  27. data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +4 -9
  28. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +7 -7
  29. data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +2 -7
  30. data/lib/selenium/webdriver/common/element.rb +57 -39
  31. data/lib/selenium/webdriver/common/error.rb +204 -106
  32. data/lib/selenium/webdriver/common/file_reaper.rb +3 -11
  33. data/lib/selenium/webdriver/common/html5/local_storage.rb +6 -10
  34. data/lib/selenium/webdriver/common/html5/session_storage.rb +6 -10
  35. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +7 -18
  36. data/lib/selenium/webdriver/{safari/options.rb → common/interactions/input_device.rb} +20 -31
  37. data/lib/selenium/webdriver/common/interactions/interaction.rb +50 -0
  38. data/lib/selenium/webdriver/{safari/browser.rb → common/interactions/interactions.rb} +16 -15
  39. data/lib/selenium/webdriver/common/interactions/key_actions.rb +143 -0
  40. data/lib/selenium/webdriver/common/interactions/key_input.rb +62 -0
  41. data/lib/selenium/webdriver/{android.rb → common/interactions/none_input.rb} +11 -6
  42. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +353 -0
  43. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +132 -0
  44. data/lib/selenium/webdriver/common/keyboard.rb +7 -14
  45. data/lib/selenium/webdriver/common/keys.rb +99 -82
  46. data/lib/selenium/webdriver/common/log_entry.rb +3 -6
  47. data/lib/selenium/webdriver/common/logger.rb +140 -0
  48. data/lib/selenium/webdriver/common/logs.rb +2 -6
  49. data/lib/selenium/webdriver/common/mouse.rb +9 -14
  50. data/lib/selenium/webdriver/common/navigation.rb +2 -6
  51. data/lib/selenium/webdriver/common/options.rb +20 -23
  52. data/lib/selenium/webdriver/common/platform.rb +70 -97
  53. data/lib/selenium/webdriver/common/port_prober.rb +3 -4
  54. data/lib/selenium/webdriver/common/profile_helper.rb +6 -11
  55. data/lib/selenium/webdriver/common/proxy.rb +58 -72
  56. data/lib/selenium/webdriver/common/search_context.rb +22 -29
  57. data/lib/selenium/webdriver/common/service.rb +161 -0
  58. data/lib/selenium/webdriver/common/socket_lock.rb +6 -14
  59. data/lib/selenium/webdriver/common/socket_poller.rb +5 -12
  60. data/lib/selenium/webdriver/common/target_locator.rb +11 -15
  61. data/lib/selenium/webdriver/common/timeouts.rb +4 -8
  62. data/lib/selenium/webdriver/common/touch_action_builder.rb +2 -6
  63. data/lib/selenium/webdriver/common/touch_screen.rb +19 -23
  64. data/lib/selenium/webdriver/common/w3c_action_builder.rb +209 -0
  65. data/lib/selenium/webdriver/{phantomjs.rb → common/w3c_options.rb} +16 -14
  66. data/lib/selenium/webdriver/common/wait.rb +6 -13
  67. data/lib/selenium/webdriver/common/window.rb +48 -17
  68. data/lib/selenium/webdriver/common/zipper.rb +6 -10
  69. data/lib/selenium/webdriver/edge.rb +5 -12
  70. data/lib/selenium/webdriver/edge/bridge.rb +32 -63
  71. data/lib/selenium/webdriver/edge/driver.rb +73 -0
  72. data/lib/selenium/webdriver/edge/service.rb +18 -87
  73. data/lib/selenium/webdriver/firefox.rb +20 -11
  74. data/lib/selenium/webdriver/firefox/binary.rb +40 -56
  75. data/lib/selenium/webdriver/firefox/driver.rb +48 -0
  76. data/lib/selenium/webdriver/firefox/extension.rb +18 -8
  77. data/lib/selenium/webdriver/firefox/extension/prefs.json +3 -11
  78. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  79. data/lib/selenium/webdriver/firefox/launcher.rb +13 -22
  80. data/lib/selenium/webdriver/firefox/legacy/driver.rb +79 -0
  81. data/lib/selenium/webdriver/{iphone.rb → firefox/marionette/bridge.rb} +25 -6
  82. data/lib/selenium/webdriver/firefox/marionette/driver.rb +96 -0
  83. data/lib/selenium/webdriver/firefox/options.rb +149 -0
  84. data/lib/selenium/webdriver/firefox/profile.rb +46 -46
  85. data/lib/selenium/webdriver/firefox/profiles_ini.rb +8 -18
  86. data/lib/selenium/webdriver/firefox/service.rb +23 -83
  87. data/lib/selenium/webdriver/firefox/util.rb +0 -4
  88. data/lib/selenium/webdriver/ie.rb +4 -8
  89. data/lib/selenium/webdriver/ie/driver.rb +90 -0
  90. data/lib/selenium/webdriver/ie/options.rb +136 -0
  91. data/lib/selenium/webdriver/ie/service.rb +58 -0
  92. data/lib/selenium/webdriver/remote.rb +8 -16
  93. data/lib/selenium/webdriver/remote/bridge.rb +96 -565
  94. data/lib/selenium/webdriver/remote/capabilities.rb +76 -94
  95. data/lib/selenium/webdriver/remote/driver.rb +49 -0
  96. data/lib/selenium/webdriver/remote/http/common.rb +22 -20
  97. data/lib/selenium/webdriver/remote/http/curb.rb +9 -12
  98. data/lib/selenium/webdriver/remote/http/default.rb +54 -41
  99. data/lib/selenium/webdriver/remote/http/persistent.rb +9 -8
  100. data/lib/selenium/webdriver/remote/oss/bridge.rb +586 -0
  101. data/lib/selenium/webdriver/remote/oss/commands.rb +221 -0
  102. data/lib/selenium/webdriver/remote/response.rb +39 -27
  103. data/lib/selenium/webdriver/remote/server_error.rb +1 -5
  104. data/lib/selenium/webdriver/remote/w3c/bridge.rb +573 -0
  105. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +290 -0
  106. data/lib/selenium/webdriver/remote/w3c/commands.rb +148 -0
  107. data/lib/selenium/webdriver/safari.rb +20 -29
  108. data/lib/selenium/webdriver/{firefox/w3c_bridge.rb → safari/driver.rb} +21 -30
  109. data/lib/selenium/webdriver/safari/service.rb +57 -0
  110. data/lib/selenium/webdriver/support.rb +1 -2
  111. data/lib/selenium/webdriver/support/abstract_event_listener.rb +17 -4
  112. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -5
  113. data/lib/selenium/webdriver/support/color.rb +57 -42
  114. data/lib/selenium/webdriver/support/escaper.rb +41 -0
  115. data/lib/selenium/webdriver/support/event_firing_bridge.rb +36 -40
  116. data/lib/selenium/webdriver/support/select.rb +33 -86
  117. data/selenium-webdriver.gemspec +22 -25
  118. metadata +254 -261
  119. data/lib/selenium-client.rb +0 -21
  120. data/lib/selenium/client.rb +0 -57
  121. data/lib/selenium/client/base.rb +0 -151
  122. data/lib/selenium/client/driver.rb +0 -29
  123. data/lib/selenium/client/errors.rb +0 -28
  124. data/lib/selenium/client/extensions.rb +0 -132
  125. data/lib/selenium/client/idiomatic.rb +0 -507
  126. data/lib/selenium/client/javascript_expression_builder.rb +0 -135
  127. data/lib/selenium/client/javascript_frameworks/jquery.rb +0 -32
  128. data/lib/selenium/client/javascript_frameworks/prototype.rb +0 -32
  129. data/lib/selenium/client/legacy_driver.rb +0 -1722
  130. data/lib/selenium/client/protocol.rb +0 -123
  131. data/lib/selenium/client/selenium_helper.rb +0 -49
  132. data/lib/selenium/rake/server_task.rb +0 -176
  133. data/lib/selenium/webdriver/android/bridge.rb +0 -68
  134. data/lib/selenium/webdriver/chrome/bridge.rb +0 -139
  135. data/lib/selenium/webdriver/common/core_ext/base64.rb +0 -28
  136. data/lib/selenium/webdriver/common/core_ext/dir.rb +0 -61
  137. data/lib/selenium/webdriver/common/html5/location.rb +0 -19
  138. data/lib/selenium/webdriver/common/w3c_error.rb +0 -194
  139. data/lib/selenium/webdriver/edge/legacy_support.rb +0 -117
  140. data/lib/selenium/webdriver/firefox/bridge.rb +0 -89
  141. data/lib/selenium/webdriver/ie/bridge.rb +0 -88
  142. data/lib/selenium/webdriver/ie/server.rb +0 -133
  143. data/lib/selenium/webdriver/iphone/bridge.rb +0 -64
  144. data/lib/selenium/webdriver/phantomjs/bridge.rb +0 -78
  145. data/lib/selenium/webdriver/phantomjs/service.rb +0 -130
  146. data/lib/selenium/webdriver/remote/commands.rb +0 -211
  147. data/lib/selenium/webdriver/remote/w3c_bridge.rb +0 -668
  148. data/lib/selenium/webdriver/remote/w3c_capabilities.rb +0 -236
  149. data/lib/selenium/webdriver/remote/w3c_commands.rb +0 -132
  150. data/lib/selenium/webdriver/safari/bridge.rb +0 -135
  151. data/lib/selenium/webdriver/safari/resources/client.js +0 -7255
  152. data/lib/selenium/webdriver/safari/server.rb +0 -187
@@ -0,0 +1,221 @@
1
+ # Licensed to the Software Freedom Conservancy (SFC) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The SFC licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ module Selenium
19
+ module WebDriver
20
+ module Remote
21
+ module OSS
22
+
23
+ #
24
+ # https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#command-reference
25
+ # @api private
26
+ #
27
+
28
+ class Bridge
29
+
30
+ COMMANDS = {
31
+ get_capabilities: [:get, 'session/:session_id'.freeze],
32
+ status: [:get, 'status'.freeze],
33
+
34
+ #
35
+ # basic driver
36
+ #
37
+
38
+ get_current_url: [:get, 'session/:session_id/url'.freeze],
39
+ get: [:post, 'session/:session_id/url'.freeze],
40
+ go_forward: [:post, 'session/:session_id/forward'.freeze],
41
+ go_back: [:post, 'session/:session_id/back'.freeze],
42
+ refresh: [:post, 'session/:session_id/refresh'.freeze],
43
+ quit: [:delete, 'session/:session_id'.freeze],
44
+ close: [:delete, 'session/:session_id/window'.freeze],
45
+ get_page_source: [:get, 'session/:session_id/source'.freeze],
46
+ get_title: [:get, 'session/:session_id/title'.freeze],
47
+ find_element: [:post, 'session/:session_id/element'.freeze],
48
+ find_elements: [:post, 'session/:session_id/elements'.freeze],
49
+ get_active_element: [:post, 'session/:session_id/element/active'.freeze],
50
+
51
+ #
52
+ # window handling
53
+ #
54
+
55
+ get_current_window_handle: [:get, 'session/:session_id/window_handle'.freeze],
56
+ get_window_handles: [:get, 'session/:session_id/window_handles'.freeze],
57
+ set_window_size: [:post, 'session/:session_id/window/:window_handle/size'.freeze],
58
+ set_window_position: [:post, 'session/:session_id/window/:window_handle/position'.freeze],
59
+ get_window_size: [:get, 'session/:session_id/window/:window_handle/size'.freeze],
60
+ get_window_position: [:get, 'session/:session_id/window/:window_handle/position'.freeze],
61
+ maximize_window: [:post, 'session/:session_id/window/:window_handle/maximize'.freeze],
62
+
63
+ #
64
+ # script execution
65
+ #
66
+
67
+ execute_script: [:post, 'session/:session_id/execute'.freeze],
68
+ execute_async_script: [:post, 'session/:session_id/execute_async'.freeze],
69
+
70
+ #
71
+ # screenshot
72
+ #
73
+
74
+ screenshot: [:get, 'session/:session_id/screenshot'.freeze],
75
+
76
+ #
77
+ # alerts
78
+ #
79
+
80
+ dismiss_alert: [:post, 'session/:session_id/dismiss_alert'.freeze],
81
+ accept_alert: [:post, 'session/:session_id/accept_alert'.freeze],
82
+ get_alert_text: [:get, 'session/:session_id/alert_text'.freeze],
83
+ set_alert_value: [:post, 'session/:session_id/alert_text'.freeze],
84
+ set_authentication: [:post, 'session/:session_id/alert/credentials'.freeze],
85
+
86
+ #
87
+ # target locator
88
+ #
89
+
90
+ switch_to_frame: [:post, 'session/:session_id/frame'.freeze],
91
+ switch_to_parent_frame: [:post, 'session/:session_id/frame/parent'.freeze],
92
+ switch_to_window: [:post, 'session/:session_id/window'.freeze],
93
+
94
+ #
95
+ # options
96
+ #
97
+
98
+ get_cookies: [:get, 'session/:session_id/cookie'.freeze],
99
+ add_cookie: [:post, 'session/:session_id/cookie'.freeze],
100
+ delete_all_cookies: [:delete, 'session/:session_id/cookie'.freeze],
101
+ delete_cookie: [:delete, 'session/:session_id/cookie/:name'.freeze],
102
+
103
+ #
104
+ # timeouts
105
+ #
106
+
107
+ implicitly_wait: [:post, 'session/:session_id/timeouts/implicit_wait'.freeze],
108
+ set_script_timeout: [:post, 'session/:session_id/timeouts/async_script'.freeze],
109
+ set_timeout: [:post, 'session/:session_id/timeouts'.freeze],
110
+
111
+ #
112
+ # element
113
+ #
114
+
115
+ describe_element: [:get, 'session/:session_id/element/:id'.freeze],
116
+ find_child_element: [:post, 'session/:session_id/element/:id/element'.freeze],
117
+ find_child_elements: [:post, 'session/:session_id/element/:id/elements'.freeze],
118
+ click_element: [:post, 'session/:session_id/element/:id/click'.freeze],
119
+ submit_element: [:post, 'session/:session_id/element/:id/submit'.freeze],
120
+ get_element_value: [:get, 'session/:session_id/element/:id/value'.freeze],
121
+ send_keys_to_element: [:post, 'session/:session_id/element/:id/value'.freeze],
122
+ upload_file: [:post, 'session/:session_id/file'.freeze],
123
+ get_element_tag_name: [:get, 'session/:session_id/element/:id/name'.freeze],
124
+ clear_element: [:post, 'session/:session_id/element/:id/clear'.freeze],
125
+ is_element_selected: [:get, 'session/:session_id/element/:id/selected'.freeze],
126
+ is_element_enabled: [:get, 'session/:session_id/element/:id/enabled'.freeze],
127
+ get_element_attribute: [:get, 'session/:session_id/element/:id/attribute/:name'.freeze],
128
+ element_equals: [:get, 'session/:session_id/element/:id/equals/:other'.freeze],
129
+ is_element_displayed: [:get, 'session/:session_id/element/:id/displayed'.freeze],
130
+ get_element_location: [:get, 'session/:session_id/element/:id/location'.freeze],
131
+ get_element_location_once_scrolled_into_view: [:get, 'session/:session_id/element/:id/location_in_view'.freeze],
132
+ get_element_size: [:get, 'session/:session_id/element/:id/size'.freeze],
133
+ drag_element: [:post, 'session/:session_id/element/:id/drag'.freeze],
134
+ get_element_value_of_css_property: [:get, 'session/:session_id/element/:id/css/:property_name'.freeze],
135
+ get_element_text: [:get, 'session/:session_id/element/:id/text'.freeze],
136
+
137
+ #
138
+ # rotatable
139
+ #
140
+
141
+ get_screen_orientation: [:get, 'session/:session_id/orientation'.freeze],
142
+ set_screen_orientation: [:post, 'session/:session_id/orientation'.freeze],
143
+
144
+ #
145
+ # interactions API
146
+ #
147
+
148
+ click: [:post, 'session/:session_id/click'.freeze],
149
+ double_click: [:post, 'session/:session_id/doubleclick'.freeze],
150
+ mouse_down: [:post, 'session/:session_id/buttondown'.freeze],
151
+ mouse_up: [:post, 'session/:session_id/buttonup'.freeze],
152
+ mouse_move_to: [:post, 'session/:session_id/moveto'.freeze],
153
+ send_modifier_key_to_active_element: [:post, 'session/:session_id/modifier'.freeze],
154
+ send_keys_to_active_element: [:post, 'session/:session_id/keys'.freeze],
155
+
156
+ #
157
+ # html 5
158
+ #
159
+
160
+ execute_sql: [:post, 'session/:session_id/execute_sql'.freeze],
161
+
162
+ get_location: [:get, 'session/:session_id/location'.freeze],
163
+ set_location: [:post, 'session/:session_id/location'.freeze],
164
+
165
+ get_app_cache: [:get, 'session/:session_id/application_cache'.freeze],
166
+ get_app_cache_status: [:get, 'session/:session_id/application_cache/status'.freeze],
167
+ clear_app_cache: [:delete, 'session/:session_id/application_cache/clear'.freeze],
168
+
169
+ get_network_connection: [:get, 'session/:session_id/network_connection'.freeze],
170
+ set_network_connection: [:post, 'session/:session_id/network_connection'.freeze],
171
+
172
+ get_local_storage_item: [:get, 'session/:session_id/local_storage/key/:key'.freeze],
173
+ remove_local_storage_item: [:delete, 'session/:session_id/local_storage/key/:key'.freeze],
174
+ get_local_storage_keys: [:get, 'session/:session_id/local_storage'.freeze],
175
+ set_local_storage_item: [:post, 'session/:session_id/local_storage'.freeze],
176
+ clear_local_storage: [:delete, 'session/:session_id/local_storage'.freeze],
177
+ get_local_storage_size: [:get, 'session/:session_id/local_storage/size'.freeze],
178
+
179
+ get_session_storage_item: [:get, 'session/:session_id/session_storage/key/:key'.freeze],
180
+ remove_session_storage_item: [:delete, 'session/:session_id/session_storage/key/:key'.freeze],
181
+ get_session_storage_keys: [:get, 'session/:session_id/session_storage'.freeze],
182
+ set_session_storage_item: [:post, 'session/:session_id/session_storage'.freeze],
183
+ clear_session_storage: [:delete, 'session/:session_id/session_storage'.freeze],
184
+ get_session_storage_size: [:get, 'session/:session_id/session_storage/size'.freeze],
185
+
186
+ #
187
+ # ime
188
+ #
189
+
190
+ ime_get_available_engines: [:get, 'session/:session_id/ime/available_engines'.freeze],
191
+ ime_get_active_engine: [:get, 'session/:session_id/ime/active_engine'.freeze],
192
+ ime_is_activated: [:get, 'session/:session_id/ime/activated'.freeze],
193
+ ime_deactivate: [:post, 'session/:session_id/ime/deactivate'.freeze],
194
+ ime_activate_engine: [:post, 'session/:session_id/ime/activate'.freeze],
195
+
196
+ #
197
+ # touch
198
+ #
199
+
200
+ touch_single_tap: [:post, 'session/:session_id/touch/click'.freeze],
201
+ touch_double_tap: [:post, 'session/:session_id/touch/doubleclick'.freeze],
202
+ touch_long_press: [:post, 'session/:session_id/touch/longclick'.freeze],
203
+ touch_down: [:post, 'session/:session_id/touch/down'.freeze],
204
+ touch_up: [:post, 'session/:session_id/touch/up'.freeze],
205
+ touch_move: [:post, 'session/:session_id/touch/move'.freeze],
206
+ touch_scroll: [:post, 'session/:session_id/touch/scroll'.freeze],
207
+ touch_flick: [:post, 'session/:session_id/touch/flick'.freeze],
208
+
209
+ #
210
+ # logs
211
+ #
212
+
213
+ get_available_log_types: [:get, 'session/:session_id/log/types'.freeze],
214
+ get_log: [:post, 'session/:session_id/log'.freeze]
215
+ }.freeze
216
+
217
+ end # Bridge
218
+ end # OSS
219
+ end # Remote
220
+ end # WebDriver
221
+ end # Selenium
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
- #
3
1
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
2
  # or more contributor license agreements. See the NOTICE file
5
3
  # distributed with this work for additional information
@@ -20,9 +18,9 @@
20
18
  module Selenium
21
19
  module WebDriver
22
20
  module Remote
23
-
24
21
  # @api private
25
22
  class Response
23
+ STACKTRACE_KEY = 'stackTrace'.freeze
26
24
 
27
25
  attr_reader :code, :payload
28
26
  attr_writer :payload
@@ -49,9 +47,10 @@ module Selenium
49
47
 
50
48
  case val
51
49
  when Hash
52
- msg = val['message'] or return "unknown error"
53
- msg << ": #{val['alert']['text'].inspect}" if val['alert'].kind_of?(Hash) && val['alert']['text']
54
- msg << " (#{ val['class'] })" if val['class']
50
+ msg = val['message']
51
+ return 'unknown error' unless msg
52
+ msg << ": #{val['alert']['text'].inspect}" if val['alert'].is_a?(Hash) && val['alert']['text']
53
+ msg << " (#{val['class']})" if val['class']
55
54
  msg
56
55
  when String
57
56
  val
@@ -67,49 +66,62 @@ module Selenium
67
66
  private
68
67
 
69
68
  def assert_ok
70
- if e = error()
71
- raise e
72
- elsif @code.nil? || @code >= 400
73
- raise Error::ServerError, self
74
- end
69
+ e = error
70
+ raise e if e
71
+ return unless @code.nil? || @code >= 400
72
+ raise Error::ServerError, self
75
73
  end
76
74
 
77
75
  def add_backtrace(ex)
78
- unless value.kind_of?(Hash) && value['stackTrace']
79
- return
80
- end
76
+ return unless error_payload.is_a?(Hash)
81
77
 
82
- server_trace = value['stackTrace']
78
+ server_trace = error_payload[STACKTRACE_KEY] ||
79
+ error_payload[STACKTRACE_KEY.downcase] ||
80
+ error_payload['value'][STACKTRACE_KEY]
81
+ return unless server_trace
83
82
 
84
- backtrace = server_trace.map do |frame|
85
- next unless frame.kind_of?(Hash)
83
+ backtrace = case server_trace
84
+ when Array
85
+ backtrace_from_remote(server_trace)
86
+ when String
87
+ server_trace.split("\n")
88
+ end
89
+
90
+ ex.set_backtrace(backtrace + ex.backtrace)
91
+ end
92
+
93
+ def backtrace_from_remote(server_trace)
94
+ server_trace.map do |frame|
95
+ next unless frame.is_a?(Hash)
86
96
 
87
97
  file = frame['fileName']
88
98
  line = frame['lineNumber']
89
99
  meth = frame['methodName']
90
100
 
91
- if class_name = frame['className']
92
- file = "#{class_name}(#{file})"
93
- end
101
+ class_name = frame['className']
102
+ file = "#{class_name}(#{file})" if class_name
94
103
 
95
- if meth.nil? || meth.empty?
96
- meth = 'unknown'
97
- end
104
+ meth = 'unknown' if meth.nil? || meth.empty?
98
105
 
99
106
  "[remote server] #{file}:#{line}:in `#{meth}'"
100
107
  end.compact
108
+ end
101
109
 
102
- ex.set_backtrace(backtrace + ex.backtrace)
110
+ def error_payload
111
+ # Even errors are wrapped in 'value' for w3c
112
+ # Grab 'value' key for error, leave original payload alone and let the bridge process
113
+ @error_payload ||= !@payload.key?('sessionId') ? @payload['value'] : @payload
103
114
  end
104
115
 
105
116
  def status
106
- @payload['status'] || @payload['error']
117
+ return unless error_payload.is_a? Hash
118
+ @status ||= error_payload['status'] || error_payload['error']
107
119
  end
108
120
 
109
121
  def value
110
- @payload['value'] || @payload['message']
122
+ return unless error_payload.is_a? Hash
123
+ @value ||= error_payload['value'] || error_payload['message']
111
124
  end
112
-
113
125
  end # Response
114
126
  end # Remote
115
127
  end # WebDriver
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
- #
3
1
  # Licensed to the Software Freedom Conservancy (SFC) under one
4
2
  # or more contributor license agreements. See the NOTICE file
5
3
  # distributed with this work for additional information
@@ -21,15 +19,13 @@ module Selenium
21
19
  module WebDriver
22
20
  module Error
23
21
  class ServerError < StandardError
24
-
25
22
  def initialize(response)
26
- if response.kind_of? String
23
+ if response.is_a? String
27
24
  super(response)
28
25
  else
29
26
  super("status code #{response.code}")
30
27
  end
31
28
  end
32
-
33
29
  end # ServerError
34
30
  end # Error
35
31
  end # WebDriver
@@ -0,0 +1,573 @@
1
+ # Licensed to the Software Freedom Conservancy (SFC) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The SFC licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ require 'json'
19
+
20
+ module Selenium
21
+ module WebDriver
22
+ module Remote
23
+ module W3C
24
+
25
+ #
26
+ # Low level bridge to the remote server implementing JSON wire
27
+ # protocol (W3C dialect), through which the rest of the API works.
28
+ # @api private
29
+ #
30
+
31
+ class Bridge < Remote::Bridge
32
+
33
+ def initialize(capabilities, session_id, **opts)
34
+ @capabilities = capabilities
35
+ @session_id = session_id
36
+ super(opts)
37
+ end
38
+
39
+ def dialect
40
+ :w3c
41
+ end
42
+
43
+ def commands(command)
44
+ case command
45
+ when :status, :is_element_displayed
46
+ Remote::OSS::Bridge::COMMANDS[command]
47
+ else
48
+ COMMANDS[command]
49
+ end
50
+ end
51
+
52
+ def status
53
+ execute :status
54
+ end
55
+
56
+ def get(url)
57
+ execute :get, {}, {url: url}
58
+ end
59
+
60
+ def implicit_wait_timeout=(milliseconds)
61
+ timeout('implicit', milliseconds)
62
+ end
63
+
64
+ def script_timeout=(milliseconds)
65
+ timeout('script', milliseconds)
66
+ end
67
+
68
+ def timeout(type, milliseconds)
69
+ type = 'pageLoad' if type == 'page load'
70
+ execute :set_timeout, {}, {type => milliseconds}
71
+ end
72
+
73
+ #
74
+ # alerts
75
+ #
76
+
77
+ def accept_alert
78
+ execute :accept_alert
79
+ end
80
+
81
+ def dismiss_alert
82
+ execute :dismiss_alert
83
+ end
84
+
85
+ def alert=(keys)
86
+ execute :send_alert_text, {}, {value: keys.split(//), text: keys}
87
+ end
88
+
89
+ def alert_text
90
+ execute :get_alert_text
91
+ end
92
+
93
+ #
94
+ # navigation
95
+ #
96
+
97
+ def go_back
98
+ execute :back
99
+ end
100
+
101
+ def go_forward
102
+ execute :forward
103
+ end
104
+
105
+ def url
106
+ execute :get_current_url
107
+ end
108
+
109
+ def title
110
+ execute :get_title
111
+ end
112
+
113
+ def page_source
114
+ execute_script('var source = document.documentElement.outerHTML;' \
115
+ 'if (!source) { source = new XMLSerializer().serializeToString(document); }' \
116
+ 'return source;')
117
+ end
118
+
119
+ def switch_to_window(name)
120
+ execute :switch_to_window, {}, {handle: name}
121
+ end
122
+
123
+ def switch_to_frame(id)
124
+ id = find_element_by('id', id) if id.is_a? String
125
+ execute :switch_to_frame, {}, {id: id}
126
+ end
127
+
128
+ def switch_to_parent_frame
129
+ execute :switch_to_parent_frame
130
+ end
131
+
132
+ def switch_to_default_content
133
+ switch_to_frame nil
134
+ end
135
+
136
+ QUIT_ERRORS = [IOError].freeze
137
+
138
+ def quit
139
+ execute :delete_session
140
+ http.close
141
+ rescue *QUIT_ERRORS
142
+ end
143
+
144
+ def close
145
+ execute :close_window
146
+ end
147
+
148
+ def refresh
149
+ execute :refresh
150
+ end
151
+
152
+ #
153
+ # window handling
154
+ #
155
+
156
+ def window_handles
157
+ execute :get_window_handles
158
+ end
159
+
160
+ def window_handle
161
+ execute :get_window_handle
162
+ end
163
+
164
+ def resize_window(width, height, handle = :current)
165
+ unless handle == :current
166
+ raise Error::WebDriverError, 'Switch to desired window before changing its size'
167
+ end
168
+ set_window_rect(width: width, height: height)
169
+ end
170
+
171
+ def window_size(handle = :current)
172
+ unless handle == :current
173
+ raise Error::UnsupportedOperationError, 'Switch to desired window before getting its size'
174
+ end
175
+ data = execute :get_window_rect
176
+
177
+ Dimension.new data['width'], data['height']
178
+ end
179
+
180
+ def minimize_window
181
+ execute :minimize_window
182
+ end
183
+
184
+ def maximize_window(handle = :current)
185
+ unless handle == :current
186
+ raise Error::UnsupportedOperationError, 'Switch to desired window before changing its size'
187
+ end
188
+ execute :maximize_window
189
+ end
190
+
191
+ def full_screen_window
192
+ execute :fullscreen_window
193
+ end
194
+
195
+ def reposition_window(x, y)
196
+ set_window_rect(x: x, y: y)
197
+ end
198
+
199
+ def window_position
200
+ data = execute :get_window_rect
201
+ Point.new data['x'], data['y']
202
+ end
203
+
204
+ def set_window_rect(x: nil, y: nil, width: nil, height: nil)
205
+ params = {x: x, y: y, width: width, height: height}
206
+ params.update(params) { |k, v| Integer(v) unless v.nil? }
207
+ execute :set_window_rect, {}, params
208
+ end
209
+
210
+ def window_rect
211
+ data = execute :get_window_rect
212
+ Rectangle.new data['x'], data['y'], data['width'], data['height']
213
+ end
214
+
215
+ def screenshot
216
+ execute :take_screenshot
217
+ end
218
+
219
+ #
220
+ # HTML 5
221
+ #
222
+
223
+ def local_storage_item(key, value = nil)
224
+ if value
225
+ execute_script("localStorage.setItem('#{key}', '#{value}')")
226
+ else
227
+ execute_script("return localStorage.getItem('#{key}')")
228
+ end
229
+ end
230
+
231
+ def remove_local_storage_item(key)
232
+ execute_script("localStorage.removeItem('#{key}')")
233
+ end
234
+
235
+ def local_storage_keys
236
+ execute_script('return Object.keys(localStorage)')
237
+ end
238
+
239
+ def clear_local_storage
240
+ execute_script('localStorage.clear()')
241
+ end
242
+
243
+ def local_storage_size
244
+ execute_script('return localStorage.length')
245
+ end
246
+
247
+ def session_storage_item(key, value = nil)
248
+ if value
249
+ execute_script("sessionStorage.setItem('#{key}', '#{value}')")
250
+ else
251
+ execute_script("return sessionStorage.getItem('#{key}')")
252
+ end
253
+ end
254
+
255
+ def remove_session_storage_item(key)
256
+ execute_script("sessionStorage.removeItem('#{key}')")
257
+ end
258
+
259
+ def session_storage_keys
260
+ execute_script('return Object.keys(sessionStorage)')
261
+ end
262
+
263
+ def clear_session_storage
264
+ execute_script('sessionStorage.clear()')
265
+ end
266
+
267
+ def session_storage_size
268
+ execute_script('return sessionStorage.length')
269
+ end
270
+
271
+ def location
272
+ raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting location'
273
+ end
274
+
275
+ def set_location(_lat, _lon, _alt)
276
+ raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting location'
277
+ end
278
+
279
+ def network_connection
280
+ raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting network connection'
281
+ end
282
+
283
+ def network_connection=(_type)
284
+ raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting network connection'
285
+ end
286
+
287
+ #
288
+ # javascript execution
289
+ #
290
+
291
+ def execute_script(script, *args)
292
+ result = execute :execute_script, {}, {script: script, args: args}
293
+ unwrap_script_result result
294
+ end
295
+
296
+ def execute_async_script(script, *args)
297
+ result = execute :execute_async_script, {}, {script: script, args: args}
298
+ unwrap_script_result result
299
+ end
300
+
301
+ #
302
+ # cookies
303
+ #
304
+
305
+ def options
306
+ @options ||= WebDriver::W3COptions.new(self)
307
+ end
308
+
309
+ def add_cookie(cookie)
310
+ execute :add_cookie, {}, {cookie: cookie}
311
+ end
312
+
313
+ def delete_cookie(name)
314
+ execute :delete_cookie, name: name
315
+ end
316
+
317
+ def cookie(name)
318
+ execute :get_cookie, name: name
319
+ end
320
+
321
+ def cookies
322
+ execute :get_all_cookies
323
+ end
324
+
325
+ def delete_all_cookies
326
+ execute :delete_all_cookies
327
+ end
328
+
329
+ #
330
+ # actions
331
+ #
332
+
333
+ def action(async = false)
334
+ W3CActionBuilder.new self,
335
+ Interactions.pointer(:mouse, name: 'mouse'),
336
+ Interactions.key('keyboard'),
337
+ async
338
+ end
339
+ alias_method :actions, :action
340
+
341
+ def mouse
342
+ raise Error::UnsupportedOperationError, '#mouse is no longer supported, use #action instead'
343
+ end
344
+
345
+ def keyboard
346
+ raise Error::UnsupportedOperationError, '#keyboard is no longer supported, use #action instead'
347
+ end
348
+
349
+ def send_actions(data)
350
+ execute :actions, {}, {actions: data}
351
+ end
352
+
353
+ def release_actions
354
+ execute :release_actions
355
+ end
356
+
357
+ def click_element(element)
358
+ execute :element_click, id: element
359
+ end
360
+
361
+ # TODO: - Implement file verification
362
+ def send_keys_to_element(element, keys)
363
+ # Keep .split(//) for backward compatibility for now
364
+ text = keys.join('')
365
+ execute :element_send_keys, {id: element}, {value: text.split(//), text: text}
366
+ end
367
+
368
+ def clear_element(element)
369
+ execute :element_clear, id: element
370
+ end
371
+
372
+ def submit_element(element)
373
+ form = find_element_by('xpath', "./ancestor-or-self::form", element)
374
+ execute_script("var e = arguments[0].ownerDocument.createEvent('Event');" \
375
+ "e.initEvent('submit', true, true);" \
376
+ 'if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }', form.as_json)
377
+ end
378
+
379
+ def drag_element(element, right_by, down_by)
380
+ execute :drag_element, {id: element}, {x: right_by, y: down_by}
381
+ end
382
+
383
+ def touch_single_tap(element)
384
+ execute :touch_single_tap, {}, {element: element}
385
+ end
386
+
387
+ def touch_double_tap(element)
388
+ execute :touch_double_tap, {}, {element: element}
389
+ end
390
+
391
+ def touch_long_press(element)
392
+ execute :touch_long_press, {}, {element: element}
393
+ end
394
+
395
+ def touch_down(x, y)
396
+ execute :touch_down, {}, {x: x, y: y}
397
+ end
398
+
399
+ def touch_up(x, y)
400
+ execute :touch_up, {}, {x: x, y: y}
401
+ end
402
+
403
+ def touch_move(x, y)
404
+ execute :touch_move, {}, {x: x, y: y}
405
+ end
406
+
407
+ def touch_scroll(element, x, y)
408
+ if element
409
+ execute :touch_scroll, {}, {element: element,
410
+ xoffset: x,
411
+ yoffset: y}
412
+ else
413
+ execute :touch_scroll, {}, {xoffset: x, yoffset: y}
414
+ end
415
+ end
416
+
417
+ def touch_flick(xspeed, yspeed)
418
+ execute :touch_flick, {}, {xspeed: xspeed, yspeed: yspeed}
419
+ end
420
+
421
+ def touch_element_flick(element, right_by, down_by, speed)
422
+ execute :touch_flick, {}, {element: element,
423
+ xoffset: right_by,
424
+ yoffset: down_by,
425
+ speed: speed}
426
+ end
427
+
428
+ def screen_orientation=(orientation)
429
+ execute :set_screen_orientation, {}, {orientation: orientation}
430
+ end
431
+
432
+ def screen_orientation
433
+ execute :get_screen_orientation
434
+ end
435
+
436
+ #
437
+ # element properties
438
+ #
439
+
440
+ def element_tag_name(element)
441
+ execute :get_element_tag_name, id: element
442
+ end
443
+
444
+ def element_attribute(element, name)
445
+ execute_atom :getAttribute, element, name
446
+ end
447
+
448
+ def element_property(element, name)
449
+ execute :get_element_property, id: element.ref, name: name
450
+ end
451
+
452
+ def element_value(element)
453
+ element_property element, 'value'
454
+ end
455
+
456
+ def element_text(element)
457
+ execute :get_element_text, id: element
458
+ end
459
+
460
+ def element_location(element)
461
+ data = execute :get_element_rect, id: element
462
+
463
+ Point.new data['x'], data['y']
464
+ end
465
+
466
+ def element_rect(element)
467
+ data = execute :get_element_rect, id: element
468
+
469
+ Rectangle.new data['x'], data['y'], data['width'], data['height']
470
+ end
471
+
472
+ def element_location_once_scrolled_into_view(element)
473
+ send_keys_to_element(element, [''])
474
+ element_location(element)
475
+ end
476
+
477
+ def element_size(element)
478
+ data = execute :get_element_rect, id: element
479
+
480
+ Dimension.new data['width'], data['height']
481
+ end
482
+
483
+ def element_enabled?(element)
484
+ execute :is_element_enabled, id: element
485
+ end
486
+
487
+ def element_selected?(element)
488
+ execute :is_element_selected, id: element
489
+ end
490
+
491
+ def element_displayed?(element)
492
+ execute :is_element_displayed, id: element
493
+ end
494
+
495
+ def element_value_of_css_property(element, prop)
496
+ execute :get_element_css_value, id: element, property_name: prop
497
+ end
498
+
499
+ #
500
+ # finding elements
501
+ #
502
+
503
+ def active_element
504
+ Element.new self, element_id_from(execute(:get_active_element))
505
+ end
506
+
507
+ alias_method :switch_to_active_element, :active_element
508
+
509
+ def find_element_by(how, what, parent = nil)
510
+ how, what = convert_locators(how, what)
511
+
512
+ id = if parent
513
+ execute :find_child_element, {id: parent}, {using: how, value: what}
514
+ else
515
+ execute :find_element, {}, {using: how, value: what}
516
+ end
517
+ Element.new self, element_id_from(id)
518
+ end
519
+
520
+ def find_elements_by(how, what, parent = nil)
521
+ how, what = convert_locators(how, what)
522
+
523
+ ids = if parent
524
+ execute :find_child_elements, {id: parent}, {using: how, value: what}
525
+ else
526
+ execute :find_elements, {}, {using: how, value: what}
527
+ end
528
+
529
+ ids.map { |id| Element.new self, element_id_from(id) }
530
+ end
531
+
532
+ private
533
+
534
+ def execute(*)
535
+ super['value']
536
+ end
537
+
538
+ def convert_locators(how, what)
539
+ case how
540
+ when 'class name'
541
+ how = 'css selector'
542
+ what = ".#{escape_css(what)}"
543
+ when 'id'
544
+ how = 'css selector'
545
+ what = "##{escape_css(what)}"
546
+ when 'name'
547
+ how = 'css selector'
548
+ what = "*[name='#{escape_css(what)}']"
549
+ when 'tag name'
550
+ how = 'css selector'
551
+ end
552
+ [how, what]
553
+ end
554
+
555
+ ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]\(\)])/
556
+ UNICODE_CODE_POINT = 30
557
+
558
+ # Escapes invalid characters in CSS selector.
559
+ # @see https://mathiasbynens.be/notes/css-escapes
560
+ def escape_css(string)
561
+ string = string.gsub(ESCAPE_CSS_REGEXP) { |match| "\\#{match}" }
562
+ if !string.empty? && string[0] =~ /[[:digit:]]/
563
+ string = "\\#{UNICODE_CODE_POINT + Integer(string[0])} #{string[1..-1]}"
564
+ end
565
+
566
+ string
567
+ end
568
+
569
+ end # Bridge
570
+ end # W3C
571
+ end # Remote
572
+ end # WebDriver
573
+ end # Selenium