selenium-webdriver 3.142.7 → 4.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +685 -5
  3. data/Gemfile +6 -1
  4. data/LICENSE +1 -1
  5. data/NOTICE +2 -0
  6. data/README.md +4 -5
  7. data/bin/linux/selenium-manager +0 -0
  8. data/bin/macos/selenium-manager +0 -0
  9. data/bin/windows/selenium-manager.exe +0 -0
  10. data/lib/selenium/server.rb +93 -90
  11. data/lib/selenium/webdriver/atoms/findElements.js +122 -0
  12. data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
  13. data/lib/selenium/webdriver/atoms/isDisplayed.js +77 -78
  14. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  15. data/lib/selenium/webdriver/atoms.rb +5 -3
  16. data/lib/selenium/webdriver/bidi/browsing_context.rb +88 -0
  17. data/lib/selenium/webdriver/bidi/browsing_context_info.rb +35 -0
  18. data/lib/selenium/webdriver/bidi/log/base_log_entry.rb +35 -0
  19. data/lib/selenium/webdriver/bidi/log/console_log_entry.rb +35 -0
  20. data/lib/selenium/webdriver/bidi/log/filter_by.rb +40 -0
  21. data/lib/selenium/webdriver/bidi/log/generic_log_entry.rb +33 -0
  22. data/lib/selenium/webdriver/bidi/log/javascript_log_entry.rb +33 -0
  23. data/lib/selenium/webdriver/bidi/log_inspector.rb +143 -0
  24. data/lib/selenium/webdriver/bidi/navigate_result.rb +33 -0
  25. data/lib/selenium/webdriver/bidi/session.rb +51 -0
  26. data/lib/selenium/webdriver/{common/keyboard.rb → bidi.rb} +21 -35
  27. data/lib/selenium/webdriver/chrome/driver.rb +9 -86
  28. data/lib/selenium/webdriver/chrome/features.rb +48 -0
  29. data/lib/selenium/webdriver/chrome/options.rb +9 -158
  30. data/lib/selenium/webdriver/chrome/profile.rb +3 -80
  31. data/lib/selenium/webdriver/chrome/service.rb +7 -29
  32. data/lib/selenium/webdriver/chrome.rb +5 -20
  33. data/lib/selenium/webdriver/chromium/driver.rb +60 -0
  34. data/lib/selenium/webdriver/{chrome/bridge.rb → chromium/features.rb} +48 -17
  35. data/lib/selenium/webdriver/chromium/options.rb +243 -0
  36. data/lib/selenium/webdriver/chromium/profile.rb +113 -0
  37. data/lib/selenium/webdriver/chromium.rb +29 -0
  38. data/lib/selenium/webdriver/common/action_builder.rb +126 -238
  39. data/lib/selenium/webdriver/common/child_process.rb +124 -0
  40. data/lib/selenium/webdriver/common/driver.rb +82 -43
  41. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
  42. data/lib/selenium/webdriver/common/driver_extensions/{has_location.rb → full_page_screenshot.rb} +13 -11
  43. data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +0 -2
  44. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +49 -0
  45. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +87 -0
  46. data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_bidi.rb} +9 -9
  47. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +86 -0
  48. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +36 -0
  49. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +42 -0
  50. data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
  51. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +41 -0
  52. data/lib/selenium/webdriver/common/driver_extensions/has_file_downloads.rb +65 -0
  53. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +36 -0
  54. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +143 -0
  55. data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_logs.rb} +4 -4
  56. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +16 -1
  57. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +69 -0
  58. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -13
  59. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +75 -0
  60. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  61. data/lib/selenium/webdriver/common/driver_finder.rb +45 -0
  62. data/lib/selenium/webdriver/common/element.rb +89 -29
  63. data/lib/selenium/webdriver/common/error.rb +53 -194
  64. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
  65. data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
  66. data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -22
  67. data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
  68. data/lib/selenium/webdriver/common/interactions/key_actions.rb +10 -6
  69. data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
  70. data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
  71. data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
  72. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +71 -82
  73. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
  74. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
  75. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
  76. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
  77. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
  78. data/lib/selenium/webdriver/common/interactions/scroll.rb +59 -0
  79. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
  80. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
  81. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
  82. data/lib/selenium/webdriver/common/{w3c_manager.rb → interactions/wheel_input.rb} +14 -17
  83. data/lib/selenium/webdriver/common/keys.rb +1 -0
  84. data/lib/selenium/webdriver/common/local_driver.rb +46 -0
  85. data/lib/selenium/webdriver/common/log_entry.rb +2 -2
  86. data/lib/selenium/webdriver/common/logger.rb +119 -19
  87. data/lib/selenium/webdriver/common/manager.rb +11 -38
  88. data/lib/selenium/webdriver/common/options.rb +154 -23
  89. data/lib/selenium/webdriver/common/platform.rb +15 -52
  90. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  91. data/lib/selenium/webdriver/common/profile_helper.rb +11 -9
  92. data/lib/selenium/webdriver/common/proxy.rb +8 -5
  93. data/lib/selenium/webdriver/common/search_context.rb +7 -9
  94. data/lib/selenium/webdriver/common/selenium_manager.rb +140 -0
  95. data/lib/selenium/webdriver/common/service.rb +26 -143
  96. data/lib/selenium/webdriver/common/service_manager.rb +144 -0
  97. data/lib/selenium/webdriver/common/shadow_root.rb +86 -0
  98. data/lib/selenium/webdriver/common/socket_lock.rb +4 -4
  99. data/lib/selenium/webdriver/common/socket_poller.rb +4 -4
  100. data/lib/selenium/webdriver/common/takes_screenshot.rb +65 -0
  101. data/lib/selenium/webdriver/common/target_locator.rb +31 -4
  102. data/lib/selenium/webdriver/common/timeouts.rb +31 -4
  103. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +85 -0
  104. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +72 -0
  105. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
  106. data/lib/selenium/webdriver/common/wait.rb +1 -1
  107. data/lib/selenium/webdriver/common/websocket_connection.rb +164 -0
  108. data/lib/selenium/webdriver/common/window.rb +6 -10
  109. data/lib/selenium/webdriver/common/zipper.rb +4 -10
  110. data/lib/selenium/webdriver/common.rb +43 -20
  111. data/lib/selenium/webdriver/devtools/console_event.rb +36 -0
  112. data/lib/selenium/webdriver/devtools/exception_event.rb +34 -0
  113. data/lib/selenium/webdriver/devtools/mutation_event.rb +35 -0
  114. data/lib/selenium/webdriver/devtools/network_interceptor.rb +173 -0
  115. data/lib/selenium/webdriver/devtools/pinned_script.rb +57 -0
  116. data/lib/selenium/webdriver/devtools/request.rb +65 -0
  117. data/lib/selenium/webdriver/devtools/response.rb +64 -0
  118. data/lib/selenium/webdriver/devtools.rb +96 -0
  119. data/lib/selenium/webdriver/edge/driver.rb +11 -27
  120. data/lib/selenium/webdriver/edge/features.rb +48 -0
  121. data/lib/selenium/webdriver/edge/options.rb +18 -43
  122. data/lib/selenium/webdriver/edge/profile.rb +33 -0
  123. data/lib/selenium/webdriver/edge/service.rb +8 -23
  124. data/lib/selenium/webdriver/edge.rb +11 -16
  125. data/lib/selenium/webdriver/firefox/driver.rb +38 -19
  126. data/lib/selenium/webdriver/firefox/extension.rb +8 -0
  127. data/lib/selenium/webdriver/firefox/features.rb +70 -0
  128. data/lib/selenium/webdriver/firefox/options.rb +73 -61
  129. data/lib/selenium/webdriver/firefox/profile.rb +20 -72
  130. data/lib/selenium/webdriver/firefox/service.rb +3 -25
  131. data/lib/selenium/webdriver/firefox/util.rb +1 -1
  132. data/lib/selenium/webdriver/firefox.rb +17 -28
  133. data/lib/selenium/webdriver/ie/driver.rb +5 -45
  134. data/lib/selenium/webdriver/ie/features.rb +34 -0
  135. data/lib/selenium/webdriver/ie/options.rb +14 -44
  136. data/lib/selenium/webdriver/ie/service.rb +3 -27
  137. data/lib/selenium/webdriver/ie.rb +4 -16
  138. data/lib/selenium/webdriver/remote/bridge/commands.rb +164 -0
  139. data/lib/selenium/webdriver/remote/bridge.rb +574 -88
  140. data/lib/selenium/webdriver/remote/capabilities.rb +144 -158
  141. data/lib/selenium/webdriver/remote/driver.rb +45 -14
  142. data/lib/selenium/webdriver/remote/features.rb +75 -0
  143. data/lib/selenium/webdriver/remote/http/common.rb +3 -8
  144. data/lib/selenium/webdriver/remote/http/curb.rb +1 -3
  145. data/lib/selenium/webdriver/remote/http/default.rb +24 -33
  146. data/lib/selenium/webdriver/remote/response.rb +17 -49
  147. data/lib/selenium/webdriver/remote/server_error.rb +1 -1
  148. data/lib/selenium/webdriver/remote.rb +15 -12
  149. data/lib/selenium/webdriver/safari/driver.rb +7 -29
  150. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +7 -5
  151. data/lib/selenium/webdriver/safari/options.rb +12 -27
  152. data/lib/selenium/webdriver/safari/service.rb +13 -11
  153. data/lib/selenium/webdriver/safari.rb +14 -20
  154. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  155. data/lib/selenium/webdriver/support/color.rb +24 -24
  156. data/lib/selenium/webdriver/support/event_firing_bridge.rb +5 -5
  157. data/lib/selenium/webdriver/support/guards/guard.rb +90 -0
  158. data/lib/selenium/webdriver/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +21 -20
  159. data/lib/selenium/webdriver/support/guards.rb +95 -0
  160. data/lib/selenium/webdriver/support/relative_locator.rb +50 -0
  161. data/lib/selenium/webdriver/support/select.rb +6 -4
  162. data/lib/selenium/webdriver/support.rb +1 -0
  163. data/lib/selenium/webdriver/version.rb +1 -1
  164. data/lib/selenium/webdriver.rb +19 -17
  165. data/selenium-webdriver.gemspec +36 -18
  166. metadata +161 -91
  167. data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
  168. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +0 -58
  169. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
  170. data/lib/selenium/webdriver/common/mouse.rb +0 -89
  171. data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
  172. data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
  173. data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
  174. data/lib/selenium/webdriver/edge/bridge.rb +0 -76
  175. data/lib/selenium/webdriver/firefox/binary.rb +0 -187
  176. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
  177. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  178. data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
  179. data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
  180. data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
  181. data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
  182. data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
  183. data/lib/selenium/webdriver/remote/http/persistent.rb +0 -60
  184. data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
  185. data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
  186. data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
  187. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
  188. data/lib/selenium/webdriver/remote/w3c/commands.rb +0 -157
