selenium-webdriver 3.0.8 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
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