mirror of
https://github.com/teamcapybara/capybara.git
synced 2022-11-09 12:08:07 -05:00
Support keys and x,y offset with mouse clicks
This commit is contained in:
parent
6599817769
commit
1a899c2a73
5 changed files with 186 additions and 21 deletions
|
@ -39,15 +39,15 @@ module Capybara
|
|||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def click
|
||||
def click(*options)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def right_click
|
||||
def right_click(*options)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def double_click
|
||||
def double_click(*options)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
|
|
|
@ -138,9 +138,14 @@ module Capybara
|
|||
#
|
||||
# Click the Element
|
||||
#
|
||||
# @!macro click_modifiers
|
||||
# @overload $0(*key_modifiers=[], offset={x: nil, y: nil})
|
||||
# @param [Array<:alt, :control, :meta, :shift>] *key_modifiers Keys to be held down when clicking
|
||||
# @param [Hash] offset x and y coordinates to offset the click location from the top left corner of the element. If not specified will click the middle of the element.
|
||||
# @return [Capybara::Node::Element] The element
|
||||
def click
|
||||
synchronize { base.click }
|
||||
def click(*options)
|
||||
verify_click_options_support(__method__) if !options.empty?
|
||||
synchronize { base.click(*options) }
|
||||
return self
|
||||
end
|
||||
|
||||
|
@ -148,9 +153,11 @@ module Capybara
|
|||
#
|
||||
# Right Click the Element
|
||||
#
|
||||
# @macro click_modifiers
|
||||
# @return [Capybara::Node::Element] The element
|
||||
def right_click
|
||||
synchronize { base.right_click }
|
||||
def right_click(*options)
|
||||
verify_click_options_support(__method__) if !options.empty?
|
||||
synchronize { base.right_click(*options) }
|
||||
return self
|
||||
end
|
||||
|
||||
|
@ -158,9 +165,11 @@ module Capybara
|
|||
#
|
||||
# Double Click the Element
|
||||
#
|
||||
# @macro click_modifiers
|
||||
# @return [Capybara::Node::Element] The element
|
||||
def double_click
|
||||
synchronize { base.double_click }
|
||||
def double_click(*options)
|
||||
verify_click_options_support(__method__) if !options.empty?
|
||||
synchronize { base.double_click(*options) }
|
||||
return self
|
||||
end
|
||||
|
||||
|
@ -381,6 +390,13 @@ module Capybara
|
|||
raise
|
||||
end
|
||||
end
|
||||
private
|
||||
|
||||
def verify_click_options_support(method)
|
||||
if base.method(method).arity == 0
|
||||
raise ArgumentError, "The current driver does not support #{method} options"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -74,8 +74,20 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|||
native.click if selected?
|
||||
end
|
||||
|
||||
def click
|
||||
native.click
|
||||
def click(*keys, **options)
|
||||
if keys.empty? && options.empty? && !(options[:x] && options[:y])
|
||||
native.click
|
||||
else
|
||||
scroll_if_needed do
|
||||
action_with_modifiers(*keys, **options) do |a|
|
||||
if options[:x] && options[:y]
|
||||
a.click
|
||||
else
|
||||
a.click(native)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue => e
|
||||
if e.is_a?(::Selenium::WebDriver::Error::ElementClickInterceptedError) ||
|
||||
e.message =~ /Other element would receive the click/
|
||||
|
@ -87,15 +99,27 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|||
raise e
|
||||
end
|
||||
|
||||
def right_click
|
||||
def right_click(*keys, **options)
|
||||
scroll_if_needed do
|
||||
driver.browser.action.context_click(native).perform
|
||||
action_with_modifiers(*keys, **options) do |a|
|
||||
if options[:x] && options[:y]
|
||||
a.context_click
|
||||
else
|
||||
a.context_click(native)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def double_click
|
||||
def double_click(*keys, **options)
|
||||
scroll_if_needed do
|
||||
driver.browser.action.double_click(native).perform
|
||||
action_with_modifiers(*keys, **options) do |a|
|
||||
if options[:x] && options[:y]
|
||||
a.double_click
|
||||
else
|
||||
a.double_click(native)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -267,4 +291,40 @@ private
|
|||
native.send_keys(value.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def action_with_modifiers(*keys, x: nil, y: nil)
|
||||
actions = driver.browser.action
|
||||
actions.move_to(native, x, y)
|
||||
modifiers_down(actions, keys)
|
||||
yield actions
|
||||
modifiers_up(actions, keys)
|
||||
actions.perform
|
||||
ensure
|
||||
a = driver.browser.action
|
||||
a.release_actions if a.respond_to?(:release_actions)
|
||||
end
|
||||
|
||||
def modifiers_down(actions, keys)
|
||||
keys.each do |key|
|
||||
key = case key
|
||||
when :ctrl then :control
|
||||
when :command, :cmd then :meta
|
||||
else
|
||||
key
|
||||
end
|
||||
actions.key_down(key)
|
||||
end
|
||||
end
|
||||
|
||||
def modifiers_up(actions, keys)
|
||||
keys.each do |key|
|
||||
key = case key
|
||||
when :ctrl then :control
|
||||
when :command, :cmd then :meta
|
||||
else
|
||||
key
|
||||
end
|
||||
actions.key_up(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,8 @@ $(function() {
|
|||
$(this).html('Dropped!');
|
||||
}
|
||||
});
|
||||
$('#clickable').click(function() {
|
||||
$('#clickable').click(function(e) {
|
||||
debugger;
|
||||
var link = $(this);
|
||||
setTimeout(function() {
|
||||
$(link).after('<a id="has-been-clicked" href="#">Has been clicked</a>');
|
||||
|
@ -64,12 +65,40 @@ $(function() {
|
|||
}, 400)
|
||||
});
|
||||
$('#click-test').on({
|
||||
dblclick: function() {
|
||||
$(this).after('<a id="has-been-double-clicked" href="#">Has been double clicked</a>');
|
||||
click: function(e) {
|
||||
var desc = "";
|
||||
if (e.altKey|| e.ctrlKey || e.metaKey || e.shiftKey) {
|
||||
if (e.altKey) desc += 'alt ';
|
||||
if (e.ctrlKey) desc += 'control ';
|
||||
if (e.metaKey) desc += 'meta ';
|
||||
if (e.shiftKey) desc += 'shift ';
|
||||
}
|
||||
var pos = this.getBoundingClientRect();
|
||||
$(this).after('<a id="has-been-clicked" href="#">Has been ' + desc + 'clicked at ' + (e.clientX - pos.left) + ',' + (e.clientY - pos.top) + '</a>');
|
||||
},
|
||||
dblclick: function(e) {
|
||||
var desc = "";
|
||||
if (e.altKey|| e.ctrlKey || e.metaKey || e.shiftKey) {
|
||||
if (e.altKey) desc += 'alt ';
|
||||
if (e.ctrlKey) desc += 'control ';
|
||||
if (e.metaKey) desc += 'meta ';
|
||||
if (e.shiftKey) desc += 'shift ';
|
||||
$(this).after('<a id="href="#">Has been ' + desc + 'double clicked</a>');
|
||||
}
|
||||
var pos = this.getBoundingClientRect();
|
||||
$(this).after('<a id="has-been-double-clicked" href="#">Has been ' + desc + 'double clicked at ' + (e.clientX - pos.left) + ',' + (e.clientY - pos.top) + '</a>');
|
||||
},
|
||||
contextmenu: function(e) {
|
||||
e.preventDefault();
|
||||
$(this).after('<a id="has-been-right-clicked" href="#">Has been right clicked</a>');
|
||||
var desc = "";
|
||||
if (e.altKey|| e.ctrlKey || e.metaKey || e.shiftKey) {
|
||||
if (e.altKey) desc += 'alt ';
|
||||
if (e.ctrlKey) desc += 'control ';
|
||||
if (e.metaKey) desc += 'meta ';
|
||||
if (e.shiftKey) desc += 'shift ';
|
||||
}
|
||||
var pos = this.getBoundingClientRect();
|
||||
$(this).after('<a id="has-been-right-clicked" href="#">Has been ' + desc + 'right clicked at ' + (e.clientX - pos.left) + ',' + (e.clientY - pos.top) + '</a>');
|
||||
}
|
||||
});
|
||||
$('#open-alert').click(function() {
|
||||
|
|
|
@ -338,15 +338,58 @@ Capybara::SpecHelper.spec "node" do
|
|||
radio.click
|
||||
expect(radio).to be_checked
|
||||
end
|
||||
|
||||
it "should allow modifiers", requires: [:js] do
|
||||
@session.visit('/with_js')
|
||||
@session.find(:css, '#click-test').click(:control)
|
||||
expect(@session).to have_link('Has been control clicked')
|
||||
end
|
||||
|
||||
it "should allow multiple modifiers", requires: [:js] do
|
||||
@session.visit('with_js')
|
||||
@session.find(:css, '#click-test').click(:control, :alt, :meta, :shift)
|
||||
expect(@session).to have_link('Has been alt control meta shift clicked')
|
||||
end
|
||||
|
||||
it "should allow to adjust the click offset", requires: [:js] do
|
||||
@session.visit('with_js')
|
||||
@session.find(:css, '#click-test').click(x:0, y:0)
|
||||
link = @session.find(:link, 'has-been-clicked')
|
||||
locations = link.text.match /^Has been clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/
|
||||
# Resulting click location should be very close to 0, 0 relative to top left corner of the element, but may not be exact due to
|
||||
# integer/float conversions and rounding.
|
||||
expect(locations[:x].to_f).to be_within(1).of(0)
|
||||
expect(locations[:y].to_f).to be_within(1).of(0)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#double_click', requires: [:js] do
|
||||
it "should double click an element" do
|
||||
describe '#double_click', requires: [:js], focus_: true do
|
||||
before do
|
||||
pending "selenium-webdriver/geckodriver doesn't generate double click event" if marionette?(@session)
|
||||
end
|
||||
|
||||
it "should double click an element" do
|
||||
@session.visit('/with_js')
|
||||
@session.find(:css, '#click-test').double_click
|
||||
expect(@session.find(:css, '#has-been-double-clicked')).to be
|
||||
end
|
||||
|
||||
it "should allow modifiers", requires: [:js] do
|
||||
@session.visit('/with_js')
|
||||
@session.find(:css, '#click-test').double_click(:alt)
|
||||
expect(@session).to have_link('Has been alt double clicked')
|
||||
end
|
||||
|
||||
it "should allow to adjust the offset", requires: [:js] do
|
||||
@session.visit('with_js')
|
||||
@session.find(:css, '#click-test').double_click(x:10, y:5)
|
||||
link = @session.find(:link, 'has-been-double-clicked')
|
||||
locations = link.text.match /^Has been double clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/
|
||||
# Resulting click location should be very close to 10, 5 relative to top left corner of the element, but may not be exact due
|
||||
# to integer/float conversions and rounding.
|
||||
expect(locations[:x].to_f).to be_within(1).of(10)
|
||||
expect(locations[:y].to_f).to be_within(1).of(5)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#right_click', requires: [:js] do
|
||||
|
@ -355,6 +398,23 @@ Capybara::SpecHelper.spec "node" do
|
|||
@session.find(:css, '#click-test').right_click
|
||||
expect(@session.find(:css, '#has-been-right-clicked')).to be
|
||||
end
|
||||
|
||||
it "should allow modifiers", requires: [:js] do
|
||||
@session.visit('/with_js')
|
||||
@session.find(:css, '#click-test').right_click(:meta)
|
||||
expect(@session).to have_link('Has been meta right clicked')
|
||||
end
|
||||
|
||||
it "should allow to adjust the offset", requires: [:js] do
|
||||
@session.visit('with_js')
|
||||
@session.find(:css, '#click-test').right_click(x:10, y:10)
|
||||
link = @session.find(:link, 'has-been-right-clicked')
|
||||
locations = link.text.match /^Has been right clicked at (?<x>[\d\.-]+),(?<y>[\d\.-]+)$/
|
||||
# Resulting click location should be very close to 10, 10 relative to top left corner of the element, but may not be exact due
|
||||
# to integer/float conversions and rounding
|
||||
expect(locations[:x].to_f).to be_within(1).of(10)
|
||||
expect(locations[:y].to_f).to be_within(1).of(10)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#send_keys', requires: [:send_keys] do
|
||||
|
|
Loading…
Add table
Reference in a new issue