@@ -24,130 +24,46 @@ module Selenium
24
24
  # Specification of the desired and/or actual capabilities of the browser that the
25
25
  # server is being asked to create.
26
26
  #
27
+
27
28
  class Capabilities
28
- DEFAULTS = {
29
- browser_name: '',
30
- version: '',
31
- platform: :any,
32
- javascript_enabled: false,
33
- css_selectors_enabled: false,
34
- takes_screenshot: false,
35
- native_events: false,
36
- rotatable: false,
37
- firefox_profile: nil,
38
- proxy: nil
39
- }.freeze
40
-
41
- DEFAULTS.each_key do |key|
42
- if key != :javascript_enabled
43
- define_method key do
44
- @capabilities.fetch(key)
45
- end
29
+ KNOWN = [
30
+ :browser_name,
31
+ :browser_version,
32
+ :platform_name,
33
+ :accept_insecure_certs,
34
+ :page_load_strategy,
35
+ :proxy,
36
+ :set_window_rect,
37
+ :timeouts,
38
+ :unhandled_prompt_behavior,
39
+ :strict_file_interactability,
40
+ :web_socket_url,
41
+
42
+ # remote-specific (webdriver.remote.sessionid)
43
+ :remote_session_id
44
+ ].freeze
45
+
46
+ (KNOWN - %i[proxy timeouts]).each do |key|
47
+ define_method key do
48
+ @capabilities[key]
46
49
  end
