selenium-webdriver 4.0.0.beta2 → 4.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
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