selenium-webdriver 2.53.4 → 3.8.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 +7 -0
- data/CHANGES +363 -10
- data/LICENSE +1 -1
- data/README.md +2 -3
- data/lib/selenium-webdriver.rb +0 -2
- data/lib/selenium/server.rb +69 -70
- data/lib/selenium/webdriver.rb +32 -23
- data/lib/selenium/webdriver/atoms.rb +18 -0
- data/lib/selenium/webdriver/atoms/getAttribute.js +8 -0
- data/lib/selenium/webdriver/chrome.rb +8 -6
- data/lib/selenium/webdriver/chrome/driver.rb +112 -0
- data/lib/selenium/webdriver/chrome/options.rb +168 -0
- data/lib/selenium/webdriver/chrome/profile.rb +17 -17
- data/lib/selenium/webdriver/chrome/service.rb +22 -89
- data/lib/selenium/webdriver/common.rb +13 -6
- data/lib/selenium/webdriver/common/action_builder.rb +49 -57
- data/lib/selenium/webdriver/common/alert.rb +5 -15
- data/lib/selenium/webdriver/common/bridge_helper.rb +10 -17
- data/lib/selenium/webdriver/common/driver.rb +53 -68
- data/lib/selenium/webdriver/common/driver_extensions/{has_input_devices.rb → has_addons.rb} +13 -23
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +4 -8
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +4 -7
- data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +0 -4
- data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +0 -4
- data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +1 -5
- data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +0 -5
- data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +4 -9
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +7 -7
- data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +2 -7
- data/lib/selenium/webdriver/common/element.rb +57 -39
- data/lib/selenium/webdriver/common/error.rb +204 -106
- data/lib/selenium/webdriver/common/file_reaper.rb +3 -11
- data/lib/selenium/webdriver/common/html5/local_storage.rb +6 -10
- data/lib/selenium/webdriver/common/html5/session_storage.rb +6 -10
- data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +7 -18
- data/lib/selenium/webdriver/{safari/options.rb → common/interactions/input_device.rb} +20 -31
- data/lib/selenium/webdriver/common/interactions/interaction.rb +50 -0
- data/lib/selenium/webdriver/{safari/browser.rb → common/interactions/interactions.rb} +16 -15
- data/lib/selenium/webdriver/common/interactions/key_actions.rb +143 -0
- data/lib/selenium/webdriver/common/interactions/key_input.rb +62 -0
- data/lib/selenium/webdriver/{android.rb → common/interactions/none_input.rb} +11 -6
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +353 -0
- data/lib/selenium/webdriver/common/interactions/pointer_input.rb +132 -0
- data/lib/selenium/webdriver/common/keyboard.rb +7 -14
- data/lib/selenium/webdriver/common/keys.rb +99 -82
- data/lib/selenium/webdriver/common/log_entry.rb +3 -6
- data/lib/selenium/webdriver/common/logger.rb +140 -0
- data/lib/selenium/webdriver/common/logs.rb +2 -6
- data/lib/selenium/webdriver/common/mouse.rb +9 -14
- data/lib/selenium/webdriver/common/navigation.rb +2 -6
- data/lib/selenium/webdriver/common/options.rb +20 -23
- data/lib/selenium/webdriver/common/platform.rb +70 -97
- data/lib/selenium/webdriver/common/port_prober.rb +3 -4
- data/lib/selenium/webdriver/common/profile_helper.rb +6 -11
- data/lib/selenium/webdriver/common/proxy.rb +58 -72
- data/lib/selenium/webdriver/common/search_context.rb +22 -29
- data/lib/selenium/webdriver/common/service.rb +161 -0
- data/lib/selenium/webdriver/common/socket_lock.rb +6 -14
- data/lib/selenium/webdriver/common/socket_poller.rb +5 -12
- data/lib/selenium/webdriver/common/target_locator.rb +11 -15
- data/lib/selenium/webdriver/common/timeouts.rb +4 -8
- data/lib/selenium/webdriver/common/touch_action_builder.rb +2 -6
- data/lib/selenium/webdriver/common/touch_screen.rb +19 -23
- data/lib/selenium/webdriver/common/w3c_action_builder.rb +209 -0
- data/lib/selenium/webdriver/{phantomjs.rb → common/w3c_options.rb} +16 -14
- data/lib/selenium/webdriver/common/wait.rb +6 -13
- data/lib/selenium/webdriver/common/window.rb +48 -17
- data/lib/selenium/webdriver/common/zipper.rb +6 -10
- data/lib/selenium/webdriver/edge.rb +5 -12
- data/lib/selenium/webdriver/edge/bridge.rb +32 -63
- data/lib/selenium/webdriver/edge/driver.rb +73 -0
- data/lib/selenium/webdriver/edge/service.rb +18 -87
- data/lib/selenium/webdriver/firefox.rb +20 -11
- data/lib/selenium/webdriver/firefox/binary.rb +40 -56
- data/lib/selenium/webdriver/firefox/driver.rb +48 -0
- data/lib/selenium/webdriver/firefox/extension.rb +18 -8
- data/lib/selenium/webdriver/firefox/extension/prefs.json +3 -11
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/launcher.rb +13 -22
- data/lib/selenium/webdriver/firefox/legacy/driver.rb +79 -0
- data/lib/selenium/webdriver/{iphone.rb → firefox/marionette/bridge.rb} +25 -6
- data/lib/selenium/webdriver/firefox/marionette/driver.rb +96 -0
- data/lib/selenium/webdriver/firefox/options.rb +149 -0
- data/lib/selenium/webdriver/firefox/profile.rb +46 -46
- data/lib/selenium/webdriver/firefox/profiles_ini.rb +8 -18
- data/lib/selenium/webdriver/firefox/service.rb +23 -83
- data/lib/selenium/webdriver/firefox/util.rb +0 -4
- data/lib/selenium/webdriver/ie.rb +4 -8
- data/lib/selenium/webdriver/ie/driver.rb +90 -0
- data/lib/selenium/webdriver/ie/options.rb +136 -0
- data/lib/selenium/webdriver/ie/service.rb +58 -0
- data/lib/selenium/webdriver/remote.rb +8 -16
- data/lib/selenium/webdriver/remote/bridge.rb +96 -565
- data/lib/selenium/webdriver/remote/capabilities.rb +76 -94
- data/lib/selenium/webdriver/remote/driver.rb +49 -0
- data/lib/selenium/webdriver/remote/http/common.rb +22 -20
- data/lib/selenium/webdriver/remote/http/curb.rb +9 -12
- data/lib/selenium/webdriver/remote/http/default.rb +54 -41
- data/lib/selenium/webdriver/remote/http/persistent.rb +9 -8
- data/lib/selenium/webdriver/remote/oss/bridge.rb +586 -0
- data/lib/selenium/webdriver/remote/oss/commands.rb +221 -0
- data/lib/selenium/webdriver/remote/response.rb +39 -27
- data/lib/selenium/webdriver/remote/server_error.rb +1 -5
- data/lib/selenium/webdriver/remote/w3c/bridge.rb +573 -0
- data/lib/selenium/webdriver/remote/w3c/capabilities.rb +290 -0
- data/lib/selenium/webdriver/remote/w3c/commands.rb +148 -0
- data/lib/selenium/webdriver/safari.rb +20 -29
- data/lib/selenium/webdriver/{firefox/w3c_bridge.rb → safari/driver.rb} +21 -30
- data/lib/selenium/webdriver/safari/service.rb +57 -0
- data/lib/selenium/webdriver/support.rb +1 -2
- data/lib/selenium/webdriver/support/abstract_event_listener.rb +17 -4
- data/lib/selenium/webdriver/support/block_event_listener.rb +1 -5
- data/lib/selenium/webdriver/support/color.rb +57 -42
- data/lib/selenium/webdriver/support/escaper.rb +41 -0
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +36 -40
- data/lib/selenium/webdriver/support/select.rb +33 -86
- data/selenium-webdriver.gemspec +22 -25
- metadata +254 -261
- data/lib/selenium-client.rb +0 -21
- data/lib/selenium/client.rb +0 -57
- data/lib/selenium/client/base.rb +0 -151
- data/lib/selenium/client/driver.rb +0 -29
- data/lib/selenium/client/errors.rb +0 -28
- data/lib/selenium/client/extensions.rb +0 -132
- data/lib/selenium/client/idiomatic.rb +0 -507
- data/lib/selenium/client/javascript_expression_builder.rb +0 -135
- data/lib/selenium/client/javascript_frameworks/jquery.rb +0 -32
- data/lib/selenium/client/javascript_frameworks/prototype.rb +0 -32
- data/lib/selenium/client/legacy_driver.rb +0 -1722
- data/lib/selenium/client/protocol.rb +0 -123
- data/lib/selenium/client/selenium_helper.rb +0 -49
- data/lib/selenium/rake/server_task.rb +0 -176
- data/lib/selenium/webdriver/android/bridge.rb +0 -68
- data/lib/selenium/webdriver/chrome/bridge.rb +0 -139
- data/lib/selenium/webdriver/common/core_ext/base64.rb +0 -28
- data/lib/selenium/webdriver/common/core_ext/dir.rb +0 -61
- data/lib/selenium/webdriver/common/html5/location.rb +0 -19
- data/lib/selenium/webdriver/common/w3c_error.rb +0 -194
- data/lib/selenium/webdriver/edge/legacy_support.rb +0 -117
- data/lib/selenium/webdriver/firefox/bridge.rb +0 -89
- data/lib/selenium/webdriver/ie/bridge.rb +0 -88
- data/lib/selenium/webdriver/ie/server.rb +0 -133
- data/lib/selenium/webdriver/iphone/bridge.rb +0 -64
- data/lib/selenium/webdriver/phantomjs/bridge.rb +0 -78
- data/lib/selenium/webdriver/phantomjs/service.rb +0 -130
- data/lib/selenium/webdriver/remote/commands.rb +0 -211
- data/lib/selenium/webdriver/remote/w3c_bridge.rb +0 -668
- data/lib/selenium/webdriver/remote/w3c_capabilities.rb +0 -236
- data/lib/selenium/webdriver/remote/w3c_commands.rb +0 -132
- data/lib/selenium/webdriver/safari/bridge.rb +0 -135
- data/lib/selenium/webdriver/safari/resources/client.js +0 -7255
- data/lib/selenium/webdriver/safari/server.rb +0 -187
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
#
|
|
3
1
|
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
2
|
# or more contributor license agreements. See the NOTICE file
|
|
5
3
|
# distributed with this work for additional information
|
|
@@ -40,13 +38,15 @@ module Selenium
|
|
|
40
38
|
|
|
41
39
|
IGNORED_ERRORS = [Errno::EADDRNOTAVAIL]
|
|
42
40
|
IGNORED_ERRORS << Errno::EBADF if Platform.cygwin?
|
|
41
|
+
IGNORED_ERRORS << Errno::EACCES if Platform.windows?
|
|
42
|
+
IGNORED_ERRORS.freeze
|
|
43
43
|
|
|
44
44
|
def self.free?(port)
|
|
45
45
|
Platform.interfaces.each do |host|
|
|
46
46
|
begin
|
|
47
47
|
TCPServer.new(host, port).close
|
|
48
48
|
rescue *IGNORED_ERRORS => ex
|
|
49
|
-
|
|
49
|
+
WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{ex.message})")
|
|
50
50
|
# ignored - some machines appear unable to bind to some of their interfaces
|
|
51
51
|
end
|
|
52
52
|
end
|
|
@@ -55,7 +55,6 @@ module Selenium
|
|
|
55
55
|
rescue SocketError, Errno::EADDRINUSE
|
|
56
56
|
false
|
|
57
57
|
end
|
|
58
|
-
|
|
59
58
|
end # PortProber
|
|
60
59
|
end # WebDriver
|
|
61
60
|
end # Selenium
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
#
|
|
3
1
|
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
2
|
# or more contributor license agreements. See the NOTICE file
|
|
5
3
|
# distributed with this work for additional information
|
|
@@ -19,7 +17,6 @@
|
|
|
19
17
|
|
|
20
18
|
module Selenium
|
|
21
19
|
module WebDriver
|
|
22
|
-
|
|
23
20
|
#
|
|
24
21
|
# @api private
|
|
25
22
|
#
|
|
@@ -28,27 +25,26 @@ module Selenium
|
|
|
28
25
|
#
|
|
29
26
|
|
|
30
27
|
module ProfileHelper
|
|
31
|
-
|
|
32
28
|
def self.included(base)
|
|
33
29
|
base.extend ClassMethods
|
|
34
30
|
end
|
|
35
31
|
|
|
36
|
-
def as_json(
|
|
37
|
-
{
|
|
32
|
+
def as_json(*)
|
|
33
|
+
{"zip" => Zipper.zip(layout_on_disk)}
|
|
38
34
|
end
|
|
39
35
|
|
|
40
|
-
def to_json(*
|
|
36
|
+
def to_json(*)
|
|
41
37
|
JSON.generate as_json
|
|
42
38
|
end
|
|
43
39
|
|
|
44
40
|
private
|
|
45
41
|
|
|
46
42
|
def create_tmp_copy(directory)
|
|
47
|
-
tmp_directory = Dir.mktmpdir(
|
|
43
|
+
tmp_directory = Dir.mktmpdir('webdriver-rb-profilecopy')
|
|
48
44
|
|
|
49
45
|
# TODO: must be a better way..
|
|
50
46
|
FileUtils.rm_rf tmp_directory
|
|
51
|
-
FileUtils.mkdir_p File.dirname(tmp_directory), :
|
|
47
|
+
FileUtils.mkdir_p File.dirname(tmp_directory), mode: 0o700
|
|
52
48
|
FileUtils.cp_r directory, tmp_directory
|
|
53
49
|
|
|
54
50
|
tmp_directory
|
|
@@ -72,7 +68,7 @@ module Selenium
|
|
|
72
68
|
tmp_dir = Dir.mktmpdir
|
|
73
69
|
begin
|
|
74
70
|
zip_path = File.join(tmp_dir, "webdriver-profile-duplicate-#{json.hash}.zip")
|
|
75
|
-
File.open(zip_path,
|
|
71
|
+
File.open(zip_path, 'wb') { |zip_file| zip_file << Base64.decode64(data) }
|
|
76
72
|
|
|
77
73
|
new Zipper.unzip(zip_path)
|
|
78
74
|
ensure
|
|
@@ -80,7 +76,6 @@ module Selenium
|
|
|
80
76
|
end
|
|
81
77
|
end
|
|
82
78
|
end # ClassMethods
|
|
83
|
-
|
|
84
79
|
end # ProfileHelper
|
|
85
80
|
end # WebDriver
|
|
86
81
|
end # Selenium
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
#
|
|
3
1
|
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
2
|
# or more contributor license agreements. See the NOTICE file
|
|
5
3
|
# distributed with this work for additional information
|
|
@@ -21,45 +19,56 @@ module Selenium
|
|
|
21
19
|
module WebDriver
|
|
22
20
|
class Proxy
|
|
23
21
|
TYPES = {
|
|
24
|
-
:
|
|
25
|
-
:
|
|
26
|
-
:
|
|
27
|
-
:
|
|
28
|
-
:
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
22
|
+
direct: 'DIRECT', # Direct connection, no proxy (default on Windows).
|
|
23
|
+
manual: 'MANUAL', # Manual proxy settings (e.g., for httpProxy).
|
|
24
|
+
pac: 'PAC', # Proxy autoconfiguration from URL.
|
|
25
|
+
auto_detect: 'AUTODETECT', # Proxy autodetection (presumably with WPAD).
|
|
26
|
+
system: 'SYSTEM' # Use system settings (default on Linux).
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
29
|
+
ALLOWED = {type: 'proxyType',
|
|
30
|
+
ftp: 'ftpProxy',
|
|
31
|
+
http: 'httpProxy',
|
|
32
|
+
no_proxy: 'noProxy',
|
|
33
|
+
pac: 'proxyAutoconfigUrl',
|
|
34
|
+
ssl: 'sslProxy',
|
|
35
|
+
auto_detect: 'autodetect',
|
|
36
|
+
socks: 'socksProxy',
|
|
37
|
+
socks_username: 'socksUsername',
|
|
38
|
+
socks_password: 'socksPassword'}.freeze
|
|
39
|
+
|
|
40
|
+
ALLOWED.each_key { |t| attr_reader t }
|
|
41
|
+
|
|
42
|
+
def self.json_create(data)
|
|
43
|
+
data['proxyType'] = data['proxyType'].downcase.to_sym
|
|
44
|
+
return if data['proxyType'] == :unspecified
|
|
45
|
+
|
|
46
|
+
proxy = new
|
|
47
|
+
|
|
48
|
+
ALLOWED.each do |k, v|
|
|
49
|
+
proxy.send("#{k}=", data[v]) if data.key?(v)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
proxy
|
|
53
|
+
end
|
|
41
54
|
|
|
42
55
|
def initialize(opts = {})
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
self.auto_detect = opts.delete(:auto_detect) if opts.has_key? :auto_detect
|
|
52
|
-
self.socks = opts.delete(:socks) if opts.has_key? :socks
|
|
53
|
-
self.socks_username = opts.delete(:socks_username) if opts.has_key? :socks_username
|
|
54
|
-
self.socks_password = opts.delete(:socks_password) if opts.has_key? :socks_password
|
|
55
|
-
|
|
56
|
-
unless opts.empty?
|
|
57
|
-
raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
|
|
56
|
+
not_allowed = []
|
|
57
|
+
|
|
58
|
+
opts.each do |k, v|
|
|
59
|
+
if ALLOWED.key?(k)
|
|
60
|
+
send("#{k}=", v)
|
|
61
|
+
else
|
|
62
|
+
not_allowed << k
|
|
63
|
+
end
|
|
58
64
|
end
|
|
65
|
+
|
|
66
|
+
return if not_allowed.empty?
|
|
67
|
+
raise ArgumentError, "unknown option#{'s' if not_allowed.size != 1}: #{not_allowed.inspect}"
|
|
59
68
|
end
|
|
60
69
|
|
|
61
70
|
def ==(other)
|
|
62
|
-
other.
|
|
71
|
+
other.is_a?(self.class) && as_json == other.as_json
|
|
63
72
|
end
|
|
64
73
|
alias_method :eql?, :==
|
|
65
74
|
|
|
@@ -109,7 +118,7 @@ module Selenium
|
|
|
109
118
|
end
|
|
110
119
|
|
|
111
120
|
def type=(type)
|
|
112
|
-
unless TYPES.
|
|
121
|
+
unless TYPES.key? type
|
|
113
122
|
raise ArgumentError, "invalid proxy type: #{type.inspect}, expected one of #{TYPES.keys.inspect}"
|
|
114
123
|
end
|
|
115
124
|
|
|
@@ -120,49 +129,26 @@ module Selenium
|
|
|
120
129
|
@type = type
|
|
121
130
|
end
|
|
122
131
|
|
|
123
|
-
def as_json(
|
|
132
|
+
def as_json(*)
|
|
124
133
|
json_result = {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
json_result["socksPassword"] = socks_password if socks_password
|
|
134
|
+
'proxyType' => TYPES[type],
|
|
135
|
+
'ftpProxy' => ftp,
|
|
136
|
+
'httpProxy' => http,
|
|
137
|
+
'noProxy' => no_proxy,
|
|
138
|
+
'proxyAutoconfigUrl' => pac,
|
|
139
|
+
'sslProxy' => ssl,
|
|
140
|
+
'autodetect' => auto_detect,
|
|
141
|
+
'socksProxy' => socks,
|
|
142
|
+
'socksUsername' => socks_username,
|
|
143
|
+
'socksPassword' => socks_password
|
|
144
|
+
}.delete_if { |_k, v| v.nil? }
|
|
137
145
|
|
|
138
146
|
json_result if json_result.length > 1
|
|
139
147
|
end
|
|
140
148
|
|
|
141
|
-
def to_json(*
|
|
149
|
+
def to_json(*)
|
|
142
150
|
JSON.generate as_json
|
|
143
151
|
end
|
|
144
|
-
|
|
145
|
-
class << self
|
|
146
|
-
def json_create(data)
|
|
147
|
-
return if data['proxyType'] == 'UNSPECIFIED'
|
|
148
|
-
|
|
149
|
-
proxy = new
|
|
150
|
-
|
|
151
|
-
proxy.type = data['proxyType'].downcase.to_sym if data.has_key? 'proxyType'
|
|
152
|
-
proxy.ftp = data['ftpProxy'] if data.has_key? 'ftpProxy'
|
|
153
|
-
proxy.http = data['httpProxy'] if data.has_key? 'httpProxy'
|
|
154
|
-
proxy.no_proxy = data['noProxy'] if data.has_key? 'noProxy'
|
|
155
|
-
proxy.pac = data['proxyAutoconfigUrl'] if data.has_key? 'proxyAutoconfigUrl'
|
|
156
|
-
proxy.ssl = data['sslProxy'] if data.has_key? 'sslProxy'
|
|
157
|
-
proxy.auto_detect = data['autodetect'] if data.has_key? 'autodetect'
|
|
158
|
-
proxy.socks = data['socksProxy'] if data.has_key? 'socksProxy'
|
|
159
|
-
proxy.socks_username = data['socksUsername'] if data.has_key? 'socksUsername'
|
|
160
|
-
proxy.socks_password = data['socksPassword'] if data.has_key? 'socksPassword'
|
|
161
|
-
|
|
162
|
-
proxy
|
|
163
|
-
end
|
|
164
|
-
end # class << self
|
|
165
|
-
|
|
166
152
|
end # Proxy
|
|
167
153
|
end # WebDriver
|
|
168
154
|
end # Selenium
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
#
|
|
3
1
|
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
4
2
|
# or more contributor license agreements. See the NOTICE file
|
|
5
3
|
# distributed with this work for additional information
|
|
@@ -20,43 +18,44 @@
|
|
|
20
18
|
module Selenium
|
|
21
19
|
module WebDriver
|
|
22
20
|
module SearchContext
|
|
23
|
-
|
|
24
21
|
# @api private
|
|
25
22
|
FINDERS = {
|
|
26
|
-
:
|
|
27
|
-
:
|
|
28
|
-
:
|
|
29
|
-
:
|
|
30
|
-
:
|
|
31
|
-
:
|
|
32
|
-
:
|
|
33
|
-
:
|
|
34
|
-
:
|
|
35
|
-
:
|
|
36
|
-
}
|
|
23
|
+
class: 'class name',
|
|
24
|
+
class_name: 'class name',
|
|
25
|
+
css: 'css selector',
|
|
26
|
+
id: 'id',
|
|
27
|
+
link: 'link text',
|
|
28
|
+
link_text: 'link text',
|
|
29
|
+
name: 'name',
|
|
30
|
+
partial_link_text: 'partial link text',
|
|
31
|
+
tag_name: 'tag name',
|
|
32
|
+
xpath: 'xpath'
|
|
33
|
+
}.freeze
|
|
37
34
|
|
|
38
35
|
#
|
|
39
|
-
# Find the first element matching the given arguments
|
|
36
|
+
# Find the first element matching the given arguments
|
|
40
37
|
#
|
|
41
38
|
# When using Element#find_element with :xpath, be aware that webdriver
|
|
42
39
|
# follows standard conventions: a search prefixed with "//" will search
|
|
43
40
|
# the entire document, not just the children of this current node. Use
|
|
44
41
|
# ".//" to limit your search to the children of the receiving Element.
|
|
45
42
|
#
|
|
46
|
-
# @
|
|
47
|
-
#
|
|
43
|
+
# @overload find_element(how, what)
|
|
44
|
+
# @param [Symbol, String] how The method to find the element by
|
|
45
|
+
# @param [String] what The locator to use
|
|
46
|
+
# @overload find_element(opts)
|
|
47
|
+
# @param [Hash] opts Find options
|
|
48
|
+
# @option opts [Symbol] :how Key named after the method to find the element by, containing the locator
|
|
48
49
|
# @return [Element]
|
|
49
50
|
#
|
|
50
51
|
# @raise [Error::NoSuchElementError] if the element doesn't exist
|
|
51
52
|
#
|
|
52
|
-
#
|
|
53
53
|
|
|
54
54
|
def find_element(*args)
|
|
55
55
|
how, what = extract_args(args)
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
end
|
|
57
|
+
by = FINDERS[how.to_sym]
|
|
58
|
+
raise ArgumentError, "cannot find element by #{how.inspect}" unless by
|
|
60
59
|
|
|
61
60
|
bridge.find_element_by by, what.to_s, ref
|
|
62
61
|
rescue Selenium::WebDriver::Error::TimeOutError
|
|
@@ -69,17 +68,12 @@ module Selenium
|
|
|
69
68
|
#
|
|
70
69
|
# @see SearchContext#find_element
|
|
71
70
|
#
|
|
72
|
-
# @param [:class, :class_name, :css, :id, :link_text, :link, :partial_link_text, :name, :tag_name, :xpath] how
|
|
73
|
-
# @param [String] what
|
|
74
|
-
# @return [Array<Element>]
|
|
75
|
-
#
|
|
76
71
|
|
|
77
72
|
def find_elements(*args)
|
|
78
73
|
how, what = extract_args(args)
|
|
79
74
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
end
|
|
75
|
+
by = FINDERS[how.to_sym]
|
|
76
|
+
raise ArgumentError, "cannot find elements by #{how.inspect}" unless by
|
|
83
77
|
|
|
84
78
|
bridge.find_elements_by by, what.to_s, ref
|
|
85
79
|
rescue Selenium::WebDriver::Error::TimeOutError
|
|
@@ -111,7 +105,6 @@ module Selenium
|
|
|
111
105
|
raise ArgumentError, "wrong number of arguments (#{args.size} for 2)"
|
|
112
106
|
end
|
|
113
107
|
end
|
|
114
|
-
|
|
115
108
|
end # SearchContext
|
|
116
109
|
end # WebDriver
|
|
117
110
|
end # Selenium
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Licensed to the Software Freedom Conservancy (SFC) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The SFC licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
|
12
|
+
# software distributed under the License is distributed on an
|
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
# KIND, either express or implied. See the License for the
|
|
15
|
+
# specific language governing permissions and limitations
|
|
16
|
+
# under the License.
|
|
17
|
+
|
|
18
|
+
module Selenium
|
|
19
|
+
module WebDriver
|
|
20
|
+
#
|
|
21
|
+
# Base class implementing default behavior of service object,
|
|
22
|
+
# responsible for starting and stopping driver implementations.
|
|
23
|
+
#
|
|
24
|
+
# Subclasses must implement the following private methods:
|
|
25
|
+
# * #start_process
|
|
26
|
+
# * #stop_server
|
|
27
|
+
# * #cannot_connect_error_text
|
|
28
|
+
#
|
|
29
|
+
# @api private
|
|
30
|
+
#
|
|
31
|
+
|
|
32
|
+
class Service
|
|
33
|
+
START_TIMEOUT = 20
|
|
34
|
+
SOCKET_LOCK_TIMEOUT = 45
|
|
35
|
+
STOP_TIMEOUT = 20
|
|
36
|
+
|
|
37
|
+
@executable = nil
|
|
38
|
+
@missing_text = nil
|
|
39
|
+
|
|
40
|
+
class << self
|
|
41
|
+
attr_reader :executable, :missing_text
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
attr_accessor :host
|
|
45
|
+
|
|
46
|
+
def initialize(executable_path, port, driver_opts)
|
|
47
|
+
@executable_path = binary_path(executable_path)
|
|
48
|
+
@host = Platform.localhost
|
|
49
|
+
@port = Integer(port)
|
|
50
|
+
@extra_args = extract_service_args(driver_opts)
|
|
51
|
+
|
|
52
|
+
raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def binary_path(path)
|
|
56
|
+
path = Platform.find_binary(self.class.executable) if path.nil?
|
|
57
|
+
raise Error::WebDriverError, self.class.missing_text unless path
|
|
58
|
+
Platform.assert_executable path
|
|
59
|
+
path
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def start
|
|
63
|
+
if process_running?
|
|
64
|
+
raise "already started: #{uri.inspect} #{@executable_path.inspect}"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Platform.exit_hook { stop } # make sure we don't leave the server running
|
|
68
|
+
|
|
69
|
+
socket_lock.locked do
|
|
70
|
+
find_free_port
|
|
71
|
+
start_process
|
|
72
|
+
connect_until_stable
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def stop
|
|
77
|
+
stop_server
|
|
78
|
+
@process.poll_for_exit STOP_TIMEOUT
|
|
79
|
+
rescue ChildProcess::TimeoutError
|
|
80
|
+
ensure
|
|
81
|
+
stop_process
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def uri
|
|
85
|
+
@uri ||= URI.parse("http://#{@host}:#{@port}")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def build_process(*command)
|
|
91
|
+
WebDriver.logger.debug("Executing Process #{command}")
|
|
92
|
+
@process = ChildProcess.build(*command)
|
|
93
|
+
if WebDriver.logger.debug?
|
|
94
|
+
@process.io.stdout = @process.io.stderr = WebDriver.logger.io
|
|
95
|
+
elsif Platform.jruby?
|
|
96
|
+
# Apparently we need to read the output of drivers on JRuby.
|
|
97
|
+
@process.io.stdout = @process.io.stderr = File.new(Platform.null_device, 'w')
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
@process
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def connect_to_server
|
|
104
|
+
Net::HTTP.start(@host, @port) do |http|
|
|
105
|
+
http.open_timeout = STOP_TIMEOUT / 2
|
|
106
|
+
http.read_timeout = STOP_TIMEOUT / 2
|
|
107
|
+
|
|
108
|
+
yield http
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def find_free_port
|
|
113
|
+
@port = PortProber.above(@port)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def start_process
|
|
117
|
+
raise NotImplementedError, 'subclass responsibility'
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def stop_process
|
|
121
|
+
return if process_exited?
|
|
122
|
+
@process.stop STOP_TIMEOUT
|
|
123
|
+
@process.io.stdout.close if Platform.jruby? && !WebDriver.logger.debug?
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def stop_server
|
|
127
|
+
return if process_exited?
|
|
128
|
+
connect_to_server { |http| http.get('/shutdown') }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def process_running?
|
|
132
|
+
@process && @process.alive?
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def process_exited?
|
|
136
|
+
@process.nil? || @process.exited?
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def connect_until_stable
|
|
140
|
+
socket_poller = SocketPoller.new @host, @port, START_TIMEOUT
|
|
141
|
+
return if socket_poller.connected?
|
|
142
|
+
raise Error::WebDriverError, cannot_connect_error_text
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def cannot_connect_error_text
|
|
146
|
+
raise NotImplementedError, 'subclass responsibility'
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def socket_lock
|
|
150
|
+
@socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
protected
|
|
154
|
+
|
|
155
|
+
def extract_service_args(driver_opts)
|
|
156
|
+
driver_opts.key?(:args) ? driver_opts.delete(:args) : []
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
end # Service
|
|
160
|
+
end # WebDriver
|
|
161
|
+
end # Selenium
|