47
50
 
48
- next if key == :proxy
49
-
50
51
  define_method "#{key}=" do |value|
51
52
  @capabilities[key] = value
52
53
  end
53
54
  end
54
55
 
55
- #
56
- # Returns javascript_enabled capability.
57
- # It is true if not set explicitly.
58
- #
59
- def javascript_enabled
60
- javascript_enabled = @capabilities.fetch(:javascript_enabled)
61
- javascript_enabled.nil? ? true : javascript_enabled
62
- end
63
-
64
- alias_method :css_selectors_enabled?, :css_selectors_enabled
65
- alias_method :javascript_enabled?, :javascript_enabled
66
- alias_method :native_events?, :native_events
67
- alias_method :takes_screenshot?, :takes_screenshot
68
- alias_method :rotatable?, :rotatable
69
-
70
56
  #
71
57
  # Convenience methods for the common choices.
72
58
  #
73
59
 
74
60
  class << self
75
- def chrome(opts = {})
76
- new({
77
- browser_name: 'chrome',
78
- javascript_enabled: true,
79
- css_selectors_enabled: true
80
- }.merge(opts))
81
- end
82
-
83
- def edge(opts = {})
84
- new({
85
- browser_name: 'MicrosoftEdge',
86
- platform: :windows
87
- }.merge(opts))
88
- end
89
-
90
- def firefox(opts = {})
91
- opts[:browser_version] = opts.delete(:version) if opts.key?(:version)
92
- opts[:platform_name] = opts.delete(:platform) if opts.key?(:platform)
93
- opts[:timeouts] = {}
94
- opts[:timeouts]['implicit'] = opts.delete(:implicit_timeout) if opts.key?(:implicit_timeout)
95
- opts[:timeouts]['pageLoad'] = opts.delete(:page_load_timeout) if opts.key?(:page_load_timeout)
96
- opts[:timeouts]['script'] = opts.delete(:script_timeout) if opts.key?(:script_timeout)
97
- new({browser_name: 'firefox', marionette: true}.merge(opts))
98
- end
99
-
100
- def firefox_legacy(opts = {})
101
- new({
102
- browser_name: 'firefox',
103
- javascript_enabled: true,
104
- takes_screenshot: true,
105
- css_selectors_enabled: true
106
- }.merge(opts))
107
- end
108
-
109
- def htmlunit(opts = {})
110
- new({
111
- browser_name: 'htmlunit'
112
- }.merge(opts))
113
- end
114
-
115
- def htmlunitwithjs(opts = {})
116
- new({
117
- browser_name: 'htmlunit',
118
- javascript_enabled: true
119
- }.merge(opts))
61
+ def always_match(capabilities)
62
+ new(always_match: capabilities)
120
63
  end
