RailsチュートリアルのテストをRspecで書いてみた[第8章]

はじめに

今回はRspecの学習の一環として、RailsチュートリアルのテストをRspecで書いていきます。
至らない点があるかもしれませんが、その際はコメントにてご指摘をお願いします。

各種バージョン

Ruby 2.7.0
Rails 6.0.3.3
Rspec 3.9
Capybara 3.33.0
Factory_bot_rails 6.1.0

第8章

リスト8.9: フラッシュメッセージの残留をキャッチするテスト

spec/system/users_logins_spec.rb

RSpec.describe "UsersLogins", type: :system do
  scenario 'Don\'t login when user submits invalid information' do
    visit login_path
    fill_in 'Email', with: ' '
    fill_in 'Password', with: ' '
    click_button 'Log in'
    aggregate_failures do
      expect(current_path).to eq login_path
      expect(has_css?('.alert-danger')).to be_truthy
      visit current_path
      expect(has_css?('.alert-danger')).to be_falsy
    end
  end
end

リスト8.24: 有効な情報を使ってユーザーログインをテストする

spec/system/users_logins_spec.rb

require 'rails_helper'

RSpec.describe "UsersLogins", type: :system do
  let(:user) { FactoryBot.create(:user) }
・・・
  scenario 'login succeeds when user submits valid information' do
    visit login_path
    fill_in 'Email',    with: user.email
    fill_in 'Password', with: user.password
    click_button 'Log in'
    aggregate_failures do
      expect(current_path).to eq user_path(user)
      expect(page).to have_no_link 'Log in'
      expect(page).to have_link 'Log out', href: logout_path
      expect(page).to have_link 'Profile', href: user_path(user)
    end
  end
end

リスト8.26: 認証部分のコードをコメントアウトしたのにテストがGREEN

spec/system/users_logins_spec.rb
 
RSpec.describe "UsersLogins", type: :system do
  let(:user) { FactoryBot.create(:user) }

  scenario 'Don\'t login when user submits invalid information' do
    visit login_path
    fill_in 'Email', with: user.email #<= 修正
    fill_in 'Password', with: ' '
    click_button 'Log in'
    aggregate_failures do
      expect(current_path).to eq login_path
      expect(has_css?('.alert-danger')).to be_truthy
      visit current_path
      expect(has_css?('.alert-danger')).to be_falsy
    end
  end
・・・
end

リスト8.31: ユーザー登録後のログインのテスト

8.30: テスト中のログインステータスを論理値で返すメソッド

これについては以下の記事を参考にさせていただきました。

qiita.com

spec/support/test_helper.rb

module TestHelper
  def is_logged_in?
    !session[:user_id].nil?
  end
end

RSpec.configure do |config|
  config.include TestHelper
end
spec/requests/users_request_spec.rb

require 'rails_helper'
・・・
  describe "POST /users" do
    let(:user) { FactoryBot.attributes_for(:user) }

    it "adds new user with correct signup information" do
      aggregate_failures do
        expect do
          post users_path, params: { user: user }
        end.to change(User, :count).by(1)
        expect(response).to have_http_status(302)
        expect(response).to redirect_to user_path(User.last)
        expect(is_logged_in?).to be_truthy  #<= 追加
      end
    end
  end
end 

リスト8.35: ユーザーログアウトのテスト (無効なログインテストも一箇所改良)

ログアウト後のURLについてのテストは「systemスペック」、
is_logged_inについてのテストは「requestスペック」に書きました。

spec_system_users_login_pec.rb

require 'rails_helper'

RSpec.describe "UsersLogins", type: :system do
  let(:user) { FactoryBot.create(:user) }
・・・
  scenario 'login succeeds when user submits valid information' do
    visit login_path
    fill_in 'Email',    with: user.email
    fill_in 'Password', with: user.password
    click_button 'Log in'
    aggregate_failures do
      expect(current_path).to eq user_path(user)
      expect(page).to have_no_link 'Log in'
      expect(page).to have_link 'Log out', href: logout_path
      expect(page).to have_link 'Profile', href: user_path(user)
    end
#以下を追加しました。
    click_on 'Log out'
    aggregate_failures do
      expect(current_path).to eq root_path
      expect(page).to have_link 'Log in', href: login_path
      expect(page).to have_no_link 'Log out'
      expect(page).to have_no_link 'Profile'
    end
  end
end
spec/requests/sessions_request_spec.rb

require 'rails_helper'

RSpec.describe "Sessions", type: :request do
  let(:user) {FactoryBot.create(:user)}

  describe "delete /logout" do
    before do
      post login_path, params: { session: {
        email: user.email,
        password: user.password,
      } }
    end

    it 'redirects to root_path' do
      delete logout_path
      aggregate_failures do
        expect(response).to redirect_to root_path
        expect(is_logged_in?).to be_falsy
      end
    end
  end
end