selenium-webdriver 4.0.0.alpha2 → 4.0.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 (113) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +338 -4
  3. data/Gemfile +3 -1
  4. data/LICENSE +1 -1
  5. data/NOTICE +2 -0
  6. data/README.md +4 -5
  7. data/lib/selenium/server.rb +21 -29
  8. data/lib/selenium/webdriver/atoms/findElements.js +122 -0
  9. data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
  10. data/lib/selenium/webdriver/atoms/isDisplayed.js +76 -78
  11. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  12. data/lib/selenium/webdriver/chrome/driver.rb +26 -56
  13. data/lib/selenium/webdriver/chrome/features.rb +106 -0
  14. data/lib/selenium/webdriver/chrome/options.rb +127 -52
  15. data/lib/selenium/webdriver/chrome/profile.rb +8 -5
  16. data/lib/selenium/webdriver/chrome/service.rb +4 -6
  17. data/lib/selenium/webdriver/chrome.rb +10 -9
  18. data/lib/selenium/webdriver/common/driver.rb +110 -19
  19. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
  20. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +51 -0
  21. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
  22. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +77 -0
  23. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +38 -0
  24. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +45 -0
  25. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +43 -0
  26. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +38 -0
  27. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
  28. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +144 -0
  29. data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +30 -0
  30. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +17 -0
  31. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  32. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +136 -0
  33. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -11
  34. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +77 -0
  35. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
  36. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  37. data/lib/selenium/webdriver/common/element.rb +79 -16
  38. data/lib/selenium/webdriver/common/error.rb +12 -0
  39. data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
  40. data/lib/selenium/webdriver/common/log_entry.rb +2 -2
  41. data/lib/selenium/webdriver/common/logger.rb +50 -15
  42. data/lib/selenium/webdriver/common/manager.rb +14 -14
  43. data/lib/selenium/webdriver/common/options.rb +186 -0
  44. data/lib/selenium/webdriver/common/platform.rb +6 -1
  45. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  46. data/lib/selenium/webdriver/common/profile_helper.rb +10 -2
  47. data/lib/selenium/webdriver/common/proxy.rb +6 -3
  48. data/lib/selenium/webdriver/common/search_context.rb +7 -3
  49. data/lib/selenium/webdriver/common/service.rb +23 -113
  50. data/lib/selenium/webdriver/common/service_manager.rb +151 -0
  51. data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
  52. data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
  53. data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
  54. data/lib/selenium/webdriver/common/target_locator.rb +32 -4
  55. data/lib/selenium/webdriver/common/timeouts.rb +31 -4
  56. data/lib/selenium/webdriver/common/wait.rb +1 -1
  57. data/lib/selenium/webdriver/common/window.rb +0 -4
  58. data/lib/selenium/webdriver/common.rb +17 -2
  59. data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
  60. data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
  61. data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
  62. data/lib/selenium/webdriver/{chrome/bridge.rb → devtools/pinned_script.rb} +26 -17
  63. data/lib/selenium/webdriver/devtools/request.rb +67 -0
  64. data/lib/selenium/webdriver/devtools/response.rb +66 -0
  65. data/lib/selenium/webdriver/devtools.rb +182 -0
  66. data/lib/selenium/webdriver/edge/driver.rb +5 -31
  67. data/lib/selenium/webdriver/edge/features.rb +44 -0
  68. data/lib/selenium/webdriver/edge/options.rb +11 -48
  69. data/lib/selenium/webdriver/edge/profile.rb +33 -0
  70. data/lib/selenium/webdriver/edge/service.rb +9 -24
  71. data/lib/selenium/webdriver/edge.rb +11 -13
  72. data/lib/selenium/webdriver/firefox/driver.rb +20 -30
  73. data/lib/selenium/webdriver/firefox/extension.rb +8 -0
  74. data/lib/selenium/webdriver/firefox/{bridge.rb → features.rb} +23 -4
  75. data/lib/selenium/webdriver/firefox/options.rb +70 -49
  76. data/lib/selenium/webdriver/firefox/profile.rb +16 -77
  77. data/lib/selenium/webdriver/firefox/service.rb +1 -5
  78. data/lib/selenium/webdriver/firefox.rb +22 -16
  79. data/lib/selenium/webdriver/ie/driver.rb +1 -34
  80. data/lib/selenium/webdriver/ie/options.rb +13 -44
  81. data/lib/selenium/webdriver/ie/service.rb +9 -11
  82. data/lib/selenium/webdriver/ie.rb +8 -7
  83. data/lib/selenium/webdriver/remote/bridge.rb +112 -86
  84. data/lib/selenium/webdriver/remote/capabilities.rb +120 -62
  85. data/lib/selenium/webdriver/remote/commands.rb +7 -0
  86. data/lib/selenium/webdriver/remote/driver.rb +15 -12
  87. data/lib/selenium/webdriver/remote/http/common.rb +0 -5
  88. data/lib/selenium/webdriver/remote/http/default.rb +17 -11
  89. data/lib/selenium/webdriver/remote/http/persistent.rb +11 -6
  90. data/lib/selenium/webdriver/remote.rb +15 -9
  91. data/lib/selenium/webdriver/safari/driver.rb +3 -34
  92. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +6 -6
  93. data/lib/selenium/webdriver/safari/options.rb +10 -29
  94. data/lib/selenium/webdriver/safari/service.rb +0 -4
  95. data/lib/selenium/webdriver/safari.rb +16 -8
  96. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  97. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
  98. data/lib/selenium/webdriver/support/cdp_client_generator.rb +108 -0
  99. data/lib/selenium/webdriver/support/color.rb +2 -2
  100. data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
  101. data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
  102. data/lib/selenium/webdriver/support/guards/guard_condition.rb +52 -0
  103. data/lib/selenium/webdriver/support/guards.rb +95 -0
  104. data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
  105. data/lib/selenium/webdriver/support/select.rb +2 -2
  106. data/lib/selenium/webdriver/support.rb +1 -0
  107. data/lib/selenium/webdriver/version.rb +1 -1
  108. data/lib/selenium/webdriver.rb +10 -8
  109. data/selenium-webdriver.gemspec +29 -13
  110. metadata +125 -51
  111. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
  112. data/lib/selenium/webdriver/firefox/binary.rb +0 -110
  113. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