121
64
 
122
- def internet_explorer(opts = {})
123
- new({
124
- browser_name: 'internet explorer',
125
- platform: :windows,
126
- takes_screenshot: true,
127
- css_selectors_enabled: true,
128
- native_events: true
129
- }.merge(opts))
130
- end
131
- alias_method :ie, :internet_explorer
132
-
133
- def phantomjs(opts = {})
134
- WebDriver.logger.deprecate 'Selenium support for PhantomJS', 'headless Chrome/Firefox or HTMLUnit'
135
- new({
136
- browser_name: 'phantomjs',
137
- javascript_enabled: true,
138
- takes_screenshot: true,
139
- css_selectors_enabled: true
140
- }.merge(opts))
141
- end
142
-
143
- def safari(opts = {})
144
- new({
145
- browser_name: 'safari',
146
- platform: :mac,
147
- javascript_enabled: true,
148
- takes_screenshot: true,
149
- css_selectors_enabled: true
150
- }.merge(opts))
65
+ def first_match(*capabilities)
66
+ new(first_match: capabilities)
151
67
  end
152
68
 
153
69
  #
@@ -156,41 +72,62 @@ module Selenium
156
72
 
157
73
  def json_create(data)
158
74
  data = data.dup
159
-
160
75
  caps = new
161
- caps.browser_name = data.delete('browserName')
162
- caps.version = data.delete('version')
163
- caps.platform = data.delete('platform').downcase.tr(' ', '_').to_sym if data.key?('platform')
164
- caps.javascript_enabled = data.delete('javascriptEnabled')
165
- caps.css_selectors_enabled = data.delete('cssSelectorsEnabled')
166
- caps.takes_screenshot = data.delete('takesScreenshot')
167
- caps.native_events = data.delete('nativeEvents')
168
- caps.rotatable = data.delete('rotatable')
169
- caps.proxy = Proxy.json_create(data['proxy']) if data.key?('proxy') && !data['proxy'].empty?
76
+
77
+ process_timeouts(caps, data.delete('timeouts'))
78
+
79
+ if data.key?('proxy')
80
+ proxy = data.delete('proxy')
81
+ caps.proxy = Proxy.json_create(proxy) unless proxy.nil? || proxy.empty?
82
+ end
83
+
84
+ # Remote Server Specific
85
+ if data.key?('webdriver.remote.sessionid')
86
+ caps[:remote_session_id] =
87
+ data.delete('webdriver.remote.sessionid')
88
+ end
89
+
90
+ KNOWN.each do |cap|
91
+ data_value = camel_case(cap)
92
+ caps[cap] = data.delete(data_value) if data.key?(data_value)
93
+ end
170
94
 
