【RSpec】で書く「Rails Tutorial　８章（前半：8.2.5まで）」のテスト

<br>
こんにちは（こんばんは）。

先日、@jnchitさんがコードレビューしてくださり、
**RSpecの理解が深まった（...はず）**のごいです。
<br>
その際に使用された記事と動画リンクは下記です。

▼レビュー記事
[【RSpec】で書く「Rails Tutorial　6章」のテスト](https://qiita.com/Goi350ml/items/7dac5bd2d3d522466d94)

▼動画
[RSpecで書かれたRailsチュートリアル 第6章のテストコードをレビューしてみた](https://www.youtube.com/watch?v=qpiKb0mdbr0)


***
###最初に
前回に引き続き↓
[【RSpec】で書く「Rails Tutorial　７章」のテスト](https://qiita.com/Goi350ml/items/aeb34df5f8e27425834b)
Rails TutorialをRSpecで進めました。

今回は８章になるのですが、
少し長くなりそうでしたので前半ということで「8.2.5」までになります。

***
###Rails Tutorial８章ですること
 - セッションを用いたログイン機能追加
 - ユーザー管理
 - メニューバーにアカウント内容追加
 - 各追加した内容に対するテスト...etc
 
***
###今回使用する各ファイル
 - Spec(Factory)
 - Spec(Request)
 - Spec(Feature)


***
####Spec(Factory)

```ruby:/spec/factories/users.rb
FactoryBot.define do
  factory :user do
    name "Example User"
    email "user@example.com"
    password "foobar"
    password_confirmation "foobar"
  end
end
```
<br>
**ログイン画面**
![スクリーンショット 2018-10-26 0.29.15.png](https://qiita-image-store.s3.amazonaws.com/0/260354/6bd39ac2-e63c-686a-6da7-67f3a58f81fe.png)

####Spec(Request)

```ruby:/spec/requests/users_login_api_spec.rb
require 'rails_helper'

RSpec.describe "UsersLoginApi", type: :request do

  it "sessions/newにアクセスできること" do
    #ログインページにアクセスします
    get login_path
    expect(response).to have_http_status(:success)
  end

  describe "<sessions#new>" do
    context "ログインに失敗した時" do
      it "フラッシュメッセージの残留をキャッチすること" do
        get login_path
        expect(response).to have_http_status(:success)

        #「email:""」と「password:""」の値を持ってlogin_pathにアクセスします
        # → バリデーションに引っかかりログインできません
        post login_path, params: { session: { email: "", password: "" }}
        expect(response).to have_http_status(:success)

        #flash[:danger]が表示されているかチェックします
        expect(flash[:danger]).to be_truthy

        #Rails Tutorialだと、minitest記述でbe_emptyとありますが、
        #be_emptyで「flash[:danger]のテストを行うとエラーになります。
        #get root_pathに移動前：expect(flash[:danger]).to_not be_empty → GREEN
        #get root_pathに移動前：expect(flash[:danger]).to be_truthy → RED
        #エラーを見ると返り値が"true"だったため、be_truthyとbe_falseyにしています。

        #root_path（別ページ）に移動してflash[:danger]が表示されていないかチェックします
        get root_path
        expect(flash[:danger]).to be_falsey
      end
    end
  end
end

```

####Spec(Feature)

```ruby:/spec/features/users_login_spec.rb
require 'rails_helper'

RSpec.feature "UsersLogin", type: :feature do

  before do
      @user = FactoryBot.create(:user)
  end

  scenario "ログインした後にメニューバーの表示内容が変わること" do
    #Request Specでの書き方が分からなかったためFeatureに書きます..
    # 1.ログイン用のパスを開く
    # 2.セッション用パスに有効な情報をpostする
    # 3.ログイン用リンクが表示されなくなったことを確認する
    # 4.ログアウト用リンクが表示されていることを確認する
    # 5.プロフィール用リンクが表示されていることを確認する

    visit login_path

    fill_in "Email", with: @user.email
    fill_in "Password", with: @user.password
    click_button "Log in"

    expect(page).to_not have_css("a", text: "Log in")
    expect(page).to have_css("a", text: "Log out")
    expect(page).to have_css("a", text: "Profile")
  end
end

```
***
###今回ハマった点
今回、すごくハマった部分があります。
それが**Feature Specに書いたテスト**です。
こちらはもともとRequestで実装しようとしましたが、
実装の仕方が思いつかず断念しました。。

Rails TutorialにあるMinitestの記述は下記の通りです。
>パスワード生成に使用するDigestメソッドとFixtureを使って行うテストです。特にDigestメソッドの部分をRSpecで記述する方法が分かりませんでした。

```ruby:app/models/user.rb
  # 渡された文字列のハッシュ値を返す
  def User.digest(string)
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                  BCrypt::Engine.cost
    BCrypt::Password.create(string, cost: cost)
  end
```
```ruby:ユーザーログインのテストで使うfixture
michael:
  name: Michael Example
  email: michael@example.com
  password_digest: <%= User.digest('password') %>
```


```ruby:fixture向けのdigestメソッドを追加する
require 'test_helper'

class UsersLoginTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end
  .
  .
  .
  test "login with valid information" do
    get login_path
    post login_path, params: { session: { email:    @user.email,
                                          password: 'password' } }
    assert_redirected_to @user
    follow_redirect!
    assert_template 'users/show'
    assert_select "a[href=?]", login_path, count: 0
    assert_select "a[href=?]", logout_path
    assert_select "a[href=?]", user_path(@user)
  end
end
```

非常に悩みました。
もしRSpecでの上記の書き方が分かる方がいらっしゃればアドバイスいただければ助かります。

***
###まとめ＆反省点
すごくハマり大変でした。
一応、先日よりもスムーズにテストを書けはしましたが、まだまだですね。
早いところ実務レベルまで持っていきたいところです。

あと、最近は周囲の人が助け舟（容赦ない指摘←ありがたい）を出していただき
前よりRSpecが好きになってきました。

優しいみなさんありがとうございます。
引き続きアドバイス・指摘・マサカリありましたらよろしくお願いします。
<br>