Using Capybara to drag a jQuery UI sortable onto a jQuery UI droppable

I've been writing integration tests for our card sorting tool, OptimalSort. Part of those tests should obviously be that, in an "open" card sort, that a user can drag a card onto the stage, drop it, and have it create a new category with that card in it.

It seemed like it should be pretty simple, using a Capybara driver that supported javascript:

should "be able to drag a card onto the stage and create a new group" do
card = page.find_by_id('unsorted-column').find('ul').find('li')
target = page.first('.column')
card.drag_to(target)
assert page.first('.group ul li')
end

That is, find the first unsorted card, find the first drop target (".column") and drag the card onto it. The final assertion checks that a group has been created that contains a card element.

The problem was when the tests ran, I could clearly see the card being dragged to the top of the column, and not triggering the column's droppable "over" or "drop" events.

The cause is that the droppable was set to tolerance:intersect - dragged elements had to be 50% inside the droppable to trigger anything. When the capybara's drag_to was called, it was dragging the card to the top of the target, in a way that it wasn't 50% inside.

The sneaky solution was to create a new element for drag_to to target, underneath and clearly inside the bounds of the droppable. I used capybara's execute_script to add a new element with jQuery, and then dragged the card to this hidden target.

should "be able to drag a card onto the stage and create a new group" do
page.execute_script("$('#sort-area').prepend($('<div id=\"test_drop_helper\" style=\"position:absolute; top:300px; left:300px; z-index:-1000; width:10px; height:10px;\" ></div>'))")

card = page.find_by_id('unsorted-column').find('ul').find('li')
target = page.first('#test_drop_helper')
card.drag_to(target)
assert page.first('.group ul li')
end

I knew that at those particular values it was where I wanted it and I only needed it for this one test. If you needed to target more than one thing you might need to be more discerning about the parameters you assigned to it, etc.

Now, if I could just get the tests to take sliiiightly less time...

heatdeathoftheuniverse.png