selenium-webdriver 4.0.0.beta2 → 4.0.0.beta3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f868be1b0140d1e41a8f499f4e4dad8f24f63716eb32094425c03adc0aadbd18
4
- data.tar.gz: 67bc7e4c0fa98744e8d9a4242c86fc281de24eaad4766de954b50c697ba0783d
3
+ metadata.gz: d43cea1b9a19e329eee91c38bb566fc2c7adb76df2da6a7efa2eee908910a9a3
4
+ data.tar.gz: cd692d2a4f562dffcb0608cfd19adec5e383509d3f150826791c7312969b0aa9
5
5
  SHA512:
6
- metadata.gz: 8cb6d82d27e472611fcfc64802febc3a192eace5c9b8ccf0a2709fadf8b3f96f090eb1c83bba081bda41c830c698c8d487cc1e7d7fbf1e0053833f156e99cadf
7
- data.tar.gz: 207f9e36de333d0033b0e24ad451d640a5076ee65e3d59e2304852fb40d5caa0cdd1ea45b98a5c853f2ce7c4cc6ed0deb597c70d68d830cdd619be41683161d2
6
+ metadata.gz: 695aa88517dc97ab25d93a1f0b983bc3a6fa55e48460d5e8ed053e300227b6b1b2693e243b8a439652d921b75eba1ac06384a33fc0c40e2cb4b194ee66483d3f
7
+ data.tar.gz: acbe3d962300eff073ce447548fb41adb62ac56f238074f3f33c0bb43ccb4ef200daab53f1ff478f20f7efe67d3fcffc34e11d0b0959f929b9c7ffcac9afad0b
@@ -48,6 +48,17 @@ module Selenium
48
48
 
49
49
  private
50
50
 
51
+ def devtools_url
52
+ uri = URI(devtools_address)
53
+ response = Net::HTTP.get(uri.hostname, '/json/version', uri.port)
54
+
55
+ JSON.parse(response)['webSocketDebuggerUrl']
56
+ end
57
+
58
+ def devtools_version
59
+ Integer(capabilities.browser_version.split('.').first)
60
+ end
61
+
51
62
  def devtools_address
52
63
  "http://#{capabilities['goog:chromeOptions']['debuggerAddress']}"
53
64
  end
@@ -27,12 +27,11 @@ module Selenium
27
27
  class Profile
28
28
  include ProfileHelper
29
29
 
30
- attr_reader :directory
31
-
32
30
  def initialize(model = nil)
33
31
  @model = verify_model(model)
34
32
  @extensions = []
35
33
  @encoded_extensions = []
34
+ @directory = nil
36
35
  end
37
36
 
38
37
  def add_extension(path)
@@ -45,6 +44,10 @@ module Selenium
45
44
  @encoded_extensions << encoded
46
45
  end
47
46
 
47
+ def directory
48
+ @directory || layout_on_disk
49
+ end
50
+
48
51
  #
49
52
  # Set a preference in the profile.
50
53
  #
@@ -37,23 +37,6 @@ module Selenium
37
37
  end
38
38
  end
39
39
 
40
- private
41
-
42
- def devtools_version
43
- return Firefox::DEVTOOLS_VERSION if browser == :firefox
44
-
45
- Integer(capabilities.browser_version.split('.').first)
46
- end
47
-
48
- def devtools_url
49
- return devtools_address if devtools_address.include?('/session/')
50
-
51
- uri = URI(devtools_address)
52
- response = Net::HTTP.get(uri.hostname, '/json/version', uri.port)
53
-
54
- JSON.parse(response)['webSocketDebuggerUrl']
55
- end
56
-
57
40
  end # HasDevTools
58
41
  end # DriverExtensions
59
42
  end # WebDriver
@@ -21,8 +21,35 @@ module Selenium
21
21
  module WebDriver
22
22
  module DriverExtensions
23
23
  module PrintsPage
