Madogiwa Blog

主に技術系の学習メモに使っていきます。

Ruby on Rails: Capybaraを使ったシステムテストでHTTPリクエストを送信する方法

Capybaraを使ったシステムテストで何かしらHTTPリクエストを送信したいときに色々ハマったのでメモしておきます📝

システムテストについてはこちら

railsguides.jp

リクエストを送る方法

以下を行うとシステムテスト内でリクエストを送信することができます。

  • current_driver:rack_testに変更
  • allow_forgery_protectionfalseに変更

上記を行うHelperみたいなのを用意してあげると便利そう(?)

module SendRequestHelper
  def send_request(method, path, params={})
    use_rack_driver do
      disable_forgery_protection do
        page.driver.send(method, path, params)
      end
    end
  end

  private

  def use_rack_driver
    driver = Capybara.current_driver
    Capybara.current_driver = :rack_test
    yield
    Capybara.current_driver = driver
  end

  def disable_forgery_protection
    csrf_protection = ActionController::Base.allow_forgery_protection
    ActionController::Base.allow_forgery_protection = false
    yield
    ActionController::Base.allow_forgery_protection = csrf_protection
  end
end

# パラメータ付きで"/foo"にPOST
send_request(:post, foo_path, { foo: 'foo'})

対応が必要な理由

current_driver:rack_testに変更

デフォルトで利用されるCapybara::Selenium::Driverだとpostgetといったリクエストを送信するようなメソッドが実装されていませんが、

www.rubydoc.info

しかしCapybara::RackTest::Driverの場合はpostgetといったリクエストを送信するようなメソッドが実装されているので、current_driverをリクエストを送信出来るCapybara::RackTest::Driverに切り替えることで任意のタイミングでリクエストを送信出来るということですね。

www.rubydoc.info

※なお、認証状態といったものをRackTestとSelenium間で引き継ぐようなことは出来ないようです。(多分、Sessionが別になるため)

allow_forgery_protectionfalseに変更

直接リクエストを送る際にCSRFの保護が有効になっているとトークンがリクエストに含まれていない場合に、422 Unprocessable Entityが発生してしまいます。

そのためリクエスト送信時にはActionController::Base.allow_forgery_protectionfalseに変更しときます。

Railsのテスト環境ではデフォルトで無効になっているのでやらなくても良いかも

github.com

参考

qiita.com

poketo7878-dev.hatenablog.com