@@ -39,23 +39,17 @@ module Selenium
39
39
  :timeouts,
40
40
  :unhandled_prompt_behavior,
41
41
  :strict_file_interactability,
42
+ :web_socket_url,
42
43
 
43
- # remote-specific
44
- :remote_session_id,
45
-
46
- # TODO: (AR) deprecate compatibility with OSS-capabilities
47
- :implicit_timeout,
48
- :page_load_timeout,
49
- :script_timeout
44
+ # remote-specific (webdriver.remote.sessionid)
45
+ :remote_session_id
50
46
  ].freeze
51
47
 
52
- KNOWN.each do |key|
48
+ (KNOWN - %i[proxy timeouts]).each do |key|
53
49
  define_method key do
54
- @capabilities.fetch(key)
50
+ @capabilities[key]
55
51
  end
56
52
 
57
- next if key == :proxy
58
-
59
53
  define_method "#{key}=" do |value|
60
54
  @capabilities[key] = value
61
55
  end
@@ -83,27 +77,21 @@ module Selenium
83
77
 
84
78
  def edge(opts = {})
85
79
  new({
86
- browser_name: 'MicrosoftEdge',
87
- platform_name: :windows
80
+ browser_name: 'MicrosoftEdge'
88
81
  }.merge(opts))
89
82
  end
83
+ alias_method :microsoftedge, :edge
90
84
 
91
85
  def firefox(opts = {})
92
- opts[:browser_version] = opts.delete(:version) if opts.key?(:version)
93
- opts[:platform_name] = opts.delete(:platform) if opts.key?(:platform)
94
- opts[:timeouts] = {}
95
- opts[:timeouts]['implicit'] = opts.delete(:implicit_timeout) if opts.key?(:implicit_timeout)
96
- opts[:timeouts]['pageLoad'] = opts.delete(:page_load_timeout) if opts.key?(:page_load_timeout)
97
- opts[:timeouts]['script'] = opts.delete(:script_timeout) if opts.key?(:script_timeout)
98
- new({browser_name: 'firefox'}.merge(opts))
86
+ new({
87
+ browser_name: 'firefox'
88
+ }.merge(opts))
99
89
  end
100
-
101
90
  alias_method :ff, :firefox
102
91
 
