selenium-webdriver 4.51.0 → 4.52.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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +15 -0
  3. data/Gemfile +14 -0
  4. data/README.md +20 -0
  5. data/bin/linux-arm64/selenium-manager +0 -0
  6. data/bin/linux-x86_64/selenium-manager +0 -0
  7. data/bin/macos/selenium-manager +0 -0
  8. data/bin/selenium-manager-THIRD-PARTY-NOTICES.txt +543 -226
  9. data/bin/selenium-manager.cdx.json +804 -722
  10. data/bin/windows/selenium-manager.exe +0 -0
  11. data/lib/selenium/webdriver/atoms/findElements.js +960 -250
  12. data/lib/selenium/webdriver/atoms/getAttribute.js +153 -127
  13. data/lib/selenium/webdriver/atoms/isDisplayed.js +433 -364
  14. data/lib/selenium/webdriver/atoms.rb +4 -1
  15. data/lib/selenium/webdriver/bidi/protocol/bluetooth.rb +6 -6
  16. data/lib/selenium/webdriver/bidi/protocol/browser.rb +21 -9
  17. data/lib/selenium/webdriver/bidi/protocol/browsing_context.rb +109 -39
  18. data/lib/selenium/webdriver/bidi/protocol/emulation.rb +89 -44
  19. data/lib/selenium/webdriver/bidi/protocol/input.rb +95 -31
  20. data/lib/selenium/webdriver/bidi/protocol/log.rb +4 -4
  21. data/lib/selenium/webdriver/bidi/protocol/moz_debugging.rb +12 -10
  22. data/lib/selenium/webdriver/bidi/protocol/moz_profiler.rb +4 -4
  23. data/lib/selenium/webdriver/bidi/protocol/network.rb +82 -39
  24. data/lib/selenium/webdriver/bidi/protocol/script.rb +38 -24
  25. data/lib/selenium/webdriver/bidi/protocol/session.rb +61 -8
  26. data/lib/selenium/webdriver/bidi/protocol/storage.rb +3 -3
  27. data/lib/selenium/webdriver/bidi/protocol/user_agent_client_hints.rb +3 -3
  28. data/lib/selenium/webdriver/bidi/protocol/web_extension.rb +17 -9
  29. data/lib/selenium/webdriver/bidi/serialization/record.rb +66 -24
  30. data/lib/selenium/webdriver/bidi/serialization.rb +2 -2
  31. data/lib/selenium/webdriver/bidi/support/bidi_generate.rb +228 -150
  32. data/lib/selenium/webdriver/common/client_config.rb +4 -1
  33. data/lib/selenium/webdriver/common/driver_finder.rb +5 -2
  34. data/lib/selenium/webdriver/common/websocket_connection.rb +51 -13
  35. data/lib/selenium/webdriver/remote/http/default.rb +17 -1
  36. data/lib/selenium/webdriver/version.rb +1 -1
  37. data/selenium-webdriver.gemspec +0 -12
  38. metadata +6 -163
@@ -30,7 +30,7 @@ module Selenium
30
30
  class Record < ::Data
31
31
  # Named Field, not Member, to avoid colliding with +::Data#members+.
32
32
  Field = ::Data.define(:name, :wire_key, :nullable, :ref, :list, :fixed, :enum, :required, :primitive,
33
- :scalar, :const, :map)
33
+ :scalar, :const, :map, :min, :max, :exclusive_min, :exclusive_max)
34
34
 
35
35
  def self.define(**spec)
36
36
  extensible = spec.delete(:extensible) || false
@@ -61,7 +61,9 @@ module Selenium
61
61
  nullable: meta[:nullable] || false, ref: meta[:ref],
62
62
  list: meta[:list] || false, fixed: meta.fetch(:fixed, UNSET), enum: meta[:enum],
63
63
  required: meta.fetch(:required, true), primitive: meta[:primitive],
64
- scalar: meta[:scalar], const: meta.fetch(:const, UNSET), map: meta[:map])
64
+ scalar: meta[:scalar], const: meta.fetch(:const, UNSET), map: meta[:map],
65
+ min: meta[:min], max: meta[:max], exclusive_min: meta[:exclusive_min] || false,
66
+ exclusive_max: meta[:exclusive_max] || false)
65
67
  end