24
+ #
25
+ # Save a page as a PDF to the given path
26
+ #
27
+ # @example Save Printed Page
28
+ # driver.save_print_page('../printed_page.pdf')
29
+ #
30
+ # @param [String] path to where the pdf should be saved
31
+ #
32
+ # @api public
33
+ #
34
+
35
+ def save_print_page(path, **options)
36
+ File.open(path, 'wb') do |file|
37
+ content = Base64.decode64 print_page(options)
38
+ file << content
39
+ end
40
+ end
41
+
42
+ #
43
+ # Return a Base64 encoded Print Page as a string
44
+ #
45
+ # @see https://w3c.github.io/webdriver/#print-page
46
+ #
47
+ # @api public
48
+ #
49
+
24
50
  def print_page(**options)
25
- options[:page_ranges] &&= Array(options[:page_ranges])
51
+ options[:pageRanges] = Array(options.delete(:page_ranges)) || []
52
+ options[:shrinkToFit] = options.delete(:shrink_to_fit) { true }
26
53
 
27
54
  @bridge.print_page(options)
28
55
  end
@@ -160,6 +160,26 @@ module Selenium
160
160
  bridge.element_property self, name
161
161
  end
162
162
 
163
+ #
164
+ # Gets the computed WAI-ARIA role of element
165
+ #
166
+ # @return [String]
167
+ #
168
+
169
+ def aria_role
170
+ bridge.element_aria_role self
171
+ end
172
+
173
+ #
174
+ # Gets the computed WAI-ARIA label of element.
175
+ #
176
+ # @return [String]
177
+ #
178
+
179
+ def accessible_name
180
+ bridge.element_aria_label self
181
+ end
182
+
163
183
  #
164
184
  # Get the text content of this element
165
185
  #
@@ -134,12 +134,7 @@ module Selenium
134
134
 
135
135
  def generate_as_json(value, camelize_keys: true)
136
136
  if value.is_a?(Hash)
137
- value.each_with_object({}) do |(key, val), hash|
138
- next if val.respond_to?(:empty?) && val.empty?
139
-
140
- key = convert_json_key(key, camelize: camelize_keys)
141
- hash[key] = generate_as_json(val, camelize_keys: camelize?(key))
142
- end
137
+ process_json_hash(value, camelize_keys)
143
138
  elsif value.respond_to?(:as_json)
144
139
  value.as_json
145
140
  elsif value.is_a?(Array)
@@ -151,6 +146,16 @@ module Selenium
151
146
  end
152
147
  end
153
148
 
149
+ def process_json_hash(value, camelize_keys)
150
+ value.each_with_object({}) do |(key, val), hash|
151
+ next if val.respond_to?(:empty?) && val.empty?
152
+
153
+ camelize = camelize_keys ? camelize?(key) : false
154
+ key = convert_json_key(key, camelize: camelize)
155
+ hash[key] = generate_as_json(val, camelize_keys: camelize)
156
+ end
157
+ end
158
+
154
159
  def convert_json_key(key, camelize: true)
155
160
  key = key.to_s if key.is_a?(Symbol)
156
161
  key = camel_case(key) if camelize
@@ -65,37 +65,26 @@ module Selenium
65
65
  arr << Errno::EALREADY if Platform.wsl?
66
66
  }.freeze
67
67
 
68
- if Platform.jruby?
69
- # we use a plain TCPSocket here since JRuby has issues closing socket
70
- # see https://github.com/jruby/jruby/issues/5709
71
- def listening?
72
- TCPSocket.new(@host, @port).close
73
- true
74
- rescue *NOT_CONNECTED_ERRORS
75
- false
76
- end
77
- else
78
- def listening?
79
- addr = Socket.getaddrinfo(@host, @port, Socket::AF_INET, Socket::SOCK_STREAM)
80
- sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
81
- sockaddr = Socket.pack_sockaddr_in(@port, addr[0][3])
82
-
83
- begin
84
- sock.connect_nonblock sockaddr
85
- rescue Errno::EINPROGRESS
86
- retry if socket_writable?(sock) && conn_completed?(sock)
87
- raise Errno::ECONNREFUSED
88
- rescue *CONNECTED_ERRORS
89
- # yay!
90
- end
91
-
92
- sock.close
93
- true
94
- rescue *NOT_CONNECTED_ERRORS
95
- sock&.close
96
- WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}")
97
- false
68
+ def listening?
69
+ addr = Socket.getaddrinfo(@host, @port, Socket::AF_INET, Socket::SOCK_STREAM)
70
+ sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
71
+ sockaddr = Socket.pack_sockaddr_in(@port, addr[0][3])
72
+
73
+ begin
74
+ sock.connect_nonblock sockaddr
75
+ rescue Errno::EINPROGRESS
76
+ retry if socket_writable?(sock) && conn_completed?(sock)
77
+ raise Errno::ECONNREFUSED
78
+ rescue *CONNECTED_ERRORS
79
+ # yay!
98
80
  end