103
92
  def safari(opts = {})
104
93
  new({
105
- browser_name: 'safari',
106
- platform_name: :mac
94
+ browser_name: Selenium::WebDriver::Safari.technology_preview? ? "Safari Technology Preview" : 'safari'
107
95
  }.merge(opts))
108
96
  end
109
97
 
@@ -121,26 +109,23 @@ module Selenium
121
109
  end
122
110
  alias_method :ie, :internet_explorer
123
111
 
112
+ def always_match(capabilities)
113
+ new(always_match: capabilities)
114
+ end
115
+
116
+ def first_match(*capabilities)
117
+ new(first_match: capabilities)
118
+ end
119
+
124
120
  #
125
121
  # @api private
126
122
  #
127
123
 
128
124
  def json_create(data)
129
125
  data = data.dup
130
-
131
126
  caps = new
132
- caps.browser_name = data.delete('browserName') if data.key?('browserName')
133
- caps.browser_version = data.delete('browserVersion') if data.key?('browserVersion')
134
- caps.platform_name = data.delete('platformName') if data.key?('platformName')
135
- caps.accept_insecure_certs = data.delete('acceptInsecureCerts') if data.key?('acceptInsecureCerts')
136
- caps.page_load_strategy = data.delete('pageLoadStrategy') if data.key?('pageLoadStrategy')
137
-
138
- if data.key?('timeouts')
139
- timeouts = data.delete('timeouts')
140
- caps.implicit_timeout = timeouts['implicit'] if timeouts
141
- caps.page_load_timeout = timeouts['pageLoad'] if timeouts
142
- caps.script_timeout = timeouts['script'] if timeouts
143
- end
127
+
128
+ process_timeouts(caps, data.delete('timeouts'))
144
129
 
145
130
  if data.key?('proxy')
146
131
  proxy = data.delete('proxy')
@@ -148,13 +133,34 @@ module Selenium
148
133
  end
149
134
 
150
135
  # Remote Server Specific
151
- caps[:remote_session_id] = data.delete('webdriver.remote.sessionid') if data.key?('webdriver.remote.sessionid')
136
+ if data.key?('webdriver.remote.sessionid')
137
+ caps[:remote_session_id] = data.delete('webdriver.remote.sessionid')
138
+ end
139
+
140
+ KNOWN.each do |cap|
141
+ data_value = camel_case(cap)
142
+ caps[cap] = data.delete(data_value) if data.key?(data_value)
143
+ end
152
144
 
153
145
  # any remaining pairs will be added as is, with no conversion
154
146
  caps.merge!(data)
155
147
 
156
148
  caps
157
149
  end
150
+
151
+ def camel_case(str_or_sym)
152
+ str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
153
+ end
154
+
155
+ private
156
+
157
+ def process_timeouts(caps, timeouts)
158
+ return if timeouts.nil?
159
+
160
+ caps.implicit_timeout = timeouts['implicit']
161
+ caps.page_load_timeout = timeouts['pageLoad']
162
+ caps.script_timeout = timeouts['script']
163
+ end
158
164
  end
159
165
 
160
166
  #
@@ -169,8 +175,9 @@ module Selenium
169
175
  #
170
176
 
171
177
  def initialize(opts = {})
172
- @capabilities = opts
173
- self.proxy = opts.delete(:proxy)
178
+ @capabilities = {}
179
+ self.proxy = opts.delete(:proxy) if opts[:proxy]
180
+ @capabilities.merge!(opts)
174
181
  end
175
182
 
176
183
  #
@@ -195,6 +202,10 @@ module Selenium
195
202
  end
196
203
  end
197
204
 
205
+ def proxy
206
+ @capabilities[:proxy]
207
+ end
208
+
198
209
  def proxy=(proxy)
199
210
  case proxy
200
211
  when Hash
@@ -206,33 +217,46 @@ module Selenium
206
217
  end
207
218
  end
208
219
 
