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 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
@@ -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
@@ -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
- firefox_options_caps = caps[:firefox_options] || {}
69
- caps[:firefox_options] = firefox_options_caps.merge(opts[:firefox_options] || {})
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
- caps[:firefox_options][:profile] = profile.encoded
104
+ firefox_options[:profile] = profile.encoded
76
105
  end
77
106
 
78
- Binary.path = caps[:firefox_options][:binary] if caps[:firefox_options].key?(:binary)
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
- WebDriver.logger.warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
44
- [DEPRECATION] `:port` is deprecated. Use `:url` with full path
45
- DEPRECATE
46
- end
47
- port = opts.delete(:port) || 4444
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 :set_window_size, {}, {width: width,
238
- height: height}
237
+ execute :set_window_rect, {}, {width: width, height: height}
239
238
  end
240
239
 
241
- def maximize_window(handle = :current)
240
+ def window_size(handle = :current)
242
241
  unless handle == :current
243
- raise Error::UnsupportedOperationError, 'Switch to desired window before changing its size'
242
+ raise Error::UnsupportedOperationError, 'Switch to desired window before getting its size'
244
243
  end
245
- execute :maximize_window
244
+ data = execute :get_window_rect
245
+
246
+ Dimension.new data['width'], data['height']
246
247
  end
247
248
 
248
- def full_screen_window
249
- execute :fullscreen_window
249
+ def minimize_window
250
+ execute :minimize_window
250
251
  end
251
252
 
252
- def window_size(handle = :current)
253
+ def maximize_window(handle = :current)
253
254
  unless handle == :current
254
- raise Error::UnsupportedOperationError, 'Switch to desired window before getting its size'
255
+ raise Error::UnsupportedOperationError, 'Switch to desired window before changing its size'
255
256
  end
256
- data = execute :get_window_size
257
+ execute :maximize_window
258
+ end
257
259
 
258
- Dimension.new data['width'], data['height']
260
+ def full_screen_window
261
+ execute :fullscreen_window
259
262
  end
260
263
 
261
264
  def reposition_window(x, y)
262
- execute :set_window_position, {}, {x: x, y: y}
265
+ execute :set_window_rect, {}, {x: x, y: y}
263
266
  end
264
267
 
265
268
  def window_position
266
- data = execute :get_window_position
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
- execute :element_send_keys, {id: element}, {value: keys.join('').split(//)}
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
 
@@ -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.3.0'
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.3.0
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-03-07 00:00:00 -06:00
14
+ date: 2017-04-21 00:00:00 -05:00
15
15
  default_executable:
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency