selenium-webdriver 4.0.0.alpha2 → 4.0.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 +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
|