66
68
  private_class_method :field
67
69
 
@@ -121,12 +123,12 @@ module Selenium
121
123
  end
122
124
 
123
125
  # Checks a field that carries an actual value (neither omitted nor nil): a nullable-const
124
- # field against its literal, list/scalar shape, primitive type (lists excepted, as inbound
125
- # does), ref type, and enum membership (resolved lazily so a cross-domain enum need not load first).
126
+ # field against its literal, list/scalar shape, primitive type (per element for a list), ref
127
+ # type, and enum membership (resolved lazily so a cross-domain enum need not load first).
126
128
  def validate_present(field, value)
127
129
  validate_const(field, value)
128
130
  check_outbound_shape(field, value)
129
- check_outbound_primitive(field, value) unless field.list
131
+ check_outbound_primitive(field, value)
130
132
  check_outbound_map(field, value) if field.map
131
133
  validate_ref(field, value) if field.ref
132
134
  Serialization.validate!("#{name}##{field.name}", value, Protocol.const_get(field.enum)) if field.enum
@@ -201,14 +203,12 @@ module Selenium
201
203
  end
202
204
 
203
205
  # Outbound mirror of check_primitive: a primitive-typed arg (`string`/`integer`/…) must be
204
- # the matching Ruby type, so a caller mistake (a string width, a float count) is a local
205
- # ArgumentError here rather than a rejection the browser reports a round-trip later. A field
206
- # with no primitive descriptor (enum, ref, opaque) passes; lists are skipped, as inbound does.
206
+ # the matching Ruby type within its declared bounds, so a caller mistake (a string width, a
207
+ # zero count) is a local ArgumentError here rather than a rejection the browser reports a
208
+ # round-trip later. A field with no primitive descriptor (enum, ref, opaque) passes.
207
209
  def check_outbound_primitive(field, value)
208
- check = PRIMITIVE_CHECKS[field.primitive]
209
- return if check.nil? || check.call(value)
210
-
211
- raise ::ArgumentError, "#{name}##{field.name} expected #{field.primitive}, got #{value.inspect}"
210
+ mismatch = primitive_mismatch(field, value)
211
+ raise ::ArgumentError, "#{name}##{field.name}#{mismatch}" if mismatch
212
212
  end
213
213
 
214
214
  # Outbound mirror of check_map: a map-typed arg must be a Hash whose values are the
@@ -243,17 +243,20 @@ module Selenium
243
243
  return Serialization.to_symbol("#{name}##{field.name}", raw, enum_hash(field)) if field.enum
244
244
 
245
245
  if field.ref.nil?
246
- return raw if field.list
247
246
  return check_map(field, raw) if field.map
248
247
 
249
248
  check_primitive(field, raw)
250
- # A whole number is exact in both types, so the declared type is held with nothing lost.
251
- return field.primitive == 'integer' && raw.is_a?(::Float) ? raw.to_i : raw
249
+ return field.list ? raw.map { |element| hold_integer(field, element) } : hold_integer(field, raw)
252
250
  end
253
251
 
254
252
  read_ref(field, raw)
255
253
  end
256
254
 
255
+ # A whole number is exact in both types, so the declared type is held with nothing lost.
256
+ def hold_integer(field, value)
257
+ WHOLE_FLOAT.call(value) && Array(field.primitive).include?('integer') ? value.to_i : value
258
+ end
259
+
257
260
  # Reads a ref-typed value into its class. A `scalar` position is an inline union with
258
261
  # a scalar arm collapsed onto its union ref (a map's string keys): a non-object leaf
259
262
  # passes through instead of being handed to the object_only union, but only when it
@@ -288,14 +291,53 @@ module Selenium
288
291
  }.freeze
289
292
 
290
293
  def check_primitive(field, raw)
