selenium-webdriver 3.142.7 → 4.10.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 (186) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +611 -5
  3. data/Gemfile +5 -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 +94 -79
  11. data/lib/selenium/webdriver/atoms/findElements.js +121 -0
  12. data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
  13. data/lib/selenium/webdriver/atoms/isDisplayed.js +76 -78
  14. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  15. data/lib/selenium/webdriver/atoms.rb +2 -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 +44 -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 +6 -33
  32. data/lib/selenium/webdriver/chrome.rb +5 -18
  33. data/lib/selenium/webdriver/chromium/driver.rb +61 -0
  34. data/lib/selenium/webdriver/{chrome/bridge.rb → chromium/features.rb} +51 -16
  35. data/lib/selenium/webdriver/chromium/options.rb +261 -0
  36. data/lib/selenium/webdriver/chromium/profile.rb +113 -0
  37. data/lib/selenium/webdriver/chromium/service.rb +42 -0
  38. data/lib/selenium/webdriver/chromium.rb +32 -0
  39. data/lib/selenium/webdriver/common/action_builder.rb +128 -238
  40. data/lib/selenium/webdriver/common/child_process.rb +124 -0
  41. data/lib/selenium/webdriver/common/driver.rb +94 -43
  42. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
  43. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +42 -0
  44. data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +0 -2
  45. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +49 -0
  46. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +87 -0
  47. data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_bidi.rb} +9 -9
  48. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +86 -0
  49. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +36 -0
  50. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +42 -0
  51. data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
  52. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +41 -0
  53. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +36 -0
  54. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -9
  55. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +143 -0
  56. data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_logs.rb} +4 -4
  57. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +16 -1
  58. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  59. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +69 -0
  60. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -13
  61. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +75 -0
  62. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  63. data/lib/selenium/webdriver/common/driver_finder.rb +47 -0
  64. data/lib/selenium/webdriver/common/element.rb +89 -29
  65. data/lib/selenium/webdriver/common/error.rb +53 -194
  66. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
  67. data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
  68. data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -22
  69. data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
  70. data/lib/selenium/webdriver/common/interactions/key_actions.rb +10 -6
  71. data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
  72. data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
  73. data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
  74. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +71 -82
  75. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
  76. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
  77. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
  78. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
  79. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
  80. data/lib/selenium/webdriver/common/interactions/scroll.rb +59 -0
  81. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
  82. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
  83. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
  84. data/lib/selenium/webdriver/common/{w3c_manager.rb → interactions/wheel_input.rb} +14 -17
  85. data/lib/selenium/webdriver/common/keys.rb +1 -0
  86. data/lib/selenium/webdriver/common/local_driver.rb +55 -0
  87. data/lib/selenium/webdriver/common/log_entry.rb +2 -2
  88. data/lib/selenium/webdriver/common/logger.rb +119 -19
  89. data/lib/selenium/webdriver/common/manager.rb +11 -38
  90. data/lib/selenium/webdriver/common/options.rb +169 -23
  91. data/lib/selenium/webdriver/common/platform.rb +14 -6
  92. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  93. data/lib/selenium/webdriver/common/profile_helper.rb +11 -9
  94. data/lib/selenium/webdriver/common/proxy.rb +8 -5
  95. data/lib/selenium/webdriver/common/search_context.rb +7 -9
  96. data/lib/selenium/webdriver/common/selenium_manager.rb +125 -0
  97. data/lib/selenium/webdriver/common/service.rb +26 -137
  98. data/lib/selenium/webdriver/common/service_manager.rb +144 -0
  99. data/lib/selenium/webdriver/common/shadow_root.rb +86 -0
  100. data/lib/selenium/webdriver/common/socket_lock.rb +4 -4
  101. data/lib/selenium/webdriver/common/socket_poller.rb +4 -4
  102. data/lib/selenium/webdriver/common/takes_screenshot.rb +65 -0
  103. data/lib/selenium/webdriver/common/target_locator.rb +31 -4
  104. data/lib/selenium/webdriver/common/timeouts.rb +31 -4
  105. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +85 -0
  106. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +72 -0
  107. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
  108. data/lib/selenium/webdriver/common/wait.rb +1 -1
  109. data/lib/selenium/webdriver/common/websocket_connection.rb +164 -0
  110. data/lib/selenium/webdriver/common/window.rb +6 -10
  111. data/lib/selenium/webdriver/common/zipper.rb +4 -10
  112. data/lib/selenium/webdriver/common.rb +42 -18
  113. data/lib/selenium/webdriver/devtools/console_event.rb +36 -0
  114. data/lib/selenium/webdriver/devtools/exception_event.rb +34 -0
  115. data/lib/selenium/webdriver/devtools/mutation_event.rb +35 -0
  116. data/lib/selenium/webdriver/devtools/network_interceptor.rb +173 -0
  117. data/lib/selenium/webdriver/devtools/pinned_script.rb +57 -0
  118. data/lib/selenium/webdriver/devtools/request.rb +65 -0
  119. data/lib/selenium/webdriver/devtools/response.rb +64 -0
  120. data/lib/selenium/webdriver/devtools.rb +96 -0
  121. data/lib/selenium/webdriver/edge/driver.rb +11 -27
  122. data/lib/selenium/webdriver/edge/features.rb +44 -0
  123. data/lib/selenium/webdriver/edge/options.rb +18 -43
  124. data/lib/selenium/webdriver/edge/profile.rb +33 -0
  125. data/lib/selenium/webdriver/edge/service.rb +7 -27
  126. data/lib/selenium/webdriver/edge.rb +11 -14
  127. data/lib/selenium/webdriver/firefox/driver.rb +38 -19
  128. data/lib/selenium/webdriver/firefox/extension.rb +8 -0
  129. data/lib/selenium/webdriver/firefox/features.rb +66 -0
  130. data/lib/selenium/webdriver/firefox/options.rb +77 -50
  131. data/lib/selenium/webdriver/firefox/profile.rb +17 -71
  132. data/lib/selenium/webdriver/firefox/service.rb +3 -13
  133. data/lib/selenium/webdriver/firefox/util.rb +1 -1
  134. data/lib/selenium/webdriver/firefox.rb +17 -28
  135. data/lib/selenium/webdriver/ie/driver.rb +5 -45
  136. data/lib/selenium/webdriver/ie/options.rb +15 -46
  137. data/lib/selenium/webdriver/ie/service.rb +11 -19
  138. data/lib/selenium/webdriver/ie.rb +3 -16
  139. data/lib/selenium/webdriver/remote/bridge/commands.rb +170 -0
  140. data/lib/selenium/webdriver/remote/bridge.rb +592 -87
  141. data/lib/selenium/webdriver/remote/capabilities.rb +182 -124
  142. data/lib/selenium/webdriver/remote/driver.rb +30 -15
  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 +23 -31
  146. data/lib/selenium/webdriver/remote/response.rb +17 -49
  147. data/lib/selenium/webdriver/remote.rb +14 -12
  148. data/lib/selenium/webdriver/safari/driver.rb +7 -29
  149. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -5
  150. data/lib/selenium/webdriver/safari/options.rb +12 -27
  151. data/lib/selenium/webdriver/safari/service.rb +13 -11
  152. data/lib/selenium/webdriver/safari.rb +14 -20
  153. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  154. data/lib/selenium/webdriver/support/color.rb +24 -24
  155. data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
  156. data/lib/selenium/webdriver/support/guards/guard.rb +87 -0
  157. data/lib/selenium/webdriver/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +21 -20
  158. data/lib/selenium/webdriver/support/guards.rb +95 -0
  159. data/lib/selenium/webdriver/support/relative_locator.rb +50 -0
  160. data/lib/selenium/webdriver/support/select.rb +6 -4
  161. data/lib/selenium/webdriver/support.rb +1 -0
  162. data/lib/selenium/webdriver/version.rb +1 -1
  163. data/lib/selenium/webdriver.rb +18 -17
  164. data/selenium-webdriver.gemspec +36 -18
  165. metadata +159 -89
  166. data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
  167. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
  168. data/lib/selenium/webdriver/common/mouse.rb +0 -89
  169. data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
  170. data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
  171. data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
  172. data/lib/selenium/webdriver/edge/bridge.rb +0 -76
  173. data/lib/selenium/webdriver/firefox/binary.rb +0 -187
  174. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
  175. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  176. data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
  177. data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
  178. data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
  179. data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
  180. data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
  181. data/lib/selenium/webdriver/remote/http/persistent.rb +0 -60
  182. data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
  183. data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
  184. data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
  185. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
  186. data/lib/selenium/webdriver/remote/w3c/commands.rb +0 -157