171
95
  # any remaining pairs will be added as is, with no conversion
172
96
  caps.merge!(data)
173
97
 
174
98
  caps
175
99
  end
100
+
101
+ def camel_case(str_or_sym)
102
+ str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
103
+ end
104
+
105
+ private
106
+
107
+ def process_timeouts(caps, timeouts)
108
+ return if timeouts.nil?
109
+
110
+ caps.implicit_timeout = timeouts['implicit']
111
+ caps.page_load_timeout = timeouts['pageLoad']
112
+ caps.script_timeout = timeouts['script']
113
+ end
176
114
  end
177
115
 
178
116
  #
179
- # @option :browser_name [String] required browser name
180
- # @option :version [String] required browser version number
181
- # @option :platform [Symbol] one of :any, :win, :mac, or :x
182
- # @option :javascript_enabled [Boolean] does the driver have javascript enabled?
183
- # @option :css_selectors_enabled [Boolean] does the driver support CSS selectors?
184
- # @option :takes_screenshot [Boolean] can this driver take screenshots?
185
- # @option :native_events [Boolean] does this driver use native events?
186
- # @option :proxy [Selenium::WebDriver::Proxy, Hash] proxy configuration
117
+ # @param [Hash] opts
118
+ # @option :browser_name [String] required browser name
119
+ # @option :browser_version [String] required browser version number
120
+ # @option :platform_name [Symbol] one of :any, :win, :mac, or :x
121
+ # @option :accept_insecure_certs [Boolean] does the driver accept insecure SSL certifications?
122
+ # @option :proxy [Selenium::WebDriver::Proxy, Hash] proxy configuration
187
123
  #
188
124
  # @api public
189
125
  #
190
126
 
191
127
  def initialize(opts = {})
192
- @capabilities = DEFAULTS.merge(opts)
193
- self.proxy = opts.delete(:proxy)
128
+ @capabilities = {}
129
+ self.proxy = opts.delete(:proxy) if opts[:proxy]
130
+ @capabilities.merge!(opts)
194
131
  end
