リア充爆発日記

You don't even know what ria-ju really is.

Railsとcapybaraで何かをドラッグアンドドロップしてソートするテストを書く

今回はカテゴリを画面でソートできることをテストする。たとえばブログで言えばブログカテゴリの表示順を管理画面でソートしたいとき、などの話。


こんな画面で、ドラッグアンドドロップでソート後、更新ボタンを押したら、その順番に更新される、という仕様のテストを書く。

実装はここでは省くとして、テストを書こうと思ったときにD&Dをどうやるかがポイントになると思われる。
で、capybara-webkitにはdrag_toというメソッドがあるので、これで解決した。
なので、capybara-webkitを使う前提なので使えるようにしといてください。
ちなみにソートUIにはjquery-sortableを使ってます。

具体的にはこんな感じ。
view

<section id="blog-categories" class="categories">
  <header class="page-header clearfix">
    <h1>カテゴリ編集</h1>
  </header>

  <ol id="category-list" class="list-group sortable-list-group">
    <% @categories.each do |c| -%>
    <li class="list-group-item"><%= c.name %><span class="glyphicon glyphicon-sort pointer"></span></li>
    <% end -%>
  </ol>

  <button class="btn btn-warning"><%= t('views.categories.strings.sort_btn') -%></button>
</section>

spec

  before do
    @category1 = FactoryGirl.create(:category)
    @category2 = FactoryGirl.create(:category)
  end

  # webkitはon
  scenario 'sorting categories', js: true do
    visit categories_path
    expect(page).to have_title I18n.t('views.categories.actions.index.title')
    # 最初の順番を確認
    expect(find('#category-list li:first-child')).to have_text @category1.name
    expect(find('#category-list li:last-child')).to have_text @category2.name

    # 1つ目のリスト要素を2番めのところまでD&D
    draggable = find('#category-list li:first-child .pointer')
    droppable = find('#category-list li:last-child')
    draggable.drag_to(droppable)

    # ドロップしたらその順番になっているか確認
    expect(find('#category-list li:first-child')).to have_text @category2.name
    expect(find('#category-list li:last-child')).to have_text @category1.name

    click_button I18n.t('views.categories.strings.sort_btn')

    # 更新ボタン押下後、リロードしても順番が維持されているか確認。
    visit current_path

    expect(find('#category-list li:first-child')).to have_text @category2.name
    expect(find('#category-list li:last-child')).to have_text @category1.name
  end

ここでは、更新ボタンを押すと反映される仕様になってるけど、ドロップ時に反映させてもたいして変わらないはず。

スーパーマリオ 3Dワールド

スーパーマリオ 3Dワールド