Capybaraのdrag_toを使ってドラッグアンドドロップのテストを書いたら動かなかったのでSeleniumのdrag_and_drop_byを使って書いた
Request SpecとCapybaraで、jQuery UI のSortableを使った並び替え部分のエンドツーエンドテストを書いていて、ハマったのでメモ。
Capybaraのドキュメントを見てみるとdrag_toというメソッドがあったので、これを使ってみたけど、ドラッグアンドドロップされなかった。動き的には、ドラッグはしてるけど、ドロップした時に元の場所に戻ってる感じかな?
ちなみにコードはこんな感じ
#drag&dropされない it "リストを並び替えると、「item2」が一番上に表示されること", :js => true do click_link "リストを並び替える" # 並び替えの画面に移動 source = page.find_by_id("item_#{items(:item2).id}") target = page.find_by_id("item_#{items(:item1).id}") source.drag_to(target) within("#jquery-ui-sortable li:first-child") do page.should have_content("item2") end end
で、drag_toのソースコードを確認してみると、実際にはこれが呼ばれている。
resynchronize { driver.browser.action.drag_and_drop(native, element.native).perform }
Seleniumのメソッドなので、Seleniumのドキュメントのdrag_and_dropを確認してみる。
def drag_and_drop(source, target) click_and_hold source move_to target release target self end
drag_and_dropの中身で呼ばれているメソッドにバラして、なぞってみたりしたけど、やはりドラッグアンドドロップできていない。
他にいいメソッドはないかと、Seleniumのドキュメントでdragと入れて調べてみると、drag_and_drop_byという移動距離を指定するメソッドがあったので、これを使ってやってみた。
it "リストを並び替えると、「item2」が一番上に表示されること", :js => true do click_link "リストを並び替える" # 並び替えの画面に移動 source = page.find_by_id("item_#{items(:item2).id}") page.driver.browser.action.drag_and_drop_by(source.native, 10,-30).perform within("#jquery-ui-sortable li:first-child") do page.should have_content("item2") end end
ドラッグの移動距離を大きくしすぎると、scroll出来なかったりで、失敗したけど、適切な移動距離を指定したら動きました。
Capybaraのissueでdragと入れてググると、わりと既知な話だったみたい。
https://github.com/jnicklas/capybara/issues/119
https://github.com/jnicklas/capybara/issues/216
https://github.com/jnicklas/capybara/issues/222
https://github.com/jnicklas/capybara/issues/477
以上。