220
+ def timeouts
221
+ @capabilities[:timeouts] ||= {}
222
+ end
223
+
224
+ def timeouts=(timeouts)
225
+ @capabilities[:timeouts] = timeouts
226
+ end
227
+
228
+ def implicit_timeout
229
+ timeouts[:implicit]
230
+ end
231
+
232
+ def implicit_timeout=(timeout)
233
+ timeouts[:implicit] = timeout
234
+ end
235
+
236
+ def page_load_timeout
237
+ timeouts[:page_load] || timeouts[:pageLoad]
238
+ end
239
+
240
+ def page_load_timeout=(timeout)
241
+ timeouts[:page_load] = timeout
242
+ end
243
+
244
+ def script_timeout
245
+ timeouts[:script]
246
+ end
247
+
248
+ def script_timeout=(timeout)
249
+ timeouts[:script] = timeout
250
+ end
251
+
209
252
  #
210
253
  # @api private
211
254
  #
212
255
 
213
256
  def as_json(*)
214
- hash = {}
215
-
216
- @capabilities.each do |key, value|
217
- case key
218
- when :platform
219
- hash['platform'] = value.to_s.upcase
220
- when :proxy
221
- if value
222
- hash['proxy'] = value.as_json
223
- hash['proxy']['proxyType'] &&= hash['proxy']['proxyType'].downcase
224
- hash['proxy']['noProxy'] = hash['proxy']['noProxy'].split(', ') if hash['proxy']['noProxy'].is_a?(String)
225
- end
226
- when String
227
- hash[key.to_s] = value
228
- when Symbol
229
- hash[camel_case(key.to_s)] = value
230
- else
231
- raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class} / #{value.inspect}"
232
- end
257
+ @capabilities.each_with_object({}) do |(key, value), hash|
258
+ hash[convert_key(key)] = process_capabilities(key, value, hash)
233
259
  end
234
-
235
- hash
236
260
  end
237
261
 
238
262
  def to_json(*)
@@ -253,10 +277,44 @@ module Selenium
253
277
 
254
278
  private
255
279
 
256
- def camel_case(str)
257
- str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
280
+ def process_capabilities(key, value, hash)
281
+ case value
282
+ when Array
283
+ value.map { |v| process_capabilities(key, v, hash) }
284
+ when Hash
285
+ value.each_with_object({}) do |(k, v), h|
286
+ h[convert_key(k)] = process_capabilities(k, v, h)
287
+ end
288
+ when Capabilities, Options
289
+ value.as_json
290
+ else
291
+ convert_value(key, value)
292
+ end
258
293
  end
259
294
 
295
+ def convert_key(key)
296
+ case key
297
+ when String
298
+ key.to_s
299
+ when Symbol
300
+ self.class.camel_case(key)
301
+ else
302
+ raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}"
303
+ end
304
+ end
305
+
306
+ def convert_value(key, value)
307
+ case key
308
+ when :platform
309
+ value.to_s.upcase
310
+ when :proxy
311
+ value&.as_json
312
+ when :unhandled_prompt_behavior
313
+ value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value
314
+ else
315
+ value
316
+ end
317
+ end
260
318
  end # Capabilities
261
319
  end # Remote
262
320
  end # WebDriver
@@ -77,11 +77,16 @@ module Selenium
77
77
  find_elements: [:post, 'session/:session_id/elements'],
78
78
  find_child_element: [:post, 'session/:session_id/element/:id/element'],
79
79
  find_child_elements: [:post, 'session/:session_id/element/:id/elements'],
80
+ find_shadow_child_element: [:post, 'session/:session_id/shadow/:id/element'],
81
+ find_shadow_child_elements: [:post, 'session/:session_id/shadow/:id/elements'],
80
82
  get_active_element: [:get, 'session/:session_id/element/active'],
83
+ get_element_shadow_root: [:get, 'session/:session_id/element/:id/shadow'],
81
84
  is_element_selected: [:get, 'session/:session_id/element/:id/selected'],
82
85
  get_element_attribute: [:get, 'session/:session_id/element/:id/attribute/:name'],
83
86
  get_element_property: [:get, 'session/:session_id/element/:id/property/:name'],
84
87
  get_element_css_value: [:get, 'session/:session_id/element/:id/css/:property_name'],
88
+ get_element_aria_role: [:get, 'session/:session_id/element/:id/computedrole'],
89
+ get_element_aria_label: [:get, 'session/:session_id/element/:id/computedlabel'],
85
90
  get_element_text: [:get, 'session/:session_id/element/:id/text'],
86
91
  get_element_tag_name: [:get, 'session/:session_id/element/:id/name'],