@@ -24,48 +24,58 @@ 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
  #
56
- # Returns javascript_enabled capability.
57
- # It is true if not set explicitly.
57
+ # Backward compatibility
58
58
  #
59
- def javascript_enabled
60
- javascript_enabled = @capabilities.fetch(:javascript_enabled)
61
- javascript_enabled.nil? ? true : javascript_enabled
59
+
60
+ def version
61
+ WebDriver.logger.deprecate('`Capabilities#version`', '`Capabilities#browser_version`', id: :jwp_caps)
62
+ browser_version
62
63
  end
63
64
 
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
65
+ def version=(value)
66
+ WebDriver.logger.deprecate('`Capabilities#version=`', '`Capabilities#browser_version=`', id: :jwp_caps)
67
+ self.browser_version = value
68
+ end
69
+
70
+ def platform
71
+ WebDriver.logger.deprecate('`Capabilities#platform`', '`Capabilities#platform_name`', id: :jwp_caps)
72
+ platform_name
73
+ end
74
+
75
+ def platform=(value)
76
+ WebDriver.logger.deprecate('`Capabilities#platform=`', '`Capabilities#platform_name=`', id: :jwp_caps)
77
+ self.platform_name = value
78
+ end
69
79
 
70
80
  #
71
81
  # Convenience methods for the common choices.
