Capybara 'drag & drop' does not work when the elements moved are too close in Rails

Using Rails + Vue.js for a project, and there is a bug with Capybara's 'drag & drop' feature while testing with Rspec. This is a workaround on how to fix it.

Capybara's 'Drag & Drop' feature works perfectly when the items being dragged are not too close. 

For example, in the code below, I am dragging the image from one product to another.  And it works as expected. 

feature "dragging image", :vcr, js: true  do
  before(:each) do 
    @apple = Fabricate(:shop)
    @ipod = Fabricate(:product, shop: @apple)
    @ipod_image_src = ""
    @ipod_image = Image.create(position: 1, src: @ipod_image_src, product: @ipod, shop: @apple)
  scenario "from one product to another product" do
    second_ipod_without_initial_image = Fabricate(:product, shop: @apple)
    ipod_image_element = find("#product_image_#{}")     
    second_ipod_without_initial_image_element = find("#product_non_image_#{}")
    ipod_image_element.drag_to second_ipod_without_initial_image_element
    sleep 0.3
    expect(@apple.products.first.images.first.src).to eq(@apple.products.second.images.first.src)

This is the resultant feature test, and it works as expected. 

But when I do the same and try to drag an image within the same product using Capybara, the test fails.

Below is the feature test. 

If you look closely, you can see that the drag does not persist. It is immediately reverted back to how it was before.  This is happening even though the code works well in production. The tests are failing, and this is a bug in Capybara's drag and drop.

One easy way to fix this is to create some dummy images between the items you want to drag. 

I created a method 'create_many_images' which does this in my spec. 
scenario "within the same product" do
    last_ipod_image_src = ""
    last_ipod_image = Image.create(position: 2, src: last_ipod_image_src, product: @ipod, shop: @apple)
    ipod_image_element = find("#product_image_#{}")     
    last_ipod_image_element = find("#product_image_#{}")     
    ipod_image_element.drag_to last_ipod_image_element
    sleep 0.3
    expect(@ipod_image.position).to_not eq(1)

And all create_many_more_images does is that it creates 10 images. 
def create_many_more_images
 10.times do |i|
   src = "image_#{i}"
   Image.create(position: 2, src: src, product: @ipod, shop: @apple)

Once I do this, all the tests pass, and if you look closely - you can see that the dragged items persists unlike before.


Weekly Newsletter

Subscribe to get my weekly newsletter and latest articles on startups, marketing and growth.

Hello 👋! I'm Arjun, a remote Ruby on Rails developer that can bring your digital product ideas to life.

Here is a list of things i've built recently.