87
92
  get_element_rect: [:get, 'session/:session_id/element/:id/rect'],
@@ -109,6 +114,7 @@ module Selenium
109
114
  # timeouts
110
115
  #
111
116
 
117
+ get_timeouts: [:get, 'session/:session_id/timeouts'],
112
118
  set_timeout: [:post, 'session/:session_id/timeouts'],
113
119
 
114
120
  #
@@ -117,6 +123,7 @@ module Selenium
117
123
 
118
124
  actions: [:post, 'session/:session_id/actions'],
119
125
  release_actions: [:delete, 'session/:session_id/actions'],
126
+ print_page: [:post, 'session/:session_id/print'],
120
127
 
121
128
  #
122
129
  # Element Operations
@@ -28,30 +28,33 @@ module Selenium
28
28
 
29
29
  class Driver < WebDriver::Driver
30
30
  include DriverExtensions::UploadsFiles
31
- include DriverExtensions::TakesScreenshot
32
31
  include DriverExtensions::HasSessionId
33
- include DriverExtensions::Rotatable
34
32
  include DriverExtensions::HasRemoteStatus
35
- include DriverExtensions::HasWebStorage
36
-
37
- def initialize(opts = {})
38
- listener = opts.delete(:listener)
39
- desired_capabilities = opts.delete(:desired_capabilities) { Capabilities.new }
40
33
 
34
+ def initialize(bridge: nil, listener: nil, **opts)
35
+ desired_capabilities = opts[:desired_capabilities]
41
36
  if desired_capabilities.is_a?(Symbol)
42
- unless Capabilities.respond_to?(desired_capabilities)
37
+ unless Remote::Capabilities.respond_to?(desired_capabilities)
43
38
  raise Error::WebDriverError, "invalid desired capability: #{desired_capabilities.inspect}"
44
39
  end
45
40
 
46
- desired_capabilities = Capabilities.__send__(desired_capabilities)
41
+ opts[:desired_capabilities] = Remote::Capabilities.__send__(desired_capabilities)
47
42
  end
43
+ opts[:url] ||= "http://#{Platform.localhost}:4444/wd/hub"
44
+ super
45
+ @bridge.file_detector = ->((filename, *)) { File.exist?(filename) && filename.to_s }
46
+ end
48
47
 
49
- @bridge = Bridge.new(opts)
50
- @bridge.create_session(desired_capabilities, opts.delete(:options))
48
+ private
51
49
 
52
- super(@bridge, listener: listener)
50
+ def devtools_url
51
+ capabilities['se:cdp']
53
52
  end
54
53
 
54
+ def devtools_version
55
+ capabilities['se:cdpVersion']&.split('.')&.first ||
56
+ raise(Error::WebDriverError, "DevTools is not supported by the Remote Server")
57
+ end
55
58
  end # Driver
56
59
  end # Remote
57
60
  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
@@ -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,6 +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
41
+ super()
42
42
  end
43
43
 
44
44
  def close
@@ -55,14 +55,18 @@ module Selenium
55
55
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
56
56
  end
57
57
 
58
- # Defaulting open_timeout to nil to be consistent with Ruby 2.2 and earlier.
59
- http.open_timeout = open_timeout
58
+ http.open_timeout = open_timeout if open_timeout
60
59
  http.read_timeout = read_timeout if read_timeout
61
60
 
62
- http.start
61
+ start(http)
62
+ http
63
63
  end
64
64
  end
65
65
 
66
+ def start(http)
67
+ http.start
68
+ end
69
+
66
70
  MAX_RETRIES = 3
67
71
 
68
72
  def request(verb, url, headers, payload, redirects = 0)
@@ -84,15 +88,15 @@ module Selenium
84
88
  retries += 1
85
89
  sleep 2
86
90
  retry
87
- rescue Errno::EADDRNOTAVAIL => ex
91
+ rescue Errno::EADDRNOTAVAIL => e
88
92
  # a retry is sometimes needed when the port becomes temporarily unavailable
89
93
  raise if retries >= MAX_RETRIES
90
94
 
91
95
  retries += 1
92
96
  sleep 2
93
97
  retry
94
- rescue Errno::ECONNREFUSED => ex
95
- raise ex.class, "using proxy: #{proxy.http}" if use_proxy?
98
+ rescue Errno::ECONNREFUSED => e
99
+ raise e.class, "using proxy: #{proxy.http}" if use_proxy?
96
100
 