81
+
82
+ sock.close
83
+ true
84
+ rescue *NOT_CONNECTED_ERRORS
85
+ sock&.close
86
+ WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}")
87
+ false
99
88
  end
100
89
 
101
90
  def socket_writable?(sock)
@@ -40,8 +40,15 @@ module Selenium
40
40
 
41
41
  private
42
42
 
43
- def devtools_address
44
- "http://#{capabilities['moz:debuggerAddress']}"
43
+ def devtools_url
44
+ uri = URI("http://#{capabilities['moz:debuggerAddress']}")
45
+ response = Net::HTTP.get(uri.hostname, '/json/version', uri.port)
46
+
47
+ JSON.parse(response)['webSocketDebuggerUrl']
48
+ end
49
+
50
+ def devtools_version
51
+ Firefox::DEVTOOLS_VERSION
45
52
  end
46
53
  end # Driver
47
54
  end # Firefox
@@ -49,7 +49,7 @@ module Selenium
49
49
  #
50
50
 
51
51
  def create_session(capabilities)
52
- response = execute(:new_session, {}, {capabilities: {firstMatch: [capabilities]}})
52
+ response = execute(:new_session, {}, prepare_capabilities_payload(capabilities))
53
53
 
54
54
  @session_id = response['sessionId']
55
55
  capabilities = response['capabilities']
@@ -458,6 +458,14 @@ module Selenium
458
458
  execute :get_element_property, id: element.ref, name: name
459
459
  end
460
460
 
461
+ def element_aria_role(element)
462
+ execute :get_element_aria_role, id: element.ref
463
+ end
464
+
465
+ def element_aria_label(element)
466
+ execute :get_element_aria_label, id: element.ref
467
+ end
468
+
461
469
  def element_value(element)
462
470
  element_property element, 'value'
463
471
  end
@@ -594,6 +602,11 @@ module Selenium
594
602
  id['ELEMENT'] || id['element-6066-11e4-a52e-4f735466cecf']
595
603
  end
596
604
 
605
+ def prepare_capabilities_payload(capabilities)
606
+ capabilities = {firstMatch: [capabilities]} if !capabilities['alwaysMatch'] && !capabilities['firstMatch']
607
+ {capabilities: capabilities}
608
+ end
609
+
597
610
  def convert_locator(how, what)
598
611
  how = SearchContext::FINDERS[how.to_sym] || how
599
612
 
@@ -40,22 +40,15 @@ module Selenium
40
40
  :unhandled_prompt_behavior,
41
41
  :strict_file_interactability,
42
42
 
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
43
+ # remote-specific (webdriver.remote.sessionid)
44
+ :remote_session_id
50
45
  ].freeze
51
46
 
52
- KNOWN.each do |key|
47
+ (KNOWN - %i[proxy timeouts]).each do |key|
53
48
  define_method key do
54
49
  @capabilities.fetch(key)
55
50
  end
56
51
 
57
- next if key == :proxy
58
-
59
52
  define_method "#{key}=" do |value|
60
53
  @capabilities[key] = value
61
54
  end
@@ -89,16 +82,10 @@ module Selenium
89
82
  alias_method :microsoftedge, :edge
90
83
 
91
84
  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
