selenium-webdriver 3.0.8 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. data/CHANGES +9 -3
  2. data/lib/selenium/webdriver/chrome/bridge.rb +0 -1
  3. data/lib/selenium/webdriver/common.rb +9 -1
  4. data/lib/selenium/webdriver/common/action_builder.rb +1 -3
  5. data/lib/selenium/webdriver/common/driver.rb +17 -0
  6. data/lib/selenium/webdriver/common/interactions/input_device.rb +53 -0
  7. data/lib/selenium/webdriver/common/interactions/interaction.rb +52 -0
  8. data/lib/selenium/webdriver/common/interactions/interactions.rb +43 -0
  9. data/lib/selenium/webdriver/common/interactions/key_actions.rb +112 -0
  10. data/lib/selenium/webdriver/common/interactions/key_input.rb +64 -0
  11. data/lib/selenium/webdriver/common/{driver_extensions/has_input_devices.rb → interactions/none_input.rb} +9 -29
  12. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +355 -0
  13. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +134 -0
  14. data/lib/selenium/webdriver/common/keys.rb +33 -12
  15. data/lib/selenium/webdriver/common/w3c_action_builder.rb +211 -0
  16. data/lib/selenium/webdriver/edge/bridge.rb +1 -4
  17. data/lib/selenium/webdriver/firefox/bridge.rb +1 -2
  18. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  19. data/lib/selenium/webdriver/firefox/w3c_bridge.rb +0 -1
  20. data/lib/selenium/webdriver/ie/bridge.rb +1 -1
  21. data/lib/selenium/webdriver/phantomjs/bridge.rb +1 -4
  22. data/lib/selenium/webdriver/remote/bridge.rb +25 -1
  23. data/lib/selenium/webdriver/remote/w3c_bridge.rb +16 -29
  24. data/lib/selenium/webdriver/remote/w3c_commands.rb +1 -0
  25. data/selenium-webdriver.gemspec +1 -1
  26. metadata +11 -3
@@ -88,7 +88,22 @@ module Selenium
88
88
  f11: "\ue03B",
89
89
  f12: "\ue03C",
90
90
  meta: "\ue03D",
91
- command: "\ue03D" # alias
91
+ command: "\ue03D", # alias
92
+ left_meta: "\ue03D", # alias
93
+ right_shift: "\ue050",
94
+ right_control: "\ue051",
95
+ right_alt: "\ue052",
96
+ right_meta: "\ue053",
97
+ numpad_page_up: "\ue054",
98
+ numpad_page_down: "\ue055",
99
+ numpad_end: "\ue056",
100
+ numpad_home: "\ue057",
101
+ numpad_left: "\ue058",
102
+ numpad_up: "\ue059",
103
+ numpad_right: "\ue05A",
104
+ numpad_down: "\ue05B",
105
+ numpad_insert: "\ue05C",
106
+ numpad_delete: "\ue05D"
92
107
  }.freeze
93
108
 
94
109
  #
@@ -105,18 +120,24 @@ module Selenium
105
120
  #
106
121
 
107
122
  def self.encode(keys)
108
- keys.map do |arg|
109
- case arg
110
- when Symbol
111
- Keys[arg]
112
- when Array
113
- arg = arg.map { |e| e.is_a?(Symbol) ? Keys[e] : e }.join
114
- arg << Keys[:null]
123
+ keys.map { |key| encode_key(key) }
124
+ end
125
+
126
+ #
127
+ # @api private
128
+ #
129
+
130
+ def self.encode_key(key)
131
+ case key
132
+ when Symbol
133
+ Keys[key]
134
+ when Array
135
+ key = key.map { |e| e.is_a?(Symbol) ? Keys[e] : e }.join
136
+ key << Keys[:null]
115
137
 
116
- arg
117
- else
118
- arg.to_s
119
- end
138
+ key
139
+ else
140
+ key.to_s
120
141
  end
121
142
  end
122
143
  end # Keys
