テスト環境でcsrf_token(csrf_meta_tags)が出力されない問題への対処法(RSpec)

【結論】

RailsにはCSRF保護の仕組みがデフォルトで備わっている

・しかし、CSRF保護はテスト環境ではオフになっており、csrf_tokenがHTMLに埋め込まれない為、それが原因でテストが通らない場合がある

・その場合は、CSRF保護をテスト環境でも有効にするか、該当箇所のコードをエラーハンドリングする必要がある

【目次】

【本題】

RailsCSRF保護

前回の記事で詳しく書きましたが、RailsにはCSRF保護の仕組みがデフォルトで備わっています。

ryoutaku-jo.hatenablog.com

CSRF保護が有効になっていると、以下の様にheadタグにcsrf_tokenが記述されます。

フォーム送信時に、このセキュリティタグも一緒に送信し、ページの正当性を判断しています。

テスト環境ではcsrf_token(csrf_meta_tags)が出力されない

しかし、このcsrf_tokenですが、テスト環境では出力されません。

その理由はconfig/environments/test.rbの以下の記述にあります。

  # Disable request forgery protection in test environment.
  config.action_controller.allow_forgery_protection = false

この記述により、CSRF保護はテスト環境ではオフになっています。

これにより、HTMLにcsrf_tokenが埋め込まれなくなります。

その為、もしAjax通信の為にcsrf_tokenをJavaScirptで取得している場合、そのコードがエラーになってしまいます。

対策

対策としては、先ほどのコードをコメントアウトして、CSRF保護をオンにする方法があります。

しかし、テスト全体への影響範囲が大きい為、正常にテストが動作しなくなる懸念があります。

もし、JavaScirptのコードだけがエラーになっているのであれば、その部分をエラーハンドリング して防ぐ方法もあります。

JavaScriptでよく使用されるのはtry~catch文です。

try{
  var csrf_token = document.getElementsByName( 'csrf-token' ).item(0).content;
}
catch(e){
  // error handling
}

これで、JavaScirptでエラーは発生せず、正常にテストを実行することが出来ます。

参考情報

Rails4.2でcsrf_tokenが表示されない環境があって調べた - mokokko desu

ruby on rails - phantomjs 2.0.0以降にするとpoltergeistでstatus_codeが304になることがある - スタック・オーバーフロー