selenium-webdriver 4.0.0.alpha2 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGES +338 -4
- data/Gemfile +3 -1
- data/LICENSE +1 -1
- data/NOTICE +2 -0
- data/README.md +4 -5
- data/lib/selenium/server.rb +21 -29
- data/lib/selenium/webdriver/atoms/findElements.js +122 -0
- data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
- data/lib/selenium/webdriver/atoms/isDisplayed.js +76 -78
- data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
- data/lib/selenium/webdriver/chrome/driver.rb +26 -56
- data/lib/selenium/webdriver/chrome/features.rb +106 -0
- data/lib/selenium/webdriver/chrome/options.rb +127 -52
- data/lib/selenium/webdriver/chrome/profile.rb +8 -5
- data/lib/selenium/webdriver/chrome/service.rb +4 -6
- data/lib/selenium/webdriver/chrome.rb +10 -9
- data/lib/selenium/webdriver/common/driver.rb +110 -19
- data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +51 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +77 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +38 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +45 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +43 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +38 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +144 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +30 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +17 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +136 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -11
- data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +77 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
- data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
- data/lib/selenium/webdriver/common/element.rb +79 -16
- data/lib/selenium/webdriver/common/error.rb +12 -0
- data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
- data/lib/selenium/webdriver/common/log_entry.rb +2 -2
- data/lib/selenium/webdriver/common/logger.rb +50 -15
- data/lib/selenium/webdriver/common/manager.rb +14 -14
- data/lib/selenium/webdriver/common/options.rb +186 -0
- data/lib/selenium/webdriver/common/platform.rb +6 -1
- data/lib/selenium/webdriver/common/port_prober.rb +4 -6
- data/lib/selenium/webdriver/common/profile_helper.rb +10 -2
- data/lib/selenium/webdriver/common/proxy.rb +6 -3
- data/lib/selenium/webdriver/common/search_context.rb +7 -3
- data/lib/selenium/webdriver/common/service.rb +23 -113
- data/lib/selenium/webdriver/common/service_manager.rb +151 -0
- data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
- data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
- data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
- data/lib/selenium/webdriver/common/target_locator.rb +32 -4
- data/lib/selenium/webdriver/common/timeouts.rb +31 -4
- data/lib/selenium/webdriver/common/wait.rb +1 -1
- data/lib/selenium/webdriver/common/window.rb +0 -4
- data/lib/selenium/webdriver/common.rb +17 -2
- data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
- data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
- data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
- data/lib/selenium/webdriver/{chrome/bridge.rb → devtools/pinned_script.rb} +26 -17
- data/lib/selenium/webdriver/devtools/request.rb +67 -0
- data/lib/selenium/webdriver/devtools/response.rb +66 -0
- data/lib/selenium/webdriver/devtools.rb +182 -0
- data/lib/selenium/webdriver/edge/driver.rb +5 -31
- data/lib/selenium/webdriver/edge/features.rb +44 -0
- data/lib/selenium/webdriver/edge/options.rb +11 -48
- data/lib/selenium/webdriver/edge/profile.rb +33 -0
- data/lib/selenium/webdriver/edge/service.rb +9 -24
- data/lib/selenium/webdriver/edge.rb +11 -13
- data/lib/selenium/webdriver/firefox/driver.rb +20 -30
- data/lib/selenium/webdriver/firefox/extension.rb +8 -0
- data/lib/selenium/webdriver/firefox/{bridge.rb → features.rb} +23 -4
- data/lib/selenium/webdriver/firefox/options.rb +70 -49
- data/lib/selenium/webdriver/firefox/profile.rb +16 -77
- data/lib/selenium/webdriver/firefox/service.rb +1 -5
- data/lib/selenium/webdriver/firefox.rb +22 -16
- data/lib/selenium/webdriver/ie/driver.rb +1 -34
- data/lib/selenium/webdriver/ie/options.rb +13 -44
- data/lib/selenium/webdriver/ie/service.rb +9 -11
- data/lib/selenium/webdriver/ie.rb +8 -7
- data/lib/selenium/webdriver/remote/bridge.rb +112 -86
- data/lib/selenium/webdriver/remote/capabilities.rb +120 -62
- data/lib/selenium/webdriver/remote/commands.rb +7 -0
- data/lib/selenium/webdriver/remote/driver.rb +15 -12
- data/lib/selenium/webdriver/remote/http/common.rb +0 -5
- data/lib/selenium/webdriver/remote/http/default.rb +17 -11
- data/lib/selenium/webdriver/remote/http/persistent.rb +11 -6
- data/lib/selenium/webdriver/remote.rb +15 -9
- data/lib/selenium/webdriver/safari/driver.rb +3 -34
- data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +6 -6
- data/lib/selenium/webdriver/safari/options.rb +10 -29
- data/lib/selenium/webdriver/safari/service.rb +0 -4
- data/lib/selenium/webdriver/safari.rb +16 -8
- data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
- data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
- data/lib/selenium/webdriver/support/cdp_client_generator.rb +108 -0
- data/lib/selenium/webdriver/support/color.rb +2 -2
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
- data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
- data/lib/selenium/webdriver/support/guards/guard_condition.rb +52 -0
- data/lib/selenium/webdriver/support/guards.rb +95 -0
- data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
- data/lib/selenium/webdriver/support/select.rb +2 -2
- data/lib/selenium/webdriver/support.rb +1 -0
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +10 -8
- data/selenium-webdriver.gemspec +29 -13
- metadata +125 -51
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
- data/lib/selenium/webdriver/firefox/binary.rb +0 -110
- data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
@@ -21,42 +21,48 @@ require 'timeout'
|
|
21
21
|
require 'socket'
|
22
22
|
require 'rexml/document'
|
23
23
|
|
24
|
-
require 'selenium/webdriver/firefox/driver'
|
25
|
-
|
26
|
-
require 'selenium/webdriver/firefox/extension'
|
27
|
-
require 'selenium/webdriver/firefox/binary'
|
28
|
-
require 'selenium/webdriver/firefox/profiles_ini'
|
29
|
-
require 'selenium/webdriver/firefox/profile'
|
30
|
-
require 'selenium/webdriver/firefox/bridge'
|
31
|
-
require 'selenium/webdriver/firefox/driver'
|
32
|
-
require 'selenium/webdriver/firefox/options'
|
33
|
-
|
34
24
|
module Selenium
|
35
25
|
module WebDriver
|
36
26
|
module Firefox
|
27
|
+
autoload :Extension, 'selenium/webdriver/firefox/extension'
|
28
|
+
autoload :ProfilesIni, 'selenium/webdriver/firefox/profiles_ini'
|
29
|
+
autoload :Profile, 'selenium/webdriver/firefox/profile'
|
30
|
+
autoload :Features, 'selenium/webdriver/firefox/features'
|
31
|
+
autoload :Driver, 'selenium/webdriver/firefox/driver'
|
32
|
+
autoload :Options, 'selenium/webdriver/firefox/options'
|
33
|
+
autoload :Service, 'selenium/webdriver/firefox/service'
|
34
|
+
|
37
35
|
DEFAULT_PORT = 7055
|
38
|
-
DEFAULT_ENABLE_NATIVE_EVENTS = Platform.os == :windows
|
39
36
|
DEFAULT_SECURE_SSL = false
|
40
37
|
DEFAULT_ASSUME_UNTRUSTED_ISSUER = true
|
41
38
|
DEFAULT_LOAD_NO_FOCUS_LIB = false
|
42
39
|
|
40
|
+
# Mozilla Automation Team asked to only support 85
|
41
|
+
# until WebDriver Bidi is available.
|
42
|
+
DEVTOOLS_VERSION = 85
|
43
|
+
|
43
44
|
def self.driver_path=(path)
|
44
45
|
WebDriver.logger.deprecate 'Selenium::WebDriver::Firefox#driver_path=',
|
45
|
-
'Selenium::WebDriver::Firefox::Service#driver_path='
|
46
|
+
'Selenium::WebDriver::Firefox::Service#driver_path=',
|
47
|
+
id: :driver_path
|
46
48
|
Selenium::WebDriver::Firefox::Service.driver_path = path
|
47
49
|
end
|
48
50
|
|
49
51
|
def self.driver_path
|
50
52
|
WebDriver.logger.deprecate 'Selenium::WebDriver::Firefox#driver_path',
|
51
|
-
'Selenium::WebDriver::Firefox::Service#driver_path'
|
53
|
+
'Selenium::WebDriver::Firefox::Service#driver_path',
|
54
|
+
id: :driver_path
|
52
55
|
Selenium::WebDriver::Firefox::Service.driver_path
|
53
56
|
end
|
54
57
|
|
55
58
|
def self.path=(path)
|
56
|
-
|
59
|
+
Platform.assert_executable path
|
60
|
+
@path = path
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.path
|
64
|
+
@path ||= nil
|
57
65
|
end
|
58
66
|
end # Firefox
|
59
67
|
end # WebDriver
|
60
68
|
end # Selenium
|
61
|
-
|
62
|
-
require 'selenium/webdriver/firefox/service'
|
@@ -28,44 +28,11 @@ module Selenium
|
|
28
28
|
#
|
29
29
|
|
30
30
|
class Driver < WebDriver::Driver
|
31
|
-
|
32
|
-
include DriverExtensions::TakesScreenshot
|
33
|
-
|
34
|
-
def initialize(opts = {})
|
35
|
-
opts[:desired_capabilities] = create_capabilities(opts)
|
36
|
-
|
37
|
-
opts[:url] ||= service_url(opts)
|
38
|
-
|
39
|
-
listener = opts.delete(:listener)
|
40
|
-
desired_capabilities = opts.delete(:desired_capabilities)
|
41
|
-
|
42
|
-
@bridge = Remote::Bridge.new(opts)
|
43
|
-
@bridge.create_session(desired_capabilities)
|
44
|
-
|
45
|
-
super(@bridge, listener: listener)
|
46
|
-
end
|
31
|
+
EXTENSIONS = [DriverExtensions::HasWebStorage].freeze
|
47
32
|
|
48
33
|
def browser
|
49
34
|
:internet_explorer
|
50
35
|
end
|
51
|
-
|
52
|
-
def quit
|
53
|
-
super
|
54
|
-
ensure
|
55
|
-
@service&.stop
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def create_capabilities(opts)
|
61
|
-
caps = opts.delete(:desired_capabilities) { Remote::Capabilities.internet_explorer }
|
62
|
-
options = opts.delete(:options) { Options.new }
|
63
|
-
options = options.as_json
|
64
|
-
caps.merge!(options) unless options.empty?
|
65
|
-
|
66
|
-
caps
|
67
|
-
end
|
68
|
-
|
69
36
|
end # Driver
|
70
37
|
end # IE
|
71
38
|
end # WebDriver
|
@@ -20,7 +20,7 @@
|
|
20
20
|
module Selenium
|
21
21
|
module WebDriver
|
22
22
|
module IE
|
23
|
-
class Options
|
23
|
+
class Options < WebDriver::Options
|
24
24
|
KEY = 'se:ieOptions'
|
25
25
|
SCROLL_TOP = 0
|
26
26
|
SCROLL_BOTTOM = 1
|
@@ -39,20 +39,13 @@ module Selenium
|
|
39
39
|
persistent_hover: 'enablePersistentHover',
|
40
40
|
require_window_focus: 'requireWindowFocus',
|
41
41
|
use_per_process_proxy: 'ie.usePerProcessProxy',
|
42
|
-
|
42
|
+
use_legacy_file_upload_dialog_handling: 'ie.useLegacyFileUploadDialogHandling',
|
43
|
+
attach_to_edge_chrome: 'ie.edgechromium',
|
44
|
+
edge_executable_path: 'ie.edgepath'
|
43
45
|
}.freeze
|
46
|
+
BROWSER = 'internet explorer'
|
44
47
|
|
45
|
-
|
46
|
-
define_method key do
|
47
|
-
@options[key]
|
48
|
-
end
|
49
|
-
|
50
|
-
define_method "#{key}=" do |value|
|
51
|
-
@options[key] = value
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
attr_reader :args, :options
|
48
|
+
attr_reader :args
|
56
49
|
|
57
50
|
#
|
58
51
|
# Create a new Options instance
|
@@ -86,8 +79,9 @@ module Selenium
|
|
86
79
|
#
|
87
80
|
|
88
81
|
def initialize(**opts)
|
89
|
-
@args =
|
90
|
-
|
82
|
+
@args = (opts.delete(:args) || []).to_set
|
83
|
+
super(**opts)
|
84
|
+
|
91
85
|
@options[:native_events] = true if @options[:native_events].nil?
|
92
86
|
end
|
93
87
|
|
@@ -101,36 +95,11 @@ module Selenium
|
|
101
95
|
@args << arg
|
102
96
|
end
|
103
97
|
|
104
|
-
|
105
|
-
# Add a new option not yet handled by these bindings.
|
106
|
-
#
|
107
|
-
# @example
|
108
|
-
# options = Selenium::WebDriver::IE::Options.new
|
109
|
-
# options.add_option(:foo, 'bar')
|
110
|
-
#
|
111
|
-
# @param [String, Symbol] name Name of the option
|
112
|
-
# @param [Boolean, String, Integer] value Value of the option
|
113
|
-
#
|
114
|
-
|
115
|
-
def add_option(name, value)
|
116
|
-
@options[name] = value
|
117
|
-
end
|
118
|
-
|
119
|
-
#
|
120
|
-
# @api private
|
121
|
-
#
|
122
|
-
|
123
|
-
def as_json(*)
|
124
|
-
opts = {}
|
125
|
-
|
126
|
-
CAPABILITIES.each do |capability_alias, capability_name|
|
127
|
-
capability_value = @options.delete(capability_alias)
|
128
|
-
opts[capability_name] = capability_value unless capability_value.nil?
|
129
|
-
end
|
130
|
-
opts['ie.browserCommandLineSwitches'] = @args.to_a.join(' ') if @args.any?
|
131
|
-
opts.merge!(@options)
|
98
|
+
private
|
132
99
|
|
133
|
-
|
100
|
+
def process_browser_options(browser_options)
|
101
|
+
options = browser_options[KEY]
|
102
|
+
options['ie.browserCommandLineSwitches'] = @args.to_a.join(' ') if @args.any?
|
134
103
|
end
|
135
104
|
end # Options
|
136
105
|
end # IE
|
@@ -20,31 +20,29 @@
|
|
20
20
|
module Selenium
|
21
21
|
module WebDriver
|
22
22
|
module IE
|
23
|
-
#
|
24
|
-
# @api private
|
25
|
-
#
|
26
|
-
|
27
23
|
class Service < WebDriver::Service
|
28
24
|
DEFAULT_PORT = 5555
|
29
25
|
EXECUTABLE = 'IEDriverServer'
|
30
26
|
MISSING_TEXT = <<~ERROR
|
31
27
|
Unable to find IEDriverServer. Please download the server from
|
32
|
-
|
28
|
+
https://www.selenium.dev/downloads/ and place it somewhere on your PATH.
|
33
29
|
More info at https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver.
|
34
30
|
ERROR
|
35
31
|
SHUTDOWN_SUPPORTED = true
|
36
32
|
|
37
33
|
private
|
38
34
|
|
39
|
-
#
|
35
|
+
# NOTE: This processing is deprecated
|
40
36
|
def extract_service_args(driver_opts)
|
41
37
|
driver_args = super
|
42
38
|
driver_opts = driver_opts.dup
|
43
|
-
driver_args << "--log-level=#{driver_opts
|
44
|
-
driver_args << "--log-file=#{driver_opts
|
45
|
-
|
46
|
-
|
47
|
-
|
39
|
+
driver_args << "--log-level=#{driver_opts[:log_level].to_s.upcase}" if driver_opts.key?(:log_level)
|
40
|
+
driver_args << "--log-file=#{driver_opts[:log_file]}" if driver_opts.key?(:log_file)
|
41
|
+
if driver_opts.key?(:implementation)
|
42
|
+
driver_args << "--implementation=#{driver_opts[:implementation].to_s.upcase}"
|
43
|
+
end
|
44
|
+
driver_args << "--host=#{driver_opts[:host]}" if driver_opts.key?(:host)
|
45
|
+
driver_args << "--extract_path=#{driver_opts[:extract_path]}" if driver_opts.key?(:extract_path)
|
48
46
|
driver_args << "--silent" if driver_opts[:silent] == true
|
49
47
|
driver_args
|
50
48
|
end
|
@@ -17,25 +17,26 @@
|
|
17
17
|
# specific language governing permissions and limitations
|
18
18
|
# under the License.
|
19
19
|
|
20
|
-
require 'selenium/webdriver/ie/driver'
|
21
|
-
require 'selenium/webdriver/ie/options'
|
22
|
-
|
23
20
|
module Selenium
|
24
21
|
module WebDriver
|
25
22
|
module IE
|
23
|
+
autoload :Driver, 'selenium/webdriver/ie/driver'
|
24
|
+
autoload :Options, 'selenium/webdriver/ie/options'
|
25
|
+
autoload :Service, 'selenium/webdriver/ie/service'
|
26
|
+
|
26
27
|
def self.driver_path=(path)
|
27
28
|
WebDriver.logger.deprecate 'Selenium::WebDriver::IE#driver_path=',
|
28
|
-
'Selenium::WebDriver::IE::Service#driver_path='
|
29
|
+
'Selenium::WebDriver::IE::Service#driver_path=',
|
30
|
+
id: :driver_path
|
29
31
|
Selenium::WebDriver::IE::Service.driver_path = path
|
30
32
|
end
|
31
33
|
|
32
34
|
def self.driver_path
|
33
35
|
WebDriver.logger.deprecate 'Selenium::WebDriver::IE#driver_path',
|
34
|
-
'Selenium::WebDriver::IE::Service#driver_path'
|
36
|
+
'Selenium::WebDriver::IE::Service#driver_path',
|
37
|
+
id: :driver_path
|
35
38
|
Selenium::WebDriver::IE::Service.driver_path
|
36
39
|
end
|
37
40
|
end # IE
|
38
41
|
end # WebDriver
|
39
42
|
end # Selenium
|
40
|
-
|
41
|
-
require 'selenium/webdriver/ie/service'
|
@@ -25,35 +25,22 @@ module Selenium
|
|
25
25
|
|
26
26
|
PORT = 4444
|
27
27
|
|
28
|
-
attr_accessor :
|
28
|
+
attr_accessor :http, :file_detector
|
29
29
|
attr_reader :capabilities
|
30
30
|
|
31
31
|
#
|
32
32
|
# Initializes the bridge with the given server URL
|
33
|
-
# @param [
|
34
|
-
# @
|
35
|
-
# @option opts [Object] :http_client an HTTP client instance that implements the same protocol as Http::Default
|
36
|
-
# @option opts [Capabilities] :desired_capabilities an instance of Remote::Capabilities describing the capabilities you want
|
33
|
+
# @param [String, URI] :url url for the remote server
|
34
|
+
# @param [Object] :http_client an HTTP client instance that implements the same protocol as Http::Default
|
37
35
|
# @api private
|
38
36
|
#
|
39
37
|
|
40
|
-
def initialize(
|
41
|
-
opts = opts.dup
|
42
|
-
|
43
|
-
http_client = opts.delete(:http_client) { Http::Default.new }
|
44
|
-
url = opts.delete(:url) { "http://#{Platform.localhost}:#{PORT}/wd/hub" }
|
45
|
-
opts.delete(:options)
|
46
|
-
|
47
|
-
unless opts.empty?
|
48
|
-
raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
|
49
|
-
end
|
50
|
-
|
38
|
+
def initialize(url:, http_client: nil)
|
51
39
|
uri = url.is_a?(URI) ? url : URI.parse(url)
|
52
|
-
uri.path += '/' unless
|
40
|
+
uri.path += '/' unless uri.path.end_with?('/')
|
53
41
|
|
54
|
-
|
55
|
-
|
56
|
-
@http = http_client
|
42
|
+
@http = http_client || Http::Default.new
|
43
|
+
@http.server_url = uri
|
57
44
|
@file_detector = nil
|
58
45
|
end
|
59
46
|
|
@@ -61,8 +48,8 @@ module Selenium
|
|
61
48
|
# Creates session.
|
62
49
|
#
|
63
50
|
|
64
|
-
def create_session(
|
65
|
-
response = execute(:new_session, {},
|
51
|
+
def create_session(capabilities)
|
52
|
+
response = execute(:new_session, {}, prepare_capabilities_payload(capabilities))
|
66
53
|
|
67
54
|
@session_id = response['sessionId']
|
68
55
|
capabilities = response['capabilities']
|
@@ -70,6 +57,17 @@ module Selenium
|
|
70
57
|
raise Error::WebDriverError, 'no sessionId in returned payload' unless @session_id
|
71
58
|
|
72
59
|
@capabilities = Capabilities.json_create(capabilities)
|
60
|
+
|
61
|
+
case @capabilities[:browser_name]
|
62
|
+
when 'chrome'
|
63
|
+
extend(WebDriver::Chrome::Features)
|
64
|
+
when 'firefox'
|
65
|
+
extend(WebDriver::Firefox::Features)
|
66
|
+
when 'msedge'
|
67
|
+
extend(WebDriver::Edge::Features)
|
68
|
+
when 'Safari', 'Safari Technology Preview'
|
69
|
+
extend(WebDriver::Safari::Features)
|
70
|
+
end
|
73
71
|
end
|
74
72
|
|
75
73
|
#
|
@@ -83,7 +81,7 @@ module Selenium
|
|
83
81
|
def browser
|
84
82
|
@browser ||= begin
|
85
83
|
name = @capabilities.browser_name
|
86
|
-
name ? name.tr(' ', '_').to_sym : 'unknown'
|
84
|
+
name ? name.tr(' ', '_').downcase.to_sym : 'unknown'
|
87
85
|
end
|
88
86
|
end
|
89
87
|
|
@@ -95,17 +93,16 @@ module Selenium
|
|
95
93
|
execute :get, {}, {url: url}
|
96
94
|
end
|
97
95
|
|
98
|
-
|
99
|
-
|
100
|
-
|
96
|
+
#
|
97
|
+
# timeouts
|
98
|
+
#
|
101
99
|
|
102
|
-
def
|
103
|
-
|
100
|
+
def timeouts
|
101
|
+
execute :get_timeouts, {}
|
104
102
|
end
|
105
103
|
|
106
|
-
def
|
107
|
-
|
108
|
-
execute :set_timeout, {}, {type => milliseconds}
|
104
|
+
def timeouts=(timeouts)
|
105
|
+
execute :set_timeout, {}, timeouts
|
109
106
|
end
|
110
107
|
|
111
108
|
#
|
@@ -220,7 +217,10 @@ module Selenium
|
|
220
217
|
end
|
221
218
|
|
222
219
|
def window_size(handle = :current)
|
223
|
-
|
220
|
+
unless handle == :current
|
221
|
+
raise Error::UnsupportedOperationError,
|
222
|
+
'Switch to desired window before getting its size'
|
223
|
+
end
|
224
224
|
|
225
225
|
data = execute :get_window_rect
|
226
226
|
Dimension.new data['width'], data['height']
|
@@ -231,7 +231,10 @@ module Selenium
|
|
231
231
|
end
|
232
232
|
|
233
233
|
def maximize_window(handle = :current)
|
234
|
-
|
234
|
+
unless handle == :current
|
235
|
+
raise Error::UnsupportedOperationError,
|
236
|
+
'Switch to desired window before changing its size'
|
237
|
+
end
|
235
238
|
|
236
239
|
execute :maximize_window
|
237
240
|
end
|
@@ -264,6 +267,10 @@ module Selenium
|
|
264
267
|
execute :take_screenshot
|
265
268
|
end
|
266
269
|
|
270
|
+
def element_screenshot(element)
|
271
|
+
execute :take_element_screenshot, id: element
|
272
|
+
end
|
273
|
+
|
267
274
|
#
|
268
275
|
# HTML 5
|
269
276
|
#
|
@@ -316,22 +323,6 @@ module Selenium
|
|
316
323
|
execute_script('return sessionStorage.length')
|
317
324
|
end
|
318
325
|
|
319
|
-
def location
|
320
|
-
raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting location'
|
321
|
-
end
|
322
|
-
|
323
|
-
def set_location(_lat, _lon, _alt)
|
324
|
-
raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting location'
|
325
|
-
end
|
326
|
-
|
327
|
-
def network_connection
|
328
|
-
raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting network connection'
|
329
|
-
end
|
330
|
-
|
331
|
-
def network_connection=(_type)
|
332
|
-
raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting network connection'
|
333
|
-
end
|
334
|
-
|
335
326
|
#
|
336
327
|
# javascript execution
|
337
328
|
#
|
@@ -402,6 +393,10 @@ module Selenium
|
|
402
393
|
execute :release_actions
|
403
394
|
end
|
404
395
|
|
396
|
+
def print_page(options = {})
|
397
|
+
execute :print_page, {}, {options: options}
|
398
|
+
end
|
399
|
+
|
405
400
|
def click_element(element)
|
406
401
|
execute :element_click, id: element
|
407
402
|
end
|
@@ -435,20 +430,12 @@ module Selenium
|
|
435
430
|
end
|
436
431
|
|
437
432
|
def submit_element(element)
|
438
|
-
form = find_element_by('xpath', "./ancestor-or-self::form", element)
|
433
|
+
form = find_element_by('xpath', "./ancestor-or-self::form", [:element, element])
|
439
434
|
execute_script("var e = arguments[0].ownerDocument.createEvent('Event');" \
|
440
435
|
"e.initEvent('submit', true, true);" \
|
441
436
|
'if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }', form.as_json)
|
442
437
|
end
|
443
438
|
|
444
|
-
def screen_orientation=(orientation)
|
445
|
-
execute :set_screen_orientation, {}, {orientation: orientation}
|
446
|
-
end
|
447
|
-
|
448
|
-
def screen_orientation
|
449
|
-
execute :get_screen_orientation
|
450
|
-
end
|
451
|
-
|
452
439
|
#
|
453
440
|
# element properties
|
454
441
|
#
|
@@ -462,8 +449,20 @@ module Selenium
|
|
462
449
|
execute_atom :getAttribute, element, name
|
463
450
|
end
|
464
451
|
|
452
|
+
def element_dom_attribute(element, name)
|
453
|
+
execute :get_element_attribute, id: element, name: name
|
454
|
+
end
|
455
|
+
|
465
456
|
def element_property(element, name)
|
466
|
-
execute :get_element_property, id: element
|
457
|
+
execute :get_element_property, id: element, name: name
|
458
|
+
end
|
459
|
+
|
460
|
+
def element_aria_role(element)
|
461
|
+
execute :get_element_aria_role, id: element
|
462
|
+
end
|
463
|
+
|
464
|
+
def element_aria_label(element)
|
465
|
+
execute :get_element_aria_label, id: element
|
467
466
|
end
|
468
467
|
|
469
468
|
def element_value(element)
|
@@ -524,29 +523,47 @@ module Selenium
|
|
524
523
|
|
525
524
|
alias_method :switch_to_active_element, :active_element
|
526
525
|
|
527
|
-
def find_element_by(how, what,
|
528
|
-
how, what =
|
526
|
+
def find_element_by(how, what, parent_ref = [])
|
527
|
+
how, what = convert_locator(how, what)
|
528
|
+
|
529
|
+
return execute_atom(:findElements, Support::RelativeLocator.new(what).as_json).first if how == 'relative'
|
529
530
|
|
530
|
-
|
531
|
-
|
531
|
+
parent_type, parent_id = parent_ref
|
532
|
+
id = case parent_type
|
533
|
+
when :element
|
534
|
+
execute :find_child_element, {id: parent_id}, {using: how, value: what.to_s}
|
535
|
+
when :shadow_root
|
536
|
+
execute :find_shadow_child_element, {id: parent_id}, {using: how, value: what.to_s}
|
532
537
|
else
|
533
|
-
execute :find_element, {}, {using: how, value: what}
|
538
|
+
execute :find_element, {}, {using: how, value: what.to_s}
|
534
539
|
end
|
540
|
+
|
535
541
|
Element.new self, element_id_from(id)
|
536
542
|
end
|
537
543
|
|
538
|
-
def find_elements_by(how, what,
|
539
|
-
how, what =
|
544
|
+
def find_elements_by(how, what, parent_ref = [])
|
545
|
+
how, what = convert_locator(how, what)
|
540
546
|
|
541
|
-
|
542
|
-
|
547
|
+
return execute_atom :findElements, Support::RelativeLocator.new(what).as_json if how == 'relative'
|
548
|
+
|
549
|
+
parent_type, parent_id = parent_ref
|
550
|
+
ids = case parent_type
|
551
|
+
when :element
|
552
|
+
execute :find_child_elements, {id: parent_id}, {using: how, value: what.to_s}
|
553
|
+
when :shadow_root
|
554
|
+
execute :find_shadow_child_elements, {id: parent_id}, {using: how, value: what.to_s}
|
543
555
|
else
|
544
|
-
execute :find_elements, {}, {using: how, value: what}
|
556
|
+
execute :find_elements, {}, {using: how, value: what.to_s}
|
545
557
|
end
|
546
558
|
|
547
559
|
ids.map { |id| Element.new self, element_id_from(id) }
|
548
560
|
end
|
549
561
|
|
562
|
+
def shadow_root(element)
|
563
|
+
id = execute :get_element_shadow_root, id: element
|
564
|
+
ShadowRoot.new self, shadow_root_id_from(id)
|
565
|
+
end
|
566
|
+
|
550
567
|
private
|
551
568
|
|
552
569
|
#
|
@@ -579,16 +596,6 @@ module Selenium
|
|
579
596
|
COMMANDS[command]
|
580
597
|
end
|
581
598
|
|
582
|
-
def merged_capabilities(capabilities, options = nil)
|
583
|
-
capabilities.merge!(options.as_json) if options
|
584
|
-
|
585
|
-
{
|
586
|
-
capabilities: {
|
587
|
-
firstMatch: [capabilities]
|
588
|
-
}
|
589
|
-
}
|
590
|
-
end
|
591
|
-
|
592
599
|
def unwrap_script_result(arg)
|
593
600
|
case arg
|
594
601
|
when Array
|
@@ -604,34 +611,53 @@ module Selenium
|
|
604
611
|
end
|
605
612
|
|
606
613
|
def element_id_from(id)
|
607
|
-
id['ELEMENT'] || id[
|
614
|
+
id['ELEMENT'] || id[Element::ELEMENT_KEY]
|
615
|
+
end
|
616
|
+
|
617
|
+
def shadow_root_id_from(id)
|
618
|
+
id[ShadowRoot::ROOT_KEY]
|
619
|
+
end
|
620
|
+
|
621
|
+
def prepare_capabilities_payload(capabilities)
|
622
|
+
capabilities = {alwaysMatch: capabilities} if !capabilities['alwaysMatch'] && !capabilities['firstMatch']
|
623
|
+
{capabilities: capabilities}
|
608
624
|
end
|
609
625
|
|
610
|
-
def
|
626
|
+
def convert_locator(how, what)
|
627
|
+
how = SearchContext::FINDERS[how.to_sym] || how
|
628
|
+
|
611
629
|
case how
|
612
630
|
when 'class name'
|
613
631
|
how = 'css selector'
|
614
|
-
what = ".#{escape_css(what)}"
|
632
|
+
what = ".#{escape_css(what.to_s)}"
|
615
633
|
when 'id'
|
616
634
|
how = 'css selector'
|
617
|
-
what = "##{escape_css(what)}"
|
635
|
+
what = "##{escape_css(what.to_s)}"
|
618
636
|
when 'name'
|
619
637
|
how = 'css selector'
|
620
|
-
what = "*[name='#{escape_css(what)}']"
|
638
|
+
what = "*[name='#{escape_css(what.to_s)}']"
|
621
639
|
when 'tag name'
|
622
640
|
how = 'css selector'
|
623
641
|
end
|
642
|
+
|
643
|
+
if what.is_a?(Hash)
|
644
|
+
what = what.each_with_object({}) do |(h, w), hash|
|
645
|
+
h, w = convert_locator(h.to_s, w)
|
646
|
+
hash[h] = w
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
624
650
|
[how, what]
|
625
651
|
end
|
626
652
|
|
627
|
-
ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]
|
653
|
+
ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]()])/.freeze
|
628
654
|
UNICODE_CODE_POINT = 30
|
629
655
|
|
630
656
|
# Escapes invalid characters in CSS selector.
|
631
657
|
# @see https://mathiasbynens.be/notes/css-escapes
|
632
658
|
def escape_css(string)
|
633
659
|
string = string.gsub(ESCAPE_CSS_REGEXP) { |match| "\\#{match}" }
|
634
|
-
string = "\\#{UNICODE_CODE_POINT + Integer(string[0])} #{string[1
|
660
|
+
string = "\\#{UNICODE_CODE_POINT + Integer(string[0])} #{string[1..]}" if string[0]&.match?(/[[:digit:]]/)
|
635
661
|
|
636
662
|
string
|
637
663
|
end
|