selenium-webdriver 3.142.7 → 4.0.3
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 +350 -5
- data/Gemfile +3 -1
- data/LICENSE +1 -1
- data/NOTICE +2 -0
- data/README.md +4 -5
- data/lib/selenium/server.rb +69 -63
- 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 -83
- data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +50 -12
- data/lib/selenium/webdriver/chrome/options.rb +129 -58
- data/lib/selenium/webdriver/chrome/profile.rb +6 -3
- data/lib/selenium/webdriver/chrome/service.rb +8 -15
- data/lib/selenium/webdriver/chrome.rb +10 -9
- data/lib/selenium/webdriver/common/action_builder.rb +97 -249
- data/lib/selenium/webdriver/common/driver.rb +112 -23
- 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_touch_screen.rb → has_cdp.rb} +10 -8
- data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +45 -0
- data/lib/selenium/webdriver/{firefox/util.rb → common/driver_extensions/has_devtools.rb} +16 -19
- 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 +82 -22
- data/lib/selenium/webdriver/common/error.rb +32 -196
- data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -5
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +13 -13
- 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 +15 -15
- data/lib/selenium/webdriver/common/options.rb +154 -23
- 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 +11 -9
- 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 +17 -125
- 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/socket_poller.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/zipper.rb +1 -9
- data/lib/selenium/webdriver/common.rb +23 -17
- 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/devtools/pinned_script.rb +59 -0
- 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 +7 -29
- data/lib/selenium/webdriver/edge/features.rb +44 -0
- data/lib/selenium/webdriver/edge/options.rb +11 -48
- data/lib/selenium/webdriver/{common/w3c_manager.rb → edge/profile.rb} +7 -19
- data/lib/selenium/webdriver/edge/service.rb +10 -26
- data/lib/selenium/webdriver/edge.rb +11 -14
- data/lib/selenium/webdriver/firefox/driver.rb +31 -19
- data/lib/selenium/webdriver/firefox/extension.rb +8 -0
- data/lib/selenium/webdriver/firefox/features.rb +66 -0
- data/lib/selenium/webdriver/firefox/options.rb +70 -49
- data/lib/selenium/webdriver/firefox/profile.rb +21 -71
- data/lib/selenium/webdriver/firefox/service.rb +5 -9
- data/lib/selenium/webdriver/firefox.rb +22 -20
- data/lib/selenium/webdriver/ie/driver.rb +1 -47
- data/lib/selenium/webdriver/ie/options.rb +13 -44
- data/lib/selenium/webdriver/ie/service.rb +13 -15
- data/lib/selenium/webdriver/ie.rb +8 -7
- data/lib/selenium/webdriver/remote/bridge.rb +558 -86
- data/lib/selenium/webdriver/remote/capabilities.rb +159 -123
- data/lib/selenium/webdriver/remote/commands.rb +163 -0
- data/lib/selenium/webdriver/remote/driver.rb +22 -12
- data/lib/selenium/webdriver/remote/http/common.rb +0 -5
- data/lib/selenium/webdriver/remote/http/default.rb +17 -20
- data/lib/selenium/webdriver/remote/http/persistent.rb +11 -6
- data/lib/selenium/webdriver/remote/response.rb +16 -47
- data/lib/selenium/webdriver/remote.rb +15 -13
- data/lib/selenium/webdriver/safari/driver.rb +3 -31
- data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
- data/lib/selenium/webdriver/safari/options.rb +10 -29
- data/lib/selenium/webdriver/safari/service.rb +4 -8
- data/lib/selenium/webdriver/safari.rb +17 -9
- 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/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +22 -19
- 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 +3 -3
- data/lib/selenium/webdriver/support.rb +1 -0
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +12 -12
- data/selenium-webdriver.gemspec +28 -12
- metadata +128 -69
- data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
- data/lib/selenium/webdriver/common/keyboard.rb +0 -70
- data/lib/selenium/webdriver/common/mouse.rb +0 -89
- data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
- data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
- data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
- data/lib/selenium/webdriver/edge/bridge.rb +0 -76
- data/lib/selenium/webdriver/firefox/binary.rb +0 -187
- data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
- data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
- data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
- data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
- data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
- data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
- data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
- data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
- data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
- data/lib/selenium/webdriver/remote/w3c/commands.rb +0 -157
|
@@ -28,8 +28,7 @@ module Selenium
|
|
|
28
28
|
class Default < Common
|
|
29
29
|
attr_writer :proxy
|
|
30
30
|
|
|
31
|
-
attr_accessor :open_timeout
|
|
32
|
-
attr_accessor :read_timeout
|
|
31
|
+
attr_accessor :open_timeout, :read_timeout
|
|
33
32
|
|
|
34
33
|
# Initializes object.
|
|
35
34
|
# Warning: Setting {#open_timeout} to non-nil values will cause a separate thread to spawn.
|
|
@@ -39,15 +38,7 @@ module Selenium
|
|
|
39
38
|
def initialize(open_timeout: nil, read_timeout: nil)
|
|
40
39
|
@open_timeout = open_timeout
|
|
41
40
|
@read_timeout = read_timeout
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
# Maintaining backward compatibility.
|
|
45
|
-
# @param [Numeric] value - Timeout in seconds to apply to both open timeout and read timeouts.
|
|
46
|
-
# @deprecated Please set the specific desired timeout {#read_timeout} or {#open_timeout} directly.
|
|
47
|
-
def timeout=(value)
|
|
48
|
-
WebDriver.logger.deprecate ':timeout=', '#read_timeout= and #open_timeout='
|
|
49
|
-
self.open_timeout = value
|
|
50
|
-
self.read_timeout = value
|
|
41
|
+
super()
|
|
51
42
|
end
|
|
52
43
|
|
|
53
44
|
def close
|
|
@@ -64,14 +55,18 @@ module Selenium
|
|
|
64
55
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
65
56
|
end
|
|
66
57
|
|
|
67
|
-
|
|
68
|
-
http.open_timeout = open_timeout
|
|
58
|
+
http.open_timeout = open_timeout if open_timeout
|
|
69
59
|
http.read_timeout = read_timeout if read_timeout
|
|
70
60
|
|
|
71
|
-
http
|
|
61
|
+
start(http)
|
|
62
|
+
http
|
|
72
63
|
end
|
|
73
64
|
end
|
|
74
65
|
|
|
66
|
+
def start(http)
|
|
67
|
+
http.start
|
|
68
|
+
end
|
|
69
|
+
|
|
75
70
|
MAX_RETRIES = 3
|
|
76
71
|
|
|
77
72
|
def request(verb, url, headers, payload, redirects = 0)
|
|
@@ -93,15 +88,15 @@ module Selenium
|
|
|
93
88
|
retries += 1
|
|
94
89
|
sleep 2
|
|
95
90
|
retry
|
|
96
|
-
rescue Errno::EADDRNOTAVAIL =>
|
|
91
|
+
rescue Errno::EADDRNOTAVAIL => e
|
|
97
92
|
# a retry is sometimes needed when the port becomes temporarily unavailable
|
|
98
93
|
raise if retries >= MAX_RETRIES
|
|
99
94
|
|
|
100
95
|
retries += 1
|
|
101
96
|
sleep 2
|
|
102
97
|
retry
|
|
103
|
-
rescue Errno::ECONNREFUSED =>
|
|
104
|
-
raise
|
|
98
|
+
rescue Errno::ECONNREFUSED => e
|
|
99
|
+
raise e.class, "using proxy: #{proxy.http}" if use_proxy?
|
|
105
100
|
|
|
106
101
|
raise
|
|
107
102
|
end
|
|
@@ -132,12 +127,14 @@ module Selenium
|
|
|
132
127
|
def new_http_client
|
|
133
128
|
if use_proxy?
|
|
134
129
|
url = @proxy.http
|
|
135
|
-
|
|
130
|
+
unless proxy.respond_to?(:http) && url
|
|
131
|
+
raise Error::WebDriverError,
|
|
132
|
+
"expected HTTP proxy, got #{@proxy.inspect}"
|
|
133
|
+
end
|
|
136
134
|
|
|
137
135
|
proxy = URI.parse(url)
|
|
138
136
|
|
|
139
|
-
|
|
140
|
-
clazz.new(server_url.host, server_url.port)
|
|
137
|
+
Net::HTTP.new(server_url.host, server_url.port, proxy.host, proxy.port, proxy.user, proxy.password)
|
|
141
138
|
else
|
|
142
139
|
Net::HTTP.new server_url.host, server_url.port
|
|
143
140
|
end
|
|
@@ -25,12 +25,22 @@ module Selenium
|
|
|
25
25
|
module Http
|
|
26
26
|
# @api private
|
|
27
27
|
class Persistent < Default
|
|
28
|
+
def initialize(open_timeout: nil, read_timeout: nil)
|
|
29
|
+
WebDriver.logger.deprecate("Selenium::WebDriver::Remote::Http::Persistent",
|
|
30
|
+
id: :http_persistent) { "The default HTTP client now uses persistence." }
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
|
|
28
34
|
def close
|
|
29
35
|
@http&.shutdown
|
|
30
36
|
end
|
|
31
37
|
|
|
32
38
|
private
|
|
33
39
|
|
|
40
|
+
def start(*)
|
|
41
|
+
# no need to explicitly start connection
|
|
42
|
+
end
|
|
43
|
+
|
|
34
44
|
def new_http_client
|
|
35
45
|
proxy = nil
|
|
36
46
|
|
|
@@ -42,12 +52,7 @@ module Selenium
|
|
|
42
52
|
proxy = URI.parse(url)
|
|
43
53
|
end
|
|
44
54
|
|
|
45
|
-
|
|
46
|
-
Net::HTTP::Persistent.new name: 'webdriver', proxy: proxy
|
|
47
|
-
else
|
|
48
|
-
WebDriver.logger.warn 'Support for this version of net-http-persistent is deprecated. Please upgrade.'
|
|
49
|
-
Net::HTTP::Persistent.new 'webdriver', proxy
|
|
50
|
-
end
|
|
55
|
+
Net::HTTP::Persistent.new name: 'webdriver', proxy: proxy
|
|
51
56
|
end
|
|
52
57
|
|
|
53
58
|
def response_for(request)
|
|
@@ -20,12 +20,13 @@
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
22
|
module Remote
|
|
23
|
+
|
|
24
|
+
#
|
|
23
25
|
# @api private
|
|
24
|
-
|
|
25
|
-
STACKTRACE_KEY = 'stackTrace'
|
|
26
|
+
#
|
|
26
27
|
|
|
28
|
+
class Response
|
|
27
29
|
attr_reader :code, :payload
|
|
28
|
-
attr_writer :payload
|
|
29
30
|
|
|
30
31
|
def initialize(code, payload = nil)
|
|
31
32
|
@code = code
|
|
@@ -35,33 +36,16 @@ module Selenium
|
|
|
35
36
|
end
|
|
36
37
|
|
|
37
38
|
def error
|
|
38
|
-
|
|
39
|
+
error, message, backtrace = process_error
|
|
40
|
+
klass = Error.for_error(error) || return
|
|
39
41
|
|
|
40
|
-
ex = klass.new(
|
|
42
|
+
ex = klass.new(message)
|
|
41
43
|
ex.set_backtrace(caller)
|
|
42
|
-
add_backtrace ex
|
|
44
|
+
add_backtrace ex, backtrace
|
|
43
45
|
|
|
44
46
|
ex
|
|
45
47
|
end
|
|
46
48
|
|
|
47
|
-
def error_message
|
|
48
|
-
val = value
|
|
49
|
-
|
|
50
|
-
case val
|
|
51
|
-
when Hash
|
|
52
|
-
msg = val['message']
|
|
53
|
-
return 'unknown error' unless msg
|
|
54
|
-
|
|
55
|
-
msg << ": #{val['alert']['text'].inspect}" if val['alert'].is_a?(Hash) && val['alert']['text']
|
|
56
|
-
msg << " (#{val['class']})" if val['class']
|
|
57
|
-
msg
|
|
58
|
-
when String
|
|
59
|
-
val
|
|
60
|
-
else
|
|
61
|
-
"unknown error, status=#{status}: #{val.inspect}"
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
49
|
def [](key)
|
|
66
50
|
@payload[key]
|
|
67
51
|
end
|
|
@@ -76,14 +60,7 @@ module Selenium
|
|
|
76
60
|
raise Error::ServerError, self
|
|
77
61
|
end
|
|
78
62
|
|
|
79
|
-
def add_backtrace(ex)
|
|
80
|
-
return unless error_payload.is_a?(Hash)
|
|
81
|
-
|
|
82
|
-
# Legacy Firefox returns String in ['value'], while we expect Hash.
|
|
83
|
-
# Use #dig when Firefox legacy is removed (4.0).
|
|
84
|
-
server_trace = error_payload[STACKTRACE_KEY] ||
|
|
85
|
-
error_payload[STACKTRACE_KEY.downcase] ||
|
|
86
|
-
(error_payload['value'] && error_payload['value'][STACKTRACE_KEY])
|
|
63
|
+
def add_backtrace(ex, server_trace)
|
|
87
64
|
return unless server_trace
|
|
88
65
|
|
|
89
66
|
backtrace = case server_trace
|
|
@@ -113,22 +90,14 @@ module Selenium
|
|
|
113
90
|
}.compact
|
|
114
91
|
end
|
|
115
92
|
|
|
116
|
-
def
|
|
117
|
-
|
|
118
|
-
# Grab 'value' key for error, leave original payload alone and let the bridge process
|
|
119
|
-
@error_payload ||= !@payload.key?('sessionId') ? @payload['value'] : @payload
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def status
|
|
123
|
-
return unless error_payload.is_a? Hash
|
|
124
|
-
|
|
125
|
-
@status ||= error_payload['status'] || error_payload['error']
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def value
|
|
129
|
-
return unless error_payload.is_a? Hash
|
|
93
|
+
def process_error
|
|
94
|
+
return unless self['value'].is_a?(Hash)
|
|
130
95
|
|
|
131
|
-
|
|
96
|
+
[
|
|
97
|
+
self['value']['error'],
|
|
98
|
+
self['value']['message'],
|
|
99
|
+
self['value']['stacktrace']
|
|
100
|
+
]
|
|
132
101
|
end
|
|
133
102
|
end # Response
|
|
134
103
|
end # Remote
|
|
@@ -18,18 +18,20 @@
|
|
|
18
18
|
# under the License.
|
|
19
19
|
|
|
20
20
|
require 'uri'
|
|
21
|
-
|
|
22
|
-
require 'selenium/webdriver/remote/bridge'
|
|
23
|
-
require 'selenium/webdriver/remote/driver'
|
|
24
|
-
require 'selenium/webdriver/remote/response'
|
|
25
21
|
require 'selenium/webdriver/remote/server_error'
|
|
26
|
-
require 'selenium/webdriver/remote/http/common'
|
|
27
|
-
require 'selenium/webdriver/remote/http/default'
|
|
28
|
-
|
|
29
|
-
require 'selenium/webdriver/remote/capabilities'
|
|
30
|
-
require 'selenium/webdriver/remote/oss/bridge'
|
|
31
|
-
require 'selenium/webdriver/remote/oss/commands'
|
|
32
22
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
module Selenium
|
|
24
|
+
module WebDriver
|
|
25
|
+
module Remote
|
|
26
|
+
autoload :Bridge, 'selenium/webdriver/remote/bridge'
|
|
27
|
+
autoload :Driver, 'selenium/webdriver/remote/driver'
|
|
28
|
+
autoload :Response, 'selenium/webdriver/remote/response'
|
|
29
|
+
autoload :Capabilities, 'selenium/webdriver/remote/capabilities'
|
|
30
|
+
autoload :COMMANDS, 'selenium/webdriver/remote/commands'
|
|
31
|
+
module Http
|
|
32
|
+
autoload :Common, 'selenium/webdriver/remote/http/common'
|
|
33
|
+
autoload :Default, 'selenium/webdriver/remote/http/default'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -27,41 +27,13 @@ module Selenium
|
|
|
27
27
|
#
|
|
28
28
|
|
|
29
29
|
class Driver < WebDriver::Driver
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
@bridge = Remote::Bridge.handshake(**opts)
|
|
41
|
-
@bridge.extend Bridge
|
|
42
|
-
|
|
43
|
-
super(@bridge, listener: listener)
|
|
44
|
-
end
|
|
30
|
+
EXTENSIONS = [DriverExtensions::HasDebugger,
|
|
31
|
+
DriverExtensions::HasApplePermissions,
|
|
32
|
+
DriverExtensions::HasWebStorage].freeze
|
|
45
33
|
|
|
46
34
|
def browser
|
|
47
35
|
:safari
|
|
48
36
|
end
|
|
49
|
-
|
|
50
|
-
def quit
|
|
51
|
-
super
|
|
52
|
-
ensure
|
|
53
|
-
@service&.stop
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
private
|
|
57
|
-
|
|
58
|
-
def create_capabilities(opts = {})
|
|
59
|
-
caps = opts.delete(:desired_capabilities) { Remote::Capabilities.safari }
|
|
60
|
-
options = opts.delete(:options) { Options.new }
|
|
61
|
-
caps.merge!(options.as_json)
|
|
62
|
-
caps
|
|
63
|
-
end
|
|
64
|
-
|
|
65
37
|
end # Driver
|
|
66
38
|
end # Safari
|
|
67
39
|
end # WebDriver
|
|
@@ -20,17 +20,17 @@
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
22
|
module Safari
|
|
23
|
-
module
|
|
23
|
+
module Features
|
|
24
24
|
|
|
25
25
|
# https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/WebDriverEndpointDoc/Commands/Commands.html
|
|
26
|
-
|
|
26
|
+
SAFARI_COMMANDS = {
|
|
27
27
|
get_permissions: [:get, 'session/:session_id/apple/permissions'],
|
|
28
28
|
set_permissions: [:post, 'session/:session_id/apple/permissions'],
|
|
29
29
|
attach_debugger: [:post, 'session/:session_id/apple/attach_debugger']
|
|
30
30
|
}.freeze
|
|
31
31
|
|
|
32
32
|
def commands(command)
|
|
33
|
-
|
|
33
|
+
SAFARI_COMMANDS[command] || self.class::COMMANDS[command]
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def permissions
|
|
@@ -20,40 +20,21 @@
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
22
|
module Safari
|
|
23
|
-
class Options
|
|
24
|
-
attr_accessor :
|
|
23
|
+
class Options < WebDriver::Options
|
|
24
|
+
attr_accessor :options
|
|
25
25
|
|
|
26
|
-
#
|
|
27
|
-
# Create a new Options instance for W3C-capable versions of Safari.
|
|
28
|
-
#
|
|
29
|
-
# @example
|
|
30
|
-
# options = Selenium::WebDriver::Safari::Options.new(automatic_inspection: true)
|
|
31
|
-
# driver = Selenium::WebDriver.for :safari, options: options
|
|
32
|
-
#
|
|
33
|
-
# @param [Hash] opts the pre-defined options to create the Safari::Options with
|
|
34
|
-
# @option opts [Boolean] :automatic_inspection Preloads Web Inspector and JavaScript debugger. Default is false
|
|
35
|
-
# @option opts [Boolean] :automatic_profiling Preloads Web Inspector and starts a timeline recording. Default is false
|
|
36
|
-
#
|
|
37
26
|
# @see https://developer.apple.com/documentation/webkit/about_webdriver_for_safari
|
|
38
|
-
|
|
27
|
+
CAPABILITIES = {automatic_inspection: 'safari:automaticInspection',
|
|
28
|
+
automatic_profiling: 'safari:automaticProfiling'}.freeze
|
|
29
|
+
BROWSER = 'safari'
|
|
39
30
|
|
|
40
|
-
def
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
#
|
|
46
|
-
# @api private
|
|
47
|
-
#
|
|
48
|
-
|
|
49
|
-
def as_json(*)
|
|
50
|
-
opts = {}
|
|
31
|
+
def add_option(name, value = nil)
|
|
32
|
+
key = name.is_a?(Hash) ? name.keys.first : name
|
|
33
|
+
raise ArgumentError, 'Safari does not support options that are not namespaced' unless key.to_s.include?(':')
|
|
51
34
|
|
|
52
|
-
|
|
53
|
-
opts['safari:automaticProfiling'] = true if @automatic_profiling
|
|
54
|
-
|
|
55
|
-
opts
|
|
35
|
+
super
|
|
56
36
|
end
|
|
37
|
+
|
|
57
38
|
end # Options
|
|
58
39
|
end # Safari
|
|
59
40
|
end # WebDriver
|
|
@@ -20,18 +20,14 @@
|
|
|
20
20
|
module Selenium
|
|
21
21
|
module WebDriver
|
|
22
22
|
module Safari
|
|
23
|
-
#
|
|
24
|
-
# @api private
|
|
25
|
-
#
|
|
26
|
-
|
|
27
23
|
class Service < WebDriver::Service
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
DEFAULT_PORT = 7050
|
|
25
|
+
EXECUTABLE = 'safaridriver'
|
|
26
|
+
MISSING_TEXT = <<~ERROR
|
|
31
27
|
Unable to find Apple's safaridriver which comes with Safari 10.
|
|
32
28
|
More info at https://webkit.org/blog/6900/webdriver-support-in-safari-10/
|
|
33
29
|
ERROR
|
|
34
|
-
|
|
30
|
+
SHUTDOWN_SUPPORTED = false
|
|
35
31
|
end # Service
|
|
36
32
|
end # Safari
|
|
37
33
|
end # WebDriver
|
|
@@ -17,20 +17,28 @@
|
|
|
17
17
|
# specific language governing permissions and limitations
|
|
18
18
|
# under the License.
|
|
19
19
|
|
|
20
|
-
require 'selenium/webdriver/safari/bridge'
|
|
21
|
-
require 'selenium/webdriver/safari/driver'
|
|
22
|
-
require 'selenium/webdriver/safari/options'
|
|
23
|
-
|
|
24
20
|
module Selenium
|
|
25
21
|
module WebDriver
|
|
26
22
|
module Safari
|
|
23
|
+
autoload :Features, 'selenium/webdriver/safari/features'
|
|
24
|
+
autoload :Driver, 'selenium/webdriver/safari/driver'
|
|
25
|
+
autoload :Options, 'selenium/webdriver/safari/options'
|
|
26
|
+
autoload :Service, 'selenium/webdriver/safari/service'
|
|
27
|
+
|
|
27
28
|
class << self
|
|
29
|
+
attr_accessor :use_technology_preview
|
|
30
|
+
|
|
28
31
|
def technology_preview
|
|
29
32
|
"/Applications/Safari\ Technology\ Preview.app/Contents/MacOS/safaridriver"
|
|
30
33
|
end
|
|
31
34
|
|
|
32
35
|
def technology_preview!
|
|
33
|
-
|
|
36
|
+
Service.driver_path = technology_preview
|
|
37
|
+
@use_technology_preview = true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def technology_preview?
|
|
41
|
+
use_technology_preview
|
|
34
42
|
end
|
|
35
43
|
|
|
36
44
|
def path=(path)
|
|
@@ -48,18 +56,18 @@ module Selenium
|
|
|
48
56
|
|
|
49
57
|
def driver_path=(path)
|
|
50
58
|
WebDriver.logger.deprecate 'Selenium::WebDriver::Safari#driver_path=',
|
|
51
|
-
'Selenium::WebDriver::Safari::Service#driver_path='
|
|
59
|
+
'Selenium::WebDriver::Safari::Service#driver_path=',
|
|
60
|
+
id: :driver_path
|
|
52
61
|
Selenium::WebDriver::Safari::Service.driver_path = path
|
|
53
62
|
end
|
|
54
63
|
|
|
55
64
|
def driver_path
|
|
56
65
|
WebDriver.logger.deprecate 'Selenium::WebDriver::Safari#driver_path',
|
|
57
|
-
'Selenium::WebDriver::Safari::Service#driver_path'
|
|
66
|
+
'Selenium::WebDriver::Safari::Service#driver_path',
|
|
67
|
+
id: :driver_path
|
|
58
68
|
Selenium::WebDriver::Safari::Service.driver_path
|
|
59
69
|
end
|
|
60
70
|
end
|
|
61
71
|
end # Safari
|
|
62
72
|
end # WebDriver
|
|
63
73
|
end # Selenium
|
|
64
|
-
|
|
65
|
-
require 'selenium/webdriver/safari/service'
|
|
@@ -25,7 +25,7 @@ module Selenium
|
|
|
25
25
|
@callback = callback
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def method_missing(meth, *args) # rubocop:disable Style/
|
|
28
|
+
def method_missing(meth, *args) # rubocop:disable Style/MissingRespondToMissing
|
|
29
29
|
@callback.call meth, *args
|
|
30
30
|
end
|
|
31
31
|
end # BlockEventListener
|
|
@@ -0,0 +1,63 @@
|
|
|
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
|
+
# This file is automatically generated. Any changes will be lost!
|
|
21
|
+
module Selenium
|
|
22
|
+
module DevTools
|
|
23
|
+
module <%= version %>
|
|
24
|
+
class <%= domain[:domain] %>
|
|
25
|
+
<% if domain[:events] %>
|
|
26
|
+
EVENTS = {
|
|
27
|
+
<% domain[:events].each do |event| %>
|
|
28
|
+
<%= h.snake_case(event[:name]) %>: '<%= event[:name] %>',
|
|
29
|
+
<% end %>
|
|
30
|
+
}.freeze
|
|
31
|
+
<% end %>
|
|
32
|
+
|
|
33
|
+
def initialize(devtools)
|
|
34
|
+
@devtools = devtools
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def on(event, &block)
|
|
38
|
+
event = EVENTS[event] if event.is_a?(Symbol)
|
|
39
|
+
@devtools.callbacks["<%= domain[:domain] %>.#{event}"] << block
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
<% domain[:commands].each do |command| %>
|
|
43
|
+
<% if command[:parameters] %>
|
|
44
|
+
def <%= h.snake_case(command[:name]) %>(<%= h.kwargs(command[:parameters]) %>)
|
|
45
|
+
<% else %>
|
|
46
|
+
def <%= h.snake_case(command[:name]) %>
|
|
47
|
+
<% end %>
|
|
48
|
+
<% if command[:parameters] %>
|
|
49
|
+
@devtools.send_cmd('<%= domain[:domain] %>.<%= command[:name] %>',
|
|
50
|
+
<% until command[:parameters].empty? %>
|
|
51
|
+
<% parameter = command[:parameters].shift %>
|
|
52
|
+
<%= parameter[:name] %>: <%= h.snake_case(parameter[:name]) %><%= command[:parameters].empty? ? ')' : ',' %>
|
|
53
|
+
<% end %>
|
|
54
|
+
<% else %>
|
|
55
|
+
@devtools.send_cmd('<%= domain[:domain] %>.<%= command[:name] %>')
|
|
56
|
+
<% end %>
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
<% end %>
|
|
60
|
+
end # <%= domain[:domain] %>
|
|
61
|
+
end # <%= version %>
|
|
62
|
+
end # DevTools
|
|
63
|
+
end # Selenium
|
|
@@ -0,0 +1,108 @@
|
|
|
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
|
+
require 'erb'
|
|
21
|
+
require 'fileutils'
|
|
22
|
+
require 'json'
|
|
23
|
+
|
|
24
|
+
module Selenium
|
|
25
|
+
module WebDriver
|
|
26
|
+
module Support
|
|
27
|
+
class CDPClientGenerator
|
|
28
|
+
# Input JSON files are generated from PDL tasks.
|
|
29
|
+
TEMPLATE_PATH = File.expand_path('cdp/domain.rb.erb', __dir__)
|
|
30
|
+
|
|
31
|
+
RESERVED_KEYWORDS = %w[end].freeze
|
|
32
|
+
|
|
33
|
+
def call(output_dir:, version:, browser_protocol_path: nil, js_protocol_path: nil, loader_path: nil, **)
|
|
34
|
+
@template = ERB.new(File.read(TEMPLATE_PATH))
|
|
35
|
+
@output_dir = output_dir
|
|
36
|
+
@loader_path = loader_path || "#{@output_dir}.rb"
|
|
37
|
+
@version = version
|
|
38
|
+
|
|
39
|
+
browser_protocol_path ||= File.expand_path('cdp/browser_protocol.json', __dir__)
|
|
40
|
+
js_protocol_path ||= File.expand_path('cdp/js_protocol.json', __dir__)
|
|
41
|
+
|
|
42
|
+
browser_protocol = JSON.parse(File.read(browser_protocol_path), symbolize_names: true)
|
|
43
|
+
js_protocol = JSON.parse(File.read(js_protocol_path), symbolize_names: true)
|
|
44
|
+
|
|
45
|
+
FileUtils.mkdir_p(@output_dir)
|
|
46
|
+
|
|
47
|
+
browser_protocol[:domains].each(&method(:process_domain))
|
|
48
|
+
js_protocol[:domains].each(&method(:process_domain))
|
|
49
|
+
require_file
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def process_domain(domain)
|
|
53
|
+
result = @template.result_with_hash(domain: domain, version: @version.upcase, h: self)
|
|
54
|
+
filename = File.join(@output_dir, "#{snake_case(domain[:domain])}.rb")
|
|
55
|
+
File.write(filename, remove_empty_lines(result))
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def snake_case(string)
|
|
59
|
+
name = string.gsub('JavaScript', 'Javascript')
|
|
60
|
+
.gsub(/([A-Z]+)([A-Z][a-z]{2,})/, '\1_\2')
|
|
61
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
62
|
+
.downcase
|
|
63
|
+
# Certain CDP parameters conflict with Ruby keywords
|
|
64
|
+
# so we prefix the name with underscore.
|
|
65
|
+
name = "_#{name}" if RESERVED_KEYWORDS.include?(name)
|
|
66
|
+
|
|
67
|
+
name
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def kwargs(parameters)
|
|
71
|
+
parameters = parameters.map do |parameter|
|
|
72
|
+
if parameter[:optional]
|
|
73
|
+
"#{snake_case(parameter[:name])}: nil"
|
|
74
|
+
else
|
|
75
|
+
"#{snake_case(parameter[:name])}:"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
parameters.join(', ')
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def remove_empty_lines(string)
|
|
82
|
+
string.split("\n").reject { |l| l =~ /^\s+$/ }.join("\n")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def require_file
|
|
86
|
+
# rubocop:disable Lint/InterpolationCheck
|
|
87
|
+
dynamic_location = '#{File.dirname(File.absolute_path(__FILE__))}'
|
|
88
|
+
# rubocop:enable Lint/InterpolationCheck
|
|
89
|
+
|
|
90
|
+
require_all = "Dir.glob(\"#{dynamic_location}/#{@version}/*\", &method(:require))"
|
|
91
|
+
File.open(@loader_path, 'w') { |file| file.write(require_all) }
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
if $PROGRAM_NAME == __FILE__
|
|
99
|
+
browser_protocol_path, js_protocol_path, output_dir, loader_path, version = *ARGV
|
|
100
|
+
|
|
101
|
+
Selenium::WebDriver::Support::CDPClientGenerator.new.call(
|
|
102
|
+
browser_protocol_path: browser_protocol_path,
|
|
103
|
+
js_protocol_path: js_protocol_path,
|
|
104
|
+
output_dir: output_dir,
|
|
105
|
+
loader_path: loader_path,
|
|
106
|
+
version: version
|
|
107
|
+
)
|
|
108
|
+
end
|
|
@@ -72,7 +72,7 @@ module Selenium
|
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
def self.from_hsl(h, s, l, a) # rubocop:disable Naming/
|
|
75
|
+
def self.from_hsl(h, s, l, a) # rubocop:disable Naming/MethodParameterName
|
|
76
76
|
h = Float(h) / 360
|
|
77
77
|
s = Float(s) / 100
|
|
78
78
|
l = Float(l) / 100
|
|
@@ -138,7 +138,7 @@ module Selenium
|
|
|
138
138
|
end
|
|
139
139
|
|
|
140
140
|
def hex
|
|
141
|
-
format '
|
|
141
|
+
format '#%<red>02x%<green>02x%<blue>02x', red: red, green: green, blue: blue
|
|
142
142
|
end
|
|
143
143
|
end # Color
|
|
144
144
|
end # Support
|