@@ -73,81 +83,59 @@ module Selenium
73
83
 
74
84
  class << self
75
85
  def chrome(opts = {})
86
+ WebDriver.logger.deprecate('Remote::Capabilities.chrome', 'Options.chrome', id: :caps_browsers)
76
87
  new({
77
- browser_name: 'chrome',
78
- javascript_enabled: true,
79
- css_selectors_enabled: true
88
+ browser_name: 'chrome'
80
89
  }.merge(opts))
81
90
  end
82
91
 
83
92
  def edge(opts = {})
93
+ WebDriver.logger.deprecate('Remote::Capabilities.edge', 'Options.edge', id: :caps_browsers)
84
94
  new({
85
- browser_name: 'MicrosoftEdge',
86
- platform: :windows
95
+ browser_name: 'MicrosoftEdge'
87
96
  }.merge(opts))
88
97
  end
98
+ alias microsoftedge edge
89
99
 
90
100
  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
+ WebDriver.logger.deprecate('Remote::Capabilities.firefox', 'Options.firefox', id: :caps_browsers)
101
102
  new({
102
- browser_name: 'firefox',
103
- javascript_enabled: true,
104
- takes_screenshot: true,
105
- css_selectors_enabled: true
103
+ browser_name: 'firefox'
106
104
  }.merge(opts))
107
105
  end
106
+ alias ff firefox
108
107
 
109
- def htmlunit(opts = {})
108
+ def safari(opts = {})
109
+ WebDriver.logger.deprecate('Remote::Capabilities.safari', 'Options.safari', id: :caps_browsers)
110
110
  new({
111
- browser_name: 'htmlunit'
111
+ browser_name: Selenium::WebDriver::Safari.technology_preview? ? 'Safari Technology Preview' : 'safari'
112
112
  }.merge(opts))
113
113
  end
114
114
 
115
- def htmlunitwithjs(opts = {})
115
+ def htmlunit(opts = {})
116
+ WebDriver.logger.deprecate('Remote::Capabilities.htmlunit',
117
+ 'as argument in constructor',
118
+ id: :caps_browsers)
116
119
  new({
117
- browser_name: 'htmlunit',
118
- javascript_enabled: true
120
+ browser_name: 'htmlunit'
119
121
  }.merge(opts))
120
122
  end
121
123
 
122
124
  def internet_explorer(opts = {})
125
+ WebDriver.logger.deprecate('Remote::Capabilities.ie', 'Options.ie', id: :caps_browsers)
123
126
  new({
124
127
  browser_name: 'internet explorer',
125
- platform: :windows,
126
- takes_screenshot: true,
127
- css_selectors_enabled: true,
128
- native_events: true
128
+ platform_name: :windows
129
129
  }.merge(opts))