195
132
 
196
133
  #
@@ -215,6 +152,10 @@ module Selenium
215
152
  end
216
153
  end
217
154
 
155
+ def proxy
156
+ @capabilities[:proxy]
157
+ end
158
+
218
159
  def proxy=(proxy)
219
160
  case proxy
220
161
  when Hash
@@ -226,37 +167,46 @@ module Selenium
226
167
  end
227
168
  end
228
169
 
170
+ def timeouts
171
+ @capabilities[:timeouts] ||= {}
172
+ end
173
+
174
+ def timeouts=(timeouts)
175
+ @capabilities[:timeouts] = timeouts
176
+ end
177
+
178
+ def implicit_timeout
179
+ timeouts[:implicit]
180
+ end
181
+
182
+ def implicit_timeout=(timeout)
183
+ timeouts[:implicit] = timeout
184
+ end
185
+
186
+ def page_load_timeout
187
+ timeouts[:page_load] || timeouts[:pageLoad]
188
+ end
189
+
190
+ def page_load_timeout=(timeout)
191
+ timeouts[:page_load] = timeout
192
+ end
193
+
194
+ def script_timeout
195
+ timeouts[:script]
196
+ end
197
+
198
+ def script_timeout=(timeout)
199
+ timeouts[:script] = timeout
200
+ end
201
+
229
202
  #
230
203
  # @api private
231
204
  #
232
205
 
233
- def as_json(*) # rubocop:disable Metrics/CyclomaticComplexity
234
- hash = {}
235
-
236
- @capabilities.each do |key, value|
237
- case key
238
- when :platform
239
- hash['platform'] = value.to_s.upcase
240
- when :firefox_profile
241
- if value
242
- WebDriver.logger.deprecate(':firefox_profile capabilitiy', 'Selenium::WebDriver::Firefox::Options#profile')
243
- hash['firefox_profile'] = value.as_json['zip']
244
- end
245
- when :proxy
246
- hash['proxy'] = value.as_json if value
247
- when String, :firefox_binary
248
- if key == :firefox_binary && value
249
- WebDriver.logger.deprecate(':firefox_binary capabilitiy', 'Selenium::WebDriver::Firefox::Options#binary')
250
- end
251
- hash[key.to_s] = value
252
- when Symbol
253
- hash[camel_case(key.to_s)] = value
254
- else
255
- raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class} / #{value.inspect}"
256
- end
206
+ def as_json(*)
207
+ @capabilities.each_with_object({}) do |(key, value), hash|
208
+ hash[convert_key(key)] = process_capabilities(key, value, hash)
257
209
  end
258
-
259
- hash
260
210
  end
261
211
 
262
212
  def to_json(*)
@@ -268,7 +218,8 @@ module Selenium
268
218
 
269
219
  as_json == other.as_json
270
220
  end
271
- alias_method :eql?, :==
221
+
222
+ alias eql? ==
272
223
 
273
224
  protected
274
225
 
@@ -276,8 +227,43 @@ module Selenium
276
227
 
277
228
  private
278
229
 
279
- def camel_case(str)
280
- str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
230
+ def process_capabilities(key, value, hash)
231
+ case value
232
+ when Array
233
+ value.map { |v| process_capabilities(key, v, hash) }
234
+ when Hash
235
+ value.each_with_object({}) do |(k, v), h|
236
+ h[convert_key(k)] = process_capabilities(k, v, h)
237
+ end
238
+ when Capabilities, Options
239
+ value.as_json
240
+ else
241
+ convert_value(key, value)
242
+ end
243
+ end
244
+
245
+ def convert_key(key)
246
+ case key
247
+ when String
248
+ key.to_s
249
+ when Symbol
250
+ self.class.camel_case(key)
251
+ else
252
+ raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}"
253
+ end
254
+ end
255
+
256
+ def convert_value(key, value)
257
+ case key
258
+ when :platform
259
+ value.to_s.upcase
260
+ when :proxy
261
+ value&.as_json
262
+ when :unhandled_prompt_behavior
263
+ value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value
264
+ else
265
+ value
266
+ end
281
267
  end