- opts.delete(:timeouts) if opts[:timeouts].empty?
99
- new({browser_name: 'firefox'}.merge(opts))
85
+ new({
86
+ browser_name: 'firefox'
87
+ }.merge(opts))
100
88
  end
101
-
102
89
  alias_method :ff, :firefox
103
90
 
104
91
  def safari(opts = {})
@@ -121,18 +108,21 @@ module Selenium
121
108
  end
122
109
  alias_method :ie, :internet_explorer
123
110
 
111
+ def always_match(capabilities)
112
+ new(always_match: capabilities)
113
+ end
114
+
115
+ def first_match(*capabilities)
116
+ new(first_match: capabilities)
117
+ end
118
+
124
119
  #
125
120
  # @api private
126
121
  #
127
122
 
128
123
  def json_create(data)
129
124
  data = data.dup
130
-
131
125
  caps = new
132
- (KNOWN - %i[timeouts proxy]).each do |cap|
133
- data_value = camel_case(cap)
134
- caps[cap] = data.delete(data_value) if data.key?(data_value)
135
- end
136
126
 
137
127
  process_timeouts(caps, data.delete('timeouts'))
138
128
 
@@ -146,6 +136,11 @@ module Selenium
146
136
  caps[:remote_session_id] = data.delete('webdriver.remote.sessionid')
147
137
  end
148
138
 
139
+ KNOWN.each do |cap|
140
+ data_value = camel_case(cap)
141
+ caps[cap] = data.delete(data_value) if data.key?(data_value)
142
+ end
143
+
149
144
  # any remaining pairs will be added as is, with no conversion
150
145
  caps.merge!(data)
151
146
 
@@ -179,8 +174,9 @@ module Selenium
179
174
  #
180
175
 
181
176
  def initialize(opts = {})
182
- @capabilities = opts
183
- self.proxy = opts.delete(:proxy)
177
+ @capabilities = {}
178
+ self.proxy = opts.delete(:proxy) if opts[:proxy]
179
+ @capabilities.merge!(opts)
184
180
  end
185
181
 
186
182
  #
@@ -205,6 +201,10 @@ module Selenium
205
201
  end
206
202
  end
207
203
 
204
+ def proxy
205
+ @capabilities.fetch(:proxy)
206
+ end
207
+
208
208
  def proxy=(proxy)
209
209
  case proxy
210
210
  when Hash
@@ -216,33 +216,46 @@ module Selenium
216
216
  end
217
217
  end
218
218
 
219
+ def timeouts
220
+ @capabilities[:timeouts] ||= {}
221
+ end
222
+
223
+ def timeouts=(timeouts)
224
+ @capabilities[:timeouts] = timeouts
225
+ end
226
+
227
+ def implicit_timeout
228
+ timeouts[:implicit]
229
+ end
230
+
231
+ def implicit_timeout=(timeout)
232
+ timeouts[:implicit] = timeout
233
+ end
234
+
235
+ def page_load_timeout
236
+ timeouts[:page_load] || timeouts[:pageLoad]
237
+ end
238
+
239
+ def page_load_timeout=(timeout)
240
+ timeouts[:page_load] = timeout
241
+ end
242
+
243
+ def script_timeout
244
+ timeouts[:script]
245
+ end
246
+
247
+ def script_timeout=(timeout)
248
+ timeouts[:script] = timeout
249
+ end
250
+
219
251
  #
220
252
  # @api private
221
253
  #
222
254
 
223
255
  def as_json(*)
224
- hash = {}
225
-
226
- @capabilities.each do |key, value|
227
- case key
228
- when :platform
229
- hash['platform'] = value.to_s.upcase
230
- when :proxy
231
- next unless value
232
-
233
- process_proxy(hash, value)
234
- when :unhandled_prompt_behavior
235
- hash['unhandledPromptBehavior'] = value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value
236
- when String
237
- hash[key.to_s] = value
238
- when Symbol
239
- hash[self.class.camel_case(key)] = value
240
- else
241
- raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class} / #{value.inspect}"
242
- end
256
+ @capabilities.each_with_object({}) do |(key, value), hash|
257
+ hash[convert_key(key)] = process_capabilities(key, value, hash)
243
258
  end