130
130
  end
131
- alias_method :ie, :internet_explorer
131
+ alias ie internet_explorer
132
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))
133
+ def always_match(capabilities)
134
+ new(always_match: capabilities)
141
135
  end
142
136
 
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))
137
+ def first_match(*capabilities)
138
+ new(first_match: capabilities)
151
139
  end
152
140
 
153
141
  #
@@ -156,41 +144,62 @@ module Selenium
156
144
 
157
145
  def json_create(data)
158
146
  data = data.dup
159
-
160
147
  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?
148
+
149
+ process_timeouts(caps, data.delete('timeouts'))
150
+
151
+ if data.key?('proxy')
152
+ proxy = data.delete('proxy')
153
+ caps.proxy = Proxy.json_create(proxy) unless proxy.nil? || proxy.empty?
154
+ end
155
+
156
+ # Remote Server Specific
157
+ if data.key?('webdriver.remote.sessionid')
158
+ caps[:remote_session_id] =
159
+ data.delete('webdriver.remote.sessionid')
160
+ end
161
+
162
+ KNOWN.each do |cap|
163
+ data_value = camel_case(cap)
164
+ caps[cap] = data.delete(data_value) if data.key?(data_value)
165
+ end
170
166
 
171
167
  # any remaining pairs will be added as is, with no conversion
172
168
  caps.merge!(data)
173
169
 
174
170
  caps
175
171
  end
172
+
173
+ def camel_case(str_or_sym)
174
+ str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
175
+ end
176
+
177
+ private
178
+
179
+ def process_timeouts(caps, timeouts)
180
+ return if timeouts.nil?
181
+
182
+ caps.implicit_timeout = timeouts['implicit']
183
+ caps.page_load_timeout = timeouts['pageLoad']
184
+ caps.script_timeout = timeouts['script']
185
+ end
176
186
  end
177
187
 
178
188
  #
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
189
+ # @param [Hash] opts
190
+ # @option :browser_name [String] required browser name
191
+ # @option :browser_version [String] required browser version number
192
+ # @option :platform_name [Symbol] one of :any, :win, :mac, or :x
193
+ # @option :accept_insecure_certs [Boolean] does the driver accept insecure SSL certifications?
194
+ # @option :proxy [Selenium::WebDriver::Proxy, Hash] proxy configuration
187
195
  #
188
196
  # @api public
189
197
  #
190
198
 
191
199
  def initialize(opts = {})
192
- @capabilities = DEFAULTS.merge(opts)
193
- self.proxy = opts.delete(:proxy)
200
+ @capabilities = {}
201
+ self.proxy = opts.delete(:proxy) if opts[:proxy]
202
+ @capabilities.merge!(opts)
194
203
  end
195
204
 
196
205
  #
@@ -215,6 +224,10 @@ module Selenium
215
224
  end
216
225
  end
217
226
 
227
+ def proxy
228
+ @capabilities[:proxy]
229
+ end
230
+
218
231
  def proxy=(proxy)
219
232
  case proxy
220
233
  when Hash
@@ -226,37 +239,46 @@ module Selenium
226
239
  end
227
240
  end
228
241
 
242
+ def timeouts
243
+ @capabilities[:timeouts] ||= {}
244
+ end
245
+
246
+ def timeouts=(timeouts)
247
+ @capabilities[:timeouts] = timeouts
248
+ end
249
+
250
+ def implicit_timeout
251
+ timeouts[:implicit]
252
+ end
253
+
254
+ def implicit_timeout=(timeout)
255
+ timeouts[:implicit] = timeout
256
+ end
257
+
258
+ def page_load_timeout
259
+ timeouts[:page_load] || timeouts[:pageLoad]
260
+ end
261
+
262
+ def page_load_timeout=(timeout)
263
+ timeouts[:page_load] = timeout
264
+ end
265
+
266
+ def script_timeout
267
+ timeouts[:script]
268
+ end
269
+
270
+ def script_timeout=(timeout)
271
+ timeouts[:script] = timeout
272
+ end
273
+
229
274
  #
230
275
  # @api private
231
276
  #
