【Rails6】RSpecによるいいね機能の結合テストの実装

#はじめに
サービスの品質を保つために必要不可欠なテストを実施しております。

今回はいいね機能の結合テストを実装し、その実装内容を記事にしていきたいと思います。

#前提
・Like（いいね）モデルの単体テストは実施済み

※完了されていない方や単体テストと並行してご覧になられたい方は、以下のLikeモデルの単体テストについての記事をご参考ください。

https://qiita.com/narimiya/items/708023931f4590901f42

#バージョン
rubyのバージョン　ruby-2.6.5
Railsのバージョン Rails:6.0.0
rspec-rails 4.0.0

#実施したテスト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1052793/ed1378dc-6a94-18de-ee23-86ad8ebbe272.png)

#likesテーブルのカラムの紹介

```xxx_create_likes.rb
class CreateLikes < ActiveRecord::Migration[6.0]
  def change
    create_table :likes do |t|
      t.references :user,       foreign_key: true
      t.references :answer,     foreign_key: true
      t.references :definition,     foreign_key: true
      t.timestamps
    end
  end
end
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1052793/e949d67f-b2d5-172a-7cf1-b80c5d40e4be.png)

#「いいね」に関するviewの内容

```app/views/definitions/show.html.erb

# 〜省略〜 

 <% if current_user.already_liked?(answer) %>

    <%= link_to definition_answer_likes_path(@definition,answer), method: :delete do %>
      <i class="fas fa-heart", id="liking-btn"></i>
    <% end %>
                  
<% else %>
    <%= link_to definition_answer_likes_path(@definition,answer), method: :post do %>
      <i class="far fa-heart", id="nolike-btn"></i>
    <% end %>

 <% end %>
                 
 <%= answer.likes.count %>
 <%= "(#{time_ago_in_words(answer.created_at)}前)" %> 

# 〜省略〜
```

#モデル内のバリデーション

```app/models/like.rb
class Like < ApplicationRecord
  belongs_to :user
  belongs_to :answer
  belongs_to :definition

  validates :user_id, presence: true
  validates :answer_id, uniqueness: { scope: :user_id }, presence: true
  validates :definition_id, uniqueness: { scope: :user_id }, presence: true
end

```

#FactoryBotの内訳

```spec/factories/likes.rb
FactoryBot.define do
  factory :like do
    association :answer
    association :definition
    user { answer.user }
  end
end

```

#サポートモジュール

```spec/support/sign_in_support.rb
module SignInSupport
  def sign_in(user)
    visit user_session_path
    fill_in 'user[email]', with: user.email
    fill_in 'user[password]', with: user.password
    find('input[name="commit"]').click
    expect(current_path).to eq(root_path)
  end
end
```

#テストコードの内容

```spec/system/likes_spec.rb
require 'rails_helper'

RSpec.describe "Likes", type: :system do
    before do
      @definition = FactoryBot.create(:definition)
      @answer = FactoryBot.create(:answer)
    end

    describe '#create,#destroy' do
      it 'ユーザーが他の投稿をいいね、いいね解除できる' do
        # ログインする
        sign_in(@definition.user)
          
        # 投稿詳細ページに遷移する
        visit definition_path(@definition.id)
          
        # フォームに情報を入力する
        fill_in 'answer_answer', with: @answer
          
        # 回答を送信すると、Answerモデルのカウントが1上がることを確認する
        expect{
          find('input[name="commit"]').click
        }.to change { Answer.count }.by(1)
          
        # いいねをするボタンを押す
        find('#nolike-btn').click
        expect(page).to have_selector '#liking-btn'
        expect(@answer.likes.count).to eq(1)

        # いいねを解除する
        find('#liking-btn').click
        expect(page).to have_selector '#nolike-btn'
        expect(@answer.likes.count).to eq(0)
        end
     end
end
```

#補足説明
##find().clickについて
今回、引数の値はview内のいいねボタンのidの要素となります。

```app/views/definitions/show.html.erb

# 〜省略〜 

      <i class="fas fa-heart", id="liking-btn"></i>

# 〜省略〜 

      <i class="far fa-heart", id="nolike-btn"></i>

# 〜省略〜 
```

##have_selectorについて

have_selector 〜の〜内に特定の要素を含んでいるか検査します。

なので、

```spec/system/likes_spec.rb
expect(page).to have_selector '#liking-btn'
```

pageでvisitで訪れた先のページのことで、そのページ内にliking-btnのidの要素を含んでいるかの確認をしています。

#expect( ).to eq( )について
AnswerモデルとLikeモデルはアソシエーションで紐付けているので

```spec/system/likes_spec.rb
expect(@answer.likes.count).to eq(1)
```

likesテーブル内のカラムのcount数は１となるという意味になります。

以上です。