Skip to content

Commit fc5326f

Browse files
committed
[rb] allow passing devices into Action Builder constructor in more extensible way
Deprecates ordered parameters which will only be seen when not initializing via Driver class Creates default keyboard and mouse input object instances in constructor instead of in Bridge
1 parent a3da5e8 commit fc5326f

File tree

6 files changed

+98
-28
lines changed

6 files changed

+98
-28
lines changed

‎rb/lib/selenium/webdriver/common/action_builder.rb

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,42 @@ class ActionBuilder
3131
# the mouse is moving. Keep in mind that pauses must be added for other devices in order to line up the actions
3232
# correctly when using asynchronous.
3333
#
34-
# @param [Selenium::WebDriver::Remote::Bridge] bridge the bridge for the current driver instance
35-
# @param [Selenium::WebDriver::Interactions::PointerInput] mouse PointerInput for the mouse.
36-
# @param [Selenium::WebDriver::Interactions::KeyInput] keyboard KeyInput for the keyboard.
37-
# @param [Boolean] async Whether to perform the actions asynchronously per device. Defaults to false for
38-
# backwards compatibility.
34+
# @param [Selenium::WebDriver::Remote::Bridge] bridge the bridge for the current driver instance.
35+
# @param [Selenium::WebDriver::Interactions::PointerInput] deprecated_mouse PointerInput for the mouse.
36+
# @param [Selenium::WebDriver::Interactions::KeyInput] deprecated_keyboard KeyInput for the keyboard.
37+
# @param [Boolean] deprecated_async Whether to perform the actions asynchronously per device.
38+
# Defaults to false for backwards compatibility.
39+
# @param [Array<Selenium::WebDriver::Interactions::InputDevices>] devices list of valid sources of input.
40+
# @param [Boolean] async Whether to perform the actions asynchronously per device.
3941
# @return [ActionBuilder] A self reference.
4042
#
4143

42-
def initialize(bridge, mouse, keyboard, async = false)
43-
# For backwards compatibility, automatically include mouse & keyboard
44+
def initialize(bridge, deprecated_mouse = nil, deprecated_keyboard = nil, deprecated_async = nil,
45+
devices: [], async: false)
4446
@bridge = bridge
45-
@devices = [mouse, keyboard]
46-
@async = async
47+
48+
@async = if deprecated_async.nil?
49+
async
50+
else
51+
WebDriver.logger.deprecate('initializing ActionBuilder with async parameter',
52+
':async keyword',
53+
id: :action_async)
54+
deprecated_async
55+
end
56+
57+
@devices = []
58+
if deprecated_keyboard || deprecated_mouse
59+
WebDriver.logger.deprecate "initializing ActionBuilder with keyboard and mouse parameters",
60+
"devices keyword or, even better, Driver#action",
61+
id: :action_devices
62+
add_input(deprecated_mouse)
63+
add_input(deprecated_keyboard)
64+
elsif devices.empty?
65+
add_pointer_input(:mouse, 'mouse')
66+
add_key_input('keyboard')
67+
else
68+
devices.each { |device| add_input(device) }
69+
end
4770
end
4871

4972
#
@@ -202,12 +225,16 @@ def tick(*action_devices)
202225
#
203226

204227
def add_input(device)
228+
raise TypeError, "#{device.inspect} is not a valid InputDevice" unless device.is_a?(Interactions::InputDevice)
229+
205230
unless @async
206231
max_device = @devices.max { |a, b| a.actions.length <=> b.actions.length }
207-
pauses(device, max_device.actions.length)
232+
pauses(device, max_device.actions.length) if max_device
208233
end
209234
@devices << device
210235
end
211-
end # ActionBuilder
236+
end
237+
238+
# ActionBuilder
212239
end # WebDriver
213240
end # Selenium

‎rb/lib/selenium/webdriver/remote/bridge.rb

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -367,11 +367,8 @@ def delete_all_cookies
367367
# actions
368368
#
369369

370-
def action(async = false)
371-
ActionBuilder.new self,
372-
Interactions.pointer(:mouse, name: 'mouse'),
373-
Interactions.key('keyboard'),
374-
async
370+
def action(deprecated_async = nil, async: false, devices: [])
371+
ActionBuilder.new self, nil, nil, deprecated_async, async: async, devices: devices
375372
end
376373
alias_method :actions, :action
377374