97
101
  raise
98
102
  end
@@ -123,12 +127,14 @@ module Selenium
123
127
  def new_http_client
124
128
  if use_proxy?
125
129
  url = @proxy.http
126
- raise Error::WebDriverError, "expected HTTP proxy, got #{@proxy.inspect}" unless proxy.respond_to?(:http) && url
130
+ unless proxy.respond_to?(:http) && url
131
+ raise Error::WebDriverError,
132
+ "expected HTTP proxy, got #{@proxy.inspect}"
133
+ end
127
134
 
128
135
  proxy = URI.parse(url)
129
136
 
130
- clazz = Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password)
131
- clazz.new(server_url.host, server_url.port)
137
+ Net::HTTP.new(server_url.host, server_url.port, proxy.host, proxy.port, proxy.user, proxy.password)
132
138
  else
133
139
  Net::HTTP.new server_url.host, server_url.port
134
140
  end
@@ -25,12 +25,22 @@ module Selenium
25
25
  module Http
26
26
  # @api private
27
27
  class Persistent < Default
28
+ def initialize(open_timeout: nil, read_timeout: nil)
29
+ WebDriver.logger.deprecate("Selenium::WebDriver::Remote::Http::Persistent",
30
+ id: :http_persistent) { "The default HTTP client now uses persistence." }
31
+ super
32
+ end
33
+
28
34
  def close
29
35
  @http&.shutdown
30
36
  end
31
37
 
32
38
  private
33
39
 
40
+ def start(*)
41
+ # no need to explicitly start connection
42
+ end
43
+
34
44
  def new_http_client
35
45
  proxy = nil
36
46
 
@@ -42,12 +52,7 @@ module Selenium
42
52
  proxy = URI.parse(url)
43
53
  end
44
54
 
45
- if Net::HTTP::Persistent::VERSION >= '3'
46
- Net::HTTP::Persistent.new name: 'webdriver', proxy: proxy
47
- else
48
- WebDriver.logger.warn 'Support for this version of net-http-persistent is deprecated. Please upgrade.'
49
- Net::HTTP::Persistent.new 'webdriver', proxy
50
- end
55
+ Net::HTTP::Persistent.new name: 'webdriver', proxy: proxy
51
56
  end
52
57
 
53
58
  def response_for(request)
@@ -18,14 +18,20 @@
18
18
  # under the License.
19
19
 
20
20
  require 'uri'
21
-
22
- require 'selenium/webdriver/remote/bridge'
23
- require 'selenium/webdriver/remote/driver'
24
- require 'selenium/webdriver/remote/response'
25
21
  require 'selenium/webdriver/remote/server_error'
26
- require 'selenium/webdriver/remote/http/common'
27
- require 'selenium/webdriver/remote/http/default'
28
22
 
29
- require 'selenium/webdriver/remote/bridge'
30
- require 'selenium/webdriver/remote/capabilities'
31
- require 'selenium/webdriver/remote/commands'
23
+ module Selenium
24
+ module WebDriver
25
+ module Remote
26
+ autoload :Bridge, 'selenium/webdriver/remote/bridge'
27
+ autoload :Driver, 'selenium/webdriver/remote/driver'
28
+ autoload :Response, 'selenium/webdriver/remote/response'
29
+ autoload :Capabilities, 'selenium/webdriver/remote/capabilities'
30
+ autoload :COMMANDS, 'selenium/webdriver/remote/commands'
31
+ module Http
32
+ autoload :Common, 'selenium/webdriver/remote/http/common'
33
+ autoload :Default, 'selenium/webdriver/remote/http/default'
34
+ end
35
+ end
36
+ end
37
+ end
@@ -27,44 +27,13 @@ module Selenium
27
27
  #
28
28
 
29
29
  class Driver < WebDriver::Driver