244
-
245
- hash
246
259
  end
247
260
 
248
261
  def to_json(*)
@@ -263,13 +276,53 @@ module Selenium
263
276
 
264
277
  private
265
278
 
266
- def process_proxy(hash, value)
267
- hash['proxy'] = value.as_json
268
- hash['proxy']['proxyType'] &&= hash['proxy']['proxyType'].downcase
279
+ def process_capabilities(key, value, hash)
280
+ case value
281
+ when Array
282
+ value.map { |v| process_capabilities(key, v, hash) }
283
+ when Hash
284
+ value.each_with_object({}) do |(k, v), h|
285
+ h[convert_key(k)] = process_capabilities(k, v, h)
286
+ end
287
+ when Capabilities, Options
288
+ value.as_json
289
+ else
290
+ convert_value(key, value)
291
+ end
292
+ end
293
+
294
+ def convert_key(key)
295
+ case key
296
+ when String
297
+ key.to_s
298
+ when Symbol
299
+ self.class.camel_case(key)
300
+ else
301
+ raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}"
302
+ end
303
+ end
269
304
 
270
- return unless hash['proxy']['noProxy'].is_a?(String)
305
+ def convert_value(key, value)
306
+ case key
307
+ when :platform
308
+ value.to_s.upcase
309
+ when :proxy
310
+ convert_proxy(value)
311
+ when :unhandled_prompt_behavior
312
+ value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value
313
+ else
314
+ value
315
+ end
316
+ end
271
317
 
272
- hash['proxy']['noProxy'] = hash['proxy']['noProxy'].split(', ')
318
+ def convert_proxy(value)
319
+ return unless value
320
+
321
+ hash = value.as_json
322
+ hash['proxyType'] &&= hash['proxyType'].downcase
323
+ hash['noProxy'] = hash['noProxy'].split(', ') if hash['noProxy'].is_a?(String)
324
+
325
+ hash
273
326
  end
274
327
  end # Capabilities
275
328
  end # Remote
@@ -82,6 +82,8 @@ module Selenium
82
82
  get_element_attribute: [:get, 'session/:session_id/element/:id/attribute/:name'],
83
83
  get_element_property: [:get, 'session/:session_id/element/:id/property/:name'],
84
84
  get_element_css_value: [:get, 'session/:session_id/element/:id/css/:property_name'],
85
+ get_element_aria_role: [:get, 'session/:session_id/element/:id/computedrole'],
86
+ get_element_aria_label: [:get, 'session/:session_id/element/:id/computedlabel'],
85
87
  get_element_text: [:get, 'session/:session_id/element/:id/text'],
86
88
  get_element_tag_name: [:get, 'session/:session_id/element/:id/name'],
87
89
  get_element_rect: [:get, 'session/:session_id/element/:id/rect'],
@@ -44,17 +44,15 @@ module Selenium
44
44
  super
45
45
  end
46
46
 
47
- def print_page(**options)
48
- options[:page_ranges] &&= Array(options[:page_ranges])
49
-
50
- @bridge.print_page(options)
51
- end
52
-
53
47
  private
54
48
 
55
- def devtools_address
49
+ def devtools_url
56
50
  capabilities['se:cdp']
57
51
  end
52
+
53
+ def devtools_version
54
+ capabilities['se:cdpVersion'].split('.').first
55
+ end
58
56
  end # Driver
59
57
  end # Remote
60
58
  end # WebDriver
@@ -19,6 +19,6 @@
19
19
 
20
20
  module Selenium
21
21
  module WebDriver
22
- VERSION = '4.0.0.beta2'
22
+ VERSION = '4.0.0.beta3'
23
23
  end # WebDriver
24
24
  end # Selenium
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: selenium-webdriver
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.beta2
4
+ version: 4.0.0.beta3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Rodionov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-03-16 00:00:00.000000000 Z
13
+ date: 2021-04-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  requirement: !ruby/object:Gem::Requirement