Workaround Chrome issue with mouse button state when dragging

This commit is contained in:
Thomas Walpole 2019-06-26 06:37:26 -07:00
parent 29e86bd9fc
commit c053ff60de
5 changed files with 67 additions and 18 deletions

View File

@ -8,15 +8,23 @@ class Capybara::Selenium::Node
driver.execute_script MOUSEDOWN_TRACKER
scroll_if_needed { browser_action.click_and_hold(native).perform }
if driver.evaluate_script('window.capybara_mousedown_prevented || !arguments[0].draggable', self)
element.scroll_if_needed { browser_action.move_to(element.native).release.perform }
perform_regular_drag(element)
else
driver.evaluate_async_script HTML5_DRAG_DROP_SCRIPT, self, element, delay * 1000
browser_action.release.perform
perform_html5_drag(element, delay)
end
end
private
def perform_regular_drag(element)
element.scroll_if_needed { browser_action.move_to(element.native).release.perform }
end
def perform_html5_drag(element, delay)
driver.evaluate_async_script HTML5_DRAG_DROP_SCRIPT, self, element, delay * 1000
browser_action.release.perform
end
def html5_drop(*args)
if args[0].is_a? String
input = driver.evaluate_script ATTACH_FILE

View File

@ -188,6 +188,21 @@ protected
yield
end
def scroll_to_center
script = <<-'JS'
try {
arguments[0].scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'});
} catch(e) {
arguments[0].scrollIntoView(true);
}
JS
begin
driver.execute_script(script, self)
rescue StandardError # rubocop:disable Lint/HandleExceptions
# Swallow error if scrollIntoView with options isn't supported
end
end
private
def sibling_index(parent, node, selector)
@ -241,21 +256,6 @@ private
end
end
def scroll_to_center
script = <<-'JS'
try {
arguments[0].scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'});
} catch(e) {
arguments[0].scrollIntoView(true);
}
JS
begin
driver.execute_script(script, self)
rescue StandardError # rubocop:disable Lint/HandleExceptions
# Swallow error if scrollIntoView with options isn't supported
end
end
def set_date(value) # rubocop:disable Naming/AccessorMethodName
value = SettableValue.new(value)
return set_text(value) unless value.dateable?

View File

@ -57,6 +57,15 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
private
def perform_regular_drag(element)
return super unless (browser_version < 77.0) && w3c? && !element.obscured?
# W3C Chrome/chromedriver < 77 doesn't maintain mouse button state across actions API performs
# https://bugs.chromium.org/p/chromedriver/issues/detail?id=2981
browser_action.release.perform
browser_action.click_and_hold(native).move_to(element.native).release.perform
end
def file_errors
@file_errors = ::Selenium::WebDriver.logger.suppress_deprecations do
[::Selenium::WebDriver::Error::ExpectedError]

View File

@ -419,6 +419,16 @@ Capybara::SpecHelper.spec 'node' do
expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
end
it 'should work with Dragula' do
@session.visit('/with_dragula')
@session.within(:css, '#sortable') do
src = @session.find('div', text: 'Item 1')
target = @session.find('div', text: 'Item 3')
src.drag_to target
expect(@session).to have_content(/Item 2.*Item 1/, normalize_ws: true)
end
end
context 'HTML5', requires: %i[js html5_drag] do
it 'should HTML5 drag and drop an object' do
@session.visit('/with_js')

View File

@ -0,0 +1,22 @@
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title>with_dragula</title>
</head>
<body id="with_dragula">
<div id="sortable">
<div class="item1">Item 1</div>
<div class="item2">Item 2</div>
<div class="item3">Item 3</div>
<div class="item4">Item 4</div>
<div class="item5">Item 5</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.js" type="text/javascript"></script>
<script>
dragula([document.getElementById("sortable")]);
</script>
</body>
</html>