‎rb/spec/unit/selenium/webdriver/common/action_builder_spec.rb

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,59 @@ module WebDriver
2525
let(:keyboard) { Interactions.key('key') }
2626
let(:mouse) { Interactions.pointer(:mouse, name: 'mouse') }
2727
let(:bridge) { instance_double('Bridge').as_null_object }
28-
let(:builder) { ActionBuilder.new(bridge, mouse, keyboard) }
29-
let(:async_builder) { ActionBuilder.new(bridge, mouse, keyboard, true) }
28+
let(:builder) { ActionBuilder.new(bridge, devices: [mouse, keyboard]) }
29+
let(:async_builder) { ActionBuilder.new(bridge, devices: [mouse, keyboard], async: true) }
30+
31+
describe '#initialize' do
32+
it 'creates default mouse and keyboard when none are provided' do
33+
action_builder = ActionBuilder.new(bridge)
34+
expect(action_builder.devices).to include(a_kind_of(Interactions::KeyInput),
35+
a_kind_of(Interactions::PointerInput))
36+
end
37+
38+
it 'deprecates using mouse and keyboard directly' do
39+
expect {
40+
action_builder = ActionBuilder.new(bridge, mouse, keyboard)
41+
expect(action_builder.devices).to eq([mouse, keyboard])
42+
}.to have_deprecated(:action_devices)
43+
end
44+
45+
it 'deprecates using async parameter' do
46+
expect {
47+
action_builder = ActionBuilder.new(bridge, nil, nil, true)
48+
expect(action_builder.devices).to include(a_kind_of(Interactions::PointerInput))
49+
expect(action_builder.devices).to include(a_kind_of(Interactions::KeyInput))
50+
}.to have_deprecated(:action_async)
51+
end
52+
53+
it 'accepts mouse and keyboard with devices keyword' do
54+
action_builder = ActionBuilder.new(bridge, devices: [mouse, keyboard])
55+
expect(action_builder.devices).to eq([mouse, keyboard])
56+
end
57+
58+
it 'accepts multiple devices with devices keyword' do
59+
none = Interactions.none('none')
60+
touch = Interactions.pointer(:touch, name: 'touch')
61+
action_builder = ActionBuilder.new(bridge, devices: [mouse, keyboard, none, touch])
62+
63+
expect(action_builder.devices).to eq([mouse, keyboard, none, touch])
64+
end
65+
66+
it 'does not accept additional devices if deprecated parameters are used' do
67+
none = Interactions.none('none')
68+
touch = Interactions.pointer(:touch, name: 'touch')
69+
expect {
70+
action_builder = ActionBuilder.new(bridge, mouse, keyboard, devices: [none, touch])
71+
expect(action_builder.devices).to eq([mouse, keyboard])
72+
}.to have_deprecated(:action_devices)
73+
end
74+
75+
it 'raises a TypeError if a non InputDevice is passed into devices' do
76+
expect {
77+
ActionBuilder.new(bridge, devices: [mouse, keyboard, "banana"])
78+
}.to raise_error(TypeError)
79+
end
80+
end
3081

3182
describe '#devices' do
3283
it 'returns Array of devices' do
@@ -36,7 +87,7 @@ module WebDriver
3687
end
3788

3889
describe '#add_pointer_input' do
39-
let(:device) { instance_double Interactions::PointerInput, actions: [] }
90+
let(:device) { Interactions.pointer :mouse }
4091

4192
it 'creates pointer and adds to devices' do
4293
builder
@@ -73,7 +124,7 @@ module WebDriver
73124
end
74125

75126
describe '#add_key_input' do
76-
let(:device) { instance_double Interactions::KeyInput, actions: [] }
127+
let(:device) { Interactions.key }
77128

78129
it 'creates keyboard and adds to devices' do
79130
builder

‎rb/spec/unit/selenium/webdriver/common/interactions/interaction_spec.rb

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,6 @@ def encode
5353
end
5454

5555
class SubActionBuilder < ActionBuilder
56-
def initialize(bridge, mouse, keyboard, async = nil)
57-
super
58-
@devices << NewDevice.new('new')
59-
end
60-
6156
def special_action(special, device: nil)
6257
special_input(device).create_special(special)
6358
self
@@ -78,7 +73,7 @@ def special_input(device = nil)
7873
it 'can create subclass' do
7974
bridge = instance_double(Remote::Bridge)
8075
allow(bridge).to receive(:send_actions)
81-
sub_action_builder = SubActionBuilder.new(bridge, Interactions.pointer(:mouse), Interactions.key('key'))
76+
sub_action_builder = SubActionBuilder.new(bridge, devices: [NewDevice.new('new')])
8277
sub_action_builder.special_action('special').perform
8378

8479
expect(bridge).to have_received(:send_actions).with([{type: :special,

‎rb/spec/unit/selenium/webdriver/common/interactions/key_actions_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ module WebDriver
2525
let(:keyboard) { Interactions::KeyInput.new('keyboard') }
2626
let(:mouse) { Interactions::PointerInput.new(:mouse, name: 'pointer') }
2727
let(:bridge) { instance_double('Bridge').as_null_object }
28-
let(:builder) { Selenium::WebDriver::ActionBuilder.new(bridge, mouse, keyboard) }
28+
let(:builder) { Selenium::WebDriver::ActionBuilder.new(bridge, devices: [mouse, keyboard]) }
2929
let(:element) { Selenium::WebDriver::Element.new(bridge, 'element') }
3030
let(:key) { 'a' }
3131
let(:keys) { 'abc' }

‎rb/spec/unit/selenium/webdriver/common/interactions/pointer_actions_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ module WebDriver
2525
let(:keyboard) { Interactions::KeyInput.new('keyboard') }
2626
let(:mouse) { Interactions::PointerInput.new(:mouse, name: 'pointer') }
2727
let(:bridge) { instance_double('Bridge').as_null_object }
28-
let(:builder) { ActionBuilder.new(bridge, mouse, keyboard) }
28+
let(:builder) { ActionBuilder.new(bridge, devices: [mouse, keyboard]) }
2929
let(:element) { Element.new(bridge, 'element') }
3030
let(:element2) { Element.new(bridge, 'element2') }
3131
let(:duration) { builder.default_move_duration }

0 commit comments

Comments
 (0)