291
- check = PRIMITIVE_CHECKS[field.primitive]
292
- return if check.nil? || check.call(raw)
294
+ mismatch = primitive_mismatch(field, raw)
295
+ raise Error::SerializationError, "#{name}##{field.name}#{mismatch}" if mismatch
296
+ end
297
+
298
+ # The suffix of the error a primitive-typed value earns, or nil when it conforms — shared by
299
+ # both directions like map_mismatch. A list checks each element, so a nil element mismatches.
300
+ def primitive_mismatch(field, value)
301
+ return if field.primitive.nil?
302
+ return element_mismatch(field, field.primitive, value) unless field.list
303
+
304
+ value.each_with_index do |element, index|
305
+ mismatch = element_mismatch(field, field.primitive, element)
306
+ return "[#{index}]#{mismatch}" if mismatch
307
+ end
308
+ nil
309
+ end
310
+
311
+ # The field's bounds hold every numeric value it carries: the scalar, each list element, each map value.
312
+ def element_mismatch(field, primitives, value)
313
+ checks = Array(primitives).filter_map { |primitive| PRIMITIVE_CHECKS[primitive] }
314
+ return bound_mismatch(field, value) if checks.empty? || checks.any? { |check| check.call(value) }
293
315
 
294
- raise Error::SerializationError, "#{name}##{field.name} expected #{field.primitive}, got #{raw.inspect}"
316
+ " expected #{Array(primitives).join(' or ')}, got #{value.inspect}"
317
+ end
318
+
319
+ def bound_mismatch(field, value)
320
+ return unless value.is_a?(::Numeric)
321
+
322
+ bound = violated_min(field, value) || violated_max(field, value)
323
+ " expected #{bound}, got #{value.inspect}" if bound
324
+ end
325
+
326
+ # Each is written as the in-bounds test, so NaN (in no range) fails rather than slipping past both sides.
327
+ def violated_min(field, value)
328
+ return if field.min.nil? || (field.exclusive_min ? value > field.min : value >= field.min)
329
+
330
+ "#{field.exclusive_min ? '>' : '>='} #{field.min}"
331
+ end
332
+
333
+ def violated_max(field, value)
334
+ return if field.max.nil? || (field.exclusive_max ? value < field.max : value <= field.max)
335
+
336
+ "#{field.exclusive_max ? '<' : '<='} #{field.max}"
295
337
  end
296
338
 
297
339
  # A `map` field (`{*text => <primitive>}`, e.g. script.NodeProperties.attributes) must arrive
298
- # as an object whose every value matches the declared primitive. Keys are JSON object keys,
340
+ # as an object whose every value matches a declared primitive. Keys are JSON object keys,
299
341
  # so they are strings by construction. The Hash passes through unchanged once validated.
300
342
  def check_map(field, raw)
301
343
  mismatch = map_mismatch(field, raw)
@@ -311,11 +353,11 @@ module Selenium
311
353
  def map_mismatch(field, value)
312
354
  return " expected a map, got #{value.inspect}" unless value.is_a?(::Hash)
313
355
 
314
- check = PRIMITIVE_CHECKS[field.map]
315
- return if check.nil?
316
-
317
- entry = value.find { |_, v| !check.call(v) }
318
- "[#{entry[0].inspect}] expected #{field.map}, got #{entry[1].inspect}" if entry
356
+ value.each do |key, entry|
357
+ mismatch = element_mismatch(field, field.map, entry)
358
+ return "[#{key.inspect}]#{mismatch}" if mismatch
359
+ end
360
+ nil
319
361
  end
320
362
 
321
363
  def enum_hash(field)
@@ -60,11 +60,11 @@ module Selenium
60
60
 
61
61
  # Inbound: map a wire token (or list) back to its enum symbol, raising on a token
62
62
  # outside our schema so a non-compliant (or newer-than-schema) browser value fails
63
- # loud instead of silently passing through untyped.
63
+ # loud instead of silently passing through untyped. A null field never reaches here
64
+ # (Record#read handles it), so a nil is a list element and raises too.
64
65
  #
65
66
  # @api private
66
67
  def self.to_symbol(name, value, enum)
67
- return value if value.nil?
68
68
  return value.map { |element| to_symbol(name, element, enum) } if value.is_a?(::Array)
69
69
 
70
70
  enum.key(value) || raise(Error::SerializationError, "#{name} received an unknown value: #{value.inspect}")