232
277
 
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
278
+ def as_json(*)
279
+ @capabilities.each_with_object({}) do |(key, value), hash|
280
+ hash[convert_key(key)] = process_capabilities(key, value, hash)
257
281
  end
258
-
259
- hash
260
282
  end
261
283
 
262
284
  def to_json(*)
@@ -268,7 +290,8 @@ module Selenium
268
290
 
269
291
  as_json == other.as_json
270
292
  end
271
- alias_method :eql?, :==
293
+
294
+ alias eql? ==
272
295
 
273
296
  protected
274
297
 
@@ -276,8 +299,43 @@ module Selenium
276
299
 
277
300
  private
278
301
 
279
- def camel_case(str)
280
- str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
302
+ def process_capabilities(key, value, hash)
303
+ case value
304
+ when Array
305
+ value.map { |v| process_capabilities(key, v, hash) }
306
+ when Hash
307
+ value.each_with_object({}) do |(k, v), h|
308
+ h[convert_key(k)] = process_capabilities(k, v, h)
309
+ end
310
+ when Capabilities, Options
311
+ value.as_json
312
+ else
313
+ convert_value(key, value)
314
+ end
315
+ end
316
+
317
+ def convert_key(key)
318
+ case key
319
+ when String
320
+ key.to_s
321
+ when Symbol
322
+ self.class.camel_case(key)
323
+ else
324
+ raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}"
325
+ end
326
+ end
327
+
328
+ def convert_value(key, value)
329
+ case key
330
+ when :platform
331
+ value.to_s.upcase
332
+ when :proxy
333
+ value&.as_json
334
+ when :unhandled_prompt_behavior
335
+ value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value
336
+ else
337
+ value
338
+ end
281
339
  end
282
340
  end # Capabilities
283
341
  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,39 @@ 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
44
- end
45
- super(@bridge, listener: listener)
31
+
32
+ def initialize(capabilities: nil, options: nil, service: nil, url: nil, **opts)
33
+ raise ArgumentError, "Can not set :service object on #{self.class}" if service
34
+
35
+ url ||= "http://#{Platform.localhost}:4444/wd/hub"
36
+ caps = process_options(options, capabilities)
37
+ super(caps: caps, url: url, **opts)
38
+ @bridge.file_detector = ->((filename, *)) { File.exist?(filename) && filename.to_s }
39
+ end
40
+
41
+ private
42
+
43
+ def devtools_url
44
+ capabilities['se:cdp']
45
+ end
46
+
47
+ def devtools_version
48
+ cdp_version = capabilities['se:cdpVersion']&.split('.')&.first
49
+ raise Error::WebDriverError, 'DevTools is not supported by the Remote Server' unless cdp_version
50
+
51
+ Integer(cdp_version)
46
52
  end
47
53
 
54
+ def process_options(options, capabilities)
55
+ if options && capabilities
56
+ msg = "Don't use both :options and :capabilities when initializing #{self.class}, prefer :options"
57
+ raise ArgumentError, msg
58
+ elsif options.nil? && capabilities.nil?
59
+ raise ArgumentError, "#{self.class} needs :options to be set"
60
+ end
61
+ options ? options.as_json : generate_capabilities(capabilities)
62
+ end
48
63
  end # Driver
49
64
  end # Remote
50
65
  end # WebDriver
@@ -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
@@ -28,8 +28,7 @@ module Selenium
28
28
  class Default < Common
29
29
  attr_writer :proxy
30
30
 
31
- attr_accessor :open_timeout
32
- attr_accessor :read_timeout
31
+ attr_accessor :open_timeout, :read_timeout
33
32
 
34
33
  # Initializes object.
35
34
  # Warning: Setting {#open_timeout} to non-nil values will cause a separate thread to spawn.
@@ -39,15 +38,7 @@ module Selenium
39
38
  def initialize(open_timeout: nil, read_timeout: nil)
40
39
  @open_timeout = open_timeout
41
40
  @read_timeout = read_timeout
42
- end
43
-
44
- # Maintaining backward compatibility.
45
- # @param [Numeric] value - Timeout in seconds to apply to both open timeout and read timeouts.
46
- # @deprecated Please set the specific desired timeout {#read_timeout} or {#open_timeout} directly.
47
- def timeout=(value)
48
- WebDriver.logger.deprecate ':timeout=', '#read_timeout= and #open_timeout='
49
- self.open_timeout = value
50
- self.read_timeout = value
41
+ super()
51
42
  end