282
268
  end # Capabilities
283
269
  end # Remote
@@ -20,7 +20,6 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Remote
23
-
24
23
  #
25
24
  # Driver implementation for remote server.
26
25
  # @api private
@@ -28,23 +27,55 @@ module Selenium
28
27
 
29
28
  class Driver < WebDriver::Driver
30
29
  include DriverExtensions::UploadsFiles
31
- include DriverExtensions::TakesScreenshot
32
30
  include DriverExtensions::HasSessionId
33
- include DriverExtensions::Rotatable
34
- include DriverExtensions::HasRemoteStatus
35
- include DriverExtensions::HasWebStorage
36
-
37
- def initialize(opts = {})
38
- listener = opts.delete(:listener)
39
- @bridge = Bridge.handshake(opts)
40
- if @bridge.dialect == :oss
41
- extend DriverExtensions::HasTouchScreen
42
- extend DriverExtensions::HasLocation
43
- extend DriverExtensions::HasNetworkConnection
31
+ include DriverExtensions::HasFileDownloads
32
+
33
+ def initialize(capabilities: nil, options: nil, service: nil, url: nil, **opts)
34
+ raise ArgumentError, "Can not set :service object on #{self.class}" if service
35
+
36
+ url ||= "http://#{Platform.localhost}:4444/wd/hub"
37
+ caps = process_options(options, capabilities)
38
+ super(caps: caps, url: url, **opts)
39
+ @bridge.file_detector = ->((filename, *)) { File.exist?(filename) && filename.to_s }
40
+ command_list = @bridge.command_list
41
+ @bridge.extend(WebDriver::Remote::Features)
42
+ @bridge.add_commands(command_list)
43
+ end
44
+
45
+ private
46
+
47
+ def devtools_url
48
+ capabilities['se:cdp']
49
+ end
50
+
51
+ def devtools_version
52
+ cdp_version = capabilities['se:cdpVersion']&.split('.')&.first
53
+ raise Error::WebDriverError, 'DevTools is not supported by the Remote Server' unless cdp_version
54
+
55
+ Integer(cdp_version)
56
+ end
57
+
58
+ def process_options(options, capabilities)
59
+ if options && capabilities
60
+ msg = "Don't use both :options and :capabilities when initializing #{self.class}, prefer :options"
61
+ raise ArgumentError, msg
62
+ elsif options.nil? && capabilities.nil?
63
+ raise ArgumentError, "#{self.class} needs :options to be set"
44
64
  end
45
- super(@bridge, listener: listener)
65
+ options ? options.as_json : generate_capabilities(capabilities)
46
66
  end
47
67
 
68
+ def generate_capabilities(capabilities)
69
+ Array(capabilities).map { |cap|
70
+ if cap.is_a? Symbol
71
+ cap = WebDriver::Options.send(cap)
72
+ elsif !cap.respond_to? :as_json
73
+ msg = ":capabilities parameter only accepts objects responding to #as_json which #{cap.class} does not"
74
+ raise ArgumentError, msg
75
+ end
76
+ cap.as_json
77
+ }.inject(:merge)
78
+ end
48
79
  end # Driver
49
80
  end # Remote