30
- include DriverExtensions::HasDebugger
31
- include DriverExtensions::HasPermissions
32
- include DriverExtensions::TakesScreenshot
33
-
34
- def initialize(opts = {})
35
- opts[:desired_capabilities] = create_capabilities(opts)
36
-
37
- opts[:url] ||= service_url(opts)
38
-
39
- listener = opts.delete(:listener)
40
- desired_capabilities = opts.delete(:desired_capabilities)
41
-
42
- @bridge = Remote::Bridge.new(opts)
43
- @bridge.extend Bridge
44
- @bridge.create_session(desired_capabilities)
45
-
46
- super(@bridge, listener: listener)
47
- end
30
+ EXTENSIONS = [DriverExtensions::HasDebugger,
31
+ DriverExtensions::HasApplePermissions,
32
+ DriverExtensions::HasWebStorage].freeze
48
33
 
49
34
  def browser
50
35
  :safari
51
36
  end
52
-
53
- def quit
54
- super
55
- ensure
56
- @service&.stop
57
- end
58
-
59
- private
60
-
61
- def create_capabilities(opts = {})
62
- caps = opts.delete(:desired_capabilities) { Remote::Capabilities.safari }
63
- options = opts.delete(:options) { Options.new }
64
- caps.merge!(options.as_json)
65
- caps
66
- end
67
-
68
37
  end # Driver
69
38
  end # Safari
70
39
  end # WebDriver
@@ -20,17 +20,17 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Safari
23
- module Bridge
23
+ module Features
24
24
 
25
25
  # https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/WebDriverEndpointDoc/Commands/Commands.html
26
- COMMANDS = {
27
- get_permissions: [:get, '/session/:session_id/apple/permissions'],
28
- set_permissions: [:post, '/session/:session_id/apple/permissions'],
29
- attach_debugger: [:post, '/session/:session_id/apple/attach_debugger']
26
+ SAFARI_COMMANDS = {
27
+ get_permissions: [:get, 'session/:session_id/apple/permissions'],
28
+ set_permissions: [:post, 'session/:session_id/apple/permissions'],
29
+ attach_debugger: [:post, 'session/:session_id/apple/attach_debugger']
30
30
  }.freeze
31
31
 
32
32
  def commands(command)
33
- COMMANDS[command] || super
33
+ SAFARI_COMMANDS[command] || self.class::COMMANDS[command]
34
34
  end
35
35
 
36
36
  def permissions
@@ -20,40 +20,21 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Safari
23
- class Options
24
- attr_accessor :automatic_inspection, :automatic_profiling
23
+ class Options < WebDriver::Options
24
+ attr_accessor :options
25
25
 
26
- #
27
- # Create a new Options instance for W3C-capable versions of Safari.
28
- #
29
- # @example
30
- # options = Selenium::WebDriver::Safari::Options.new(automatic_inspection: true)
31
- # driver = Selenium::WebDriver.for :safari, options: options
32
- #
33
- # @param [Hash] opts the pre-defined options to create the Safari::Options with
34
- # @option opts [Boolean] :automatic_inspection Preloads Web Inspector and JavaScript debugger. Default is false
35
- # @option opts [Boolean] :automatic_profiling Preloads Web Inspector and starts a timeline recording. Default is false
36
- #
37
26
  # @see https://developer.apple.com/documentation/webkit/about_webdriver_for_safari
38
- #
27
+ CAPABILITIES = {automatic_inspection: 'safari:automaticInspection',
28
+ automatic_profiling: 'safari:automaticProfiling'}.freeze
29
+ BROWSER = 'safari'
39
30
 
40
- def initialize(**opts)
41
- @automatic_inspection = opts.delete(:automatic_inspection) || false
42
- @automatic_profiling = opts.delete(:automatic_profiling) || false
43
- end
44
-
45
- #
46
- # @api private
47
- #
48
-
49
- def as_json(*)
50
- opts = {}
31
+ def add_option(name, value = nil)
32
+ key = name.is_a?(Hash) ? name.keys.first : name
33
+ raise ArgumentError, 'Safari does not support options that are not namespaced' unless key.to_s.include?(':')
51
34
 
52
- opts['safari:automaticInspection'] = true if @automatic_inspection
53
- opts['safari:automaticProfiling'] = true if @automatic_profiling
54
-
55
- opts
35
+ super
56
36
  end
37
+
57
38
  end # Options
58
39
  end # Safari
59
40
  end # WebDriver
@@ -20,10 +20,6 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Safari
23
- #
24
- # @api private
25
- #
26
-
27
23
  class Service < WebDriver::Service
28
24
  DEFAULT_PORT = 7050
29
25
  EXECUTABLE = 'safaridriver'