selenium-webdriver 4.0.0.beta3 → 4.0.0.rc3
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 +1953 -0
- data/Gemfile +6 -0
- data/LICENSE +202 -0
- data/NOTICE +2 -0
- data/README.md +34 -0
- data/lib/selenium/webdriver/atoms/findElements.js +0 -0
- data/lib/selenium/webdriver/atoms/getAttribute.js +25 -25
- data/lib/selenium/webdriver/atoms/isDisplayed.js +0 -0
- data/lib/selenium/webdriver/chrome/driver.rb +6 -5
- data/lib/selenium/webdriver/chrome/features.rb +44 -4
- data/lib/selenium/webdriver/chrome/options.rb +25 -2
- data/lib/selenium/webdriver/chrome/profile.rb +0 -0
- data/lib/selenium/webdriver/common/driver.rb +5 -1
- 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_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/{devtools.rb → webdriver/common/driver_extensions/has_launching.rb} +16 -8
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -6
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +8 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +87 -18
- 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/prints_page.rb +1 -1
- data/lib/selenium/webdriver/common/element.rb +17 -8
- data/lib/selenium/webdriver/common/error.rb +12 -0
- data/lib/selenium/webdriver/common/log_entry.rb +2 -2
- data/lib/selenium/webdriver/common/manager.rb +3 -13
- data/lib/selenium/webdriver/common/options.rb +20 -6
- data/lib/selenium/webdriver/common/proxy.rb +2 -2
- data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
- data/lib/selenium/webdriver/common/takes_screenshot.rb +9 -6
- data/lib/selenium/webdriver/common/target_locator.rb +28 -0
- data/lib/selenium/webdriver/common/timeouts.rb +31 -4
- data/lib/selenium/webdriver/common/window.rb +0 -4
- data/lib/selenium/webdriver/common.rb +8 -0
- data/lib/selenium/webdriver/devtools/pinned_script.rb +59 -0
- data/lib/selenium/webdriver/devtools/request.rb +27 -17
- data/lib/selenium/webdriver/devtools/response.rb +66 -0
- data/lib/selenium/webdriver/devtools.rb +50 -12
- data/lib/selenium/webdriver/edge/features.rb +5 -0
- data/lib/selenium/webdriver/edge/options.rb +0 -0
- data/lib/selenium/webdriver/edge/profile.rb +0 -0
- data/lib/selenium/webdriver/firefox/driver.rb +6 -0
- data/lib/selenium/webdriver/firefox/features.rb +20 -1
- data/lib/selenium/webdriver/firefox/options.rb +24 -1
- data/lib/selenium/webdriver/firefox.rb +0 -1
- data/lib/selenium/webdriver/ie/options.rb +3 -1
- data/lib/selenium/webdriver/ie/service.rb +1 -1
- data/lib/selenium/webdriver/remote/bridge.rb +39 -23
- data/lib/selenium/webdriver/remote/capabilities.rb +4 -13
- data/lib/selenium/webdriver/remote/commands.rb +4 -0
- data/lib/selenium/webdriver/remote/driver.rb +3 -1
- data/lib/selenium/webdriver/remote.rb +1 -1
- data/lib/selenium/webdriver/safari/driver.rb +1 -1
- data/lib/selenium/webdriver/safari/options.rb +7 -0
- 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/event_firing_bridge.rb +2 -2
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +1 -1
- data/selenium-webdriver.gemspec +63 -0
- metadata +60 -44
@@ -20,21 +20,34 @@
|
|
20
20
|
module Selenium
|
21
21
|
module WebDriver
|
22
22
|
class DevTools
|
23
|
+
RESPONSE_WAIT_TIMEOUT = 30
|
24
|
+
RESPONSE_WAIT_INTERVAL = 0.1
|
25
|
+
|
23
26
|
autoload :ConsoleEvent, 'selenium/webdriver/devtools/console_event'
|
24
27
|
autoload :ExceptionEvent, 'selenium/webdriver/devtools/exception_event'
|
25
28
|
autoload :MutationEvent, 'selenium/webdriver/devtools/mutation_event'
|
29
|
+
autoload :PinnedScript, 'selenium/webdriver/devtools/pinned_script'
|
26
30
|
autoload :Request, 'selenium/webdriver/devtools/request'
|
31
|
+
autoload :Response, 'selenium/webdriver/devtools/response'
|
27
32
|
|
28
33
|
def initialize(url:)
|
34
|
+
@callback_threads = ThreadGroup.new
|
35
|
+
|
29
36
|
@messages = []
|
30
37
|
@session_id = nil
|
31
38
|
@url = url
|
32
39
|
|
33
40
|
process_handshake
|
34
|
-
attach_socket_listener
|
41
|
+
@socket_thread = attach_socket_listener
|
35
42
|
start_session
|
36
43
|
end
|
37
44
|
|
45
|
+
def close
|
46
|
+
@callback_threads.list.each(&:exit)
|
47
|
+
@socket_thread.exit
|
48
|
+
socket.close
|
49
|
+
end
|
50
|
+
|
38
51
|
def callbacks
|
39
52
|
@callbacks ||= Hash.new { |callbacks, event| callbacks[event] = [] }
|
40
53
|
end
|
@@ -84,27 +97,24 @@ module Selenium
|
|
84
97
|
end
|
85
98
|
|
86
99
|
def attach_socket_listener
|
87
|
-
|
100
|
+
Thread.new do
|
101
|
+
Thread.current.abort_on_exception = true
|
102
|
+
Thread.current.report_on_exception = false
|
103
|
+
|
88
104
|
until socket.eof?
|
89
105
|
incoming_frame << socket.readpartial(1024)
|
90
106
|
|
91
107
|
while (frame = incoming_frame.next)
|
92
|
-
|
93
|
-
break if frame.to_s.empty?
|
94
|
-
|
95
|
-
message = JSON.parse(frame.to_s)
|
96
|
-
@messages << message
|
97
|
-
WebDriver.logger.debug "DevTools <- #{message}"
|
108
|
+
message = process_frame(frame)
|
98
109
|
next unless message['method']
|
99
110
|
|
111
|
+
params = message['params']
|
100
112
|
callbacks[message['method']].each do |callback|
|
101
|
-
params
|
102
|
-
Thread.new { callback.call(params) }
|
113
|
+
@callback_threads.add(callback_thread(params, &callback))
|
103
114
|
end
|
104
115
|
end
|
105
116
|
end
|
106
117
|
end
|
107
|
-
socket_listener.abort_on_exception = true
|
108
118
|
end
|
109
119
|
|
110
120
|
def start_session
|
@@ -118,8 +128,36 @@ module Selenium
|
|
118
128
|
@incoming_frame ||= WebSocket::Frame::Incoming::Client.new(version: ws.version)
|
119
129
|
end
|
120
130
|
|
131
|
+
def process_frame(frame)
|
132
|
+
message = frame.to_s
|
133
|
+
|
134
|
+
# Firefox will periodically fail on unparsable empty frame
|
135
|
+
return {} if message.empty?
|
136
|
+
|
137
|
+
message = JSON.parse(message)
|
138
|
+
@messages << message
|
139
|
+
WebDriver.logger.debug "DevTools <- #{message}"
|
140
|
+
|
141
|
+
message
|
142
|
+
end
|
143
|
+
|
144
|
+
def callback_thread(params)
|
145
|
+
Thread.new do
|
146
|
+
Thread.current.abort_on_exception = true
|
147
|
+
|
148
|
+
# We might end up blocked forever when we have an error in event.
|
149
|
+
# For example, if network interception event raises error,
|
150
|
+
# the browser will keep waiting for the request to be proceeded
|
151
|
+
# before returning back to the original thread. In this case,
|
152
|
+
# we should at least print the error.
|
153
|
+
Thread.current.report_on_exception = true
|
154
|
+
|
155
|
+
yield params
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
121
159
|
def wait
|
122
|
-
@wait ||= Wait.new(timeout:
|
160
|
+
@wait ||= Wait.new(timeout: RESPONSE_WAIT_TIMEOUT, interval: RESPONSE_WAIT_INTERVAL)
|
123
161
|
end
|
124
162
|
|
125
163
|
def socket
|
@@ -27,6 +27,11 @@ module Selenium
|
|
27
27
|
include WebDriver::Chrome::Features
|
28
28
|
|
29
29
|
EDGE_COMMANDS = {
|
30
|
+
get_cast_sinks: [:get, 'session/:session_id/ms/cast/get_sinks'],
|
31
|
+
set_cast_sink_to_use: [:post, 'session/:session_id/ms/cast/set_sink_to_use'],
|
32
|
+
start_cast_tab_mirroring: [:post, 'session/:session_id/ms/cast/start_tab_mirroring'],
|
33
|
+
get_cast_issue_message: [:get, 'session/:session_id/ms/cast/get_issue_message'],
|
34
|
+
stop_casting: [:post, 'session/:session_id/ms/cast/stop_casting'],
|
30
35
|
send_command: [:post, 'session/:session_id/ms/cdp/execute']
|
31
36
|
}.freeze
|
32
37
|
|
File without changes
|
File without changes
|
@@ -28,6 +28,8 @@ module Selenium
|
|
28
28
|
|
29
29
|
class Driver < WebDriver::Driver
|
30
30
|
EXTENSIONS = [DriverExtensions::HasAddons,
|
31
|
+
DriverExtensions::FullPageScreenshot,
|
32
|
+
DriverExtensions::HasContext,
|
31
33
|
DriverExtensions::HasDevTools,
|
32
34
|
DriverExtensions::HasLogEvents,
|
33
35
|
DriverExtensions::HasNetworkInterception,
|
@@ -41,6 +43,10 @@ module Selenium
|
|
41
43
|
private
|
42
44
|
|
43
45
|
def devtools_url
|
46
|
+
if capabilities['moz:debuggerAddress'].nil?
|
47
|
+
raise(Error::WebDriverError, "DevTools is not supported by this version of Firefox; use v85 or higher")
|
48
|
+
end
|
49
|
+
|
44
50
|
uri = URI("http://#{capabilities['moz:debuggerAddress']}")
|
45
51
|
response = Net::HTTP.get(uri.hostname, '/json/version', uri.port)
|
46
52
|
|
@@ -23,8 +23,11 @@ module Selenium
|
|
23
23
|
module Features
|
24
24
|
|
25
25
|
FIREFOX_COMMANDS = {
|
26
|
+
get_context: [:get, 'session/:session_id/moz/context'],
|
27
|
+
set_context: [:post, 'session/:session_id/moz/context'],
|
26
28
|
install_addon: [:post, 'session/:session_id/moz/addon/install'],
|
27
|
-
uninstall_addon: [:post, 'session/:session_id/moz/addon/uninstall']
|
29
|
+
uninstall_addon: [:post, 'session/:session_id/moz/addon/uninstall'],
|
30
|
+
full_page_screenshot: [:get, 'session/:session_id/moz/screenshot/full']
|
28
31
|
}.freeze
|
29
32
|
|
30
33
|
def commands(command)
|
@@ -32,6 +35,11 @@ module Selenium
|
|
32
35
|
end
|
33
36
|
|
34
37
|
def install_addon(path, temporary)
|
38
|
+
if @file_detector
|
39
|
+
local_file = @file_detector.call(path)
|
40
|
+
path = upload(local_file) if local_file
|
41
|
+
end
|
42
|
+
|
35
43
|
payload = {path: path}
|
36
44
|
payload[:temporary] = temporary unless temporary.nil?
|
37
45
|
execute :install_addon, {}, payload
|
@@ -41,6 +49,17 @@ module Selenium
|
|
41
49
|
execute :uninstall_addon, {}, {id: id}
|
42
50
|
end
|
43
51
|
|
52
|
+
def full_screenshot
|
53
|
+
execute :full_page_screenshot
|
54
|
+
end
|
55
|
+
|
56
|
+
def context=(context)
|
57
|
+
execute :set_context, {}, {context: context}
|
58
|
+
end
|
59
|
+
|
60
|
+
def context
|
61
|
+
execute :get_context
|
62
|
+
end
|
44
63
|
end # Bridge
|
45
64
|
end # Firefox
|
46
65
|
end # WebDriver
|
@@ -29,7 +29,11 @@ module Selenium
|
|
29
29
|
CAPABILITIES = {binary: 'binary',
|
30
30
|
args: 'args',
|
31
31
|
log: 'log',
|
32
|
-
prefs: 'prefs'
|
32
|
+
prefs: 'prefs',
|
33
|
+
android_package: 'androidPackage',
|
34
|
+
android_activity: 'androidActivity',
|
35
|
+
android_device_serial: 'androidDeviceSerial',
|
36
|
+
android_intent_arguments: 'androidIntentArguments'}.freeze
|
33
37
|
BROWSER = 'firefox'
|
34
38
|
|
35
39
|
# NOTE: special handling of 'profile' to validate when set instead of when used
|
@@ -131,6 +135,25 @@ module Selenium
|
|
131
135
|
@options[:log] = {level: level}
|
132
136
|
end
|
133
137
|
|
138
|
+
#
|
139
|
+
# Enables mobile browser use on Android.
|
140
|
+
#
|
141
|
+
# @see https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions#android
|
142
|
+
#
|
143
|
+
# @param [String] package The package name of the Chrome or WebView app.
|
144
|
+
# @param [String] serial_number The serial number of the device on which to launch the application.
|
145
|
+
# If not specified and multiple devices are attached, an error will be returned.
|
146
|
+
# @param [String] activity The fully qualified class name of the activity to be launched.
|
147
|
+
# @param [Array] intent_arguments Arguments to launch the intent with.
|
148
|
+
#
|
149
|
+
|
150
|
+
def enable_android(package: 'org.mozilla.firefox', serial_number: nil, activity: nil, intent_arguments: nil)
|
151
|
+
@options[:android_package] = package
|
152
|
+
@options[:android_activity] = activity unless activity.nil?
|
153
|
+
@options[:android_device_serial] = serial_number unless serial_number.nil?
|
154
|
+
@options[:android_intent_arguments] = intent_arguments unless intent_arguments.nil?
|
155
|
+
end
|
156
|
+
|
134
157
|
private
|
135
158
|
|
136
159
|
def process_browser_options(browser_options)
|
@@ -33,7 +33,6 @@ module Selenium
|
|
33
33
|
autoload :Service, 'selenium/webdriver/firefox/service'
|
34
34
|
|
35
35
|
DEFAULT_PORT = 7055
|
36
|
-
DEFAULT_ENABLE_NATIVE_EVENTS = Platform.os == :windows
|
37
36
|
DEFAULT_SECURE_SSL = false
|
38
37
|
DEFAULT_ASSUME_UNTRUSTED_ISSUER = true
|
39
38
|
DEFAULT_LOAD_NO_FOCUS_LIB = false
|
@@ -39,7 +39,9 @@ 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
|
44
46
|
BROWSER = 'internet explorer'
|
45
47
|
|
@@ -25,7 +25,7 @@ module Selenium
|
|
25
25
|
EXECUTABLE = 'IEDriverServer'
|
26
26
|
MISSING_TEXT = <<~ERROR
|
27
27
|
Unable to find IEDriverServer. Please download the server from
|
28
|
-
|
28
|
+
https://www.selenium.dev/downloads/ and place it somewhere on your PATH.
|
29
29
|
More info at https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver.
|
30
30
|
ERROR
|
31
31
|
SHUTDOWN_SUPPORTED = true
|
@@ -25,7 +25,7 @@ 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
|
#
|
@@ -93,17 +93,16 @@ module Selenium
|
|
93
93
|
execute :get, {}, {url: url}
|
94
94
|
end
|
95
95
|
|
96
|
-
|
97
|
-
|
98
|
-
|
96
|
+
#
|
97
|
+
# timeouts
|
98
|
+
#
|
99
99
|
|
100
|
-
def
|
101
|
-
|
100
|
+
def timeouts
|
101
|
+
execute :get_timeouts, {}
|
102
102
|
end
|
103
103
|
|
104
|
-
def
|
105
|
-
|
106
|
-
execute :set_timeout, {}, {type => milliseconds}
|
104
|
+
def timeouts=(timeouts)
|
105
|
+
execute :set_timeout, {}, timeouts
|
107
106
|
end
|
108
107
|
|
109
108
|
#
|
@@ -269,7 +268,7 @@ module Selenium
|
|
269
268
|
end
|
270
269
|
|
271
270
|
def element_screenshot(element)
|
272
|
-
execute :take_element_screenshot, id: element
|
271
|
+
execute :take_element_screenshot, id: element
|
273
272
|
end
|
274
273
|
|
275
274
|
#
|
@@ -431,7 +430,7 @@ module Selenium
|
|
431
430
|
end
|
432
431
|
|
433
432
|
def submit_element(element)
|
434
|
-
form = find_element_by('xpath', "./ancestor-or-self::form", element)
|
433
|
+
form = find_element_by('xpath', "./ancestor-or-self::form", [:element, element])
|
435
434
|
execute_script("var e = arguments[0].ownerDocument.createEvent('Event');" \
|
436
435
|
"e.initEvent('submit', true, true);" \
|
437
436
|
'if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }', form.as_json)
|
@@ -451,19 +450,19 @@ module Selenium
|
|
451
450
|
end
|
452
451
|
|
453
452
|
def element_dom_attribute(element, name)
|
454
|
-
execute :get_element_attribute, id: element
|
453
|
+
execute :get_element_attribute, id: element, name: name
|
455
454
|
end
|
456
455
|
|
457
456
|
def element_property(element, name)
|
458
|
-
execute :get_element_property, id: element
|
457
|
+
execute :get_element_property, id: element, name: name
|
459
458
|
end
|
460
459
|
|
461
460
|
def element_aria_role(element)
|
462
|
-
execute :get_element_aria_role, id: element
|
461
|
+
execute :get_element_aria_role, id: element
|
463
462
|
end
|
464
463
|
|
465
464
|
def element_aria_label(element)
|
466
|
-
execute :get_element_aria_label, id: element
|
465
|
+
execute :get_element_aria_label, id: element
|
467
466
|
end
|
468
467
|
|
469
468
|
def element_value(element)
|
@@ -524,13 +523,17 @@ module Selenium
|
|
524
523
|
|
525
524
|
alias_method :switch_to_active_element, :active_element
|
526
525
|
|
527
|
-
def find_element_by(how, what,
|
526
|
+
def find_element_by(how, what, parent_ref = [])
|
528
527
|
how, what = convert_locator(how, what)
|
529
528
|
|
530
529
|
return execute_atom(:findElements, Support::RelativeLocator.new(what).as_json).first if how == 'relative'
|
531
530
|
|
532
|
-
|
533
|
-
|
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}
|
534
537
|
else
|
535
538
|
execute :find_element, {}, {using: how, value: what.to_s}
|
536
539
|
end
|
@@ -538,13 +541,17 @@ module Selenium
|
|
538
541
|
Element.new self, element_id_from(id)
|
539
542
|
end
|
540
543
|
|
541
|
-
def find_elements_by(how, what,
|
544
|
+
def find_elements_by(how, what, parent_ref = [])
|
542
545
|
how, what = convert_locator(how, what)
|
543
546
|
|
544
547
|
return execute_atom :findElements, Support::RelativeLocator.new(what).as_json if how == 'relative'
|
545
548
|
|
546
|
-
|
547
|
-
|
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}
|
548
555
|
else
|
549
556
|
execute :find_elements, {}, {using: how, value: what.to_s}
|
550
557
|
end
|
@@ -552,6 +559,11 @@ module Selenium
|
|
552
559
|
ids.map { |id| Element.new self, element_id_from(id) }
|
553
560
|
end
|
554
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
|
+
|
555
567
|
private
|
556
568
|
|
557
569
|
#
|
@@ -599,11 +611,15 @@ module Selenium
|
|
599
611
|
end
|
600
612
|
|
601
613
|
def element_id_from(id)
|
602
|
-
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]
|
603
619
|
end
|
604
620
|
|
605
621
|
def prepare_capabilities_payload(capabilities)
|
606
|
-
capabilities = {
|
622
|
+
capabilities = {alwaysMatch: capabilities} if !capabilities['alwaysMatch'] && !capabilities['firstMatch']
|
607
623
|
{capabilities: capabilities}
|
608
624
|
end
|
609
625
|
|
@@ -39,6 +39,7 @@ module Selenium
|
|
39
39
|
:timeouts,
|
40
40
|
:unhandled_prompt_behavior,
|
41
41
|
:strict_file_interactability,
|
42
|
+
:web_socket_url,
|
42
43
|
|
43
44
|
# remote-specific (webdriver.remote.sessionid)
|
44
45
|
:remote_session_id
|
@@ -46,7 +47,7 @@ module Selenium
|
|
46
47
|
|
47
48
|
(KNOWN - %i[proxy timeouts]).each do |key|
|
48
49
|
define_method key do
|
49
|
-
@capabilities
|
50
|
+
@capabilities[key]
|
50
51
|
end
|
51
52
|
|
52
53
|
define_method "#{key}=" do |value|
|
@@ -202,7 +203,7 @@ module Selenium
|
|
202
203
|
end
|
203
204
|
|
204
205
|
def proxy
|
205
|
-
@capabilities
|
206
|
+
@capabilities[:proxy]
|
206
207
|
end
|
207
208
|
|
208
209
|
def proxy=(proxy)
|
@@ -307,23 +308,13 @@ module Selenium
|
|
307
308
|
when :platform
|
308
309
|
value.to_s.upcase
|
309
310
|
when :proxy
|
310
|
-
|
311
|
+
value&.as_json
|
311
312
|
when :unhandled_prompt_behavior
|
312
313
|
value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value
|
313
314
|
else
|
314
315
|
value
|
315
316
|
end
|
316
317
|
end
|
317
|
-
|
318
|
-
def convert_proxy(value)
|
319
|
-
return unless value
|
320
|
-
|
321
|
-
hash = value.as_json
|
322
|
-
hash['proxyType'] &&= hash['proxyType'].downcase
|
323
|
-
hash['noProxy'] = hash['noProxy'].split(', ') if hash['noProxy'].is_a?(String)
|
324
|
-
|
325
|
-
hash
|
326
|
-
end
|
327
318
|
end # Capabilities
|
328
319
|
end # Remote
|
329
320
|
end # WebDriver
|
@@ -77,7 +77,10 @@ module Selenium
|
|
77
77
|
find_elements: [:post, 'session/:session_id/elements'],
|
78
78
|
find_child_element: [:post, 'session/:session_id/element/:id/element'],
|
79
79
|
find_child_elements: [:post, 'session/:session_id/element/:id/elements'],
|
80
|
+
find_shadow_child_element: [:post, 'session/:session_id/shadow/:id/element'],
|
81
|
+
find_shadow_child_elements: [:post, 'session/:session_id/shadow/:id/elements'],
|
80
82
|
get_active_element: [:get, 'session/:session_id/element/active'],
|
83
|
+
get_element_shadow_root: [:get, 'session/:session_id/element/:id/shadow'],
|
81
84
|
is_element_selected: [:get, 'session/:session_id/element/:id/selected'],
|
82
85
|
get_element_attribute: [:get, 'session/:session_id/element/:id/attribute/:name'],
|
83
86
|
get_element_property: [:get, 'session/:session_id/element/:id/property/:name'],
|
@@ -111,6 +114,7 @@ module Selenium
|
|
111
114
|
# timeouts
|
112
115
|
#
|
113
116
|
|
117
|
+
get_timeouts: [:get, 'session/:session_id/timeouts'],
|
114
118
|
set_timeout: [:post, 'session/:session_id/timeouts'],
|
115
119
|
|
116
120
|
#
|
@@ -42,6 +42,7 @@ module Selenium
|
|
42
42
|
end
|
43
43
|
opts[:url] ||= "http://#{Platform.localhost}:4444/wd/hub"
|
44
44
|
super
|
45
|
+
@bridge.file_detector = ->((filename, *)) { File.exist?(filename) && filename.to_s }
|
45
46
|
end
|
46
47
|
|
47
48
|
private
|
@@ -51,7 +52,8 @@ module Selenium
|
|
51
52
|
end
|
52
53
|
|
53
54
|
def devtools_version
|
54
|
-
capabilities['se:cdpVersion']
|
55
|
+
capabilities['se:cdpVersion']&.split('.')&.first ||
|
56
|
+
raise(Error::WebDriverError, "DevTools is not supported by the Remote Server")
|
55
57
|
end
|
56
58
|
end # Driver
|
57
59
|
end # Remote
|
@@ -18,6 +18,7 @@
|
|
18
18
|
# under the License.
|
19
19
|
|
20
20
|
require 'uri'
|
21
|
+
require 'selenium/webdriver/remote/server_error'
|
21
22
|
|
22
23
|
module Selenium
|
23
24
|
module WebDriver
|
@@ -25,7 +26,6 @@ module Selenium
|
|
25
26
|
autoload :Bridge, 'selenium/webdriver/remote/bridge'
|
26
27
|
autoload :Driver, 'selenium/webdriver/remote/driver'
|
27
28
|
autoload :Response, 'selenium/webdriver/remote/response'
|
28
|
-
autoload :ServerError, 'selenium/webdriver/remote/server_error'
|
29
29
|
autoload :Capabilities, 'selenium/webdriver/remote/capabilities'
|
30
30
|
autoload :COMMANDS, 'selenium/webdriver/remote/commands'
|
31
31
|
module Http
|
@@ -28,6 +28,13 @@ module Selenium
|
|
28
28
|
automatic_profiling: 'safari:automaticProfiling'}.freeze
|
29
29
|
BROWSER = 'safari'
|
30
30
|
|
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?(':')
|
34
|
+
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
31
38
|
end # Options
|
32
39
|
end # Safari
|
33
40
|
end # WebDriver
|
@@ -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
|