@@ -0,0 +1,211 @@
1
+ # encoding: utf-8
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
+ class W3CActionBuilder
23
+ include KeyActions # Actions specific to key inputs
24
+ include PointerActions # Actions specific to pointer inputs
25
+ attr_reader :devices
26
+
27
+ #
28
+ # Initialize a W3C Action Builder. Differs from previous by requiring a bridge and allowing asynchronous actions.
29
+ # The W3C implementation allows asynchronous actions per device. e.g. A key can be pressed at the same time that
30
+ # the mouse is moving. Keep in mind that pauses must be added for other devices in order to line up the actions
31
+ # correctly when using asynchronous.
32
+ #
33
+ # @param [Selenium::WebDriver::Remote::W3CBridge] bridge the bridge for the current driver instance
34
+ # @param [Selenium::WebDriver::Interactions::PointerInput] mouse PointerInput for the mouse.
35
+ # @param [Selenium::WebDriver::Interactions::KeyInput] keyboard KeyInput for the keyboard.
36
+ # @param [Boolean] async Whether to perform the actions asynchronously per device. Defaults to false for
37
+ # backwards compatibility.
38
+ # @return [W3CActionBuilder] A self reference.
39
+ #
40
+
41
+ def initialize(bridge, mouse, keyboard, async = false)
42
+ # For backwards compatibility, automatically include mouse & keyboard
43
+ @bridge = bridge
44
+ @devices = [mouse, keyboard]
45
+ @async = async
46
+ end
47
+
48
+ #
49
+ # Adds a PointerInput device of the given kind
50
+ #
51
+ # @example Add a touch pointer input device
52
+ #
53
+ # builder = device.action
54
+ # builder.add_pointer_input('touch', :touch)
55
+ #
56
+ # @param [String] name name for the device
57
+ # @param [Symbol] kind kind of pointer device to create
58
+ # @return [Interactions::PointerInput] The pointer input added
59
+ #
60
+ #
61
+
62
+ def add_pointer_input(kind, name)
63
+ new_input = Interactions.pointer(kind, name: name)
64
+ add_input(new_input)
65
+ new_input
66
+ end
67
+
68
+ #
69
+ # Adds a KeyInput device
70
+ #
71
+ # @example Add a key input device
72
+ #
73
+ # builder = device.action
74
+ # builder.add_key_input('keyboard2')
75
+ #
76
+ # @param [String] name name for the device
77
+ # @return [Interactions::KeyInput] The key input added
78
+ #
79
+
80
+ def add_key_input(name)
81
+ new_input = Interactions.key(name)
82
+ add_input(new_input)
83
+ new_input
84
+ end
85
+
86
+ #
87
+ # Retrieves the input device for the given name
88
+ #
89
+ # @param [String] name name of the input device
90
+ # @return [Selenium::WebDriver::Interactions::InputDevice] input device with given name
91
+ #
92
+
93
+ def get_device(name)
94
+ @devices.find { |device| device.name == name.to_s }
95
+ end
96
+
97
+ #
98
+ # Retrieves the current PointerInput devices
99
+ #
100
+ # @return [Array] array of current PointerInput devices
101
+ #
102
+
103
+ def pointer_inputs
104
+ @devices.select { |device| device.type == Interactions::POINTER }
105
+ end
106
+
107
+ #
108
+ # Retrieves the current KeyInput device
109
+ #
110
+ # @return [Selenium::WebDriver::Interactions::InputDevice] current KeyInput device
111
+ #
112
+
113
+ def key_inputs
114
+ @devices.select { |device| device.type == Interactions::KEY }
115
+ end
116
+
117
+ #
118
+ # Creates a pause for the given device of the given duration. If no duration is given, the pause will only wait
119
+ # for all actions to complete in that tick.
120
+ #
121
+ # @example Send keys to an element
122
+ #
123
+ # action_builder = driver.action
124
+ # keyboard = action_builder.key_input
125
+ # el = driver.find_element(id: "some_id")
126
+ # driver.action.click(el).pause(keyboard).pause(keyboard).pause(keyboard).send_keys('keys').perform
127
+ #
128
+ # @param [InputDevice] device Input device to pause
129
+ # @param [Float] duration Duration to pause
130
+ # @return [W3CActionBuilder] A self reference.
131
+ #
132
+
133
+ def pause(device, duration = nil)
134
+ device.create_pause(duration)
135
+ self
136
+ end
137
+
138
+ #
139
+ # Creates multiple pauses for the given device of the given duration.
140
+ #
141
+ # @example Send keys to an element
142
+ #
143
+ # action_builder = driver.action
144
+ # keyboard = action_builder.key_input
145
+ # el = driver.find_element(id: "some_id")
146
+ # driver.action.click(el).pauses(keyboard, 3).send_keys('keys').perform
147
+ #
148
+ # @param [InputDevice] device Input device to pause
149
+ # @param [Integer] number of pauses to add for the device
150
+ # @param [Float] duration Duration to pause
151
+ # @return [W3CActionBuilder] A self reference.
152
+ #
153
+
154
+ def pauses(device, number, duration = nil)
155
+ number.times { device.create_pause(duration) }
156
+ self
157
+ end
158
+
159
+ #
160
+ # Executes the actions added to the builder.
161
+ #
162
+
163
+ def perform
164
+ @bridge.send_actions @devices.map(&:encode).compact
165
+ clear_all_actions
166
+ nil
167
+ end
168
+
169
+ #
170
+ # Clears all actions from the builder.
171
+ #
172
+
173
+ def clear_all_actions
174
+ @devices.each(&:clear_actions)
175
+ end
176
+
177
+ #
178
+ # Releases all action states from the browser.
179
+ #
180
+
181
+ def release_actions
182
+ @bridge.release_actions
183
+ end
184
+
185
+ private
186
+
187
+ #
188
+ # Adds pauses for all devices but the given devices
189
+ #
190
+ # @param [Array[InputDevice]] action_devices Array of Input Devices performing an action in this tick.
191
+ #
192
+
193
+ def tick(*action_devices)
194
+ return if @async
195
+ @devices.each { |device| device.create_pause unless action_devices.include? device }
196
+ end
197
+
198
+ #
199
+ # Adds an InputDevice
200
+ #
201
+
202
+ def add_input(device)
203
+ unless @async
204
+ max_device = @devices.max { |a, b| a.actions.length <=> b.actions.length }
205
+ pauses(device, max_device.actions.length)
206
+ end
207
+ @devices << device
208
+ end
209
+ end # W3CActionBuilder
210
+ end # WebDriver
211
+ end # Selenium
@@ -47,10 +47,7 @@ module Selenium
47
47
  end