52
43
 
53
44
  def close
@@ -64,14 +55,18 @@ module Selenium
64
55
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
65
56
  end
66
57
 
67
- # Defaulting open_timeout to nil to be consistent with Ruby 2.2 and earlier.
68
- http.open_timeout = open_timeout
58
+ http.open_timeout = open_timeout if open_timeout
69
59
  http.read_timeout = read_timeout if read_timeout
70
60
 
71
- http.start
61
+ start(http)
62
+ http
72
63
  end
73
64
  end
74
65
 
66
+ def start(http)
67
+ http.start
68
+ end
69
+
75
70
  MAX_RETRIES = 3
76
71
 
77
72
  def request(verb, url, headers, payload, redirects = 0)
@@ -80,9 +75,10 @@ module Selenium
80
75
  begin
81
76
  request = new_request_for(verb, url, headers, payload)
82
77
  response = response_for(request)
83
- rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EADDRINUSE
84
- # a retry is sometimes needed on Windows XP where we may quickly
85
- # run out of ephemeral ports
78
+ rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EADDRINUSE, Errno::EADDRNOTAVAIL
79
+ # a retry is sometimes needed:
80
+ # on Windows XP where we may quickly run out of ephemeral ports
81
+ # when the port becomes temporarily unavailable
86
82
  #
87
83
  # A more robust solution is bumping the MaxUserPort setting
88
84
  # as described here:
@@ -93,15 +89,8 @@ module Selenium
93
89
  retries += 1
94
90
  sleep 2
95
91
  retry
96
- rescue Errno::EADDRNOTAVAIL => ex
97
- # a retry is sometimes needed when the port becomes temporarily unavailable
98
- raise if retries >= MAX_RETRIES
99
-
100
- retries += 1
101
- sleep 2
102
- retry
103
- rescue Errno::ECONNREFUSED => ex
104
- raise ex.class, "using proxy: #{proxy.http}" if use_proxy?
92
+ rescue Errno::ECONNREFUSED => e
93
+ raise e.class, "using proxy: #{proxy.http}" if use_proxy?
105
94
 
106
95
  raise
107
96
  end
@@ -111,6 +100,7 @@ module Selenium
111
100
 
112
101
  request(:get, URI.parse(response['Location']), DEFAULT_HEADERS.dup, nil, redirects + 1)
113
102
  else
103
+ WebDriver.logger.debug(" <<< #{response.instance_variable_get(:@header).inspect}", id: :header)
114
104
  create_response response.code, response.body, response.content_type
115
105
  end
116
106
  end
@@ -132,12 +122,14 @@ module Selenium
132
122
  def new_http_client
133
123
  if use_proxy?
134
124
  url = @proxy.http
135
- raise Error::WebDriverError, "expected HTTP proxy, got #{@proxy.inspect}" unless proxy.respond_to?(:http) && url
125
+ unless proxy.respond_to?(:http) && url
126
+ raise Error::WebDriverError,
127
+ "expected HTTP proxy, got #{@proxy.inspect}"
128
+ end
136
129
 
137
130
  proxy = URI.parse(url)
138
131
 
139
- clazz = Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password)
140
- clazz.new(server_url.host, server_url.port)
132
+ Net::HTTP.new(server_url.host, server_url.port, proxy.host, proxy.port, proxy.user, proxy.password)
141
133
  else
142
134
  Net::HTTP.new server_url.host, server_url.port
143
135
  end
@@ -145,8 +137,8 @@ module Selenium
145
137
 
146
138
  def proxy
147
139
  @proxy ||= begin
148
- proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
149
- no_proxy = ENV['no_proxy'] || ENV['NO_PROXY']
140
+ proxy = ENV.fetch('http_proxy', nil) || ENV.fetch('HTTP_PROXY', nil)
141
+ no_proxy = ENV.fetch('no_proxy', nil) || ENV.fetch('NO_PROXY', nil)
150
142
 
151
143
  if proxy
152
144
  proxy = "http://#{proxy}" unless proxy.start_with?('http://')