capybaraとrspecを使ったテストコード

こんにちは!
今回は趣向を変えて、ヲタクトークから始めます。
本日8/26は私が好きなバンド、PEDROの2nd フルアルバム「浪漫」の発売日です!
リード曲「浪漫」のMVを置いておきます。
www.youtube.com
初期の「自律神経出張中」みたいな、世の中にツバかけるような曲も好きですが、最近は「生活革命」のように"ふとした幸せ"みたいな曲が増えてて、好きが増しています。
「浪漫」は後者ですね。
早くライブに行きたい。。。

では、今回のコンテンツです。

本題と概要

最近Rspecでテストコードを書く練習をしています。
今回の記事では、アプリを使うときの一連の動作をテストコードで模した時に、私が気になったポイントを何点か紹介します。
なお、上記のテストは「結合テスト」とか、「統合テスト」とか、「エンドツーエンドテスト」などと呼ばれています。

rails g rspec:system hoges

みたいにするとRSpec

spec/system/hoges_spec.rb

を作ってくれます。(gem 'rspec-rails'がインストールされている前提です。)
テストコードで、ブラウザ操作を実行する時には、Capybaraというgemの機能を使っていくのですが、このメソッドの種類がかなりあります。
下記のサイトでほとんど網羅されているので、操作に対応するメソッドを忘れた時には、ここを調べています。
qiita.com

Basic認証の突破

Basic認証とは、あらかじめ設定したユーザ名とパスワードを要求するだけの簡単な認証機能です。
本番環境では使わないので、コメントアウトしておけば良いと思います。
が、どうしてもテストを突破したい場合は、下記のようにするとできます。

user_name = 'user_name'
password = 'password'
visit "http://#{user_name}:#{password}@#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}#{path}"

「user_name」と「password」には、自身で設定した変数や文字を入れてください。
毎回最初に必要になるので、サポートモジュールを使用して、メソッドにしておくと便利です。

deviseのログイン

deviseを使っていると、毎回ログイン処理が必要になります。
メソッドを自身で作っても良いのですが、公式ですでに準備されています。
How To: Test with Capybara · heartcombo/devise Wiki · GitHub
使い方を簡単にまとめると

spec/rails_helper.rb

にこう書きます。(RSpec.configure do~endは33行目くらいに準備されているので、do~endの中に記載します。)

RSpec.configure do |config|
  config.include Warden::Test::Helpers
  config.after :each do
    Warden.test_reset!
  end
end

これで、ログイン処理のメソッドlogin_asが使えるようになります。
また、各テストの最後にログイン状態のリセットを実施してくれます。
あとは、テストコードの最初で、login_asを使ってログインするだけです。

user = User.create!(email: 'test@example.com', password: 'f4k3p455w0rd')
login_as(user, scope: :user)

FactoryBotなどのあらかじめユーザ情報を作成しておくgemを使っていれば、もう少し簡単になります。

user = FactoryBot.create(:user)
login_as(user, scope: :user)

注意点は、あくまでプログラム上でログイン処理をするだけのため、ログイン状態でページの表示が変わるような場合、login_asだけでは表示が変わりません。

visit root_path

などで、一度画面のリロード・遷移をする必要があります。
login_as後に、visitすればokです。

データベースに保存した画像が表示されていることの確認

データベースに保存されている画像のurlをみてみると以下のように???の感じになっています。
img class="item-image" src="http://localhost:3000/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBDZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--531d820f23be7783715afe29f9c98a9d5f33caaa/output-image1.png"
have_selectorマッチャを使用することで、img要素の存在を確認することはできるのですが、どうせなら「output-image1.png」というファイル名の一致まで確認したいです。
以下のようにするとできます。

expect(page).to have_selector('img[src*="output-image1.png"]')

これは、「output-image1.png」と部分一致するsrc属性を持つimg要素が存在するかを確認しています。
=を*=にすることで、完全一致ではなく、部分一致となっています。
他にも、
^=とすることで前方一致、
$=とすることで後方一致の検索ができます。

最後までお付き合いいただき、ありがとうございました!