Rails チュートリアル（8章）をRSpecでテスト

#はじめに

以前書いた記事です！

[Rails チュートリアル（３章、４章、５章）をRSpecでテスト](https://qiita.com/sakakinn/items/9c4d6e278cd19867f80f)
[Rails チュートリアル（6章）をRSpecでテスト](https://qiita.com/sakakinn/items/e7f8115c3bd8fc6053e5)
[Rails チュートリアル（7章）をRSpecでテスト](https://qiita.com/sakakinn/items/41c0f39152c3713fefc4)

#テストを書く（８章)

###Sessionsのフラッシュメッセージのテスト（ログイン失敗）

元のテスト↓
[8.1.5 フラッシュのテスト -Ruby on Rails チュートリアル](https://railstutorial.jp/chapters/basic_login?version=5.1#sec-a_flash_test)

```rb:spec/systems/sessions_spec.rb

require 'rails_helper'

RSpec.describe 'Sessions', type: :system do
  before do
    visit login_path
  end
  #無効な値を入力する
  describe 'enter an invalid values' do
    before do
      fill_in 'Email', with: ''
      fill_in 'Password', with: ''
      click_button 'Log in'
    end
    subject { page }
    #フラッシュメッセージが出る
    it 'gets an flash messages' do
      is_expected.to have_selector('.alert-danger', text: 'Invalid email/password combination')
      is_expected.to have_current_path login_path
    end
    #違うページにアクセスしたとき
    context 'access to other page' do
      before { visit root_path }
      #フラッシュメッセージが消える
      it 'is flash disappear' do
        is_expected.to_not have_selector('.alert-danger', text: 'Invalid email/password combination')
      end
    end
  end
end
```

###ログインのテスト（ログイン成功）

```rb:spec/systems/sessions_spec.rb

RSpec.describe 'Sessions', type: :system do
  before do
    visit login_path
  end

  describe 'enter an valid values' do
    let!(:user) { create(:user, email: 'loginuser@example.com', password: 'password') }
    before do
      fill_in 'Email', with: 'loginuser@example.com'
      fill_in 'Password', with: 'password'
      click_button 'Log in'
    end
    subject { page }
    #ログインしたときのページのレイアウトの確認
    it 'log in' do
      is_expected.to have_current_path user_path(user) #現在のページのurlについて検証
      is_expected.to_not have_link nil, href: login_path
      click_link 'Account' #ドロップダウンリンクをクリック
      is_expected.to have_link 'Profile', href: user_path(user)
      is_expected.to have_link 'Log out', href: logout_path
    end
  end

#ここから下は以前書いた分-------------------------------------------------------------
  describe 'enter an invalid values' do
    before do
      fill_in 'Email', with: ''
      fill_in 'Password', with: ''
      click_button 'Log in'
    end
    subject { page }
    it 'gets an flash messages' do
      is_expected.to have_selector('.alert-danger', text: 'Invalid email/password combination')
      is_expected.to have_current_path login_path
    end
    context 'access to other page' do
      before { visit root_path }
      it 'is flash disappear' do
        is_expected.to_not have_selector('.alert-danger', text: 'Invalid email/password combination')
      end
    end
  end
end
```

次にRequest Specで有効な値でログインしたときにセッションに値が入っているかテストします。
そのために`is_logged_in?`という論理値を返すテスト用のヘルパーメソッドをつくります。

###Helperの作成
まず、ヘルパーを使うための設定

```rb:spec/rails_helper.rb

#コメントアウトになっているので解除、なければ追加する
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }

RSpec.configure do |config|
  config.include TestHelper #作成したヘルパーを追加
end
```

specフォルダーにsupportフォルダーをつくり、その中にヘルパーファイルを追加します。

```rb:spec/support/test_helper.rb

module TestHelper
  def is_logged_in?
    !session[:user_id].nil?
  end
end
```
これでテストで`is_logged_in?`が使えます。

###ログインのテスト（ログイン成功）

```rb:spec/requests/access_to_sessions_spec.rb

require 'rails_helper'

RSpec.describe 'access to sessions', type: :request do
  let!(:user) { create(:user) }
  describe 'POST #create' do
    it 'log in and redirect to detail page' do
      post login_path, params: { session: { email: user.email,
                                            password: user.password } }
      expect(response).to redirect_to user_path(user)
      expect(is_logged_in?).to be_truthy #ログインしているかのテストここでis_logged_in?を使ってます。
    end
  end
end
```
###ユーザー作成時にログインしているかのテスト

```rb:spec/requests/access_to_users_spec.rb

# ほとんど以前書いていた分です。
describe 'POST #create' do
    context 'valid request' do
      it 'adds a user' do
        expect do
          post signup_path, params: { user: attributes_for(:user) }
        end.to change(User, :count).by(1)
      end

      context 'adds a user' do
        before { post signup_path, params: { user: attributes_for(:user) } }
        subject { response }

        it { is_expected.to redirect_to user_path(User.last) }
        it { is_expected.to have_http_status 302 }
        #ここから追加----------------------------------------------------------
        it 'log in' do
          expect(is_logged_in?).to be_truthy
        end
        #ここまで-------------------------------------------------------------
      end
    end
  end
```

###ログアウトのテスト

`sessions_spec.rb`にログアウトのテストを追記します。

```rb:spec/systems/sessions_spec.rb

require 'rails_helper'

RSpec.describe 'Sessions', type: :system do
  before do
    visit login_path
  end

  describe 'enter an valid values' do
    let!(:user) { create(:user, email: 'loginuser@example.com', password: 'password') }
    before do
      fill_in 'Email', with: 'loginuser@example.com'
      fill_in 'Password', with: 'password'
      click_button 'Log in'
    end
    subject { page }
    it 'log in' do
      is_expected.to have_current_path user_path(user)
      is_expected.to_not have_link nil, href: login_path
      click_link 'Account'
      is_expected.to have_link 'Profile', href: user_path(user)
      is_expected.to have_link 'Log out', href: logout_path
    end
    #追記したログアウトのテストです。-----------------------------------------------
    it 'log out after log in' do
      click_link 'Account'
      click_link 'Log out'
      is_expected.to have_current_path root_path
      is_expected.to have_link 'Log in', href: login_path
      is_expected.to_not have_link 'Account'
      is_expected.to_not have_link nil, href: logout_path
      is_expected.to_not have_link nil, href: user_path(user)
    end
    #ここまで----------------------------------------------------------------
  end

  describe 'enter an invalid values' do
    before do
      fill_in 'Email', with: ''
      fill_in 'Password', with: ''
      click_button 'Log in'
    end
    subject { page }
    it 'gets an flash messages' do
      is_expected.to have_selector('.alert-danger', text: 'Invalid email/password combination')
      is_expected.to have_current_path login_path
    end
    context 'access to other page' do
      before { visit root_path }
      it 'is flash disappear' do
        is_expected.to_not have_selector('.alert-danger', text: 'Invalid email/password combination')
      end
    end
  end
end
```

Request Specでログアウトしたときにセッションがnilになっているかテストします。

```rb:spec/requests/access_to_sessions_spec.rb

describe 'DELETE #destroy' do
  it 'log out and redirect to root page' do
    delete logout_path
    expect(response).to redirect_to root_path
    expect(is_logged_in?).to be_falsey #ここでセッションの値をテストしています。
  end
end
```

これで8章のテストがおわりです。