selenium-webdriver 4.32.0 → 4.33.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.
- checksums.yaml +4 -4
- data/CHANGES +6 -0
- data/README.md +1 -1
- data/bin/linux/selenium-manager +0 -0
- data/bin/macos/selenium-manager +0 -0
- data/bin/windows/selenium-manager.exe +0 -0
- data/lib/selenium/webdriver/atoms.rb +2 -2
- data/lib/selenium/webdriver/bidi/log/console_log_entry.rb +2 -2
- data/lib/selenium/webdriver/chrome/driver.rb +2 -2
- data/lib/selenium/webdriver/chromium/options.rb +2 -2
- data/lib/selenium/webdriver/common/driver.rb +8 -8
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +4 -4
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +10 -10
- data/lib/selenium/webdriver/common/interactions/pointer_input.rb +6 -6
- data/lib/selenium/webdriver/common/options.rb +10 -10
- data/lib/selenium/webdriver/common/service.rb +10 -10
- data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +4 -4
- data/lib/selenium/webdriver/edge/driver.rb +2 -2
- data/lib/selenium/webdriver/firefox/driver.rb +2 -2
- data/lib/selenium/webdriver/firefox/service.rb +2 -2
- data/lib/selenium/webdriver/ie/driver.rb +2 -2
- data/lib/selenium/webdriver/remote/driver.rb +2 -2
- data/lib/selenium/webdriver/safari/driver.rb +2 -2
- data/lib/selenium/webdriver/support/block_event_listener.rb +2 -2
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +3 -3
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +4 -5
- data/selenium-webdriver.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fd4b623fa86d431079ad03fad528adf52a72f477333c14ed0ed36741a4f41e6
|
4
|
+
data.tar.gz: 214779166b857477353b6e9b2ebc200287a6735329cfc59f734af42bff23332f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24f46301be793d2a21a347a75f5aafa0cc7aac2c82ee504f34cc6dad76047ef6831cb57724f7c02c4efee1debf39dfa7dc2dade342c3c0945b004b7a9651f617
|
7
|
+
data.tar.gz: 9a711961bb2b3925cfb4b47a35c0cc15c47bb4b5d8480213f5ba6010e94bca64e539050f9007e7b0ef2f7e0f407bee0db0830bf970b7b1ed23b40ccba5e76ff4
|
data/CHANGES
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
4.33.0 (2025-05-23)
|
2
|
+
=========================
|
3
|
+
* Add CDP for Chrome 137 and remove 134
|
4
|
+
* Let firefox choose the bidi port by default (#15727)
|
5
|
+
* Upgrade to Ruby 3.2
|
6
|
+
|
1
7
|
4.32.0 (2025-05-02)
|
2
8
|
=========================
|
3
9
|
* Add CDP for Chrome 136 and remove 133
|
data/README.md
CHANGED
data/bin/linux/selenium-manager
CHANGED
Binary file
|
data/bin/macos/selenium-manager
CHANGED
Binary file
|
Binary file
|
@@ -31,8 +31,8 @@ module Selenium
|
|
31
31
|
File.read(File.expand_path("../atoms/#{function}.js", __FILE__))
|
32
32
|
end
|
33
33
|
|
34
|
-
def execute_atom(function_name, *
|
35
|
-
execute_script(atom_script(function_name), *
|
34
|
+
def execute_atom(function_name, *)
|
35
|
+
execute_script(atom_script(function_name), *)
|
36
36
|
end
|
37
37
|
end # Atoms
|
38
38
|
end # WebDriver
|
@@ -23,8 +23,8 @@ module Selenium
|
|
23
23
|
class ConsoleLogEntry < GenericLogEntry
|
24
24
|
attr_accessor :method, :realm, :args
|
25
25
|
|
26
|
-
def initialize(method:, realm:, args:, **
|
27
|
-
super(**
|
26
|
+
def initialize(method:, realm:, args:, **)
|
27
|
+
super(**)
|
28
28
|
@method = method
|
29
29
|
@realm = realm
|
30
30
|
@args = args
|
@@ -30,9 +30,9 @@ module Selenium
|
|
30
30
|
class Driver < Chromium::Driver
|
31
31
|
include LocalDriver
|
32
32
|
|
33
|
-
def initialize(options: nil, service: nil, url: nil, **
|
33
|
+
def initialize(options: nil, service: nil, url: nil, **)
|
34
34
|
caps, url = initialize_local_driver(options, service, url)
|
35
|
-
super(caps: caps, url: url, **
|
35
|
+
super(caps: caps, url: url, **)
|
36
36
|
end
|
37
37
|
|
38
38
|
def browser
|
@@ -67,8 +67,8 @@ module Selenium
|
|
67
67
|
# @option opts [Array<String>] window_types A list of window types to appear in the list of window handles
|
68
68
|
#
|
69
69
|
|
70
|
-
def initialize(profile: nil, **
|
71
|
-
super(**
|
70
|
+
def initialize(profile: nil, **)
|
71
|
+
super(**)
|
72
72
|
|
73
73
|
@profile = profile
|
74
74
|
|
@@ -68,9 +68,9 @@ module Selenium
|
|
68
68
|
# @api private
|
69
69
|
#
|
70
70
|
|
71
|
-
def initialize(bridge: nil, listener: nil, **
|
71
|
+
def initialize(bridge: nil, listener: nil, **)
|
72
72
|
@devtools = nil
|
73
|
-
bridge ||= create_bridge(**
|
73
|
+
bridge ||= create_bridge(**)
|
74
74
|
@bridge = listener ? Support::EventFiringBridge.new(bridge, listener) : bridge
|
75
75
|
add_extensions(@bridge.browser)
|
76
76
|
end
|
@@ -131,8 +131,8 @@ module Selenium
|
|
131
131
|
# @see ActionBuilder
|
132
132
|
#
|
133
133
|
|
134
|
-
def action(**
|
135
|
-
bridge.action(**
|
134
|
+
def action(**)
|
135
|
+
bridge.action(**)
|
136
136
|
end
|
137
137
|
|
138
138
|
#
|
@@ -225,8 +225,8 @@ module Selenium
|
|
225
225
|
# The value returned from the script.
|
226
226
|
#
|
227
227
|
|
228
|
-
def execute_script(script, *
|
229
|
-
bridge.execute_script(script, *
|
228
|
+
def execute_script(script, *)
|
229
|
+
bridge.execute_script(script, *)
|
230
230
|
end
|
231
231
|
|
232
232
|
# Execute an asynchronous piece of JavaScript in the context of the
|
@@ -244,8 +244,8 @@ module Selenium
|
|
244
244
|
# @return [WebDriver::Element,Integer,Float,Boolean,NilClass,String,Array]
|
245
245
|
#
|
246
246
|
|
247
|
-
def execute_async_script(script, *
|
248
|
-
bridge.execute_async_script(script, *
|
247
|
+
def execute_async_script(script, *)
|
248
|
+
bridge.execute_async_script(script, *)
|
249
249
|
end
|
250
250
|
|
251
251
|
#
|
@@ -44,8 +44,8 @@ module Selenium
|
|
44
44
|
# @return [ActionBuilder] A self reference
|
45
45
|
#
|
46
46
|
|
47
|
-
def key_down(
|
48
|
-
key_action(
|
47
|
+
def key_down(*, device: nil)
|
48
|
+
key_action(*, action: :create_key_down, device: device)
|
49
49
|
end
|
50
50
|
|
51
51
|
#
|
@@ -71,8 +71,8 @@ module Selenium
|
|
71
71
|
# @return [ActionBuilder] A self reference
|
72
72
|
#
|
73
73
|
|
74
|
-
def key_up(
|
75
|
-
key_action(
|
74
|
+
def key_up(*, device: nil)
|
75
|
+
key_action(*, action: :create_key_up, device: device)
|
76
76
|
end
|
77
77
|
|
78
78
|
#
|
@@ -46,8 +46,8 @@ module Selenium
|
|
46
46
|
# @return [ActionBuilder] A self reference.
|
47
47
|
#
|
48
48
|
|
49
|
-
def pointer_down(button = :left, device: nil, **
|
50
|
-
button_action(button, :create_pointer_down, device: device, **
|
49
|
+
def pointer_down(button = :left, device: nil, **)
|
50
|
+
button_action(button, :create_pointer_down, device: device, **)
|
51
51
|
end
|
52
52
|
|
53
53
|
#
|
@@ -63,8 +63,8 @@ module Selenium
|
|
63
63
|
# @return [ActionBuilder] A self reference.
|
64
64
|
#
|
65
65
|
|
66
|
-
def pointer_up(button = :left, device: nil, **
|
67
|
-
button_action(button, :create_pointer_up, device: device, **
|
66
|
+
def pointer_up(button = :left, device: nil, **)
|
67
|
+
button_action(button, :create_pointer_up, device: device, **)
|
68
68
|
end
|
69
69
|
|
70
70
|
#
|
@@ -122,13 +122,13 @@ module Selenium
|
|
122
122
|
# @raise [MoveTargetOutOfBoundsError] if the provided offset is outside the document's boundaries.
|
123
123
|
#
|
124
124
|
|
125
|
-
def move_by(right_by, down_by, device: nil, duration: default_move_duration, **
|
125
|
+
def move_by(right_by, down_by, device: nil, duration: default_move_duration, **)
|
126
126
|
pointer = pointer_input(device)
|
127
127
|
pointer.create_pointer_move(duration: duration,
|
128
128
|
x: Integer(right_by),
|
129
129
|
y: Integer(down_by),
|
130
130
|
origin: Interactions::PointerMove::POINTER,
|
131
|
-
**
|
131
|
+
**)
|
132
132
|
tick(pointer)
|
133
133
|
self
|
134
134
|
end
|
@@ -150,13 +150,13 @@ module Selenium
|
|
150
150
|
# @raise [MoveTargetOutOfBoundsError] if the provided x or y value is outside the document's boundaries.
|
151
151
|
#
|
152
152
|
|
153
|
-
def move_to_location(x, y, device: nil, duration: default_move_duration, **
|
153
|
+
def move_to_location(x, y, device: nil, duration: default_move_duration, **)
|
154
154
|
pointer = pointer_input(device)
|
155
155
|
pointer.create_pointer_move(duration: duration,
|
156
156
|
x: Integer(x),
|
157
157
|
y: Integer(y),
|
158
158
|
origin: Interactions::PointerMove::VIEWPORT,
|
159
|
-
**
|
159
|
+
**)
|
160
160
|
tick(pointer)
|
161
161
|
self
|
162
162
|
end
|
@@ -336,9 +336,9 @@ module Selenium
|
|
336
336
|
|
337
337
|
private
|
338
338
|
|
339
|
-
def button_action(button, action, device: nil, **
|
339
|
+
def button_action(button, action, device: nil, **)
|
340
340
|
pointer = pointer_input(device)
|
341
|
-
pointer.send(action, button, **
|
341
|
+
pointer.send(action, button, **)
|
342
342
|
tick(pointer)
|
343
343
|
self
|
344
344
|
end
|
@@ -49,16 +49,16 @@ module Selenium
|
|
49
49
|
KIND[pointer]
|
50
50
|
end
|
51
51
|
|
52
|
-
def create_pointer_move(duration: 0, x: 0, y: 0, origin: nil, **
|
53
|
-
add_action(PointerMove.new(self, duration, x, y, origin: origin, **
|
52
|
+
def create_pointer_move(duration: 0, x: 0, y: 0, origin: nil, **)
|
53
|
+
add_action(PointerMove.new(self, duration, x, y, origin: origin, **))
|
54
54
|
end
|
55
55
|
|
56
|
-
def create_pointer_down(button, **
|
57
|
-
add_action(PointerPress.new(self, :down, button, **
|
56
|
+
def create_pointer_down(button, **)
|
57
|
+
add_action(PointerPress.new(self, :down, button, **))
|
58
58
|
end
|
59
59
|
|
60
|
-
def create_pointer_up(button, **
|
61
|
-
add_action(PointerPress.new(self, :up, button, **
|
60
|
+
def create_pointer_up(button, **)
|
61
|
+
add_action(PointerPress.new(self, :up, button, **))
|
62
62
|
end
|
63
63
|
|
64
64
|
def create_pointer_cancel
|
@@ -29,26 +29,26 @@ module Selenium
|
|
29
29
|
class << self
|
30
30
|
attr_reader :driver_path
|
31
31
|
|
32
|
-
def chrome(**
|
33
|
-
Chrome::Options.new(**
|
32
|
+
def chrome(**)
|
33
|
+
Chrome::Options.new(**)
|
34
34
|
end
|
35
35
|
|
36
|
-
def firefox(**
|
37
|
-
Firefox::Options.new(**
|
36
|
+
def firefox(**)
|
37
|
+
Firefox::Options.new(**)
|
38
38
|
end
|
39
39
|
|
40
|
-
def ie(**
|
41
|
-
IE::Options.new(**
|
40
|
+
def ie(**)
|
41
|
+
IE::Options.new(**)
|
42
42
|
end
|
43
43
|
alias internet_explorer ie
|
44
44
|
|
45
|
-
def edge(**
|
46
|
-
Edge::Options.new(**
|
45
|
+
def edge(**)
|
46
|
+
Edge::Options.new(**)
|
47
47
|
end
|
48
48
|
alias microsoftedge edge
|
49
49
|
|
50
|
-
def safari(**
|
51
|
-
Safari::Options.new(**
|
50
|
+
def safari(**)
|
51
|
+
Safari::Options.new(**)
|
52
52
|
end
|
53
53
|
|
54
54
|
def set_capabilities
|
@@ -28,27 +28,27 @@ module Selenium
|
|
28
28
|
class << self
|
29
29
|
attr_reader :driver_path
|
30
30
|
|
31
|
-
def chrome(**
|
32
|
-
Chrome::Service.new(**
|
31
|
+
def chrome(**)
|
32
|
+
Chrome::Service.new(**)
|
33
33
|
end
|
34
34
|
|
35
|
-
def firefox(**
|
36
|
-
Firefox::Service.new(**
|
35
|
+
def firefox(**)
|
36
|
+
Firefox::Service.new(**)
|
37
37
|
end
|
38
38
|
|
39
|
-
def ie(**
|
40
|
-
IE::Service.new(**
|
39
|
+
def ie(**)
|
40
|
+
IE::Service.new(**)
|
41
41
|
end
|
42
42
|
alias internet_explorer ie
|
43
43
|
|
44
|
-
def edge(**
|
45
|
-
Edge::Service.new(**
|
44
|
+
def edge(**)
|
45
|
+
Edge::Service.new(**)
|
46
46
|
end
|
47
47
|
alias microsoftedge edge
|
48
48
|
alias msedge edge
|
49
49
|
|
50
|
-
def safari(**
|
51
|
-
Safari::Service.new(**
|
50
|
+
def safari(**)
|
51
|
+
Safari::Service.new(**)
|
52
52
|
end
|
53
53
|
|
54
54
|
def driver_path=(path)
|
@@ -26,12 +26,12 @@ module Selenium
|
|
26
26
|
module WebDriver
|
27
27
|
class Credential
|
28
28
|
class << self
|
29
|
-
def resident(**
|
30
|
-
Credential.new(resident_credential: true, **
|
29
|
+
def resident(**)
|
30
|
+
Credential.new(resident_credential: true, **)
|
31
31
|
end
|
32
32
|
|
33
|
-
def non_resident(**
|
34
|
-
Credential.new(resident_credential: false, **
|
33
|
+
def non_resident(**)
|
34
|
+
Credential.new(resident_credential: false, **)
|
35
35
|
end
|
36
36
|
|
37
37
|
def encode(byte_array)
|
@@ -30,9 +30,9 @@ module Selenium
|
|
30
30
|
class Driver < Chromium::Driver
|
31
31
|
include LocalDriver
|
32
32
|
|
33
|
-
def initialize(options: nil, service: nil, url: nil, **
|
33
|
+
def initialize(options: nil, service: nil, url: nil, **)
|
34
34
|
caps, url = initialize_local_driver(options, service, url)
|
35
|
-
super(caps: caps, url: url, **
|
35
|
+
super(caps: caps, url: url, **)
|
36
36
|
end
|
37
37
|
|
38
38
|
def browser
|
@@ -36,9 +36,9 @@ module Selenium
|
|
36
36
|
|
37
37
|
include LocalDriver
|
38
38
|
|
39
|
-
def initialize(options: nil, service: nil, url: nil, **
|
39
|
+
def initialize(options: nil, service: nil, url: nil, **)
|
40
40
|
caps, url = initialize_local_driver(options, service, url)
|
41
|
-
super(caps: caps, url: url, **
|
41
|
+
super(caps: caps, url: url, **)
|
42
42
|
end
|
43
43
|
|
44
44
|
def browser
|
@@ -28,9 +28,9 @@ module Selenium
|
|
28
28
|
|
29
29
|
def initialize(path: nil, port: nil, log: nil, args: nil)
|
30
30
|
args ||= []
|
31
|
-
unless args.any? { |arg| arg.include?('--connect-existing') }
|
31
|
+
unless args.any? { |arg| arg.include?('--connect-existing') || arg.include?('--websocket-port') }
|
32
32
|
args << '--websocket-port'
|
33
|
-
args <<
|
33
|
+
args << '0'
|
34
34
|
end
|
35
35
|
super
|
36
36
|
end
|
@@ -31,9 +31,9 @@ module Selenium
|
|
31
31
|
|
32
32
|
include LocalDriver
|
33
33
|
|
34
|
-
def initialize(options: nil, service: nil, url: nil, **
|
34
|
+
def initialize(options: nil, service: nil, url: nil, **)
|
35
35
|
caps, url = initialize_local_driver(options, service, url)
|
36
|
-
super(caps: caps, url: url, **
|
36
|
+
super(caps: caps, url: url, **)
|
37
37
|
end
|
38
38
|
|
39
39
|
def browser
|
@@ -30,12 +30,12 @@ module Selenium
|
|
30
30
|
include DriverExtensions::HasSessionId
|
31
31
|
include DriverExtensions::HasFileDownloads
|
32
32
|
|
33
|
-
def initialize(capabilities: nil, options: nil, service: nil, url: nil, **
|
33
|
+
def initialize(capabilities: nil, options: nil, service: nil, url: nil, **)
|
34
34
|
raise ArgumentError, "Can not set :service object on #{self.class}" if service
|
35
35
|
|
36
36
|
url ||= "http://#{Platform.localhost}:4444/wd/hub"
|
37
37
|
caps = process_options(options, capabilities)
|
38
|
-
super(caps: caps, url: url, **
|
38
|
+
super(caps: caps, url: url, **)
|
39
39
|
@bridge.file_detector = ->((filename, *)) { File.exist?(filename) && filename.to_s }
|
40
40
|
command_list = @bridge.command_list
|
41
41
|
@bridge.extend(WebDriver::Remote::Features)
|
@@ -31,9 +31,9 @@ module Selenium
|
|
31
31
|
|
32
32
|
include LocalDriver
|
33
33
|
|
34
|
-
def initialize(options: nil, service: nil, url: nil, **
|
34
|
+
def initialize(options: nil, service: nil, url: nil, **)
|
35
35
|
caps, url = initialize_local_driver(options, service, url)
|
36
|
-
super(caps: caps, url: url, **
|
36
|
+
super(caps: caps, url: url, **)
|
37
37
|
end
|
38
38
|
|
39
39
|
def browser
|
@@ -25,8 +25,8 @@ module Selenium
|
|
25
25
|
@callback = callback
|
26
26
|
end
|
27
27
|
|
28
|
-
def method_missing(meth, *
|
29
|
-
@callback.call
|
28
|
+
def method_missing(meth, *) # rubocop:disable Style/MissingRespondToMissing
|
29
|
+
@callback.call(meth, *)
|
30
30
|
end
|
31
31
|
end # BlockEventListener
|
32
32
|
end # Support
|
@@ -112,10 +112,10 @@ module Selenium
|
|
112
112
|
@driver ||= Driver.new(bridge: self)
|
113
113
|
end
|
114
114
|
|
115
|
-
def dispatch(name, *
|
116
|
-
@listener.__send__(:"before_#{name}", *
|
115
|
+
def dispatch(name, *)
|
116
|
+
@listener.__send__(:"before_#{name}", *)
|
117
117
|
returned = yield
|
118
|
-
@listener.__send__(:"after_#{name}", *
|
118
|
+
@listener.__send__(:"after_#{name}", *)
|
119
119
|
|
120
120
|
returned
|
121
121
|
end
|
data/lib/selenium/webdriver.rb
CHANGED
@@ -21,7 +21,6 @@ require 'tmpdir'
|
|
21
21
|
require 'fileutils'
|
22
22
|
require 'date'
|
23
23
|
require 'json'
|
24
|
-
require 'set'
|
25
24
|
require 'uri'
|
26
25
|
require 'net/http'
|
27
26
|
|
@@ -85,8 +84,8 @@ module Selenium
|
|
85
84
|
# @see Selenium::WebDriver::Support::AbstractEventListener
|
86
85
|
#
|
87
86
|
|
88
|
-
def self.for(*
|
89
|
-
WebDriver::Driver.for(*
|
87
|
+
def self.for(*)
|
88
|
+
WebDriver::Driver.for(*)
|
90
89
|
end
|
91
90
|
|
92
91
|
#
|
@@ -95,9 +94,9 @@ module Selenium
|
|
95
94
|
# @return [Logger]
|
96
95
|
#
|
97
96
|
|
98
|
-
def self.logger(**
|
97
|
+
def self.logger(**)
|
99
98
|
level = $DEBUG || ENV.key?('DEBUG') ? :debug : :info
|
100
|
-
@logger ||= WebDriver::Logger.new('Selenium', default_level: level, **
|
99
|
+
@logger ||= WebDriver::Logger.new('Selenium', default_level: level, **)
|
101
100
|
end
|
102
101
|
end # WebDriver
|
103
102
|
end # Selenium
|
data/selenium-webdriver.gemspec
CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |s|
|
|
30
30
|
}
|
31
31
|
|
32
32
|
s.required_rubygems_version = Gem::Requirement.new('> 1.3.1') if s.respond_to? :required_rubygems_version=
|
33
|
-
s.required_ruby_version = Gem::Requirement.new('>= 3.
|
33
|
+
s.required_ruby_version = Gem::Requirement.new('>= 3.2')
|
34
34
|
|
35
35
|
s.files = [
|
36
36
|
'CHANGES',
|
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.
|
4
|
+
version: 4.33.0
|
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: 2025-05-
|
13
|
+
date: 2025-05-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: base64
|
@@ -475,14 +475,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
475
475
|
requirements:
|
476
476
|
- - ">="
|
477
477
|
- !ruby/object:Gem::Version
|
478
|
-
version: '3.
|
478
|
+
version: '3.2'
|
479
479
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
480
480
|
requirements:
|
481
481
|
- - ">"
|
482
482
|
- !ruby/object:Gem::Version
|
483
483
|
version: 1.3.1
|
484
484
|
requirements: []
|
485
|
-
rubygems_version: 3.
|
485
|
+
rubygems_version: 3.4.19
|
486
486
|
signing_key:
|
487
487
|
specification_version: 4
|
488
488
|
summary: Selenium is a browser automation tool for automated testing of webapps and
|