selenium-webdriver 2.53.4 → 3.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +24 -18
- data/README.md +2 -3
- data/lib/selenium/server.rb +64 -68
- data/lib/selenium/webdriver.rb +5 -9
- data/lib/selenium/webdriver/chrome.rb +18 -3
- data/lib/selenium/webdriver/chrome/bridge.rb +13 -16
- data/lib/selenium/webdriver/chrome/profile.rb +7 -9
- data/lib/selenium/webdriver/chrome/service.rb +8 -84
- data/lib/selenium/webdriver/common.rb +1 -2
- data/lib/selenium/webdriver/common/action_builder.rb +28 -38
- data/lib/selenium/webdriver/common/alert.rb +7 -10
- data/lib/selenium/webdriver/common/bridge_helper.rb +10 -15
- data/lib/selenium/webdriver/common/driver.rb +19 -28
- data/lib/selenium/webdriver/common/driver_extensions/has_input_devices.rb +0 -3
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +4 -6
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +4 -5
- data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +0 -2
- data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +0 -3
- data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +3 -6
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +2 -5
- data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +2 -5
- data/lib/selenium/webdriver/common/element.rb +27 -29
- data/lib/selenium/webdriver/common/error.rb +17 -20
- data/lib/selenium/webdriver/common/file_reaper.rb +3 -9
- data/lib/selenium/webdriver/common/html5/local_storage.rb +6 -8
- data/lib/selenium/webdriver/common/html5/session_storage.rb +6 -8
- data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +6 -15
- data/lib/selenium/webdriver/common/keyboard.rb +7 -12
- data/lib/selenium/webdriver/common/keys.rb +67 -69
- data/lib/selenium/webdriver/common/log_entry.rb +3 -4
- data/lib/selenium/webdriver/common/logs.rb +2 -4
- data/lib/selenium/webdriver/common/mouse.rb +9 -12
- data/lib/selenium/webdriver/common/navigation.rb +2 -4
- data/lib/selenium/webdriver/common/options.rb +16 -19
- data/lib/selenium/webdriver/common/platform.rb +61 -90
- data/lib/selenium/webdriver/common/port_prober.rb +1 -2
- data/lib/selenium/webdriver/common/profile_helper.rb +5 -8
- data/lib/selenium/webdriver/common/proxy.rb +58 -70
- data/lib/selenium/webdriver/common/search_context.rb +15 -19
- data/lib/selenium/webdriver/common/service.rb +127 -0
- data/lib/selenium/webdriver/common/socket_lock.rb +5 -11
- data/lib/selenium/webdriver/common/socket_poller.rb +4 -9
- data/lib/selenium/webdriver/common/target_locator.rb +11 -13
- data/lib/selenium/webdriver/common/timeouts.rb +4 -6
- data/lib/selenium/webdriver/common/touch_action_builder.rb +2 -4
- data/lib/selenium/webdriver/common/touch_screen.rb +15 -18
- data/lib/selenium/webdriver/common/w3c_error.rb +3 -6
- data/lib/selenium/webdriver/common/wait.rb +6 -11
- data/lib/selenium/webdriver/common/window.rb +12 -15
- data/lib/selenium/webdriver/common/zipper.rb +6 -8
- data/lib/selenium/webdriver/edge.rb +18 -3
- data/lib/selenium/webdriver/edge/bridge.rb +11 -16
- data/lib/selenium/webdriver/edge/legacy_support.rb +38 -39
- data/lib/selenium/webdriver/edge/service.rb +8 -82
- data/lib/selenium/webdriver/firefox.rb +25 -6
- data/lib/selenium/webdriver/firefox/binary.rb +37 -53
- data/lib/selenium/webdriver/firefox/bridge.rb +3 -6
- data/lib/selenium/webdriver/firefox/extension.rb +4 -6
- data/lib/selenium/webdriver/firefox/extension/prefs.json +1 -10
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/launcher.rb +8 -11
- data/lib/selenium/webdriver/firefox/profile.rb +40 -42
- data/lib/selenium/webdriver/firefox/profiles_ini.rb +8 -15
- data/lib/selenium/webdriver/firefox/service.rb +23 -79
- data/lib/selenium/webdriver/firefox/util.rb +0 -2
- data/lib/selenium/webdriver/firefox/w3c_bridge.rb +2 -4
- data/lib/selenium/webdriver/ie.rb +16 -7
- data/lib/selenium/webdriver/ie/bridge.rb +16 -23
- data/lib/selenium/webdriver/{iphone.rb → ie/service.rb} +26 -4
- data/lib/selenium/webdriver/phantomjs.rb +8 -3
- data/lib/selenium/webdriver/phantomjs/bridge.rb +9 -11
- data/lib/selenium/webdriver/phantomjs/service.rb +17 -81
- data/lib/selenium/webdriver/remote.rb +0 -2
- data/lib/selenium/webdriver/remote/bridge.rb +193 -191
- data/lib/selenium/webdriver/remote/capabilities.rb +60 -90
- data/lib/selenium/webdriver/remote/commands.rb +197 -192
- data/lib/selenium/webdriver/remote/http/common.rb +15 -13
- data/lib/selenium/webdriver/remote/http/curb.rb +5 -9
- data/lib/selenium/webdriver/remote/http/default.rb +32 -37
- data/lib/selenium/webdriver/remote/http/persistent.rb +4 -6
- data/lib/selenium/webdriver/remote/response.rb +13 -21
- data/lib/selenium/webdriver/remote/server_error.rb +1 -3
- data/lib/selenium/webdriver/remote/w3c_bridge.rb +200 -195
- data/lib/selenium/webdriver/remote/w3c_capabilities.rb +38 -46
- data/lib/selenium/webdriver/remote/w3c_commands.rb +116 -113
- data/lib/selenium/webdriver/safari.rb +23 -7
- data/lib/selenium/{client/javascript_frameworks/jquery.rb → webdriver/safari/apple_bridge.rb} +28 -9
- data/lib/selenium/webdriver/safari/browser.rb +0 -2
- data/lib/selenium/webdriver/safari/{bridge.rb → legacy_bridge.rb} +12 -9
- data/lib/selenium/webdriver/safari/options.rb +3 -4
- data/lib/selenium/webdriver/safari/resources/client.js +56 -7255
- data/lib/selenium/webdriver/safari/server.rb +18 -24
- data/lib/selenium/{client/javascript_frameworks/prototype.rb → webdriver/safari/service.rb} +27 -9
- data/lib/selenium/webdriver/support.rb +1 -0
- data/lib/selenium/webdriver/support/abstract_event_listener.rb +17 -2
- data/lib/selenium/webdriver/support/block_event_listener.rb +1 -3
- data/lib/selenium/webdriver/support/color.rb +55 -38
- data/lib/selenium/webdriver/{android.rb → support/escaper.rb} +19 -4
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +36 -38
- data/lib/selenium/webdriver/support/select.rb +33 -84
- data/selenium-webdriver.gemspec +23 -23
- metadata +19 -30
- 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/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/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/ie/server.rb +0 -133
- data/lib/selenium/webdriver/iphone/bridge.rb +0 -64
@@ -23,8 +23,8 @@ module Selenium
|
|
23
23
|
module Http
|
24
24
|
class Common
|
25
25
|
MAX_REDIRECTS = 20 # same as chromium/gecko
|
26
|
-
CONTENT_TYPE =
|
27
|
-
DEFAULT_HEADERS = {
|
26
|
+
CONTENT_TYPE = 'application/json'.freeze
|
27
|
+
DEFAULT_HEADERS = {'Accept' => CONTENT_TYPE}.freeze
|
28
28
|
|
29
29
|
attr_accessor :timeout
|
30
30
|
attr_writer :server_url
|
@@ -38,22 +38,22 @@ module Selenium
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def call(verb, url, command_hash)
|
41
|
-
url = server_url.merge(url) unless url.
|
41
|
+
url = server_url.merge(url) unless url.is_a?(URI)
|
42
42
|
headers = DEFAULT_HEADERS.dup
|
43
|
-
headers['Cache-Control'] =
|
43
|
+
headers['Cache-Control'] = 'no-cache' if verb == :get
|
44
44
|
|
45
45
|
if command_hash
|
46
46
|
payload = JSON.generate(command_hash)
|
47
|
-
headers[
|
48
|
-
headers[
|
47
|
+
headers['Content-Type'] = "#{CONTENT_TYPE}; charset=utf-8"
|
48
|
+
headers['Content-Length'] = payload.bytesize.to_s if [:post, :put].include?(verb)
|
49
49
|
|
50
50
|
if $DEBUG
|
51
51
|
puts " >>> #{url} | #{payload}"
|
52
52
|
puts " > #{headers.inspect}"
|
53
53
|
end
|
54
54
|
elsif verb == :post
|
55
|
-
payload =
|
56
|
-
headers[
|
55
|
+
payload = '{}'
|
56
|
+
headers['Content-Length'] = '2'
|
57
57
|
end
|
58
58
|
|
59
59
|
request verb, url, headers, payload
|
@@ -62,15 +62,18 @@ module Selenium
|
|
62
62
|
private
|
63
63
|
|
64
64
|
def server_url
|
65
|
-
@server_url
|
65
|
+
return @server_url if @server_url
|
66
|
+
raise Error::WebDriverError, 'server_url not set'
|
66
67
|
end
|
67
68
|
|
68
|
-
def request(
|
69
|
-
raise NotImplementedError,
|
69
|
+
def request(*)
|
70
|
+
raise NotImplementedError, 'subclass responsibility'
|
70
71
|
end
|
71
72
|
|
72
73
|
def create_response(code, body, content_type)
|
73
|
-
code
|
74
|
+
code = code.to_i
|
75
|
+
body = body.to_s.strip
|
76
|
+
content_type = content_type.to_s
|
74
77
|
puts "<- #{body}\n" if $DEBUG
|
75
78
|
|
76
79
|
if content_type.include? CONTENT_TYPE
|
@@ -85,7 +88,6 @@ module Selenium
|
|
85
88
|
raise Error::WebDriverError, msg
|
86
89
|
end
|
87
90
|
end
|
88
|
-
|
89
91
|
end # Common
|
90
92
|
end # Http
|
91
93
|
end # Remote
|
@@ -22,12 +22,10 @@ require 'curb'
|
|
22
22
|
module Selenium
|
23
23
|
module WebDriver
|
24
24
|
module Remote
|
25
|
-
|
26
25
|
# added for rescue
|
27
26
|
Bridge::QUIT_ERRORS << Curl::Err::RecvError
|
28
27
|
|
29
28
|
module Http
|
30
|
-
|
31
29
|
#
|
32
30
|
# An alternative to the default Net::HTTP client.
|
33
31
|
#
|
@@ -42,15 +40,14 @@ module Selenium
|
|
42
40
|
#
|
43
41
|
|
44
42
|
class Curb < Common
|
45
|
-
|
46
43
|
private
|
47
44
|
|
48
45
|
def request(verb, url, headers, payload)
|
49
|
-
client.url
|
46
|
+
client.url = url.to_s
|
50
47
|
|
51
48
|
# workaround for http://github.com/taf2/curb/issues/issue/40
|
52
49
|
# curb will handle this for us anyway
|
53
|
-
headers.delete
|
50
|
+
headers.delete 'Content-Length'
|
54
51
|
|
55
52
|
client.headers = headers
|
56
53
|
|
@@ -62,10 +59,10 @@ module Selenium
|
|
62
59
|
when :get
|
63
60
|
client.http_get
|
64
61
|
when :post
|
65
|
-
client.post_body = payload ||
|
62
|
+
client.post_body = payload || ''
|
66
63
|
client.http_post
|
67
64
|
when :put
|
68
|
-
client.put_data = payload ||
|
65
|
+
client.put_data = payload || ''
|
69
66
|
client.http_put
|
70
67
|
when :delete
|
71
68
|
client.http_delete
|
@@ -85,12 +82,11 @@ module Selenium
|
|
85
82
|
c.max_redirects = MAX_REDIRECTS
|
86
83
|
c.follow_location = true
|
87
84
|
c.timeout = @timeout if @timeout
|
88
|
-
c.verbose =
|
85
|
+
c.verbose = $DEBUG
|
89
86
|
|
90
87
|
c
|
91
88
|
)
|
92
89
|
end
|
93
|
-
|
94
90
|
end # Curb
|
95
91
|
end # Http
|
96
92
|
end # Remote
|
@@ -24,7 +24,6 @@ module Selenium
|
|
24
24
|
module WebDriver
|
25
25
|
module Remote
|
26
26
|
module Http
|
27
|
-
|
28
27
|
# @api private
|
29
28
|
class Default < Common
|
30
29
|
attr_accessor :proxy
|
@@ -33,18 +32,18 @@ module Selenium
|
|
33
32
|
|
34
33
|
def http
|
35
34
|
@http ||= (
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
http = new_http_client
|
36
|
+
if server_url.scheme == 'https'
|
37
|
+
http.use_ssl = true
|
38
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
39
|
+
end
|
41
40
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
41
|
+
if @timeout
|
42
|
+
http.open_timeout = @timeout
|
43
|
+
http.read_timeout = @timeout
|
44
|
+
end
|
46
45
|
|
47
|
-
|
46
|
+
http
|
48
47
|
)
|
49
48
|
end
|
50
49
|
|
@@ -76,15 +75,12 @@ module Selenium
|
|
76
75
|
retry
|
77
76
|
|
78
77
|
rescue Errno::ECONNREFUSED => ex
|
79
|
-
if use_proxy?
|
80
|
-
|
81
|
-
else
|
82
|
-
raise
|
83
|
-
end
|
78
|
+
raise ex.class, "using proxy: #{proxy.http}" if use_proxy?
|
79
|
+
raise
|
84
80
|
end
|
85
81
|
|
86
|
-
if response.
|
87
|
-
raise Error::WebDriverError,
|
82
|
+
if response.is_a? Net::HTTPRedirection
|
83
|
+
raise Error::WebDriverError, 'too many redirects' if redirects >= MAX_REDIRECTS
|
88
84
|
request(:get, URI.parse(response['Location']), DEFAULT_HEADERS.dup, nil, redirects + 1)
|
89
85
|
else
|
90
86
|
create_response response.code, response.body, response.content_type
|
@@ -109,7 +105,8 @@ module Selenium
|
|
109
105
|
|
110
106
|
def new_http_client
|
111
107
|
if use_proxy?
|
112
|
-
|
108
|
+
url = @proxy.http
|
109
|
+
unless proxy.respond_to?(:http) && url
|
113
110
|
raise Error::WebDriverError, "expected HTTP proxy, got #{@proxy.inspect}"
|
114
111
|
end
|
115
112
|
|
@@ -124,13 +121,13 @@ module Selenium
|
|
124
121
|
|
125
122
|
def proxy
|
126
123
|
@proxy ||= (
|
127
|
-
|
128
|
-
|
124
|
+
proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
|
125
|
+
no_proxy = ENV['no_proxy'] || ENV['NO_PROXY']
|
129
126
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
127
|
+
if proxy
|
128
|
+
proxy = "http://#{proxy}" unless proxy.start_with?('http://')
|
129
|
+
Proxy.new(http: proxy, no_proxy: no_proxy)
|
130
|
+
end
|
134
131
|
)
|
135
132
|
end
|
136
133
|
|
@@ -138,24 +135,22 @@ module Selenium
|
|
138
135
|
return false if proxy.nil?
|
139
136
|
|
140
137
|
if proxy.no_proxy
|
141
|
-
ignored = proxy.no_proxy.split(
|
142
|
-
host ==
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
138
|
+
ignored = proxy.no_proxy.split(',').any? do |host|
|
139
|
+
host == '*' ||
|
140
|
+
host == server_url.host || (
|
141
|
+
begin
|
142
|
+
IPAddr.new(host).include?(server_url.host)
|
143
|
+
rescue ArgumentError
|
144
|
+
false
|
145
|
+
end
|
146
|
+
)
|
151
147
|
end
|
152
148
|
|
153
|
-
|
149
|
+
!ignored
|
154
150
|
else
|
155
151
|
true
|
156
152
|
end
|
157
153
|
end
|
158
|
-
|
159
154
|
end # Default
|
160
155
|
end # Http
|
161
156
|
end # Remote
|
@@ -23,10 +23,8 @@ module Selenium
|
|
23
23
|
module WebDriver
|
24
24
|
module Remote
|
25
25
|
module Http
|
26
|
-
|
27
26
|
# @api private
|
28
27
|
class Persistent < Default
|
29
|
-
|
30
28
|
def close
|
31
29
|
@http.shutdown if @http
|
32
30
|
end
|
@@ -37,19 +35,19 @@ module Selenium
|
|
37
35
|
proxy = nil
|
38
36
|
|
39
37
|
if @proxy
|
40
|
-
unless @proxy.respond_to?(:http)
|
41
|
-
|
38
|
+
unless @proxy.respond_to?(:http)
|
39
|
+
url = @proxy.http
|
40
|
+
raise Error::WebDriverError, "expected HTTP proxy, got #{@proxy.inspect}" unless url
|
42
41
|
end
|
43
42
|
proxy = URI.parse(url)
|
44
43
|
end
|
45
44
|
|
46
|
-
Net::HTTP::Persistent.new
|
45
|
+
Net::HTTP::Persistent.new 'webdriver', proxy
|
47
46
|
end
|
48
47
|
|
49
48
|
def response_for(request)
|
50
49
|
http.request server_url, request
|
51
50
|
end
|
52
|
-
|
53
51
|
end # Persistent
|
54
52
|
end # Http
|
55
53
|
end # Remote
|
@@ -20,10 +20,8 @@
|
|
20
20
|
module Selenium
|
21
21
|
module WebDriver
|
22
22
|
module Remote
|
23
|
-
|
24
23
|
# @api private
|
25
24
|
class Response
|
26
|
-
|
27
25
|
attr_reader :code, :payload
|
28
26
|
attr_writer :payload
|
29
27
|
|
@@ -49,9 +47,10 @@ module Selenium
|
|
49
47
|
|
50
48
|
case val
|
51
49
|
when Hash
|
52
|
-
msg = val['message']
|
53
|
-
|
54
|
-
msg << "
|
50
|
+
msg = val['message']
|
51
|
+
return 'unknown error' unless msg
|
52
|
+
msg << ": #{val['alert']['text'].inspect}" if val['alert'].is_a?(Hash) && val['alert']['text']
|
53
|
+
msg << " (#{val['class']})" if val['class']
|
55
54
|
msg
|
56
55
|
when String
|
57
56
|
val
|
@@ -67,34 +66,28 @@ module Selenium
|
|
67
66
|
private
|
68
67
|
|
69
68
|
def assert_ok
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
69
|
+
e = error
|
70
|
+
raise e if e
|
71
|
+
return unless @code.nil? || @code >= 400
|
72
|
+
raise Error::ServerError, self
|
75
73
|
end
|
76
74
|
|
77
75
|
def add_backtrace(ex)
|
78
|
-
unless value.
|
79
|
-
return
|
80
|
-
end
|
76
|
+
return unless value.is_a?(Hash) && value['stackTrace']
|
81
77
|
|
82
78
|
server_trace = value['stackTrace']
|
83
79
|
|
84
80
|
backtrace = server_trace.map do |frame|
|
85
|
-
next unless frame.
|
81
|
+
next unless frame.is_a?(Hash)
|
86
82
|
|
87
83
|
file = frame['fileName']
|
88
84
|
line = frame['lineNumber']
|
89
85
|
meth = frame['methodName']
|
90
86
|
|
91
|
-
|
92
|
-
|
93
|
-
end
|
87
|
+
class_name = frame['className']
|
88
|
+
file = "#{class_name}(#{file})" if class_name
|
94
89
|
|
95
|
-
if meth.nil? || meth.empty?
|
96
|
-
meth = 'unknown'
|
97
|
-
end
|
90
|
+
meth = 'unknown' if meth.nil? || meth.empty?
|
98
91
|
|
99
92
|
"[remote server] #{file}:#{line}:in `#{meth}'"
|
100
93
|
end.compact
|
@@ -109,7 +102,6 @@ module Selenium
|
|
109
102
|
def value
|
110
103
|
@payload['value'] || @payload['message']
|
111
104
|
end
|
112
|
-
|
113
105
|
end # Response
|
114
106
|
end # Remote
|
115
107
|
end # WebDriver
|
@@ -21,15 +21,13 @@ module Selenium
|
|
21
21
|
module WebDriver
|
22
22
|
module Error
|
23
23
|
class ServerError < StandardError
|
24
|
-
|
25
24
|
def initialize(response)
|
26
|
-
if response.
|
25
|
+
if response.is_a? String
|
27
26
|
super(response)
|
28
27
|
else
|
29
28
|
super("status code #{response.code}")
|
30
29
|
end
|
31
30
|
end
|
32
|
-
|
33
31
|
end # ServerError
|
34
32
|
end # Error
|
35
33
|
end # WebDriver
|
@@ -22,7 +22,6 @@ require 'json'
|
|
22
22
|
module Selenium
|
23
23
|
module WebDriver
|
24
24
|
module Remote
|
25
|
-
|
26
25
|
#
|
27
26
|
# Low level bridge to the remote server, through which the rest of the API works.
|
28
27
|
#
|
@@ -32,6 +31,7 @@ module Selenium
|
|
32
31
|
class W3CBridge
|
33
32
|
include BridgeHelper
|
34
33
|
|
34
|
+
# TODO: constant shouldn't be modified in class
|
35
35
|
COMMANDS = {}
|
36
36
|
|
37
37
|
#
|
@@ -62,16 +62,13 @@ module Selenium
|
|
62
62
|
#
|
63
63
|
|
64
64
|
def initialize(opts = {})
|
65
|
-
|
66
|
-
require_relative '../edge/legacy_support'
|
67
|
-
extend Edge::LegacySupport
|
68
|
-
end
|
65
|
+
edge_check(opts)
|
69
66
|
|
70
67
|
opts = opts.dup
|
71
68
|
|
72
|
-
http_client
|
69
|
+
http_client = opts.delete(:http_client) { Http::Default.new }
|
73
70
|
desired_capabilities = opts.delete(:desired_capabilities) { W3CCapabilities.firefox }
|
74
|
-
url
|
71
|
+
url = opts.delete(:url) { "http://#{Platform.localhost}:4444/wd/hub" }
|
75
72
|
|
76
73
|
desired_capabilities = W3CCapabilities.send(desired_capabilities) if desired_capabilities.is_a? Symbol
|
77
74
|
|
@@ -81,23 +78,30 @@ module Selenium
|
|
81
78
|
raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
|
82
79
|
end
|
83
80
|
|
84
|
-
uri = url.
|
85
|
-
uri.path +=
|
81
|
+
uri = url.is_a?(URI) ? url : URI.parse(url)
|
82
|
+
uri.path += '/' unless uri.path =~ %r{\/$}
|
86
83
|
|
87
84
|
http_client.server_url = uri
|
88
85
|
|
89
|
-
@http
|
90
|
-
@capabilities
|
86
|
+
@http = http_client
|
87
|
+
@capabilities = create_session(desired_capabilities)
|
91
88
|
@file_detector = nil
|
92
89
|
end
|
93
90
|
|
94
91
|
def browser
|
95
92
|
@browser ||= (
|
96
|
-
|
97
|
-
|
93
|
+
name = @capabilities.browser_name
|
94
|
+
name ? name.tr(' ', '_').to_sym : 'unknown'
|
98
95
|
)
|
99
96
|
end
|
100
97
|
|
98
|
+
def edge_check(opts)
|
99
|
+
caps = opts[:desired_capabilities]
|
100
|
+
return unless caps && caps[:browser_name] && caps[:browser_name] == 'MicrosoftEdge'
|
101
|
+
require_relative '../edge/legacy_support'
|
102
|
+
extend Edge::LegacySupport
|
103
|
+
end
|
104
|
+
|
101
105
|
def driver_extensions
|
102
106
|
[
|
103
107
|
DriverExtensions::HasInputDevices,
|
@@ -116,14 +120,15 @@ module Selenium
|
|
116
120
|
#
|
117
121
|
|
118
122
|
def session_id
|
119
|
-
@session_id || raise(Error::WebDriverError,
|
123
|
+
@session_id || raise(Error::WebDriverError, 'no current session exists')
|
120
124
|
end
|
121
125
|
|
122
126
|
def create_session(desired_capabilities)
|
123
|
-
resp = raw_execute :newSession, {}, :
|
124
|
-
@session_id = resp['sessionId']
|
127
|
+
resp = raw_execute :newSession, {}, {desiredCapabilities: desired_capabilities}
|
128
|
+
@session_id = resp['sessionId']
|
129
|
+
return W3CCapabilities.json_create resp['value'] if @session_id
|
125
130
|
|
126
|
-
|
131
|
+
raise Error::WebDriverError, 'no sessionId in returned payload'
|
127
132
|
end
|
128
133
|
|
129
134
|
def status
|
@@ -133,38 +138,38 @@ module Selenium
|
|
133
138
|
end
|
134
139
|
|
135
140
|
def get(url)
|
136
|
-
execute :get, {}, :
|
141
|
+
execute :get, {}, {url: url}
|
137
142
|
end
|
138
143
|
|
139
|
-
def
|
140
|
-
|
144
|
+
def implicit_wait_timeout=(milliseconds)
|
145
|
+
timeout('implicit', milliseconds)
|
141
146
|
end
|
142
147
|
|
143
|
-
def
|
144
|
-
|
148
|
+
def script_timeout=(milliseconds)
|
149
|
+
timeout('script', milliseconds)
|
145
150
|
end
|
146
151
|
|
147
|
-
def
|
148
|
-
execute :setTimeout, {}, :
|
152
|
+
def timeout(type, milliseconds)
|
153
|
+
execute :setTimeout, {}, {type: type, ms: milliseconds}
|
149
154
|
end
|
150
155
|
|
151
156
|
#
|
152
157
|
# alerts
|
153
158
|
#
|
154
159
|
|
155
|
-
def
|
160
|
+
def accept_alert
|
156
161
|
execute :acceptAlert
|
157
162
|
end
|
158
163
|
|
159
|
-
def
|
164
|
+
def dismiss_alert
|
160
165
|
execute :dismissAlert
|
161
166
|
end
|
162
167
|
|
163
|
-
def
|
164
|
-
execute :sendAlertText, {}, {:
|
168
|
+
def alert=(keys)
|
169
|
+
execute :sendAlertText, {}, {handler: 'prompt', text: keys}
|
165
170
|
end
|
166
171
|
|
167
|
-
def
|
172
|
+
def alert_text
|
168
173
|
execute :getAlertText
|
169
174
|
end
|
170
175
|
|
@@ -172,46 +177,46 @@ module Selenium
|
|
172
177
|
# navigation
|
173
178
|
#
|
174
179
|
|
175
|
-
def
|
180
|
+
def go_back
|
176
181
|
execute :back
|
177
182
|
end
|
178
183
|
|
179
|
-
def
|
184
|
+
def go_forward
|
180
185
|
execute :forward
|
181
186
|
end
|
182
187
|
|
183
|
-
def
|
188
|
+
def url
|
184
189
|
execute :getCurrentUrl
|
185
190
|
end
|
186
191
|
|
187
|
-
def
|
192
|
+
def title
|
188
193
|
execute :getTitle
|
189
194
|
end
|
190
195
|
|
191
|
-
def
|
192
|
-
|
193
|
-
|
194
|
-
|
196
|
+
def page_source
|
197
|
+
execute_script('var source = document.documentElement.outerHTML;' \
|
198
|
+
'if (!source) { source = new XMLSerializer().serializeToString(document); }' \
|
199
|
+
'return source;')
|
195
200
|
end
|
196
201
|
|
197
|
-
def
|
198
|
-
execute :switchToWindow, {}, :
|
202
|
+
def switch_to_window(name)
|
203
|
+
execute :switchToWindow, {}, {handle: name}
|
199
204
|
end
|
200
205
|
|
201
|
-
def
|
206
|
+
def switch_to_frame(id)
|
202
207
|
id = find_element_by('id', id) if id.is_a? String
|
203
|
-
execute :switchToFrame, {}, :
|
208
|
+
execute :switchToFrame, {}, {id: id}
|
204
209
|
end
|
205
210
|
|
206
|
-
def
|
211
|
+
def switch_to_parent_frame
|
207
212
|
execute :switchToParentFrame
|
208
213
|
end
|
209
214
|
|
210
|
-
def
|
211
|
-
|
215
|
+
def switch_to_default_content
|
216
|
+
switch_to_frame nil
|
212
217
|
end
|
213
218
|
|
214
|
-
QUIT_ERRORS = [IOError]
|
219
|
+
QUIT_ERRORS = [IOError].freeze
|
215
220
|
|
216
221
|
def quit
|
217
222
|
execute :deleteSession
|
@@ -231,34 +236,34 @@ module Selenium
|
|
231
236
|
# window handling
|
232
237
|
#
|
233
238
|
|
234
|
-
def
|
239
|
+
def window_handles
|
235
240
|
execute :getWindowHandles
|
236
241
|
end
|
237
242
|
|
238
|
-
def
|
243
|
+
def window_handle
|
239
244
|
execute :getWindowHandle
|
240
245
|
end
|
241
246
|
|
242
|
-
def
|
247
|
+
def resize_window(width, height, handle = :current)
|
243
248
|
unless handle == :current
|
244
249
|
raise Error::WebDriverError, 'Switch to desired window before changing its size'
|
245
250
|
end
|
246
|
-
execute :setWindowSize, {}, {:
|
247
|
-
|
251
|
+
execute :setWindowSize, {}, {width: width,
|
252
|
+
height: height}
|
248
253
|
end
|
249
254
|
|
250
|
-
def
|
255
|
+
def maximize_window(handle = :current)
|
251
256
|
unless handle == :current
|
252
257
|
raise Error::UnsupportedOperationError, 'Switch to desired window before changing its size'
|
253
258
|
end
|
254
259
|
execute :maximizeWindow
|
255
260
|
end
|
256
261
|
|
257
|
-
def
|
262
|
+
def full_screen_window
|
258
263
|
execute :fullscreenWindow
|
259
264
|
end
|
260
265
|
|
261
|
-
def
|
266
|
+
def window_size(handle = :current)
|
262
267
|
unless handle == :current
|
263
268
|
raise Error::UnsupportedOperationError, 'Switch to desired window before getting its size'
|
264
269
|
end
|
@@ -267,15 +272,15 @@ module Selenium
|
|
267
272
|
Dimension.new data['width'], data['height']
|
268
273
|
end
|
269
274
|
|
270
|
-
def
|
275
|
+
def reposition_window(_x, _y, _handle = nil)
|
271
276
|
raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting the Window Position'
|
272
277
|
end
|
273
278
|
|
274
|
-
def
|
279
|
+
def window_position(_handle = nil)
|
275
280
|
raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting the Window Position'
|
276
281
|
end
|
277
282
|
|
278
|
-
def
|
283
|
+
def screenshot
|
279
284
|
execute :takeScreenshot
|
280
285
|
end
|
281
286
|
|
@@ -283,67 +288,67 @@ module Selenium
|
|
283
288
|
# HTML 5
|
284
289
|
#
|
285
290
|
|
286
|
-
def
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
end
|
293
|
-
|
294
|
-
def getLocalStorageKeys
|
295
|
-
executeScript("return Object.keys(localStorage)")
|
291
|
+
def local_storage_item(key, value = nil)
|
292
|
+
if value
|
293
|
+
execute_script("localStorage.setItem('#{key}', '#{value}')")
|
294
|
+
else
|
295
|
+
execute_script("return localStorage.getItem('#{key}')")
|
296
|
+
end
|
296
297
|
end
|
297
298
|
|
298
|
-
def
|
299
|
-
|
299
|
+
def remove_local_storage_item(key)
|
300
|
+
execute_script("localStorage.removeItem('#{key}')")
|
300
301
|
end
|
301
302
|
|
302
|
-
def
|
303
|
-
|
303
|
+
def local_storage_keys
|
304
|
+
execute_script('return Object.keys(localStorage)')
|
304
305
|
end
|
305
306
|
|
306
|
-
def
|
307
|
-
|
307
|
+
def clear_local_storage
|
308
|
+
execute_script('localStorage.clear()')
|
308
309
|
end
|
309
310
|
|
310
|
-
def
|
311
|
-
|
311
|
+
def local_storage_size
|
312
|
+
execute_script('return localStorage.length')
|
312
313
|
end
|
313
314
|
|
314
|
-
def
|
315
|
-
|
315
|
+
def session_storage_item(key, value = nil)
|
316
|
+
if value
|
317
|
+
execute_script("sessionStorage.setItem('#{key}', '#{value}')")
|
318
|
+
else
|
319
|
+
execute_script("return sessionStorage.getItem('#{key}')")
|
320
|
+
end
|
316
321
|
end
|
317
322
|
|
318
|
-
def
|
319
|
-
|
323
|
+
def remove_session_storage_item(key)
|
324
|
+
execute_script("sessionStorage.removeItem('#{key}')")
|
320
325
|
end
|
321
326
|
|
322
|
-
def
|
323
|
-
|
327
|
+
def session_storage_keys
|
328
|
+
execute_script('return Object.keys(sessionStorage)')
|
324
329
|
end
|
325
330
|
|
326
|
-
def
|
327
|
-
|
331
|
+
def clear_session_storage
|
332
|
+
execute_script('sessionStorage.clear()')
|
328
333
|
end
|
329
334
|
|
330
|
-
def
|
331
|
-
|
335
|
+
def session_storage_size
|
336
|
+
execute_script('return sessionStorage.length')
|
332
337
|
end
|
333
338
|
|
334
|
-
def
|
339
|
+
def location
|
335
340
|
raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting location'
|
336
341
|
end
|
337
342
|
|
338
|
-
def
|
343
|
+
def set_location(_lat, _lon, _alt)
|
339
344
|
raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting location'
|
340
345
|
end
|
341
346
|
|
342
|
-
def
|
347
|
+
def network_connection
|
343
348
|
raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting network connection'
|
344
349
|
end
|
345
350
|
|
346
|
-
def
|
351
|
+
def network_connection=(_type)
|
347
352
|
raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting network connection'
|
348
353
|
end
|
349
354
|
|
@@ -351,13 +356,13 @@ module Selenium
|
|
351
356
|
# javascript execution
|
352
357
|
#
|
353
358
|
|
354
|
-
def
|
355
|
-
result = execute :executeScript, {}, :
|
359
|
+
def execute_script(script, *args)
|
360
|
+
result = execute :executeScript, {}, {script: script, args: args}
|
356
361
|
unwrap_script_result result
|
357
362
|
end
|
358
363
|
|
359
|
-
def
|
360
|
-
result = execute :executeAsyncScript, {}, :
|
364
|
+
def execute_async_script(script, *args)
|
365
|
+
result = execute :executeAsyncScript, {}, {script: script, args: args}
|
361
366
|
unwrap_script_result result
|
362
367
|
end
|
363
368
|
|
@@ -365,139 +370,139 @@ module Selenium
|
|
365
370
|
# cookies
|
366
371
|
#
|
367
372
|
|
368
|
-
def
|
369
|
-
execute :addCookie, {}, :
|
373
|
+
def add_cookie(cookie)
|
374
|
+
execute :addCookie, {}, {cookie: cookie}
|
370
375
|
end
|
371
376
|
|
372
|
-
def
|
373
|
-
execute :deleteCookie, :
|
377
|
+
def delete_cookie(name)
|
378
|
+
execute :deleteCookie, name: name
|
374
379
|
end
|
375
380
|
|
376
|
-
# TODO - write specs
|
377
|
-
def
|
378
|
-
execute :getCookie, :
|
381
|
+
# TODO: - write specs
|
382
|
+
def cookie(name)
|
383
|
+
execute :getCookie, name: name
|
379
384
|
end
|
380
385
|
|
381
|
-
def
|
386
|
+
def cookies
|
382
387
|
execute :getAllCookies
|
383
388
|
end
|
384
389
|
|
385
|
-
def
|
386
|
-
|
390
|
+
def delete_all_cookies
|
391
|
+
cookies.each { |cookie| delete_cookie(cookie['name']) }
|
387
392
|
end
|
388
393
|
|
389
394
|
#
|
390
395
|
# actions
|
391
396
|
#
|
392
397
|
|
393
|
-
def
|
394
|
-
execute :elementClick, :
|
398
|
+
def click_element(element)
|
399
|
+
execute :elementClick, id: element
|
395
400
|
end
|
396
401
|
|
397
402
|
def click
|
398
|
-
execute :click, {}, :
|
403
|
+
execute :click, {}, {button: 0}
|
399
404
|
end
|
400
405
|
|
401
|
-
def
|
406
|
+
def double_click
|
402
407
|
execute :doubleClick
|
403
408
|
end
|
404
409
|
|
405
|
-
def
|
406
|
-
execute :click, {}, :
|
410
|
+
def context_click
|
411
|
+
execute :click, {}, {button: 2}
|
407
412
|
end
|
408
413
|
|
409
|
-
def
|
414
|
+
def mouse_down
|
410
415
|
execute :mouseDown
|
411
416
|
end
|
412
417
|
|
413
|
-
def
|
418
|
+
def mouse_up
|
414
419
|
execute :mouseUp
|
415
420
|
end
|
416
421
|
|
417
|
-
def
|
418
|
-
params = {
|
422
|
+
def mouse_move_to(element, x = nil, y = nil)
|
423
|
+
params = {element: element}
|
419
424
|
|
420
425
|
if x && y
|
421
|
-
params
|
426
|
+
params[:xoffset] = x
|
427
|
+
params[:yoffset] = y
|
422
428
|
end
|
423
429
|
|
424
430
|
execute :mouseMoveTo, {}, params
|
425
431
|
end
|
426
432
|
|
427
|
-
def
|
428
|
-
|
433
|
+
def send_keys_to_active_element(keys)
|
434
|
+
send_keys_to_element(active_element, keys)
|
429
435
|
end
|
430
436
|
|
431
|
-
# TODO - Implement file verification
|
432
|
-
def
|
433
|
-
execute :elementSendKeys, {:
|
437
|
+
# TODO: - Implement file verification
|
438
|
+
def send_keys_to_element(element, keys)
|
439
|
+
execute :elementSendKeys, {id: element}, {value: keys.join('').split(//)}
|
434
440
|
end
|
435
441
|
|
436
|
-
def
|
437
|
-
execute :elementClear, :
|
442
|
+
def clear_element(element)
|
443
|
+
execute :elementClear, id: element
|
438
444
|
end
|
439
445
|
|
440
|
-
def
|
441
|
-
|
442
|
-
"e.initEvent('submit', true, true);"
|
443
|
-
|
446
|
+
def submit_element(element)
|
447
|
+
execute_script("var e = arguments[0].ownerDocument.createEvent('Event');" \
|
448
|
+
"e.initEvent('submit', true, true);" \
|
449
|
+
'if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }', element)
|
444
450
|
end
|
445
451
|
|
446
|
-
def
|
447
|
-
execute :dragElement, {:
|
452
|
+
def drag_element(element, right_by, down_by)
|
453
|
+
execute :dragElement, {id: element}, {x: right_by, y: down_by}
|
448
454
|
end
|
449
455
|
|
450
|
-
def
|
451
|
-
execute :touchSingleTap, {}, :
|
456
|
+
def touch_single_tap(element)
|
457
|
+
execute :touchSingleTap, {}, {element: element}
|
452
458
|
end
|
453
459
|
|
454
|
-
def
|
455
|
-
execute :touchDoubleTap, {}, :
|
460
|
+
def touch_double_tap(element)
|
461
|
+
execute :touchDoubleTap, {}, {element: element}
|
456
462
|
end
|
457
463
|
|
458
|
-
def
|
459
|
-
execute :touchLongPress, {}, :
|
464
|
+
def touch_long_press(element)
|
465
|
+
execute :touchLongPress, {}, {element: element}
|
460
466
|
end
|
461
467
|
|
462
|
-
def
|
463
|
-
execute :touchDown, {}, :
|
468
|
+
def touch_down(x, y)
|
469
|
+
execute :touchDown, {}, {x: x, y: y}
|
464
470
|
end
|
465
471
|
|
466
|
-
def
|
467
|
-
execute :touchUp, {}, :
|
472
|
+
def touch_up(x, y)
|
473
|
+
execute :touchUp, {}, {x: x, y: y}
|
468
474
|
end
|
469
475
|
|
470
|
-
def
|
471
|
-
execute :touchMove, {}, :
|
476
|
+
def touch_move(x, y)
|
477
|
+
execute :touchMove, {}, {x: x, y: y}
|
472
478
|
end
|
473
479
|
|
474
|
-
def
|
480
|
+
def touch_scroll(element, x, y)
|
475
481
|
if element
|
476
|
-
execute :touchScroll, {}, :
|
477
|
-
|
478
|
-
|
482
|
+
execute :touchScroll, {}, {element: element,
|
483
|
+
xoffset: x,
|
484
|
+
yoffset: y}
|
479
485
|
else
|
480
|
-
execute :touchScroll, {}, :
|
486
|
+
execute :touchScroll, {}, {xoffset: x, yoffset: y}
|
481
487
|
end
|
482
488
|
end
|
483
489
|
|
484
|
-
def
|
485
|
-
execute :touchFlick, {}, :
|
490
|
+
def touch_flick(xspeed, yspeed)
|
491
|
+
execute :touchFlick, {}, {xspeed: xspeed, yspeed: yspeed}
|
486
492
|
end
|
487
493
|
|
488
|
-
def
|
489
|
-
execute :touchFlick, {}, :
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
+
def touch_element_flick(element, right_by, down_by, speed)
|
495
|
+
execute :touchFlick, {}, {element: element,
|
496
|
+
xoffset: right_by,
|
497
|
+
yoffset: down_by,
|
498
|
+
speed: speed}
|
494
499
|
end
|
495
500
|
|
496
|
-
def
|
497
|
-
execute :setScreenOrientation, {}, :
|
501
|
+
def screen_orientation=(orientation)
|
502
|
+
execute :setScreenOrientation, {}, {orientation: orientation}
|
498
503
|
end
|
499
504
|
|
500
|
-
def
|
505
|
+
def screen_orientation
|
501
506
|
execute :getScreenOrientation
|
502
507
|
end
|
503
508
|
|
@@ -505,74 +510,75 @@ module Selenium
|
|
505
510
|
# element properties
|
506
511
|
#
|
507
512
|
|
508
|
-
def
|
509
|
-
execute :getElementTagName, :
|
513
|
+
def element_tag_name(element)
|
514
|
+
execute :getElementTagName, id: element
|
510
515
|
end
|
511
516
|
|
512
|
-
def
|
513
|
-
execute :getElementAttribute, :
|
517
|
+
def element_attribute(element, name)
|
518
|
+
execute :getElementAttribute, id: element, name: name
|
514
519
|
end
|
515
520
|
|
516
|
-
def
|
517
|
-
execute :getElementProperty, :
|
521
|
+
def element_value(element)
|
522
|
+
execute :getElementProperty, id: element, name: 'value'
|
518
523
|
end
|
519
524
|
|
520
|
-
def
|
521
|
-
execute :getElementText, :
|
525
|
+
def element_text(element)
|
526
|
+
execute :getElementText, id: element
|
522
527
|
end
|
523
528
|
|
524
|
-
def
|
525
|
-
data = execute :getElementRect, :
|
529
|
+
def element_location(element)
|
530
|
+
data = execute :getElementRect, id: element
|
526
531
|
|
527
532
|
Point.new data['x'], data['y']
|
528
533
|
end
|
529
534
|
|
530
|
-
def
|
531
|
-
|
532
|
-
|
535
|
+
def element_location_once_scrolled_into_view(element)
|
536
|
+
send_keys_to_element(element, [''])
|
537
|
+
element_location(element)
|
533
538
|
end
|
534
539
|
|
535
|
-
def
|
536
|
-
data = execute :getElementRect, :
|
540
|
+
def element_size(element)
|
541
|
+
data = execute :getElementRect, id: element
|
537
542
|
|
538
543
|
Dimension.new data['width'], data['height']
|
539
544
|
end
|
540
545
|
|
541
|
-
def
|
542
|
-
execute :isElementEnabled, :
|
546
|
+
def element_enabled?(element)
|
547
|
+
execute :isElementEnabled, id: element
|
543
548
|
end
|
544
549
|
|
545
|
-
def
|
546
|
-
execute :isElementSelected, :
|
550
|
+
def element_selected?(element)
|
551
|
+
execute :isElementSelected, id: element
|
547
552
|
end
|
548
553
|
|
549
|
-
def
|
554
|
+
def element_displayed?(element)
|
550
555
|
jwp = Selenium::WebDriver::Remote::Bridge::COMMANDS[:isElementDisplayed]
|
551
556
|
self.class.command(:isElementDisplayed, jwp.first, jwp.last)
|
552
|
-
execute :isElementDisplayed, :
|
557
|
+
execute :isElementDisplayed, id: element
|
553
558
|
end
|
554
559
|
|
555
|
-
def
|
556
|
-
execute :getElementCssValue, :
|
560
|
+
def element_value_of_css_property(element, prop)
|
561
|
+
execute :getElementCssValue, id: element, property_name: prop
|
557
562
|
end
|
558
563
|
|
559
564
|
#
|
560
565
|
# finding elements
|
561
566
|
#
|
562
567
|
|
563
|
-
def
|
568
|
+
def active_element
|
564
569
|
Element.new self, element_id_from(execute(:getActiveElement))
|
565
570
|
end
|
566
|
-
|
571
|
+
|
572
|
+
alias_method :switch_to_active_element, :active_element
|
567
573
|
|
568
574
|
def find_element_by(how, what, parent = nil)
|
569
575
|
how, what = convert_locators(how, what)
|
570
576
|
|
571
|
-
if parent
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
577
|
+
id = if parent
|
578
|
+
execute :findChildElement, {id: parent}, {using: how, value: what}
|
579
|
+
else
|
580
|
+
execute :findElement, {}, {using: how, value: what}
|
581
|
+
end
|
576
582
|
|
577
583
|
Element.new self, element_id_from(id)
|
578
584
|
end
|
@@ -580,11 +586,11 @@ module Selenium
|
|
580
586
|
def find_elements_by(how, what, parent = nil)
|
581
587
|
how, what = convert_locators(how, what)
|
582
588
|
|
583
|
-
if parent
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
589
|
+
ids = if parent
|
590
|
+
execute :findChildElements, {id: parent}, {using: how, value: what}
|
591
|
+
else
|
592
|
+
execute :findElements, {}, {using: how, value: what}
|
593
|
+
end
|
588
594
|
|
589
595
|
ids.map { |id| Element.new self, element_id_from(id) }
|
590
596
|
end
|
@@ -605,7 +611,7 @@ module Selenium
|
|
605
611
|
when 'tag name'
|
606
612
|
how = 'css selector'
|
607
613
|
end
|
608
|
-
|
614
|
+
[how, what]
|
609
615
|
end
|
610
616
|
|
611
617
|
#
|
@@ -628,14 +634,14 @@ module Selenium
|
|
628
634
|
|
629
635
|
def raw_execute(command, opts = {}, command_hash = nil)
|
630
636
|
verb, path = COMMANDS[command] || raise(ArgumentError, "unknown command: #{command.inspect}")
|
631
|
-
path
|
637
|
+
path = path.dup
|
632
638
|
|
633
|
-
path[':session_id'] = @session_id if path.include?(
|
639
|
+
path[':session_id'] = @session_id if path.include?(':session_id')
|
634
640
|
|
635
641
|
begin
|
636
|
-
opts.each
|
642
|
+
opts.each do |key, value|
|
637
643
|
path[key.inspect] = escaper.escape(value.to_s)
|
638
|
-
|
644
|
+
end
|
639
645
|
rescue IndexError
|
640
646
|
raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
|
641
647
|
end
|
@@ -661,7 +667,6 @@ module Selenium
|
|
661
667
|
|
662
668
|
string
|
663
669
|
end
|
664
|
-
|
665
670
|
end # W3CBridge
|
666
671
|
end # Remote
|
667
672
|
end # WebDriver
|