selenium-webdriver 4.20.1 → 4.21.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 +12 -0
- 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/server.rb +2 -1
- data/lib/selenium/webdriver/common/search_context.rb +10 -2
- data/lib/selenium/webdriver/remote/bridge/locator_converter.rb +76 -0
- data/lib/selenium/webdriver/remote/bridge.rb +32 -46
- data/lib/selenium/webdriver/remote/http/common.rb +21 -3
- data/lib/selenium/webdriver/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f5e5266f21804cd7520e61a6036171a3bda203460d944ac61cfd324283f72ae
|
4
|
+
data.tar.gz: 8a58672a580239e27c909e781b16ff588f216f535dda5e495eff5123224e36b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78473145c4ce27a7acf22c58e6c204f7beac53b47a3b18139bb895c08c5d1da90ec5ac558bab429f5284604bba717415be0d8606bb298a68278a22a57947a546
|
7
|
+
data.tar.gz: b1ae030703351b2b799881b041c9554e0c23c8cfc60a6e8eb32e7f679a7ea23f1c72c7cdbca203b2830439e2488a1ff56c6763df960f8eb873f08356f79ccf91
|
data/CHANGES
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
4.21.0 (2024-05-16)
|
2
|
+
=========================
|
3
|
+
|
4
|
+
* Add CDP for Chrome 125 and remove 122
|
5
|
+
* Initial extensibility points for Appium
|
6
|
+
* Support registering extra headers in HTTP client
|
7
|
+
* Support overriding User-Agent in HTTP client
|
8
|
+
* Support registering extra bridge commands
|
9
|
+
* Support overriding default locator conversion
|
10
|
+
* Support registering custom finders for SearchContext
|
11
|
+
* Support using custom element classes
|
12
|
+
|
1
13
|
4.20.1 (2024-04-25)
|
2
14
|
=========================
|
3
15
|
|
data/bin/linux/selenium-manager
CHANGED
Binary file
|
data/bin/macos/selenium-manager
CHANGED
Binary file
|
Binary file
|
data/lib/selenium/server.rb
CHANGED
@@ -183,6 +183,7 @@ module Selenium
|
|
183
183
|
def initialize(jar, opts = {})
|
184
184
|
raise Errno::ENOENT, jar unless File.exist?(jar)
|
185
185
|
|
186
|
+
@java = opts.fetch(:java, 'java')
|
186
187
|
@jar = jar
|
187
188
|
@host = '127.0.0.1'
|
188
189
|
@role = opts.fetch(:role, 'standalone')
|
@@ -241,7 +242,7 @@ module Selenium
|
|
241
242
|
# extract any additional_args that start with -D as options
|
242
243
|
properties = @additional_args.dup - @additional_args.delete_if { |arg| arg[/^-D/] }
|
243
244
|
args = ['-jar', @jar, @role, '--port', @port.to_s]
|
244
|
-
server_command = [
|
245
|
+
server_command = [@java] + properties + args + @additional_args
|
245
246
|
cp = WebDriver::ChildProcess.build(*server_command)
|
246
247
|
|
247
248
|
if @log.is_a?(String)
|
@@ -35,6 +35,14 @@ module Selenium
|
|
35
35
|
xpath: 'xpath'
|
36
36
|
}.freeze
|
37
37
|
|
38
|
+
class << self
|
39
|
+
attr_accessor :extra_finders
|
40
|
+
|
41
|
+
def finders
|
42
|
+
FINDERS.merge(extra_finders || {})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
38
46
|
#
|
39
47
|
# Find the first element matching the given arguments
|
40
48
|
#
|
@@ -57,7 +65,7 @@ module Selenium
|
|
57
65
|
def find_element(*args)
|
58
66
|
how, what = extract_args(args)
|
59
67
|
|
60
|
-
by =
|
68
|
+
by = SearchContext.finders[how.to_sym]
|
61
69
|
raise ArgumentError, "cannot find element by #{how.inspect}" unless by
|
62
70
|
|
63
71
|
bridge.find_element_by by, what, ref
|
@@ -72,7 +80,7 @@ module Selenium
|
|
72
80
|
def find_elements(*args)
|
73
81
|
how, what = extract_args(args)
|
74
82
|
|
75
|
-
by =
|
83
|
+
by = SearchContext.finders[how.to_sym]
|
76
84
|
raise ArgumentError, "cannot find elements by #{how.inspect}" unless by
|
77
85
|
|
78
86
|
bridge.find_elements_by by, what, ref
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Licensed to the Software Freedom Conservancy (SFC) under one
|
4
|
+
# or more contributor license agreements. See the NOTICE file
|
5
|
+
# distributed with this work for additional information
|
6
|
+
# regarding copyright ownership. The SFC licenses this file
|
7
|
+
# to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance
|
9
|
+
# with the License. You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing,
|
14
|
+
# software distributed under the License is distributed on an
|
15
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
16
|
+
# KIND, either express or implied. See the License for the
|
17
|
+
# specific language governing permissions and limitations
|
18
|
+
# under the License.
|
19
|
+
|
20
|
+
module Selenium
|
21
|
+
module WebDriver
|
22
|
+
module Remote
|
23
|
+
class Bridge
|
24
|
+
class LocatorConverter
|
25
|
+
ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]()])/
|
26
|
+
UNICODE_CODE_POINT = 30
|
27
|
+
|
28
|
+
#
|
29
|
+
# Converts a locator to a specification compatible one.
|
30
|
+
# @param [String, Symbol] how
|
31
|
+
# @param [String] what
|
32
|
+
#
|
33
|
+
|
34
|
+
def convert(how, what)
|
35
|
+
how = SearchContext.finders[how.to_sym] || how
|
36
|
+
|
37
|
+
case how
|
38
|
+
when 'class name'
|
39
|
+
how = 'css selector'
|
40
|
+
what = ".#{escape_css(what.to_s)}"
|
41
|
+
when 'id'
|
42
|
+
how = 'css selector'
|
43
|
+
what = "##{escape_css(what.to_s)}"
|
44
|
+
when 'name'
|
45
|
+
how = 'css selector'
|
46
|
+
what = "*[name='#{escape_css(what.to_s)}']"
|
47
|
+
end
|
48
|
+
|
49
|
+
if what.is_a?(Hash)
|
50
|
+
what = what.each_with_object({}) do |(h, w), hash|
|
51
|
+
h, w = convert(h.to_s, w)
|
52
|
+
hash[h] = w
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
[how, what]
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
#
|
62
|
+
# Escapes invalid characters in CSS selector.
|
63
|
+
# @see https://mathiasbynens.be/notes/css-escapes
|
64
|
+
#
|
65
|
+
|
66
|
+
def escape_css(string)
|
67
|
+
string = string.gsub(ESCAPE_CSS_REGEXP) { |match| "\\#{match}" }
|
68
|
+
string = "\\#{UNICODE_CODE_POINT + Integer(string[0])} #{string[1..]}" if string[0]&.match?(/[[:digit:]]/)
|
69
|
+
|
70
|
+
string
|
71
|
+
end
|
72
|
+
end # LocatorConverter
|
73
|
+
end # Bridge
|
74
|
+
end # Remote
|
75
|
+
end # WebDriver
|
76
|
+
end # Selenium
|
@@ -22,6 +22,8 @@ module Selenium
|
|
22
22
|
module Remote
|
23
23
|
class Bridge
|
24
24
|
autoload :COMMANDS, 'selenium/webdriver/remote/bridge/commands'
|
25
|
+
autoload :LocatorConverter, 'selenium/webdriver/remote/bridge/locator_converter'
|
26
|
+
|
25
27
|
include Atoms
|
26
28
|
|
27
29
|
PORT = 4444
|
@@ -29,6 +31,25 @@ module Selenium
|
|
29
31
|
attr_accessor :http, :file_detector
|
30
32
|
attr_reader :capabilities
|
31
33
|
|
34
|
+
class << self
|
35
|
+
attr_reader :extra_commands
|
36
|
+
attr_writer :element_class, :locator_converter
|
37
|
+
|
38
|
+
def add_command(name, verb, url, &block)
|
39
|
+
@extra_commands ||= {}
|
40
|
+
@extra_commands[name] = [verb, url]
|
41
|
+
define_method(name, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def locator_converter
|
45
|
+
@locator_converter ||= LocatorConverter.new
|
46
|
+
end
|
47
|
+
|
48
|
+
def element_class
|
49
|
+
@element_class ||= Element
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
32
53
|
#
|
33
54
|
# Initializes the bridge with the given server URL
|
34
55
|
# @param [String, URI] url url for the remote server
|
@@ -43,6 +64,8 @@ module Selenium
|
|
43
64
|
@http = http_client || Http::Default.new
|
44
65
|
@http.server_url = uri
|
45
66
|
@file_detector = nil
|
67
|
+
|
68
|
+
@locator_converter = self.class.locator_converter
|
46
69
|
end
|
47
70
|
|
48
71
|
#
|
@@ -413,7 +436,7 @@ module Selenium
|
|
413
436
|
"e.initEvent('submit', true, true);\n" \
|
414
437
|
"if (form.dispatchEvent(e)) { HTMLFormElement.prototype.submit.call(form) }\n"
|
415
438
|
|
416
|
-
execute_script(script,
|
439
|
+
execute_script(script, Bridge.element_class::ELEMENT_KEY => element)
|
417
440
|
rescue Error::JavascriptError
|
418
441
|
raise Error::UnsupportedOperationError, 'To submit an element, it must be nested inside a form element'
|
419
442
|
end
|
@@ -500,13 +523,13 @@ module Selenium
|
|
500
523
|
#
|
501
524
|
|
502
525
|
def active_element
|
503
|
-
|
526
|
+
Bridge.element_class.new self, element_id_from(execute(:get_active_element))
|
504
527
|
end
|
505
528
|
|
506
529
|
alias switch_to_active_element active_element
|
507
530
|
|
508
531
|
def find_element_by(how, what, parent_ref = [])
|
509
|
-
how, what =
|
532
|
+
how, what = @locator_converter.convert(how, what)
|
510
533
|
|
511
534
|
return execute_atom(:findElements, Support::RelativeLocator.new(what).as_json).first if how == 'relative'
|
512
535
|
|
@@ -520,11 +543,11 @@ module Selenium
|
|
520
543
|
execute :find_element, {}, {using: how, value: what.to_s}
|
521
544
|
end
|
522
545
|
|
523
|
-
|
546
|
+
Bridge.element_class.new self, element_id_from(id)
|
524
547
|
end
|
525
548
|
|
526
549
|
def find_elements_by(how, what, parent_ref = [])
|
527
|
-
how, what =
|
550
|
+
how, what = @locator_converter.convert(how, what)
|
528
551
|
|
529
552
|
return execute_atom :findElements, Support::RelativeLocator.new(what).as_json if how == 'relative'
|
530
553
|
|
@@ -538,7 +561,7 @@ module Selenium
|
|
538
561
|
execute :find_elements, {}, {using: how, value: what.to_s}
|
539
562
|
end
|
540
563
|
|
541
|
-
ids.map { |id|
|
564
|
+
ids.map { |id| Bridge.element_class.new self, element_id_from(id) }
|
542
565
|
end
|
543
566
|
|
544
567
|
def shadow_root(element)
|
@@ -612,7 +635,7 @@ module Selenium
|
|
612
635
|
end
|
613
636
|
|
614
637
|
def commands(command)
|
615
|
-
command_list[command]
|
638
|
+
command_list[command] || Bridge.extra_commands[command]
|
616
639
|
end
|
617
640
|
|
618
641
|
def unwrap_script_result(arg)
|
@@ -621,7 +644,7 @@ module Selenium
|
|
621
644
|
arg.map { |e| unwrap_script_result(e) }
|
622
645
|
when Hash
|
623
646
|
element_id = element_id_from(arg)
|
624
|
-
return
|
647
|
+
return Bridge.element_class.new(self, element_id) if element_id
|
625
648
|
|
626
649
|
shadow_root_id = shadow_root_id_from(arg)
|
627
650
|
return ShadowRoot.new self, shadow_root_id if shadow_root_id
|
@@ -633,7 +656,7 @@ module Selenium
|
|
633
656
|
end
|
634
657
|
|
635
658
|
def element_id_from(id)
|
636
|
-
id['ELEMENT'] || id[
|
659
|
+
id['ELEMENT'] || id[Bridge.element_class::ELEMENT_KEY]
|
637
660
|
end
|
638
661
|
|
639
662
|
def shadow_root_id_from(id)
|
@@ -644,43 +667,6 @@ module Selenium
|
|
644
667
|
capabilities = {alwaysMatch: capabilities} if !capabilities['alwaysMatch'] && !capabilities['firstMatch']
|
645
668
|
{capabilities: capabilities}
|
646
669
|
end
|
647
|
-
|
648
|
-
def convert_locator(how, what)
|
649
|
-
how = SearchContext::FINDERS[how.to_sym] || how
|
650
|
-
|
651
|
-
case how
|
652
|
-
when 'class name'
|
653
|
-
how = 'css selector'
|
654
|
-
what = ".#{escape_css(what.to_s)}"
|
655
|
-
when 'id'
|
656
|
-
how = 'css selector'
|
657
|
-
what = "##{escape_css(what.to_s)}"
|
658
|
-
when 'name'
|
659
|
-
how = 'css selector'
|
660
|
-
what = "*[name='#{escape_css(what.to_s)}']"
|
661
|
-
end
|
662
|
-
|
663
|
-
if what.is_a?(Hash)
|
664
|
-
what = what.each_with_object({}) do |(h, w), hash|
|
665
|
-
h, w = convert_locator(h.to_s, w)
|
666
|
-
hash[h] = w
|
667
|
-
end
|
668
|
-
end
|
669
|
-
|
670
|
-
[how, what]
|
671
|
-
end
|
672
|
-
|
673
|
-
ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]()])/
|
674
|
-
UNICODE_CODE_POINT = 30
|
675
|
-
|
676
|
-
# Escapes invalid characters in CSS selector.
|
677
|
-
# @see https://mathiasbynens.be/notes/css-escapes
|
678
|
-
def escape_css(string)
|
679
|
-
string = string.gsub(ESCAPE_CSS_REGEXP) { |match| "\\#{match}" }
|
680
|
-
string = "\\#{UNICODE_CODE_POINT + Integer(string[0])} #{string[1..]}" if string[0]&.match?(/[[:digit:]]/)
|
681
|
-
|
682
|
-
string
|
683
|
-
end
|
684
670
|
end # Bridge
|
685
671
|
end # Remote
|
686
672
|
end # WebDriver
|
@@ -26,10 +26,18 @@ module Selenium
|
|
26
26
|
CONTENT_TYPE = 'application/json'
|
27
27
|
DEFAULT_HEADERS = {
|
28
28
|
'Accept' => CONTENT_TYPE,
|
29
|
-
'Content-Type' => "#{CONTENT_TYPE}; charset=UTF-8"
|
30
|
-
'User-Agent' => "selenium/#{WebDriver::VERSION} (ruby #{Platform.os})"
|
29
|
+
'Content-Type' => "#{CONTENT_TYPE}; charset=UTF-8"
|
31
30
|
}.freeze
|
32
31
|
|
32
|
+
class << self
|
33
|
+
attr_accessor :extra_headers
|
34
|
+
attr_writer :user_agent
|
35
|
+
|
36
|
+
def user_agent
|
37
|
+
@user_agent ||= "selenium/#{WebDriver::VERSION} (ruby #{Platform.os})"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
33
41
|
attr_writer :server_url
|
34
42
|
|
35
43
|
def quit_errors
|
@@ -42,7 +50,7 @@ module Selenium
|
|
42
50
|
|
43
51
|
def call(verb, url, command_hash)
|
44
52
|
url = server_url.merge(url) unless url.is_a?(URI)
|
45
|
-
headers =
|
53
|
+
headers = common_headers.dup
|
46
54
|
headers['Cache-Control'] = 'no-cache' if verb == :get
|
47
55
|
|
48
56
|
if command_hash
|
@@ -61,6 +69,16 @@ module Selenium
|
|
61
69
|
|
62
70
|
private
|
63
71
|
|
72
|
+
def common_headers
|
73
|
+
@common_headers ||= begin
|
74
|
+
headers = DEFAULT_HEADERS.dup
|
75
|
+
headers['User-Agent'] = Common.user_agent
|
76
|
+
headers = headers.merge(Common.extra_headers || {})
|
77
|
+
|
78
|
+
headers
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
64
82
|
def server_url
|
65
83
|
return @server_url if @server_url
|
66
84
|
|
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.21.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: 2024-
|
13
|
+
date: 2024-05-16 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: base64
|
@@ -395,6 +395,7 @@ files:
|
|
395
395
|
- lib/selenium/webdriver/remote.rb
|
396
396
|
- lib/selenium/webdriver/remote/bridge.rb
|
397
397
|
- lib/selenium/webdriver/remote/bridge/commands.rb
|
398
|
+
- lib/selenium/webdriver/remote/bridge/locator_converter.rb
|
398
399
|
- lib/selenium/webdriver/remote/capabilities.rb
|
399
400
|
- lib/selenium/webdriver/remote/driver.rb
|
400
401
|
- lib/selenium/webdriver/remote/features.rb
|