48
48
 
49
49
  def driver_extensions
50
- [
51
- DriverExtensions::TakesScreenshot,
52
- DriverExtensions::HasInputDevices
53
- ]
50
+ [DriverExtensions::TakesScreenshot]
54
51
  end
55
52
 
56
53
  def commands(command)
@@ -48,8 +48,7 @@ module Selenium
48
48
 
49
49
  def driver_extensions
50
50
  [
51
- DriverExtensions::TakesScreenshot,
52
- DriverExtensions::HasInputDevices
51
+ DriverExtensions::TakesScreenshot
53
52
  ]
54
53
  end
55
54
 
@@ -42,7 +42,6 @@ module Selenium
42
42
  def driver_extensions
43
43
  [
44
44
  DriverExtensions::TakesScreenshot,
45
- DriverExtensions::HasInputDevices,
46
45
  DriverExtensions::HasWebStorage
47
46
  ]
48
47
  end
@@ -47,7 +47,7 @@ module Selenium
47
47
  end
48
48
 
49
49
  def driver_extensions
50
- [DriverExtensions::TakesScreenshot, DriverExtensions::HasInputDevices]
50
+ [DriverExtensions::TakesScreenshot]
51
51
  end
52
52
 
53
53
  def quit
@@ -45,10 +45,7 @@ module Selenium
45
45
  end
46
46
 
47
47
  def driver_extensions
48
- [
49
- DriverExtensions::TakesScreenshot,
50
- DriverExtensions::HasInputDevices
51
- ]
48
+ [DriverExtensions::TakesScreenshot]
52
49
  end
53
50
 
54
51
  def capabilities
