selenium-webdriver 3.0.0.beta4.0 → 4.0.0.alpha5
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 +7 -0
- data/CHANGES +679 -0
- data/Gemfile +2 -0
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/lib/selenium-webdriver.rb +2 -2
- data/lib/selenium/server.rb +23 -16
- data/lib/selenium/webdriver.rb +43 -25
- data/lib/selenium/webdriver/atoms.rb +20 -1
- data/lib/selenium/webdriver/atoms/findElements.js +122 -0
- data/lib/selenium/webdriver/atoms/getAttribute.js +84 -11
- data/lib/selenium/webdriver/atoms/isDisplayed.js +100 -0
- data/lib/selenium/webdriver/chrome.rb +15 -20
- data/lib/selenium/webdriver/chrome/bridge.rb +29 -66
- data/lib/selenium/webdriver/{edge/service.rb → chrome/driver.rb} +19 -22
- data/lib/selenium/webdriver/chrome/options.rb +221 -0
- data/lib/selenium/webdriver/chrome/profile.rb +6 -7
- data/lib/selenium/webdriver/chrome/service.rb +20 -20
- data/lib/selenium/webdriver/common.rb +19 -11
- data/lib/selenium/webdriver/common/action_builder.rb +98 -246
- data/lib/selenium/webdriver/common/alert.rb +2 -7
- data/lib/selenium/webdriver/common/driver.rb +89 -51
- data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +45 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +50 -0
- data/lib/selenium/webdriver/common/driver_extensions/{has_input_devices.rb → has_debugger.rb} +12 -25
- data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +38 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +3 -5
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +51 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +3 -3
- data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +51 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +2 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +2 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +2 -2
- data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +4 -4
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +9 -3
- data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +3 -5
- data/lib/selenium/webdriver/common/element.rb +32 -10
- data/lib/selenium/webdriver/common/error.rb +103 -121
- data/lib/selenium/webdriver/common/file_reaper.rb +3 -5
- data/lib/selenium/webdriver/common/html5/local_storage.rb +2 -2
- data/lib/selenium/webdriver/common/html5/session_storage.rb +2 -2
- data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +3 -2
- data/lib/selenium/webdriver/common/interactions/input_device.rb +54 -0
- data/lib/selenium/webdriver/common/interactions/interaction.rb +53 -0
- data/lib/selenium/webdriver/{phantomjs.rb → common/interactions/interactions.rb} +17 -20
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +145 -0
- data/lib/selenium/webdriver/common/interactions/key_input.rb +66 -0
- data/lib/selenium/webdriver/common/interactions/none_input.rb +36 -0
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +363 -0
- data/lib/selenium/webdriver/common/interactions/pointer_input.rb +139 -0
- data/lib/selenium/webdriver/common/keys.rb +37 -15
- data/lib/selenium/webdriver/common/log_entry.rb +4 -4
- data/lib/selenium/webdriver/common/logger.rb +147 -0
- data/lib/selenium/webdriver/common/logs.rb +2 -2
- data/lib/selenium/webdriver/common/manager.rb +177 -0
- data/lib/selenium/webdriver/common/navigation.rb +2 -2
- data/lib/selenium/webdriver/common/options.rb +47 -105
- data/lib/selenium/webdriver/common/platform.rb +44 -38
- data/lib/selenium/webdriver/common/port_prober.rb +8 -19
- data/lib/selenium/webdriver/common/profile_helper.rb +13 -5
- data/lib/selenium/webdriver/common/proxy.rb +14 -8
- data/lib/selenium/webdriver/common/search_context.rb +16 -20
- data/lib/selenium/webdriver/common/service.rb +115 -30
- data/lib/selenium/webdriver/common/socket_lock.rb +12 -7
- data/lib/selenium/webdriver/common/socket_poller.rb +29 -22
- data/lib/selenium/webdriver/common/target_locator.rb +6 -6
- data/lib/selenium/webdriver/common/timeouts.rb +2 -2
- data/lib/selenium/webdriver/common/wait.rb +14 -8
- data/lib/selenium/webdriver/common/window.rb +38 -2
- data/lib/selenium/webdriver/common/zipper.rb +3 -5
- data/lib/selenium/webdriver/edge.rb +33 -20
- data/lib/selenium/webdriver/edge_chrome/bridge.rb +30 -0
- data/lib/selenium/webdriver/edge_chrome/driver.rb +38 -0
- data/lib/selenium/webdriver/{common/driver_extensions/has_touch_screen.rb → edge_chrome/options.rb} +10 -12
- data/lib/selenium/webdriver/edge_chrome/profile.rb +33 -0
- data/lib/selenium/webdriver/edge_chrome/service.rb +36 -0
- data/lib/selenium/webdriver/edge_html/driver.rb +39 -0
- data/lib/selenium/webdriver/edge_html/options.rb +91 -0
- data/lib/selenium/webdriver/edge_html/service.rb +47 -0
- data/lib/selenium/webdriver/firefox.rb +24 -29
- data/lib/selenium/webdriver/firefox/bridge.rb +15 -39
- data/lib/selenium/webdriver/firefox/{util.rb → driver.rb} +13 -19
- data/lib/selenium/webdriver/firefox/extension.rb +28 -8
- data/lib/selenium/webdriver/firefox/options.rb +162 -0
- data/lib/selenium/webdriver/firefox/profile.rb +23 -82
- data/lib/selenium/webdriver/firefox/profiles_ini.rb +5 -5
- data/lib/selenium/webdriver/firefox/service.rb +18 -37
- data/lib/selenium/webdriver/ie.rb +13 -19
- data/lib/selenium/webdriver/ie/driver.rb +40 -0
- data/lib/selenium/webdriver/ie/options.rb +118 -0
- data/lib/selenium/webdriver/ie/service.rb +20 -20
- data/lib/selenium/webdriver/remote.rb +15 -17
- data/lib/selenium/webdriver/remote/bridge.rb +281 -300
- data/lib/selenium/webdriver/remote/capabilities.rb +102 -83
- data/lib/selenium/webdriver/remote/commands.rb +132 -192
- data/lib/selenium/webdriver/remote/driver.rb +52 -0
- data/lib/selenium/webdriver/remote/http/common.rb +23 -13
- data/lib/selenium/webdriver/remote/http/curb.rb +10 -7
- data/lib/selenium/webdriver/remote/http/default.rb +52 -32
- data/lib/selenium/webdriver/remote/http/persistent.rb +8 -4
- data/lib/selenium/webdriver/remote/response.rb +32 -35
- data/lib/selenium/webdriver/remote/server_error.rb +2 -2
- data/lib/selenium/webdriver/safari.rb +24 -22
- data/lib/selenium/webdriver/safari/bridge.rb +21 -21
- data/lib/selenium/webdriver/safari/driver.rb +41 -0
- data/lib/selenium/webdriver/safari/options.rb +66 -0
- data/lib/selenium/webdriver/safari/service.rb +8 -24
- data/lib/selenium/webdriver/support.rb +3 -2
- data/lib/selenium/webdriver/support/abstract_event_listener.rb +2 -2
- data/lib/selenium/webdriver/support/block_event_listener.rb +3 -3
- data/lib/selenium/webdriver/support/color.rb +13 -13
- data/lib/selenium/webdriver/support/escaper.rb +2 -2
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
- data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
- data/lib/selenium/webdriver/support/select.rb +20 -21
- data/lib/selenium/webdriver/version.rb +24 -0
- data/selenium-webdriver.gemspec +31 -17
- metadata +331 -248
- data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
- data/lib/selenium/webdriver/common/keyboard.rb +0 -69
- data/lib/selenium/webdriver/common/mouse.rb +0 -88
- data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -81
- data/lib/selenium/webdriver/common/touch_screen.rb +0 -121
- data/lib/selenium/webdriver/common/w3c_error.rb +0 -191
- data/lib/selenium/webdriver/edge/bridge.rb +0 -76
- data/lib/selenium/webdriver/edge/legacy_support.rb +0 -117
- data/lib/selenium/webdriver/firefox/binary.rb +0 -186
- 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 -114
- 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/firefox/w3c_bridge.rb +0 -79
- data/lib/selenium/webdriver/ie/bridge.rb +0 -76
- data/lib/selenium/webdriver/phantomjs/bridge.rb +0 -65
- data/lib/selenium/webdriver/phantomjs/service.rb +0 -66
- data/lib/selenium/webdriver/remote/w3c_bridge.rb +0 -682
- data/lib/selenium/webdriver/remote/w3c_capabilities.rb +0 -228
- data/lib/selenium/webdriver/remote/w3c_commands.rb +0 -135
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
3
|
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
4
|
# or more contributor license agreements. See the NOTICE file
|
|
5
5
|
# distributed with this work for additional information
|
|
@@ -27,12 +27,11 @@ module Selenium
|
|
|
27
27
|
module_function
|
|
28
28
|
|
|
29
29
|
def home
|
|
30
|
-
|
|
31
|
-
@home ||= jruby? ? ENV_JAVA['user.home'] : ENV['HOME']
|
|
30
|
+
@home ||= Dir.home
|
|
32
31
|
end
|
|
33
32
|
|
|
34
33
|
def engine
|
|
35
|
-
@engine ||=
|
|
34
|
+
@engine ||= RUBY_ENGINE.to_sym
|
|
36
35
|
end
|
|
37
36
|
|
|
38
37
|
def os
|
|
@@ -52,8 +51,13 @@ module Selenium
|
|
|
52
51
|
end
|
|
53
52
|
|
|
54
53
|
def ci
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
if ENV['TRAVIS']
|
|
55
|
+
:travis
|
|
56
|
+
elsif ENV['JENKINS']
|
|
57
|
+
:jenkins
|
|
58
|
+
elsif ENV['APPVEYOR']
|
|
59
|
+
:appveyor
|
|
60
|
+
end
|
|
57
61
|
end
|
|
58
62
|
|
|
59
63
|
def bitsize
|
|
@@ -72,10 +76,6 @@ module Selenium
|
|
|
72
76
|
engine == :jruby
|
|
73
77
|
end
|
|
74
78
|
|
|
75
|
-
def ironruby?
|
|
76
|
-
engine == :ironruby
|
|
77
|
-
end
|
|
78
|
-
|
|
79
79
|
def ruby_version
|
|
80
80
|
RUBY_VERSION
|
|
81
81
|
end
|
|
@@ -92,36 +92,50 @@ module Selenium
|
|
|
92
92
|
os == :linux
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
+
def wsl?
|
|
96
|
+
return false unless linux?
|
|
97
|
+
|
|
98
|
+
File.read('/proc/version').include?('Microsoft')
|
|
99
|
+
rescue Errno::EACCES
|
|
100
|
+
# the file cannot be accessed on Linux on DeX
|
|
101
|
+
false
|
|
102
|
+
end
|
|
103
|
+
|
|
95
104
|
def cygwin?
|
|
96
105
|
RUBY_PLATFORM =~ /cygwin/
|
|
97
106
|
!Regexp.last_match.nil?
|
|
98
107
|
end
|
|
99
108
|
|
|
100
109
|
def null_device
|
|
101
|
-
|
|
102
|
-
File::NULL
|
|
103
|
-
else
|
|
104
|
-
Platform.windows? ? 'NUL' : '/dev/null'
|
|
105
|
-
end
|
|
110
|
+
File::NULL
|
|
106
111
|
end
|
|
107
112
|
|
|
108
113
|
def wrap_in_quotes_if_necessary(str)
|
|
109
114
|
windows? && !cygwin? ? %("#{str}") : str
|
|
110
115
|
end
|
|
111
116
|
|
|
112
|
-
def cygwin_path(path, opts
|
|
117
|
+
def cygwin_path(path, **opts)
|
|
113
118
|
flags = []
|
|
114
119
|
opts.each { |k, v| flags << "--#{k}" if v }
|
|
115
120
|
|
|
116
121
|
`cygpath #{flags.join ' '} "#{path}"`.strip
|
|
117
122
|
end
|
|
118
123
|
|
|
124
|
+
def unix_path(path)
|
|
125
|
+
path.tr(File::ALT_SEPARATOR, File::SEPARATOR)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def windows_path(path)
|
|
129
|
+
path.tr(File::SEPARATOR, File::ALT_SEPARATOR)
|
|
130
|
+
end
|
|
131
|
+
|
|
119
132
|
def make_writable(file)
|
|
120
|
-
File.chmod
|
|
133
|
+
File.chmod 0o766, file
|
|
121
134
|
end
|
|
122
135
|
|
|
123
136
|
def assert_file(path)
|
|
124
137
|
return if File.file? path
|
|
138
|
+
|
|
125
139
|
raise Error::WebDriverError, "not a file: #{path.inspect}"
|
|
126
140
|
end
|
|
127
141
|
|
|
@@ -129,6 +143,7 @@ module Selenium
|
|
|
129
143
|
assert_file(path)
|
|
130
144
|
|
|
131
145
|
return if File.executable? path
|
|
146
|
+
|
|
132
147
|
raise Error::WebDriverError, "not executable: #{path.inspect}"
|
|
133
148
|
end
|
|
134
149
|
|
|
@@ -140,15 +155,18 @@ module Selenium
|
|
|
140
155
|
|
|
141
156
|
def find_binary(*binary_names)
|
|
142
157
|
paths = ENV['PATH'].split(File::PATH_SEPARATOR)
|
|
143
|
-
|
|
158
|
+
|
|
159
|
+
if windows?
|
|
160
|
+
binary_names.map! { |n| "#{n}.exe" }
|
|
161
|
+
binary_names.dup.each { |n| binary_names << n.gsub('exe', 'bat') }
|
|
162
|
+
end
|
|
144
163
|
|
|
145
164
|
binary_names.each do |binary_name|
|
|
146
165
|
paths.each do |path|
|
|
147
166
|
full_path = File.join(path, binary_name)
|
|
148
|
-
full_path
|
|
149
|
-
exe = Dir.glob(full_path).
|
|
150
|
-
|
|
151
|
-
return exe if File.executable?(exe)
|
|
167
|
+
full_path = unix_path(full_path) if windows?
|
|
168
|
+
exe = Dir.glob(full_path).find { |f| File.executable?(f) }
|
|
169
|
+
return exe if exe
|
|
152
170
|
end
|
|
153
171
|
end
|
|
154
172
|
|
|
@@ -158,7 +176,8 @@ module Selenium
|
|
|
158
176
|
def find_in_program_files(*binary_names)
|
|
159
177
|
paths = [
|
|
160
178
|
ENV['PROGRAMFILES'] || '\\Program Files',
|
|
161
|
-
ENV['ProgramFiles(x86)'] || '\\Program Files (x86)'
|
|
179
|
+
ENV['ProgramFiles(x86)'] || '\\Program Files (x86)',
|
|
180
|
+
ENV['ProgramW6432'] || '\\Program Files'
|
|
162
181
|
]
|
|
163
182
|
|
|
164
183
|
paths.each do |root|
|
|
@@ -175,6 +194,7 @@ module Selenium
|
|
|
175
194
|
info = Socket.getaddrinfo 'localhost', 80, Socket::AF_INET, Socket::SOCK_STREAM
|
|
176
195
|
|
|
177
196
|
return info[0][3] unless info.empty?
|
|
197
|
+
|
|
178
198
|
raise Error::WebDriverError, "unable to translate 'localhost' for TCP + IPv4"
|
|
179
199
|
end
|
|
180
200
|
|
|
@@ -203,17 +223,3 @@ module Selenium
|
|
|
203
223
|
end # Platform
|
|
204
224
|
end # WebDriver
|
|
205
225
|
end # Selenium
|
|
206
|
-
|
|
207
|
-
if __FILE__ == $PROGRAM_NAME
|
|
208
|
-
p engine: Selenium::WebDriver::Platform.engine,
|
|
209
|
-
os: Selenium::WebDriver::Platform.os,
|
|
210
|
-
ruby_version: Selenium::WebDriver::Platform.ruby_version,
|
|
211
|
-
jruby?: Selenium::WebDriver::Platform.jruby?,
|
|
212
|
-
windows?: Selenium::WebDriver::Platform.windows?,
|
|
213
|
-
home: Selenium::WebDriver::Platform.home,
|
|
214
|
-
bitsize: Selenium::WebDriver::Platform.bitsize,
|
|
215
|
-
localhost: Selenium::WebDriver::Platform.localhost,
|
|
216
|
-
ip: Selenium::WebDriver::Platform.ip,
|
|
217
|
-
interfaces: Selenium::WebDriver::Platform.interfaces,
|
|
218
|
-
null_device: Selenium::WebDriver::Platform.null_device
|
|
219
|
-
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
3
|
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
4
|
# or more contributor license agreements. See the NOTICE file
|
|
5
5
|
# distributed with this work for additional information
|
|
@@ -25,28 +25,17 @@ module Selenium
|
|
|
25
25
|
port
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# (b) should pick a random port outside the ephemeral port range
|
|
33
|
-
#
|
|
34
|
-
server = TCPServer.new(Platform.localhost, 0)
|
|
35
|
-
port = server.addr[1]
|
|
36
|
-
server.close
|
|
37
|
-
|
|
38
|
-
port
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
IGNORED_ERRORS = [Errno::EADDRNOTAVAIL].freeze
|
|
42
|
-
IGNORED_ERRORS << Errno::EBADF if Platform.cygwin?
|
|
28
|
+
IGNORED_ERRORS = [Errno::EADDRNOTAVAIL, Errno::EAFNOSUPPORT].tap { |arr|
|
|
29
|
+
arr << Errno::EBADF if Platform.cygwin?
|
|
30
|
+
arr << Errno::EACCES if Platform.windows?
|
|
31
|
+
}.freeze
|
|
43
32
|
|
|
44
33
|
def self.free?(port)
|
|
45
34
|
Platform.interfaces.each do |host|
|
|
46
35
|
begin
|
|
47
36
|
TCPServer.new(host, port).close
|
|
48
|
-
rescue *IGNORED_ERRORS =>
|
|
49
|
-
|
|
37
|
+
rescue *IGNORED_ERRORS => e
|
|
38
|
+
WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{e.message})")
|
|
50
39
|
# ignored - some machines appear unable to bind to some of their interfaces
|
|
51
40
|
end
|
|
52
41
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
3
|
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
4
|
# or more contributor license agreements. See the NOTICE file
|
|
5
5
|
# distributed with this work for additional information
|
|
@@ -31,8 +31,16 @@ module Selenium
|
|
|
31
31
|
base.extend ClassMethods
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
def self.decoded(json)
|
|
35
|
+
JSON.parse(json).fetch('zip')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def encoded
|
|
39
|
+
Zipper.zip(layout_on_disk)
|
|
40
|
+
end
|
|
41
|
+
|
|
34
42
|
def as_json(*)
|
|
35
|
-
{
|
|
43
|
+
{"zip" => encoded}
|
|
36
44
|
end
|
|
37
45
|
|
|
38
46
|
def to_json(*)
|
|
@@ -46,7 +54,7 @@ module Selenium
|
|
|
46
54
|
|
|
47
55
|
# TODO: must be a better way..
|
|
48
56
|
FileUtils.rm_rf tmp_directory
|
|
49
|
-
FileUtils.mkdir_p File.dirname(tmp_directory), mode:
|
|
57
|
+
FileUtils.mkdir_p File.dirname(tmp_directory), mode: 0o700
|
|
50
58
|
FileUtils.cp_r directory, tmp_directory
|
|
51
59
|
|
|
52
60
|
tmp_directory
|
|
@@ -63,7 +71,7 @@ module Selenium
|
|
|
63
71
|
|
|
64
72
|
module ClassMethods
|
|
65
73
|
def from_json(json)
|
|
66
|
-
data =
|
|
74
|
+
data = decoded(json)
|
|
67
75
|
|
|
68
76
|
# can't use Tempfile here since it doesn't support File::BINARY mode on 1.8
|
|
69
77
|
# can't use Dir.mktmpdir(&blk) because of http://jira.codehaus.org/browse/JRUBY-4082
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
3
|
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
4
|
# or more contributor license agreements. See the NOTICE file
|
|
5
5
|
# distributed with this work for additional information
|
|
@@ -37,9 +37,10 @@ module Selenium
|
|
|
37
37
|
auto_detect: 'autodetect',
|
|
38
38
|
socks: 'socksProxy',
|
|
39
39
|
socks_username: 'socksUsername',
|
|
40
|
-
socks_password: 'socksPassword'
|
|
40
|
+
socks_password: 'socksPassword',
|
|
41
|
+
socks_version: 'socksVersion'}.freeze
|
|
41
42
|
|
|
42
|
-
ALLOWED.
|
|
43
|
+
ALLOWED.each_key { |t| attr_reader t }
|
|
43
44
|
|
|
44
45
|
def self.json_create(data)
|
|
45
46
|
data['proxyType'] = data['proxyType'].downcase.to_sym
|
|
@@ -66,6 +67,7 @@ module Selenium
|
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
return if not_allowed.empty?
|
|
70
|
+
|
|
69
71
|
raise ArgumentError, "unknown option#{'s' if not_allowed.size != 1}: #{not_allowed.inspect}"
|
|
70
72
|
end
|
|
71
73
|
|
|
@@ -119,10 +121,13 @@ module Selenium
|
|
|
119
121
|
@socks_password = value
|
|
120
122
|
end
|
|
121
123
|
|
|
124
|
+
def socks_version=(value)
|
|
125
|
+
self.type = :manual
|
|
126
|
+
@socks_version = value
|
|
127
|
+
end
|
|
128
|
+
|
|
122
129
|
def type=(type)
|
|
123
|
-
unless TYPES.key? type
|
|
124
|
-
raise ArgumentError, "invalid proxy type: #{type.inspect}, expected one of #{TYPES.keys.inspect}"
|
|
125
|
-
end
|
|
130
|
+
raise ArgumentError, "invalid proxy type: #{type.inspect}, expected one of #{TYPES.keys.inspect}" unless TYPES.key? type
|
|
126
131
|
|
|
127
132
|
if defined?(@type) && type != @type
|
|
128
133
|
raise ArgumentError, "incompatible proxy type #{type.inspect} (already set to #{@type.inspect})"
|
|
@@ -142,7 +147,8 @@ module Selenium
|
|
|
142
147
|
'autodetect' => auto_detect,
|
|
143
148
|
'socksProxy' => socks,
|
|
144
149
|
'socksUsername' => socks_username,
|
|
145
|
-
'socksPassword' => socks_password
|
|
150
|
+
'socksPassword' => socks_password,
|
|
151
|
+
'socksVersion' => socks_version
|
|
146
152
|
}.delete_if { |_k, v| v.nil? }
|
|
147
153
|
|
|
148
154
|
json_result if json_result.length > 1
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
3
|
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
4
|
# or more contributor license agreements. See the NOTICE file
|
|
5
5
|
# distributed with this work for additional information
|
|
@@ -30,25 +30,29 @@ module Selenium
|
|
|
30
30
|
link_text: 'link text',
|
|
31
31
|
name: 'name',
|
|
32
32
|
partial_link_text: 'partial link text',
|
|
33
|
+
relative: 'relative',
|
|
33
34
|
tag_name: 'tag name',
|
|
34
35
|
xpath: 'xpath'
|
|
35
36
|
}.freeze
|
|
36
37
|
|
|
37
38
|
#
|
|
38
|
-
# Find the first element matching the given arguments
|
|
39
|
+
# Find the first element matching the given arguments
|
|
39
40
|
#
|
|
40
41
|
# When using Element#find_element with :xpath, be aware that webdriver
|
|
41
42
|
# follows standard conventions: a search prefixed with "//" will search
|
|
42
43
|
# the entire document, not just the children of this current node. Use
|
|
43
44
|
# ".//" to limit your search to the children of the receiving Element.
|
|
44
45
|
#
|
|
45
|
-
# @
|
|
46
|
-
#
|
|
46
|
+
# @overload find_element(how, what)
|
|
47
|
+
# @param [Symbol, String] how The method to find the element by
|
|
48
|
+
# @param [String] what The locator to use
|
|
49
|
+
# @overload find_element(opts)
|
|
50
|
+
# @param [Hash] opts Find options
|
|
51
|
+
# @option opts [Symbol] :how Key named after the method to find the element by, containing the locator
|
|
47
52
|
# @return [Element]
|
|
48
53
|
#
|
|
49
54
|
# @raise [Error::NoSuchElementError] if the element doesn't exist
|
|
50
55
|
#
|
|
51
|
-
#
|
|
52
56
|
|
|
53
57
|
def find_element(*args)
|
|
54
58
|
how, what = extract_args(args)
|
|
@@ -56,8 +60,8 @@ module Selenium
|
|
|
56
60
|
by = FINDERS[how.to_sym]
|
|
57
61
|
raise ArgumentError, "cannot find element by #{how.inspect}" unless by
|
|
58
62
|
|
|
59
|
-
bridge.find_element_by by, what
|
|
60
|
-
rescue Selenium::WebDriver::Error::
|
|
63
|
+
bridge.find_element_by by, what, ref
|
|
64
|
+
rescue Selenium::WebDriver::Error::TimeoutError
|
|
61
65
|
# Implicit Wait times out in Edge
|
|
62
66
|
raise Selenium::WebDriver::Error::NoSuchElementError
|
|
63
67
|
end
|
|
@@ -67,10 +71,6 @@ module Selenium
|
|
|
67
71
|
#
|
|
68
72
|
# @see SearchContext#find_element
|
|
69
73
|
#
|
|
70
|
-
# @param [:class, :class_name, :css, :id, :link_text, :link, :partial_link_text, :name, :tag_name, :xpath] how
|
|
71
|
-
# @param [String] what
|
|
72
|
-
# @return [Array<Element>]
|
|
73
|
-
#
|
|
74
74
|
|
|
75
75
|
def find_elements(*args)
|
|
76
76
|
how, what = extract_args(args)
|
|
@@ -78,8 +78,8 @@ module Selenium
|
|
|
78
78
|
by = FINDERS[how.to_sym]
|
|
79
79
|
raise ArgumentError, "cannot find elements by #{how.inspect}" unless by
|
|
80
80
|
|
|
81
|
-
bridge.find_elements_by by, what
|
|
82
|
-
rescue Selenium::WebDriver::Error::
|
|
81
|
+
bridge.find_elements_by by, what, ref
|
|
82
|
+
rescue Selenium::WebDriver::Error::TimeoutError
|
|
83
83
|
# Implicit Wait times out in Edge
|
|
84
84
|
[]
|
|
85
85
|
end
|
|
@@ -93,15 +93,11 @@ module Selenium
|
|
|
93
93
|
when 1
|
|
94
94
|
arg = args.first
|
|
95
95
|
|
|
96
|
-
unless arg.respond_to?(:shift)
|
|
97
|
-
raise ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift"
|
|
98
|
-
end
|
|
96
|
+
raise ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift" unless arg.respond_to?(:shift)
|
|
99
97
|
|
|
100
98
|
# this will be a single-entry hash, so use #shift over #first or #[]
|
|
101
99
|
arr = arg.dup.shift
|
|
102
|
-
unless arr.size == 2
|
|
103
|
-
raise ArgumentError, "expected #{arr.inspect} to have 2 elements"
|
|
104
|
-
end
|
|
100
|
+
raise ArgumentError, "expected #{arr.inspect} to have 2 elements" unless arr.size == 2
|
|
105
101
|
|
|
106
102
|
arr
|
|
107
103
|
else
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
3
|
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
4
|
# or more contributor license agreements. See the NOTICE file
|
|
5
5
|
# distributed with this work for additional information
|
|
@@ -23,36 +23,77 @@ module Selenium
|
|
|
23
23
|
# Base class implementing default behavior of service object,
|
|
24
24
|
# responsible for starting and stopping driver implementations.
|
|
25
25
|
#
|
|
26
|
-
# Subclasses must implement the following private methods:
|
|
27
|
-
# * #start_process
|
|
28
|
-
# * #stop_server
|
|
29
|
-
# * #cannot_connect_error_text
|
|
30
|
-
#
|
|
31
|
-
# @api private
|
|
32
|
-
#
|
|
33
26
|
|
|
34
27
|
class Service
|
|
35
|
-
START_TIMEOUT
|
|
28
|
+
START_TIMEOUT = 20
|
|
36
29
|
SOCKET_LOCK_TIMEOUT = 45
|
|
37
|
-
STOP_TIMEOUT
|
|
30
|
+
STOP_TIMEOUT = 20
|
|
31
|
+
|
|
32
|
+
class << self
|
|
33
|
+
attr_reader :driver_path
|
|
34
|
+
|
|
35
|
+
def chrome(**opts)
|
|
36
|
+
Chrome::Service.new(**opts)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def firefox(**opts)
|
|
40
|
+
Firefox::Service.new(**opts)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def ie(**opts)
|
|
44
|
+
IE::Service.new(**opts)
|
|
45
|
+
end
|
|
46
|
+
alias_method :internet_explorer, :ie
|
|
47
|
+
|
|
48
|
+
def edge(**opts)
|
|
49
|
+
Edge::Service.new(**opts)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def edge_chrome(**opts)
|
|
53
|
+
EdgeChrome::Service.new(**opts)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def edge_html(**opts)
|
|
57
|
+
EdgeHtml::Service.new(**opts)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def safari(**opts)
|
|
61
|
+
Safari::Service.new(**opts)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def driver_path=(path)
|
|
65
|
+
Platform.assert_executable path if path.is_a?(String)
|
|
66
|
+
@driver_path = path
|
|
67
|
+
end
|
|
68
|
+
end
|
|
38
69
|
|
|
39
70
|
attr_accessor :host
|
|
71
|
+
attr_reader :executable_path
|
|
72
|
+
|
|
73
|
+
#
|
|
74
|
+
# End users should use a class method for the desired driver, rather than using this directly.
|
|
75
|
+
#
|
|
76
|
+
# @api private
|
|
77
|
+
#
|
|
78
|
+
|
|
79
|
+
def initialize(path: nil, port: nil, args: nil)
|
|
80
|
+
path ||= self.class.driver_path
|
|
81
|
+
port ||= self.class::DEFAULT_PORT
|
|
82
|
+
args ||= []
|
|
83
|
+
|
|
84
|
+
@executable_path = binary_path(path)
|
|
85
|
+
@host = Platform.localhost
|
|
86
|
+
@port = Integer(port)
|
|
40
87
|
|
|
41
|
-
|
|
42
|
-
@executable_path = executable_path
|
|
43
|
-
@host = Platform.localhost
|
|
44
|
-
@port = Integer(port)
|
|
45
|
-
@extra_args = extra_args
|
|
88
|
+
@extra_args = args.is_a?(Hash) ? extract_service_args(args) : args
|
|
46
89
|
|
|
47
90
|
raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
|
|
48
91
|
end
|
|
49
92
|
|
|
50
93
|
def start
|
|
51
|
-
if process_running?
|
|
52
|
-
raise "already started: #{uri.inspect} #{@executable_path.inspect}"
|
|
53
|
-
end
|
|
94
|
+
raise "already started: #{uri.inspect} #{@executable_path.inspect}" if process_running?
|
|
54
95
|
|
|
55
|
-
Platform.exit_hook
|
|
96
|
+
Platform.exit_hook(&method(:stop)) # make sure we don't leave the server running
|
|
56
97
|
|
|
57
98
|
socket_lock.locked do
|
|
58
99
|
find_free_port
|
|
@@ -62,8 +103,12 @@ module Selenium
|
|
|
62
103
|
end
|
|
63
104
|
|
|
64
105
|
def stop
|
|
65
|
-
return
|
|
106
|
+
return unless self.class::SHUTDOWN_SUPPORTED
|
|
107
|
+
|
|
66
108
|
stop_server
|
|
109
|
+
@process.poll_for_exit STOP_TIMEOUT
|
|
110
|
+
rescue ChildProcess::TimeoutError
|
|
111
|
+
nil # noop
|
|
67
112
|
ensure
|
|
68
113
|
stop_process
|
|
69
114
|
end
|
|
@@ -74,6 +119,29 @@ module Selenium
|
|
|
74
119
|
|
|
75
120
|
private
|
|
76
121
|
|
|
122
|
+
def binary_path(path = nil)
|
|
123
|
+
path = path.call if path.is_a?(Proc)
|
|
124
|
+
path ||= Platform.find_binary(self.class::EXECUTABLE)
|
|
125
|
+
|
|
126
|
+
raise Error::WebDriverError, self.class::MISSING_TEXT unless path
|
|
127
|
+
|
|
128
|
+
Platform.assert_executable path
|
|
129
|
+
path
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def build_process(*command)
|
|
133
|
+
WebDriver.logger.debug("Executing Process #{command}")
|
|
134
|
+
@process = ChildProcess.build(*command)
|
|
135
|
+
if WebDriver.logger.debug?
|
|
136
|
+
@process.io.stdout = @process.io.stderr = WebDriver.logger.io
|
|
137
|
+
elsif Platform.jruby?
|
|
138
|
+
# Apparently we need to read the output of drivers on JRuby.
|
|
139
|
+
@process.io.stdout = @process.io.stderr = File.new(Platform.null_device, 'w')
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
@process
|
|
143
|
+
end
|
|
144
|
+
|
|
77
145
|
def connect_to_server
|
|
78
146
|
Net::HTTP.start(@host, @port) do |http|
|
|
79
147
|
http.open_timeout = STOP_TIMEOUT / 2
|
|
@@ -88,21 +156,30 @@ module Selenium
|
|
|
88
156
|
end
|
|
89
157
|
|
|
90
158
|
def start_process
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
raise NotImplementedError, 'subclass responsibility'
|
|
159
|
+
@process = build_process(@executable_path, "--port=#{@port}", *@extra_args)
|
|
160
|
+
# Note: this is a bug only in Windows 7
|
|
161
|
+
@process.leader = true unless Platform.windows?
|
|
162
|
+
@process.start
|
|
96
163
|
end
|
|
97
164
|
|
|
98
165
|
def stop_process
|
|
99
|
-
|
|
100
|
-
|
|
166
|
+
return if process_exited?
|
|
167
|
+
|
|
101
168
|
@process.stop STOP_TIMEOUT
|
|
169
|
+
@process.io.stdout.close if Platform.jruby? && !WebDriver.logger.debug?
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def stop_server
|
|
173
|
+
return if process_exited?
|
|
174
|
+
|
|
175
|
+
connect_to_server do |http|
|
|
176
|
+
headers = WebDriver::Remote::Http::Common::DEFAULT_HEADERS.dup
|
|
177
|
+
http.get('/shutdown', headers)
|
|
178
|
+
end
|
|
102
179
|
end
|
|
103
180
|
|
|
104
181
|
def process_running?
|
|
105
|
-
@process && @process
|
|
182
|
+
defined?(@process) && @process&.alive?
|
|
106
183
|
end
|
|
107
184
|
|
|
108
185
|
def process_exited?
|
|
@@ -112,16 +189,24 @@ module Selenium
|
|
|
112
189
|
def connect_until_stable
|
|
113
190
|
socket_poller = SocketPoller.new @host, @port, START_TIMEOUT
|
|
114
191
|
return if socket_poller.connected?
|
|
192
|
+
|
|
115
193
|
raise Error::WebDriverError, cannot_connect_error_text
|
|
116
194
|
end
|
|
117
195
|
|
|
118
196
|
def cannot_connect_error_text
|
|
119
|
-
|
|
197
|
+
"unable to connect to #{self.class::EXECUTABLE} #{@host}:#{@port}"
|
|
120
198
|
end
|
|
121
199
|
|
|
122
200
|
def socket_lock
|
|
123
201
|
@socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
|
|
124
202
|
end
|
|
203
|
+
|
|
204
|
+
protected
|
|
205
|
+
|
|
206
|
+
def extract_service_args(driver_opts)
|
|
207
|
+
driver_opts.key?(:args) ? driver_opts.delete(:args) : []
|
|
208
|
+
end
|
|
209
|
+
|
|
125
210
|
end # Service
|
|
126
211
|
end # WebDriver
|
|
127
212
|
end # Selenium
|