selenium-webdriver 3.3.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +18 -0
- data/lib/selenium/webdriver.rb +1 -0
- data/lib/selenium/webdriver/common/element.rb +10 -0
- data/lib/selenium/webdriver/common/w3c_error.rb +13 -0
- data/lib/selenium/webdriver/common/window.rb +36 -0
- data/lib/selenium/webdriver/edge/bridge.rb +44 -0
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/w3c_bridge.rb +34 -4
- data/lib/selenium/webdriver/remote/bridge.rb +15 -6
- data/lib/selenium/webdriver/remote/capabilities.rb +1 -1
- data/lib/selenium/webdriver/remote/w3c_bridge.rb +36 -16
- data/lib/selenium/webdriver/remote/w3c_commands.rb +3 -0
- data/selenium-webdriver.gemspec +1 -1
- metadata +2 -2
data/CHANGES
CHANGED
@@ -1,6 +1,24 @@
|
|
1
|
+
3.4.0 (Unreleased)
|
2
|
+
===================
|
3
|
+
|
4
|
+
Edge:
|
5
|
+
* Fix bug when response is not wrapped with "value"
|
6
|
+
|
7
|
+
Firefox:
|
8
|
+
* Support geckodriver v0.16
|
9
|
+
|
10
|
+
Ruby:
|
11
|
+
* Support ElementClickIntercepted error from W3C spec
|
12
|
+
* Support ElementNotInteractable error from W3C spec
|
13
|
+
* Implement window rect commands
|
14
|
+
* Implement window minimize command
|
15
|
+
|
1
16
|
3.3.0 (2017-03-07)
|
2
17
|
===================
|
3
18
|
|
19
|
+
Firefox:
|
20
|
+
* geckodriver v0.15 or later is required
|
21
|
+
|
4
22
|
W3C:
|
5
23
|
* Support for command response data to be wrapped in a 'value' key
|
6
24
|
* Support for updated timeout formats
|
data/lib/selenium/webdriver.rb
CHANGED
@@ -30,6 +30,7 @@ module Selenium
|
|
30
30
|
module WebDriver
|
31
31
|
Point = Struct.new(:x, :y)
|
32
32
|
Dimension = Struct.new(:width, :height)
|
33
|
+
Rectangle = Struct.new(:x, :y, :width, :height)
|
33
34
|
Location = Struct.new(:latitude, :longitude, :altitude)
|
34
35
|
|
35
36
|
autoload :Chrome, 'selenium/webdriver/chrome'
|
@@ -235,6 +235,16 @@ module Selenium
|
|
235
235
|
bridge.element_location @id
|
236
236
|
end
|
237
237
|
|
238
|
+
#
|
239
|
+
# Get the dimensions and coordinates of this element.
|
240
|
+
#
|
241
|
+
# @return [WebDriver::Rectangle]
|
242
|
+
#
|
243
|
+
|
244
|
+
def rect
|
245
|
+
bridge.element_rect @id
|
246
|
+
end
|
247
|
+
|
238
248
|
#
|
239
249
|
# Determine an element's location on the screen once it has been scrolled into view.
|
240
250
|
#
|
@@ -178,6 +178,19 @@ module Selenium
|
|
178
178
|
|
179
179
|
class UnsupportedOperationError < WebDriverError; end
|
180
180
|
|
181
|
+
#
|
182
|
+
# Indicates that the Element Click command could not be completed because the element receiving the events
|
183
|
+
# is obscuring the element that was requested clicked.
|
184
|
+
#
|
185
|
+
|
186
|
+
class ElementClickIntercepted < WebDriverError; end
|
187
|
+
|
188
|
+
#
|
189
|
+
# Indicates that a command could not be completed because the element is not pointer or keyboard interactable.
|
190
|
+
#
|
191
|
+
|
192
|
+
class ElementNotInteractable < WebDriverError; end
|
193
|
+
|
181
194
|
# aliased for backwards compatibility
|
182
195
|
NoAlertPresentError = NoSuchAlertError
|
183
196
|
ScriptTimeOutError = ScriptTimeoutError
|
@@ -82,6 +82,34 @@ module Selenium
|
|
82
82
|
@bridge.window_position
|
83
83
|
end
|
84
84
|
|
85
|
+
#
|
86
|
+
# Sets the current window rect to the given point and position.
|
87
|
+
#
|
88
|
+
# @param [Selenium::WebDriver::Rectangle, #x, #y, #width, #height] rectangle The new rect.
|
89
|
+
#
|
90
|
+
|
91
|
+
def rect=(rectangle)
|
92
|
+
unless %w[x y width height].all? { |val| rectangle.respond_to? val }
|
93
|
+
raise ArgumentError, "expected #{rectangle.inspect}:#{rectangle.class}" \
|
94
|
+
' to respond to #x, #y, #width, and #height'
|
95
|
+
end
|
96
|
+
|
97
|
+
@bridge.set_window_rect(x: rectangle.x,
|
98
|
+
y: rectangle.y,
|
99
|
+
width: rectangle.width,
|
100
|
+
height: rectangle.height)
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Get the rect of the current window.
|
105
|
+
#
|
106
|
+
# @return [Selenium::WebDriver::Rectangle] The rectangle.
|
107
|
+
#
|
108
|
+
|
109
|
+
def rect
|
110
|
+
@bridge.window_rect
|
111
|
+
end
|
112
|
+
|
85
113
|
#
|
86
114
|
# Equivalent to #size=, but accepts width and height arguments.
|
87
115
|
#
|
@@ -115,6 +143,14 @@ module Selenium
|
|
115
143
|
@bridge.maximize_window
|
116
144
|
end
|
117
145
|
|
146
|
+
#
|
147
|
+
# Minimize the current window
|
148
|
+
#
|
149
|
+
|
150
|
+
def minimize
|
151
|
+
@bridge.minimize_window
|
152
|
+
end
|
153
|
+
|
118
154
|
#
|
119
155
|
# Make current window full screen
|
120
156
|
#
|
@@ -115,6 +115,50 @@ module Selenium
|
|
115
115
|
def maximize_window(handle = :current)
|
116
116
|
execute :maximize_window, window_handle: handle
|
117
117
|
end
|
118
|
+
|
119
|
+
def create_session(desired_capabilities)
|
120
|
+
resp = raw_execute :new_session, {}, {desiredCapabilities: desired_capabilities}
|
121
|
+
@session_id = resp['sessionId']
|
122
|
+
return Remote::W3CCapabilities.json_create resp['value'] if @session_id
|
123
|
+
|
124
|
+
raise Error::WebDriverError, 'no sessionId in returned payload'
|
125
|
+
end
|
126
|
+
|
127
|
+
#
|
128
|
+
# executes a command on the remote server.
|
129
|
+
#
|
130
|
+
#
|
131
|
+
# Returns the 'value' of the returned payload
|
132
|
+
#
|
133
|
+
|
134
|
+
def execute(*args)
|
135
|
+
result = raw_execute(*args)
|
136
|
+
result.payload.key?('value') ? result['value'] : result
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# executes a command on the remote server.
|
141
|
+
#
|
142
|
+
# @return [WebDriver::Remote::Response]
|
143
|
+
#
|
144
|
+
|
145
|
+
def raw_execute(command, opts = {}, command_hash = nil)
|
146
|
+
verb, path = commands(command) || raise(ArgumentError, "unknown command: #{command.inspect}")
|
147
|
+
path = path.dup
|
148
|
+
|
149
|
+
path[':session_id'] = @session_id if path.include?(':session_id')
|
150
|
+
|
151
|
+
begin
|
152
|
+
opts.each do |key, value|
|
153
|
+
path[key.inspect] = escaper.escape(value.to_s)
|
154
|
+
end
|
155
|
+
rescue IndexError
|
156
|
+
raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
|
157
|
+
end
|
158
|
+
|
159
|
+
WebDriver.logger.info("-> #{verb.to_s.upcase} #{path}")
|
160
|
+
http.call verb, path, command_hash
|
161
|
+
end
|
118
162
|
end # Bridge
|
119
163
|
end # Edge
|
120
164
|
end # WebDriver
|
Binary file
|
@@ -60,22 +60,52 @@ module Selenium
|
|
60
60
|
@service.stop if @service
|
61
61
|
end
|
62
62
|
|
63
|
+
# Support for geckodriver < 0.15
|
64
|
+
def resize_window(width, height, handle = :current)
|
65
|
+
super
|
66
|
+
rescue Error::UnknownCommandError
|
67
|
+
execute :set_window_size, {}, {width: width, height: height}
|
68
|
+
end
|
69
|
+
|
70
|
+
def window_size(handle = :current)
|
71
|
+
data = super
|
72
|
+
rescue Error::UnknownCommandError
|
73
|
+
data = execute :get_window_size
|
74
|
+
ensure
|
75
|
+
return Dimension.new data['width'], data['height']
|
76
|
+
end
|
77
|
+
|
78
|
+
def reposition_window(x, y)
|
79
|
+
super
|
80
|
+
rescue Error::UnknownCommandError
|
81
|
+
execute :set_window_position, {}, {x: x, y: y}
|
82
|
+
end
|
83
|
+
|
84
|
+
def window_position
|
85
|
+
data = super
|
86
|
+
rescue Error::UnknownCommandError
|
87
|
+
data = execute :get_window_position
|
88
|
+
ensure
|
89
|
+
return Point.new data['x'], data['y']
|
90
|
+
end
|
91
|
+
|
63
92
|
private
|
64
93
|
|
65
94
|
def create_capabilities(opts)
|
66
95
|
caps = Remote::W3CCapabilities.firefox
|
67
96
|
caps.merge!(opts.delete(:desired_capabilities)) if opts.key? :desired_capabilities
|
68
|
-
|
69
|
-
|
97
|
+
firefox_options = caps[:firefox_options] || {}
|
98
|
+
firefox_options = firefox_options_caps.merge(opts[:firefox_options]) if opts.key?(:firefox_options)
|
70
99
|
if opts.key?(:profile)
|
71
100
|
profile = opts.delete(:profile)
|
72
101
|
unless profile.is_a?(Profile)
|
73
102
|
profile = Profile.from_name(profile)
|
74
103
|
end
|
75
|
-
|
104
|
+
firefox_options[:profile] = profile.encoded
|
76
105
|
end
|
77
106
|
|
78
|
-
Binary.path =
|
107
|
+
Binary.path = firefox_options[:binary] if firefox_options.key?(:binary)
|
108
|
+
caps[:firefox_options] = firefox_options unless firefox_options.empty?
|
79
109
|
caps
|
80
110
|
end
|
81
111
|
end # W3CBridge
|
@@ -39,12 +39,14 @@ module Selenium
|
|
39
39
|
def initialize(opts = {})
|
40
40
|
opts = opts.dup
|
41
41
|
|
42
|
-
if opts.key?(:port)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
port = if opts.key?(:port)
|
43
|
+
WebDriver.logger.warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
|
44
|
+
[DEPRECATION] `:port` is deprecated. Use `:url` with full path
|
45
|
+
DEPRECATE
|
46
|
+
opts.delete(:port)
|
47
|
+
else
|
48
|
+
4444
|
49
|
+
end
|
48
50
|
|
49
51
|
http_client = opts.delete(:http_client) { Http::Default.new }
|
50
52
|
desired_capabilities = opts.delete(:desired_capabilities) { Capabilities.firefox }
|
@@ -571,6 +573,13 @@ module Selenium
|
|
571
573
|
Point.new data['x'], data['y']
|
572
574
|
end
|
573
575
|
|
576
|
+
def element_rect(element)
|
577
|
+
loc = execute :get_element_location, id: element
|
578
|
+
size = execute :get_element_size, id: element
|
579
|
+
|
580
|
+
Rectangle.new loc['x'], loc['y'], size['width'], size['height']
|
581
|
+
end
|
582
|
+
|
574
583
|
def element_location_once_scrolled_into_view(element)
|
575
584
|
data = execute :get_element_location_once_scrolled_into_view, id: element
|
576
585
|
|
@@ -139,7 +139,7 @@ module Selenium
|
|
139
139
|
caps = new
|
140
140
|
caps.browser_name = data.delete('browserName')
|
141
141
|
caps.version = data.delete('version')
|
142
|
-
caps.platform = data.delete('platform').downcase.to_sym if data.key?('platform')
|
142
|
+
caps.platform = data.delete('platform').downcase.tr(' ','_').to_sym if data.key?('platform')
|
143
143
|
caps.javascript_enabled = data.delete('javascriptEnabled')
|
144
144
|
caps.css_selectors_enabled = data.delete('cssSelectorsEnabled')
|
145
145
|
caps.takes_screenshot = data.delete('takesScreenshot')
|
@@ -113,7 +113,7 @@ module Selenium
|
|
113
113
|
def create_session(desired_capabilities)
|
114
114
|
resp = execute :new_session, {}, {desiredCapabilities: desired_capabilities}
|
115
115
|
@session_id = resp['sessionId']
|
116
|
-
return W3CCapabilities.json_create resp['value'] if @session_id
|
116
|
+
return W3CCapabilities.json_create(resp['capabilities'] || resp['value']) if @session_id
|
117
117
|
|
118
118
|
raise Error::WebDriverError, 'no sessionId in returned payload'
|
119
119
|
end
|
@@ -152,7 +152,7 @@ module Selenium
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def alert=(keys)
|
155
|
-
execute :send_alert_text, {}, {value: keys.split(//)}
|
155
|
+
execute :send_alert_text, {}, {value: keys.split(//), text: keys}
|
156
156
|
end
|
157
157
|
|
158
158
|
def alert_text
|
@@ -234,39 +234,51 @@ module Selenium
|
|
234
234
|
unless handle == :current
|
235
235
|
raise Error::WebDriverError, 'Switch to desired window before changing its size'
|
236
236
|
end
|
237
|
-
execute :
|
238
|
-
height: height}
|
237
|
+
execute :set_window_rect, {}, {width: width, height: height}
|
239
238
|
end
|
240
239
|
|
241
|
-
def
|
240
|
+
def window_size(handle = :current)
|
242
241
|
unless handle == :current
|
243
|
-
raise Error::UnsupportedOperationError, 'Switch to desired window before
|
242
|
+
raise Error::UnsupportedOperationError, 'Switch to desired window before getting its size'
|
244
243
|
end
|
245
|
-
execute :
|
244
|
+
data = execute :get_window_rect
|
245
|
+
|
246
|
+
Dimension.new data['width'], data['height']
|
246
247
|
end
|
247
248
|
|
248
|
-
def
|
249
|
-
execute :
|
249
|
+
def minimize_window
|
250
|
+
execute :minimize_window
|
250
251
|
end
|
251
252
|
|
252
|
-
def
|
253
|
+
def maximize_window(handle = :current)
|
253
254
|
unless handle == :current
|
254
|
-
raise Error::UnsupportedOperationError, 'Switch to desired window before
|
255
|
+
raise Error::UnsupportedOperationError, 'Switch to desired window before changing its size'
|
255
256
|
end
|
256
|
-
|
257
|
+
execute :maximize_window
|
258
|
+
end
|
257
259
|
|
258
|
-
|
260
|
+
def full_screen_window
|
261
|
+
execute :fullscreen_window
|
259
262
|
end
|
260
263
|
|
261
264
|
def reposition_window(x, y)
|
262
|
-
execute :
|
265
|
+
execute :set_window_rect, {}, {x: x, y: y}
|
263
266
|
end
|
264
267
|
|
265
268
|
def window_position
|
266
|
-
data = execute :
|
269
|
+
data = execute :get_window_rect
|
267
270
|
Point.new data['x'], data['y']
|
268
271
|
end
|
269
272
|
|
273
|
+
def set_window_rect(x: nil, y: nil, width: nil, height: nil)
|
274
|
+
execute :set_window_rect, {}, {x: x, y: y, width: width, height: height}
|
275
|
+
end
|
276
|
+
|
277
|
+
def window_rect
|
278
|
+
data = execute :get_window_rect
|
279
|
+
Rectangle.new data['x'], data['y'], data['width'], data['height']
|
280
|
+
end
|
281
|
+
|
270
282
|
def screenshot
|
271
283
|
execute :take_screenshot
|
272
284
|
end
|
@@ -415,7 +427,9 @@ module Selenium
|
|
415
427
|
|
416
428
|
# TODO: - Implement file verification
|
417
429
|
def send_keys_to_element(element, keys)
|
418
|
-
|
430
|
+
# Keep .split(//) for backward compatibility for now
|
431
|
+
text = keys.join('')
|
432
|
+
execute :element_send_keys, {id: element}, {value: text.split(//), text: text}
|
419
433
|
end
|
420
434
|
|
421
435
|
def clear_element(element)
|
@@ -516,6 +530,12 @@ module Selenium
|
|
516
530
|
Point.new data['x'], data['y']
|
517
531
|
end
|
518
532
|
|
533
|
+
def element_rect(element)
|
534
|
+
data = execute :get_element_rect, id: element
|
535
|
+
|
536
|
+
Rectangle.new data['x'], data['y'], data['width'], data['height']
|
537
|
+
end
|
538
|
+
|
519
539
|
def element_location_once_scrolled_into_view(element)
|
520
540
|
send_keys_to_element(element, [''])
|
521
541
|
element_location(element)
|
@@ -54,11 +54,14 @@ module Selenium
|
|
54
54
|
switch_to_window: [:post, 'session/:session_id/window'.freeze],
|
55
55
|
get_window_handles: [:get, 'session/:session_id/window/handles'.freeze],
|
56
56
|
fullscreen_window: [:post, 'session/:session_id/window/fullscreen'.freeze],
|
57
|
+
minimize_window: [:post, 'session/:session_id/window/minimize'.freeze],
|
57
58
|
maximize_window: [:post, 'session/:session_id/window/maximize'.freeze],
|
58
59
|
set_window_size: [:post, 'session/:session_id/window/size'.freeze],
|
59
60
|
get_window_size: [:get, 'session/:session_id/window/size'.freeze],
|
60
61
|
set_window_position: [:post, 'session/:session_id/window/position'.freeze],
|
61
62
|
get_window_position: [:get, 'session/:session_id/window/position'.freeze],
|
63
|
+
set_window_rect: [:post, 'session/:session_id/window/rect'.freeze],
|
64
|
+
get_window_rect: [:get, 'session/:session_id/window/rect'.freeze],
|
62
65
|
switch_to_frame: [:post, 'session/:session_id/frame'.freeze],
|
63
66
|
switch_to_parent_frame: [:post, 'session/:session_id/frame/parent'.freeze],
|
64
67
|
|
data/selenium-webdriver.gemspec
CHANGED
@@ -5,7 +5,7 @@ raise "cwd must be #{root} when reading gemspec" if root != Dir.pwd
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = 'selenium-webdriver'
|
8
|
-
s.version = '3.
|
8
|
+
s.version = '3.4.0'
|
9
9
|
|
10
10
|
s.authors = ['Alex Rodionov', 'Titus Fortner']
|
11
11
|
s.email = ['p0deje@gmail.com', 'titusfortner@gmail.com']
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: selenium-webdriver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 3.
|
5
|
+
version: 3.4.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Alex Rodionov
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2017-
|
14
|
+
date: 2017-04-21 00:00:00 -05:00
|
15
15
|
default_executable:
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|