Add w3c_click_offset setting to allow click offsets from element centers

This commit is contained in:
Thomas Walpole 2019-06-15 14:17:08 -07:00
parent 34889915f7
commit 2f2d822471
7 changed files with 68 additions and 22 deletions

View File

@ -97,6 +97,7 @@ module Capybara
# and {configure raise_server_errors} is `true`.
# - **test_id** (Symbol, String, `nil` = `nil`) - Optional attribute to match locator against with built-in selectors along with id.
# - **threadsafe** (Boolean = `false`) - Whether sessions can be configured individually.
# - **w3c_click_offset** (Boolean = 'false') - Whether click offsets should be from element center (true) or top left (false)
#
# #### DSL Options
#
@ -506,4 +507,5 @@ Capybara.configure do |config|
config.predicates_wait = true
config.default_normalize_ws = false
config.allow_gumbo = false
config.w3c_click_offset = false
end

View File

@ -157,13 +157,16 @@ module Capybara
# Both x: and y: must be specified if an offset is wanted, if not specified the click will occur at the middle of the element.
# @overload $0(*modifier_keys, wait: nil, **offset)
# @param *modifier_keys [:alt, :control, :meta, :shift] ([]) Keys to be held down when clicking
# @option offset [Integer] x X coordinate to offset the click location from the top left corner of the element
# @option offset [Integer] y Y coordinate to offset the click location from the top left corner of the element
# @option options [Integer] x X coordinate to offset the click location. If {Capybara.configure w3c_click_offset} is `true` the
# offset will be from the element center, otherwise it will be from the top left corner of the element
# @option options [Integer] y Y coordinate to offset the click location. If {Capybara.configure w3c_click_offset} is `true` the
# offset will be from the element center, otherwise it will be from the top left corner of the element
# @return [Capybara::Node::Element] The element
def click(*keys, wait: nil, **offset)
raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^ offset[:x] ^ offset[:y]
def click(*keys, wait: nil, **options)
raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^ options[:x] ^ options[:y]
synchronize(wait) { base.click(Array(keys), offset) }
options[:offset] = :center if session_options.w3c_click_offset
synchronize(wait) { base.click(Array(keys), options) }
self
end

View File

@ -63,8 +63,9 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
native.remove_attribute('selected')
end
def click(keys = [], **offset)
raise ArgumentError, 'The RackTest driver does not support click options' unless keys.empty? && offset.empty?
def click(keys = [], **options)
options.delete(:offset)
raise ArgumentError, 'The RackTest driver does not support click options' unless keys.empty? && options.empty?
if link?
follow_link

View File

@ -328,7 +328,13 @@ private
end
def action_with_modifiers(click_options)
actions = browser_action.move_to(native, *click_options.coords)
actions = browser_action.tap do |acts|
if click_options.center_offset? && click_options.coords?
acts.move_to(native).move_by(*click_options.coords)
else
acts.move_to(native, *click_options.coords)
end
end
modifiers_down(actions, click_options.keys)
yield actions
modifiers_up(actions, click_options.keys)
@ -483,6 +489,10 @@ private
[options[:x], options[:y]]
end
def center_offset?
options[:offset] == :center
end
def empty?
keys.empty? && !coords?
end

View File

@ -8,7 +8,7 @@ module Capybara
automatic_reload match exact exact_text raise_server_errors visible_text_only
automatic_label_click enable_aria_label save_path asset_host default_host app_host
server_host server_port server_errors default_set_options disable_animation test_id
predicates_wait default_normalize_ws].freeze
predicates_wait default_normalize_ws w3c_click_offset].freeze
attr_accessor(*OPTIONS)
@ -59,6 +59,8 @@ module Capybara
# See {Capybara.configure}
# @!method default_normalize_ws
# See {Capybara.configure}
# @!method w3c_click_offset
# See {Capybara.configure}
remove_method :server_host

View File

@ -636,25 +636,52 @@ Capybara::SpecHelper.spec 'node' do
expect { obscured.click(wait: 0) }.to(raise_error { |e| expect(e).to be_an_invalid_element_error(@session) })
end
context "offset" do
context 'offset', requires: [:js] do
before do
@session.visit('/offset')
@clicker = @session.find(:id, 'clicker')
end
it 'should offset from top left of element' do
@clicker.click(x: 10, y: 5)
expect(@session).to have_text(/clicked at 110,105/)
context 'when w3c_click_offset is false' do
before do
Capybara.w3c_click_offset = false
end
it 'should offset from top left of element' do
@clicker.click(x: 10, y: 5)
expect(@session).to have_text(/clicked at 110,105/)
end
it 'should offset outside the element' do
@clicker.click(x: -15, y: -10)
expect(@session).to have_text(/clicked at 85,90/)
end
it 'should default to click the middle' do
@clicker.click
expect(@session).to have_text(/clicked at 150,150/)
end
end
it 'should offset outside the element' do
@clicker.click(x: -15, y: -10)
expect(@session).to have_text(/clicked at 85,90/)
end
context 'when w3c_click_offset is true' do
before do
Capybara.w3c_click_offset = true
end
it 'should default to click the middle' do
@clicker.click
expect(@session).to have_text(/clicked at 150,150/)
it 'should offset from center of element' do
@clicker.click(x: 10, y: 5)
expect(@session).to have_text(/clicked at 160,155/)
end
it 'should offset outside from center of element' do
@clicker.click(x: -65, y: -60)
expect(@session).to have_text(/clicked at 85,90/)
end
it 'should default to click the middle' do
@clicker.click
expect(@session).to have_text(/clicked at 150,150/)
end
end
end
end
@ -692,7 +719,7 @@ Capybara::SpecHelper.spec 'node' do
expect { obscured.double_click }.not_to raise_error
end
context "offset" do
context 'offset', requires: [:js] do
before do
@session.visit('/offset')
@clicker = @session.find(:id, 'clicker')
@ -748,7 +775,7 @@ Capybara::SpecHelper.spec 'node' do
expect { obscured.right_click }.not_to raise_error
end
context "offset" do
context 'offset', requires: [:js] do
before do
@session.visit('/offset')
@clicker = @session.find(:id, 'clicker')

View File

@ -36,6 +36,7 @@ module Capybara
Capybara.predicates_wait = true
Capybara.default_normalize_ws = false
Capybara.allow_gumbo = true
Capybara.w3c_click_offset = false
reset_threadsafe
end