selenium-webdriver 2.45.0 → 3.142.7
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 +795 -3
- data/Gemfile +2 -0
- data/{COPYING → LICENSE} +1 -3
- data/README.md +13 -9
- data/lib/selenium/server.rb +93 -71
- data/lib/selenium/webdriver/atoms/getAttribute.js +7 -0
- data/lib/selenium/webdriver/atoms/isDisplayed.js +102 -0
- data/lib/selenium/webdriver/atoms.rb +37 -0
- data/lib/selenium/webdriver/chrome/bridge.rb +47 -99
- data/lib/selenium/webdriver/chrome/driver.rb +127 -0
- data/lib/selenium/webdriver/chrome/options.rb +190 -0
- data/lib/selenium/webdriver/chrome/profile.rb +40 -20
- data/lib/selenium/webdriver/chrome/service.rb +46 -62
- data/lib/selenium/webdriver/chrome.rb +34 -6
- data/lib/selenium/webdriver/common/action_builder.rb +69 -56
- data/lib/selenium/webdriver/common/alert.rb +25 -8
- data/lib/selenium/webdriver/common/bridge_helper.rb +35 -20
- data/lib/selenium/webdriver/common/driver.rb +90 -63
- 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_debugger.rb +42 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +26 -11
- data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +51 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +58 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +51 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +23 -6
- data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +19 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +24 -7
- data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +19 -3
- data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +23 -7
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +26 -5
- data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +20 -6
- data/lib/selenium/webdriver/common/element.rb +79 -37
- data/lib/selenium/webdriver/common/error.rb +282 -106
- data/lib/selenium/webdriver/common/file_reaper.rb +23 -12
- data/lib/selenium/webdriver/common/html5/local_storage.rb +29 -12
- data/lib/selenium/webdriver/common/html5/session_storage.rb +29 -12
- data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +29 -18
- 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/common/interactions/interactions.rb +43 -0
- 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/keyboard.rb +27 -12
- data/lib/selenium/webdriver/common/keys.rb +118 -81
- data/lib/selenium/webdriver/common/log_entry.rb +27 -8
- data/lib/selenium/webdriver/common/logger.rb +115 -0
- data/lib/selenium/webdriver/common/logs.rb +24 -7
- data/lib/selenium/webdriver/common/manager.rb +177 -0
- data/lib/selenium/webdriver/common/mouse.rb +29 -12
- data/lib/selenium/webdriver/common/navigation.rb +21 -4
- data/lib/selenium/webdriver/common/options.rb +43 -126
- data/lib/selenium/webdriver/common/platform.rb +101 -97
- data/lib/selenium/webdriver/common/port_prober.rb +24 -17
- data/lib/selenium/webdriver/common/profile_helper.rb +27 -11
- data/lib/selenium/webdriver/common/proxy.rb +86 -73
- data/lib/selenium/webdriver/common/search_context.rb +49 -33
- data/lib/selenium/webdriver/common/service.rb +219 -0
- data/lib/selenium/webdriver/common/socket_lock.rb +82 -0
- data/lib/selenium/webdriver/common/socket_poller.rb +47 -26
- data/lib/selenium/webdriver/common/target_locator.rb +35 -14
- data/lib/selenium/webdriver/common/timeouts.rb +23 -6
- data/lib/selenium/webdriver/common/touch_action_builder.rb +25 -11
- data/lib/selenium/webdriver/common/touch_screen.rb +42 -24
- data/lib/selenium/webdriver/common/w3c_action_builder.rb +212 -0
- data/lib/selenium/webdriver/common/w3c_manager.rb +45 -0
- data/lib/selenium/webdriver/common/wait.rb +34 -14
- data/lib/selenium/webdriver/common/window.rb +75 -16
- data/lib/selenium/webdriver/common/zipper.rb +26 -11
- data/lib/selenium/webdriver/common.rb +40 -7
- data/lib/selenium/webdriver/edge/bridge.rb +76 -0
- data/lib/selenium/webdriver/edge/driver.rb +66 -0
- data/lib/selenium/webdriver/edge/options.rb +80 -0
- data/lib/selenium/webdriver/edge/service.rb +52 -0
- data/lib/selenium/webdriver/edge.rb +44 -0
- data/lib/selenium/webdriver/firefox/binary.rb +70 -48
- data/lib/selenium/webdriver/firefox/driver.rb +50 -0
- data/lib/selenium/webdriver/firefox/extension/prefs.json +14 -13
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/extension.rb +50 -19
- data/lib/selenium/webdriver/firefox/launcher.rb +33 -28
- data/lib/selenium/webdriver/firefox/legacy/driver.rb +83 -0
- data/lib/selenium/webdriver/firefox/marionette/bridge.rb +49 -0
- data/lib/selenium/webdriver/firefox/marionette/driver.rb +90 -0
- data/lib/selenium/webdriver/firefox/options.rb +162 -0
- data/lib/selenium/webdriver/firefox/profile.rb +66 -48
- data/lib/selenium/webdriver/firefox/profiles_ini.rb +28 -16
- data/lib/selenium/webdriver/firefox/service.rb +52 -0
- data/lib/selenium/webdriver/firefox/util.rb +19 -2
- data/lib/selenium/webdriver/firefox.rb +46 -10
- data/lib/selenium/webdriver/ie/driver.rb +85 -0
- data/lib/selenium/webdriver/ie/options.rb +138 -0
- data/lib/selenium/webdriver/ie/service.rb +54 -0
- data/lib/selenium/webdriver/ie.rb +32 -10
- data/lib/selenium/webdriver/remote/bridge.rb +117 -572
- data/lib/selenium/webdriver/remote/capabilities.rb +116 -99
- data/lib/selenium/webdriver/remote/driver.rb +51 -0
- data/lib/selenium/webdriver/remote/http/common.rb +54 -23
- data/lib/selenium/webdriver/remote/http/curb.rb +30 -12
- data/lib/selenium/webdriver/remote/http/default.rb +85 -42
- data/lib/selenium/webdriver/remote/http/persistent.rb +29 -7
- data/lib/selenium/webdriver/remote/oss/bridge.rb +594 -0
- data/lib/selenium/webdriver/remote/oss/commands.rb +223 -0
- data/lib/selenium/webdriver/remote/response.rb +68 -30
- data/lib/selenium/webdriver/remote/server_error.rb +22 -5
- data/lib/selenium/webdriver/remote/w3c/bridge.rb +605 -0
- data/lib/selenium/webdriver/remote/w3c/capabilities.rb +310 -0
- data/lib/selenium/webdriver/remote/w3c/commands.rb +157 -0
- data/lib/selenium/webdriver/remote.rb +27 -13
- data/lib/selenium/webdriver/safari/bridge.rb +38 -107
- data/lib/selenium/webdriver/safari/driver.rb +68 -0
- data/lib/selenium/webdriver/safari/options.rb +56 -75
- data/lib/selenium/webdriver/safari/service.rb +38 -0
- data/lib/selenium/webdriver/safari.rb +49 -31
- data/lib/selenium/webdriver/support/abstract_event_listener.rb +40 -6
- data/lib/selenium/webdriver/support/block_event_listener.rb +24 -7
- data/lib/selenium/webdriver/support/color.rb +82 -46
- data/lib/selenium/webdriver/support/escaper.rb +43 -0
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +56 -39
- data/lib/selenium/webdriver/support/select.rb +66 -89
- data/lib/selenium/webdriver/support.rb +20 -0
- data/lib/selenium/webdriver/version.rb +24 -0
- data/lib/selenium/webdriver.rb +55 -25
- data/lib/selenium-webdriver.rb +19 -0
- data/selenium-webdriver.gemspec +42 -29
- metadata +331 -260
- data/Gemfile.lock +0 -48
- data/lib/selenium/client/base.rb +0 -132
- data/lib/selenium/client/driver.rb +0 -10
- data/lib/selenium/client/errors.rb +0 -9
- data/lib/selenium/client/extensions.rb +0 -118
- data/lib/selenium/client/idiomatic.rb +0 -488
- data/lib/selenium/client/javascript_expression_builder.rb +0 -116
- data/lib/selenium/client/javascript_frameworks/jquery.rb +0 -13
- data/lib/selenium/client/javascript_frameworks/prototype.rb +0 -13
- data/lib/selenium/client/legacy_driver.rb +0 -1720
- data/lib/selenium/client/protocol.rb +0 -104
- data/lib/selenium/client/selenium_helper.rb +0 -34
- data/lib/selenium/client.rb +0 -38
- data/lib/selenium/rake/server_task.rb +0 -157
- data/lib/selenium/webdriver/android/bridge.rb +0 -49
- data/lib/selenium/webdriver/android.rb +0 -9
- data/lib/selenium/webdriver/common/core_ext/base64.rb +0 -9
- data/lib/selenium/webdriver/common/core_ext/dir.rb +0 -42
- data/lib/selenium/webdriver/common/core_ext/string.rb +0 -5
- data/lib/selenium/webdriver/common/driver_extensions/has_browser_connection.rb +0 -17
- data/lib/selenium/webdriver/common/driver_extensions/has_input_devices.rb +0 -39
- data/lib/selenium/webdriver/common/html5/location.rb +0 -0
- data/lib/selenium/webdriver/common/json_helper.rb +0 -34
- data/lib/selenium/webdriver/firefox/bridge.rb +0 -70
- data/lib/selenium/webdriver/firefox/socket_lock.rb +0 -61
- data/lib/selenium/webdriver/ie/bridge.rb +0 -69
- data/lib/selenium/webdriver/ie/server.rb +0 -90
- data/lib/selenium/webdriver/iphone/bridge.rb +0 -45
- data/lib/selenium/webdriver/iphone.rb +0 -9
- data/lib/selenium/webdriver/opera/bridge.rb +0 -112
- data/lib/selenium/webdriver/opera/service.rb +0 -49
- data/lib/selenium/webdriver/opera.rb +0 -24
- data/lib/selenium/webdriver/phantomjs/bridge.rb +0 -59
- data/lib/selenium/webdriver/phantomjs/service.rb +0 -90
- data/lib/selenium/webdriver/phantomjs.rb +0 -22
- data/lib/selenium/webdriver/remote/commands.rb +0 -192
- data/lib/selenium/webdriver/safari/browser.rb +0 -20
- data/lib/selenium/webdriver/safari/extensions.rb +0 -170
- data/lib/selenium/webdriver/safari/resources/SafariDriver.safariextz +0 -0
- data/lib/selenium/webdriver/safari/resources/client.js +0 -6903
- data/lib/selenium/webdriver/safari/server.rb +0 -145
- data/lib/selenium-client.rb +0 -2
|
@@ -1,6 +1,24 @@
|
|
|
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
|
+
|
|
1
20
|
module Selenium
|
|
2
21
|
module WebDriver
|
|
3
|
-
|
|
4
22
|
#
|
|
5
23
|
# @api private
|
|
6
24
|
#
|
|
@@ -9,27 +27,26 @@ module Selenium
|
|
|
9
27
|
#
|
|
10
28
|
|
|
11
29
|
module ProfileHelper
|
|
12
|
-
|
|
13
30
|
def self.included(base)
|
|
14
31
|
base.extend ClassMethods
|
|
15
32
|
end
|
|
16
33
|
|
|
17
|
-
def as_json(
|
|
18
|
-
{
|
|
34
|
+
def as_json(*)
|
|
35
|
+
{"zip" => Zipper.zip(layout_on_disk)}
|
|
19
36
|
end
|
|
20
37
|
|
|
21
|
-
def to_json(*
|
|
22
|
-
|
|
38
|
+
def to_json(*)
|
|
39
|
+
JSON.generate as_json
|
|
23
40
|
end
|
|
24
41
|
|
|
25
42
|
private
|
|
26
43
|
|
|
27
44
|
def create_tmp_copy(directory)
|
|
28
|
-
tmp_directory = Dir.mktmpdir(
|
|
45
|
+
tmp_directory = Dir.mktmpdir('webdriver-rb-profilecopy')
|
|
29
46
|
|
|
30
47
|
# TODO: must be a better way..
|
|
31
48
|
FileUtils.rm_rf tmp_directory
|
|
32
|
-
FileUtils.mkdir_p File.dirname(tmp_directory), :
|
|
49
|
+
FileUtils.mkdir_p File.dirname(tmp_directory), mode: 0o700
|
|
33
50
|
FileUtils.cp_r directory, tmp_directory
|
|
34
51
|
|
|
35
52
|
tmp_directory
|
|
@@ -46,14 +63,14 @@ module Selenium
|
|
|
46
63
|
|
|
47
64
|
module ClassMethods
|
|
48
65
|
def from_json(json)
|
|
49
|
-
data =
|
|
66
|
+
data = JSON.parse(json).fetch('zip')
|
|
50
67
|
|
|
51
68
|
# can't use Tempfile here since it doesn't support File::BINARY mode on 1.8
|
|
52
69
|
# can't use Dir.mktmpdir(&blk) because of http://jira.codehaus.org/browse/JRUBY-4082
|
|
53
70
|
tmp_dir = Dir.mktmpdir
|
|
54
71
|
begin
|
|
55
72
|
zip_path = File.join(tmp_dir, "webdriver-profile-duplicate-#{json.hash}.zip")
|
|
56
|
-
File.open(zip_path,
|
|
73
|
+
File.open(zip_path, 'wb') { |zip_file| zip_file << Base64.decode64(data) }
|
|
57
74
|
|
|
58
75
|
new Zipper.unzip(zip_path)
|
|
59
76
|
ensure
|
|
@@ -61,7 +78,6 @@ module Selenium
|
|
|
61
78
|
end
|
|
62
79
|
end
|
|
63
80
|
end # ClassMethods
|
|
64
|
-
|
|
65
81
|
end # ProfileHelper
|
|
66
82
|
end # WebDriver
|
|
67
83
|
end # Selenium
|
|
@@ -1,46 +1,78 @@
|
|
|
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
|
+
|
|
1
20
|
module Selenium
|
|
2
21
|
module WebDriver
|
|
3
22
|
class Proxy
|
|
4
23
|
TYPES = {
|
|
5
|
-
:
|
|
6
|
-
:
|
|
7
|
-
:
|
|
8
|
-
:
|
|
9
|
-
:
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
direct: 'DIRECT', # Direct connection, no proxy (default on Windows).
|
|
25
|
+
manual: 'MANUAL', # Manual proxy settings (e.g., for httpProxy).
|
|
26
|
+
pac: 'PAC', # Proxy autoconfiguration from URL.
|
|
27
|
+
auto_detect: 'AUTODETECT', # Proxy autodetection (presumably with WPAD).
|
|
28
|
+
system: 'SYSTEM' # Use system settings (default on Linux).
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
ALLOWED = {type: 'proxyType',
|
|
32
|
+
ftp: 'ftpProxy',
|
|
33
|
+
http: 'httpProxy',
|
|
34
|
+
no_proxy: 'noProxy',
|
|
35
|
+
pac: 'proxyAutoconfigUrl',
|
|
36
|
+
ssl: 'sslProxy',
|
|
37
|
+
auto_detect: 'autodetect',
|
|
38
|
+
socks: 'socksProxy',
|
|
39
|
+
socks_username: 'socksUsername',
|
|
40
|
+
socks_password: 'socksPassword',
|
|
41
|
+
socks_version: 'socksVersion'}.freeze
|
|
42
|
+
|
|
43
|
+
ALLOWED.each_key { |t| attr_reader t }
|
|
44
|
+
|
|
45
|
+
def self.json_create(data)
|
|
46
|
+
data['proxyType'] = data['proxyType'].downcase.to_sym
|
|
47
|
+
return if data['proxyType'] == :unspecified
|
|
48
|
+
|
|
49
|
+
proxy = new
|
|
50
|
+
|
|
51
|
+
ALLOWED.each do |k, v|
|
|
52
|
+
proxy.send("#{k}=", data[v]) if data.key?(v)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
proxy
|
|
56
|
+
end
|
|
22
57
|
|
|
23
58
|
def initialize(opts = {})
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
self.auto_detect = opts.delete(:auto_detect) if opts.has_key? :auto_detect
|
|
33
|
-
self.socks = opts.delete(:socks) if opts.has_key? :socks
|
|
34
|
-
self.socks_username = opts.delete(:socks_username) if opts.has_key? :socks_username
|
|
35
|
-
self.socks_password = opts.delete(:socks_password) if opts.has_key? :socks_password
|
|
36
|
-
|
|
37
|
-
unless opts.empty?
|
|
38
|
-
raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
|
|
59
|
+
not_allowed = []
|
|
60
|
+
|
|
61
|
+
opts.each do |k, v|
|
|
62
|
+
if ALLOWED.key?(k)
|
|
63
|
+
send("#{k}=", v)
|
|
64
|
+
else
|
|
65
|
+
not_allowed << k
|
|
66
|
+
end
|
|
39
67
|
end
|
|
68
|
+
|
|
69
|
+
return if not_allowed.empty?
|
|
70
|
+
|
|
71
|
+
raise ArgumentError, "unknown option#{'s' if not_allowed.size != 1}: #{not_allowed.inspect}"
|
|
40
72
|
end
|
|
41
73
|
|
|
42
74
|
def ==(other)
|
|
43
|
-
other.
|
|
75
|
+
other.is_a?(self.class) && as_json == other.as_json
|
|
44
76
|
end
|
|
45
77
|
alias_method :eql?, :==
|
|
46
78
|
|
|
@@ -89,10 +121,13 @@ module Selenium
|
|
|
89
121
|
@socks_password = value
|
|
90
122
|
end
|
|
91
123
|
|
|
124
|
+
def socks_version=(value)
|
|
125
|
+
self.type = :manual
|
|
126
|
+
@socks_version = value
|
|
127
|
+
end
|
|
128
|
+
|
|
92
129
|
def type=(type)
|
|
93
|
-
unless TYPES.
|
|
94
|
-
raise ArgumentError, "invalid proxy type: #{type.inspect}, expected one of #{TYPES.keys.inspect}"
|
|
95
|
-
end
|
|
130
|
+
raise ArgumentError, "invalid proxy type: #{type.inspect}, expected one of #{TYPES.keys.inspect}" unless TYPES.key? type
|
|
96
131
|
|
|
97
132
|
if defined?(@type) && type != @type
|
|
98
133
|
raise ArgumentError, "incompatible proxy type #{type.inspect} (already set to #{@type.inspect})"
|
|
@@ -101,49 +136,27 @@ module Selenium
|
|
|
101
136
|
@type = type
|
|
102
137
|
end
|
|
103
138
|
|
|
104
|
-
def as_json(
|
|
139
|
+
def as_json(*)
|
|
105
140
|
json_result = {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
141
|
+
'proxyType' => TYPES[type],
|
|
142
|
+
'ftpProxy' => ftp,
|
|
143
|
+
'httpProxy' => http,
|
|
144
|
+
'noProxy' => no_proxy,
|
|
145
|
+
'proxyAutoconfigUrl' => pac,
|
|
146
|
+
'sslProxy' => ssl,
|
|
147
|
+
'autodetect' => auto_detect,
|
|
148
|
+
'socksProxy' => socks,
|
|
149
|
+
'socksUsername' => socks_username,
|
|
150
|
+
'socksPassword' => socks_password,
|
|
151
|
+
'socksVersion' => socks_version
|
|
152
|
+
}.delete_if { |_k, v| v.nil? }
|
|
118
153
|
|
|
119
154
|
json_result if json_result.length > 1
|
|
120
155
|
end
|
|
121
156
|
|
|
122
|
-
def to_json(*
|
|
123
|
-
|
|
157
|
+
def to_json(*)
|
|
158
|
+
JSON.generate as_json
|
|
124
159
|
end
|
|
125
|
-
|
|
126
|
-
class << self
|
|
127
|
-
def json_create(data)
|
|
128
|
-
return if data['proxyType'] == 'UNSPECIFIED'
|
|
129
|
-
|
|
130
|
-
proxy = new
|
|
131
|
-
|
|
132
|
-
proxy.type = data['proxyType'].downcase.to_sym if data.has_key? 'proxyType'
|
|
133
|
-
proxy.ftp = data['ftpProxy'] if data.has_key? 'ftpProxy'
|
|
134
|
-
proxy.http = data['httpProxy'] if data.has_key? 'httpProxy'
|
|
135
|
-
proxy.no_proxy = data['noProxy'] if data.has_key? 'noProxy'
|
|
136
|
-
proxy.pac = data['proxyAutoconfigUrl'] if data.has_key? 'proxyAutoconfigUrl'
|
|
137
|
-
proxy.ssl = data['sslProxy'] if data.has_key? 'sslProxy'
|
|
138
|
-
proxy.auto_detect = data['autodetect'] if data.has_key? 'autodetect'
|
|
139
|
-
proxy.socks = data['socksProxy'] if data.has_key? 'socksProxy'
|
|
140
|
-
proxy.socks_username = data['socksUsername'] if data.has_key? 'socksUsername'
|
|
141
|
-
proxy.socks_password = data['socksPassword'] if data.has_key? 'socksPassword'
|
|
142
|
-
|
|
143
|
-
proxy
|
|
144
|
-
end
|
|
145
|
-
end # class << self
|
|
146
|
-
|
|
147
160
|
end # Proxy
|
|
148
161
|
end # WebDriver
|
|
149
162
|
end # Selenium
|
|
@@ -1,45 +1,68 @@
|
|
|
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
|
+
|
|
1
20
|
module Selenium
|
|
2
21
|
module WebDriver
|
|
3
22
|
module SearchContext
|
|
4
|
-
|
|
5
23
|
# @api private
|
|
6
24
|
FINDERS = {
|
|
7
|
-
:
|
|
8
|
-
:
|
|
9
|
-
:
|
|
10
|
-
:
|
|
11
|
-
:
|
|
12
|
-
:
|
|
13
|
-
:
|
|
14
|
-
:
|
|
15
|
-
:
|
|
16
|
-
:
|
|
17
|
-
}
|
|
25
|
+
class: 'class name',
|
|
26
|
+
class_name: 'class name',
|
|
27
|
+
css: 'css selector',
|
|
28
|
+
id: 'id',
|
|
29
|
+
link: 'link text',
|
|
30
|
+
link_text: 'link text',
|
|
31
|
+
name: 'name',
|
|
32
|
+
partial_link_text: 'partial link text',
|
|
33
|
+
tag_name: 'tag name',
|
|
34
|
+
xpath: 'xpath'
|
|
35
|
+
}.freeze
|
|
18
36
|
|
|
19
37
|
#
|
|
20
|
-
# Find the first element matching the given arguments
|
|
38
|
+
# Find the first element matching the given arguments
|
|
21
39
|
#
|
|
22
40
|
# When using Element#find_element with :xpath, be aware that webdriver
|
|
23
41
|
# follows standard conventions: a search prefixed with "//" will search
|
|
24
42
|
# the entire document, not just the children of this current node. Use
|
|
25
43
|
# ".//" to limit your search to the children of the receiving Element.
|
|
26
44
|
#
|
|
27
|
-
# @
|
|
28
|
-
#
|
|
45
|
+
# @overload find_element(how, what)
|
|
46
|
+
# @param [Symbol, String] how The method to find the element by
|
|
47
|
+
# @param [String] what The locator to use
|
|
48
|
+
# @overload find_element(opts)
|
|
49
|
+
# @param [Hash] opts Find options
|
|
50
|
+
# @option opts [Symbol] :how Key named after the method to find the element by, containing the locator
|
|
29
51
|
# @return [Element]
|
|
30
52
|
#
|
|
31
53
|
# @raise [Error::NoSuchElementError] if the element doesn't exist
|
|
32
54
|
#
|
|
33
|
-
#
|
|
34
55
|
|
|
35
56
|
def find_element(*args)
|
|
36
57
|
how, what = extract_args(args)
|
|
37
58
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
end
|
|
59
|
+
by = FINDERS[how.to_sym]
|
|
60
|
+
raise ArgumentError, "cannot find element by #{how.inspect}" unless by
|
|
41
61
|
|
|
42
62
|
bridge.find_element_by by, what.to_s, ref
|
|
63
|
+
rescue Selenium::WebDriver::Error::TimeoutError
|
|
64
|
+
# Implicit Wait times out in Edge
|
|
65
|
+
raise Selenium::WebDriver::Error::NoSuchElementError
|
|
43
66
|
end
|
|
44
67
|
|
|
45
68
|
#
|
|
@@ -47,19 +70,17 @@ module Selenium
|
|
|
47
70
|
#
|
|
48
71
|
# @see SearchContext#find_element
|
|
49
72
|
#
|
|
50
|
-
# @param [:class, :class_name, :css, :id, :link_text, :link, :partial_link_text, :name, :tag_name, :xpath] how
|
|
51
|
-
# @param [String] what
|
|
52
|
-
# @return [Array<Element>]
|
|
53
|
-
#
|
|
54
73
|
|
|
55
74
|
def find_elements(*args)
|
|
56
75
|
how, what = extract_args(args)
|
|
57
76
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
end
|
|
77
|
+
by = FINDERS[how.to_sym]
|
|
78
|
+
raise ArgumentError, "cannot find elements by #{how.inspect}" unless by
|
|
61
79
|
|
|
62
80
|
bridge.find_elements_by by, what.to_s, ref
|
|
81
|
+
rescue Selenium::WebDriver::Error::TimeoutError
|
|
82
|
+
# Implicit Wait times out in Edge
|
|
83
|
+
[]
|
|
63
84
|
end
|
|
64
85
|
|
|
65
86
|
private
|
|
@@ -71,22 +92,17 @@ module Selenium
|
|
|
71
92
|
when 1
|
|
72
93
|
arg = args.first
|
|
73
94
|
|
|
74
|
-
unless arg.respond_to?(:shift)
|
|
75
|
-
raise ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift"
|
|
76
|
-
end
|
|
95
|
+
raise ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift" unless arg.respond_to?(:shift)
|
|
77
96
|
|
|
78
97
|
# this will be a single-entry hash, so use #shift over #first or #[]
|
|
79
98
|
arr = arg.dup.shift
|
|
80
|
-
unless arr.size == 2
|
|
81
|
-
raise ArgumentError, "expected #{arr.inspect} to have 2 elements"
|
|
82
|
-
end
|
|
99
|
+
raise ArgumentError, "expected #{arr.inspect} to have 2 elements" unless arr.size == 2
|
|
83
100
|
|
|
84
101
|
arr
|
|
85
102
|
else
|
|
86
103
|
raise ArgumentError, "wrong number of arguments (#{args.size} for 2)"
|
|
87
104
|
end
|
|
88
105
|
end
|
|
89
|
-
|
|
90
106
|
end # SearchContext
|
|
91
107
|
end # WebDriver
|
|
92
108
|
end # Selenium
|
|
@@ -0,0 +1,219 @@
|
|
|
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
|
+
module Selenium
|
|
21
|
+
module WebDriver
|
|
22
|
+
#
|
|
23
|
+
# Base class implementing default behavior of service object,
|
|
24
|
+
# responsible for starting and stopping driver implementations.
|
|
25
|
+
#
|
|
26
|
+
|
|
27
|
+
class Service
|
|
28
|
+
START_TIMEOUT = 20
|
|
29
|
+
SOCKET_LOCK_TIMEOUT = 45
|
|
30
|
+
STOP_TIMEOUT = 20
|
|
31
|
+
|
|
32
|
+
@default_port = nil
|
|
33
|
+
@driver_path = nil
|
|
34
|
+
@executable = nil
|
|
35
|
+
@missing_text = nil
|
|
36
|
+
|
|
37
|
+
class << self
|
|
38
|
+
attr_reader :default_port, :driver_path, :executable, :missing_text, :shutdown_supported
|
|
39
|
+
|
|
40
|
+
def chrome(**opts)
|
|
41
|
+
Chrome::Service.new(**opts)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def firefox(**opts)
|
|
45
|
+
binary_path = Firefox::Binary.path
|
|
46
|
+
args = opts.delete(:args)
|
|
47
|
+
case args
|
|
48
|
+
when Hash
|
|
49
|
+
args[:binary] ||= binary_path
|
|
50
|
+
opts[:args] = args
|
|
51
|
+
when Array
|
|
52
|
+
opts[:args] = ["--binary=#{binary_path}"]
|
|
53
|
+
opts[:args] += args
|
|
54
|
+
else
|
|
55
|
+
opts[:args] = ["--binary=#{binary_path}"]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
Firefox::Service.new(**opts)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def ie(**opts)
|
|
62
|
+
IE::Service.new(**opts)
|
|
63
|
+
end
|
|
64
|
+
alias_method :internet_explorer, :ie
|
|
65
|
+
|
|
66
|
+
def edge(**opts)
|
|
67
|
+
Edge::Service.new(**opts)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def safari(**opts)
|
|
71
|
+
Safari::Service.new(**opts)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def driver_path=(path)
|
|
75
|
+
Platform.assert_executable path if path.is_a?(String)
|
|
76
|
+
@driver_path = path
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
attr_accessor :host
|
|
81
|
+
attr_reader :executable_path
|
|
82
|
+
|
|
83
|
+
#
|
|
84
|
+
# End users should use a class method for the desired driver, rather than using this directly.
|
|
85
|
+
#
|
|
86
|
+
# @api private
|
|
87
|
+
#
|
|
88
|
+
|
|
89
|
+
def initialize(path: nil, port: nil, args: nil)
|
|
90
|
+
path ||= self.class.driver_path
|
|
91
|
+
port ||= self.class.default_port
|
|
92
|
+
args ||= []
|
|
93
|
+
|
|
94
|
+
@executable_path = binary_path(path)
|
|
95
|
+
@host = Platform.localhost
|
|
96
|
+
@port = Integer(port)
|
|
97
|
+
|
|
98
|
+
@extra_args = args.is_a?(Hash) ? extract_service_args(args) : args
|
|
99
|
+
|
|
100
|
+
raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def start
|
|
104
|
+
raise "already started: #{uri.inspect} #{@executable_path.inspect}" if process_running?
|
|
105
|
+
|
|
106
|
+
Platform.exit_hook(&method(:stop)) # make sure we don't leave the server running
|
|
107
|
+
|
|
108
|
+
socket_lock.locked do
|
|
109
|
+
find_free_port
|
|
110
|
+
start_process
|
|
111
|
+
connect_until_stable
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def stop
|
|
116
|
+
return unless self.class.shutdown_supported
|
|
117
|
+
|
|
118
|
+
stop_server
|
|
119
|
+
@process.poll_for_exit STOP_TIMEOUT
|
|
120
|
+
rescue ChildProcess::TimeoutError
|
|
121
|
+
nil # noop
|
|
122
|
+
ensure
|
|
123
|
+
stop_process
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def uri
|
|
127
|
+
@uri ||= URI.parse("http://#{@host}:#{@port}")
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
def binary_path(path = nil)
|
|
133
|
+
path = path.call if path.is_a?(Proc)
|
|
134
|
+
path ||= Platform.find_binary(self.class.executable)
|
|
135
|
+
|
|
136
|
+
raise Error::WebDriverError, self.class.missing_text unless path
|
|
137
|
+
|
|
138
|
+
Platform.assert_executable path
|
|
139
|
+
path
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def build_process(*command)
|
|
143
|
+
WebDriver.logger.debug("Executing Process #{command}")
|
|
144
|
+
@process = ChildProcess.build(*command)
|
|
145
|
+
if WebDriver.logger.debug?
|
|
146
|
+
@process.io.stdout = @process.io.stderr = WebDriver.logger.io
|
|
147
|
+
elsif Platform.jruby?
|
|
148
|
+
# Apparently we need to read the output of drivers on JRuby.
|
|
149
|
+
@process.io.stdout = @process.io.stderr = File.new(Platform.null_device, 'w')
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
@process
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def connect_to_server
|
|
156
|
+
Net::HTTP.start(@host, @port) do |http|
|
|
157
|
+
http.open_timeout = STOP_TIMEOUT / 2
|
|
158
|
+
http.read_timeout = STOP_TIMEOUT / 2
|
|
159
|
+
|
|
160
|
+
yield http
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def find_free_port
|
|
165
|
+
@port = PortProber.above(@port)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def start_process
|
|
169
|
+
@process = build_process(@executable_path, "--port=#{@port}", *@extra_args)
|
|
170
|
+
# Note: this is a bug only in Windows 7
|
|
171
|
+
@process.leader = true unless Platform.windows?
|
|
172
|
+
@process.start
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def stop_process
|
|
176
|
+
return if process_exited?
|
|
177
|
+
|
|
178
|
+
@process.stop STOP_TIMEOUT
|
|
179
|
+
@process.io.stdout.close if Platform.jruby? && !WebDriver.logger.debug?
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def stop_server
|
|
183
|
+
return if process_exited?
|
|
184
|
+
|
|
185
|
+
connect_to_server { |http| http.get('/shutdown') }
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def process_running?
|
|
189
|
+
defined?(@process) && @process&.alive?
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def process_exited?
|
|
193
|
+
@process.nil? || @process.exited?
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def connect_until_stable
|
|
197
|
+
socket_poller = SocketPoller.new @host, @port, START_TIMEOUT
|
|
198
|
+
return if socket_poller.connected?
|
|
199
|
+
|
|
200
|
+
raise Error::WebDriverError, cannot_connect_error_text
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def cannot_connect_error_text
|
|
204
|
+
"unable to connect to #{self.class.executable} #{@host}:#{@port}"
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def socket_lock
|
|
208
|
+
@socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
protected
|
|
212
|
+
|
|
213
|
+
def extract_service_args(driver_opts)
|
|
214
|
+
driver_opts.key?(:args) ? driver_opts.delete(:args) : []
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
end # Service
|
|
218
|
+
end # WebDriver
|
|
219
|
+
end # Selenium
|