50
81
  end # WebDriver
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Licensed to the Software Freedom Conservancy (SFC) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The SFC licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+
20
+ module Selenium
21
+ module WebDriver
22
+ module Remote
23
+ module Features
24
+ REMOTE_COMMANDS = {
25
+ upload_file: [:post, 'session/:session_id/se/file'],
26
+ get_downloadable_files: [:get, 'session/:session_id/se/files'],
27
+ download_file: [:post, 'session/:session_id/se/files'],
28
+ delete_downloadable_files: [:delete, 'session/:session_id/se/files']
29
+ }.freeze
30
+
31
+ def add_commands(commands)
32
+ @command_list = command_list.merge(commands)
33
+ end
34
+
35
+ def command_list
36
+ @command_list ||= REMOTE_COMMANDS
37
+ end
38
+
39
+ def commands(command)
40
+ command_list[command]
41
+ end
42
+
43
+ def upload(local_file)
44
+ unless File.file?(local_file)
45
+ WebDriver.logger.error("File detector only works with files. #{local_file.inspect} isn`t a file!",
46
+ id: :file_detector)
47
+ raise Error::WebDriverError, "You are trying to upload something that isn't a file."
48
+ end
49
+
50
+ execute :upload_file, {}, {file: Zipper.zip_file(local_file)}
51
+ end
52
+
53
+ def upload_if_necessary(keys)
54
+ local_files = keys.first&.split("\n")&.map { |key| @file_detector.call(Array(key)) }&.compact
55
+ return keys unless local_files&.any?
56
+
57
+ keys = local_files.map { |local_file| upload(local_file) }
58
+ Array(keys.join("\n"))
59
+ end
60
+
61
+ def downloadable_files
62
+ execute :get_downloadable_files
63
+ end
64
+
65
+ def download_file(name)
66
+ execute :download_file, {}, {name: name}
67
+ end
68
+
69
+ def delete_downloadable_files
70
+ execute :delete_downloadable_files
71
+ end
72
+ end
73
+ end # Remote
74
+ end # WebDriver
75
+ end # Selenium
@@ -30,13 +30,8 @@ module Selenium
30
30
  'User-Agent' => "selenium/#{WebDriver::VERSION} (ruby #{Platform.os})"
31
31
  }.freeze
32
32
 
33
- attr_accessor :timeout
34
33
  attr_writer :server_url
35
34
 
36
- def initialize
37
- @timeout = nil
38
- end
39
-
40
35
  def quit_errors
41
36
  [IOError]
42
37
  end
@@ -54,8 +49,8 @@ module Selenium
54
49
  payload = JSON.generate(command_hash)
55
50
  headers['Content-Length'] = payload.bytesize.to_s if %i[post put].include?(verb)
56
51
 
57
- WebDriver.logger.info(" >>> #{url} | #{payload}")
58
- WebDriver.logger.debug(" > #{headers.inspect}")
52
+ WebDriver.logger.debug(" >>> #{url} | #{payload}", id: :command)
53
+ WebDriver.logger.debug(" > #{headers.inspect}", id: :header)
59
54
  elsif verb == :post
60
55
  payload = '{}'
61
56
  headers['Content-Length'] = '2'
@@ -80,7 +75,7 @@ module Selenium
80
75
  code = code.to_i
81
76
  body = body.to_s.strip
82
77
  content_type = content_type.to_s
83
- WebDriver.logger.info("<- #{body}")
78
+ WebDriver.logger.debug("<- #{body}", id: :command)
84
79
 
85
80
  if content_type.include? CONTENT_TYPE
86
81
  raise Error::WebDriverError, "empty body: #{content_type.inspect} (#{code})\n#{body}" if body.empty?
@@ -22,7 +22,6 @@ require 'curb'
22
22
  module Selenium
23
23
  module WebDriver
24
24
  module Remote
25
-
26
25
  module Http
27
26
  #
28
27
  # An alternative to the default Net::HTTP client.
@@ -38,7 +37,6 @@ module Selenium
38
37
  #
39
38
 
40
39
  class Curb < Common
41
-
42
40
  def quit_errors
43
41
  [Curl::Err::RecvError] + super
44
42
  end
@@ -85,7 +83,7 @@ module Selenium
85
83
  c.max_redirects = MAX_REDIRECTS
86
84
  c.follow_location = true
87
85
  c.timeout = @timeout if @timeout
88
- c.verbose = WebDriver.logger.info?
86
+ c.verbose = WebDriver.logger.debug?
89
87
 
90
88
  c
91
89
  end