@@ -80,7 +80,6 @@ module Selenium
80
80
 
81
81
  def driver_extensions
82
82
  [
83
- DriverExtensions::HasInputDevices,
84
83
  DriverExtensions::UploadsFiles,
85
84
  DriverExtensions::TakesScreenshot,
86
85
  DriverExtensions::HasSessionId,
@@ -374,6 +373,31 @@ module Selenium
374
373
  # actions
375
374
  #
376
375
 
376
+ #
377
+ # @return [ActionBuilder]
378
+ # @api public
379
+ #
380
+
381
+ def action
382
+ ActionBuilder.new Mouse.new(self), Keyboard.new(self)
383
+ end
384
+
385
+ def mouse
386
+ warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
387
+ [DEPRECATION] `Driver#mouse` is deprecated with w3c implementation. Instead use
388
+ driver.action.<command>.perform
389
+ DEPRECATE
390
+ Mouse.new self
391
+ end
392
+
393
+ def keyboard
394
+ warn <<-DEPRECATE.gsub(/\n +| {2,}/, ' ').freeze
395
+ [DEPRECATION] `Driver#keyboard` is deprecated with w3c implementation. Instead use
396
+ driver.action.<command>.perform
397
+ DEPRECATE
398
+ Keyboard.new self
399
+ end
400
+
377
401
  def click_element(element)
378
402
  execute :click_element, id: element
379
403
  end
@@ -79,12 +79,10 @@ module Selenium
79
79
 
80
80
  def driver_extensions
81
81
  [
82
- DriverExtensions::HasInputDevices,
83
82
  DriverExtensions::UploadsFiles,
84
83
  DriverExtensions::TakesScreenshot,
85
84
  DriverExtensions::HasSessionId,
86
85
  DriverExtensions::Rotatable,
87
- DriverExtensions::HasTouchScreen,
88
86
  DriverExtensions::HasRemoteStatus,
89
87
  DriverExtensions::HasWebStorage
90
88
  ]
@@ -381,43 +379,32 @@ module Selenium
381
379
  # actions
382
380
  #
383
381
 
384
- def click_element(element)
385
- execute :element_click, id: element
386
- end
387
-
388
- def click
389
- execute :click, {}, {button: 0}
382
+ def action(async = false)
383
+ W3CActionBuilder.new self,
384
+ Interactions.pointer(:mouse, name: 'mouse'),
385
+ Interactions.key('keyboard'),
386
+ async
390
387
  end
388
+ alias_method :actions, :action
391
389
 
392
- def double_click
393
- execute :double_click
390
+ def mouse
391
+ raise Error::UnsupportedOperationError, '#mouse is no longer supported, use #action instead'
394
392
  end
395
393
 
396
- def context_click
397
- execute :click, {}, {button: 2}
394
+ def keyboard
395
+ raise Error::UnsupportedOperationError, '#keyboard is no longer supported, use #action instead'
398
396
  end
399
397
 
400
- def mouse_down
401
- execute :mouse_down
398
+ def send_actions(data)
399
+ execute :actions, {}, {actions: data}
402
400
  end
403
401
 
404
- def mouse_up
405
- execute :mouse_up
402
+ def release_actions
403
+ execute :release_actions
406
404
  end
407
405
 
408
- def mouse_move_to(element, x = nil, y = nil)
409
- params = {element: element}
410
-
411
- if x && y
412
- params[:xoffset] = x
413
- params[:yoffset] = y
414
- end
415
-
416
- execute :mouse_move_to, {}, params
417
- end
418
-
419
- def send_keys_to_active_element(keys)
420
- send_keys_to_element(active_element, keys)
406
+ def click_element(element)
407
+ execute :element_click, id: element
421
408
  end
422
409
 
423
410
  # TODO: - Implement file verification
@@ -109,6 +109,7 @@ module Selenium
109
109
  #
110
110
 
111
111
  actions: [:post, 'session/:session_id/actions'.freeze],
112
+ release_actions: [:delete, 'session/:session_id/actions'.freeze],
112
113
 
113
114
  #
114
115
  # Element Operations