Programming Journal

学習したことの整理用です。

【RSpec】System Spec

今回の記事の目的

System Specのコードを書いていて迷うことがいくつかあったので、復習していきます。
前回の記事同様、RSpec,FactoryBot and Capybaraは設定済です。

実行するテストケースを限定したいとき

itの代わりにfitを使います。
spec_helper.rb config.filter_run_when_matching :focusと設定しているため、各テストの頭文字にfをつけることで、focus: trueを設定できます。

別タブで開いたページをテストしたいとき

リンクをクリックし、遷移したページ先の項目についてテストしたいときは、within_window(windows.last)で最後に開いたタブを指定します。

it 'Project詳細からTask一覧ページにアクセスした場合、Taskが表示されること' do
        visit project_path(project)
        click_link 'View Todos' #これでページ遷移する。
        within_window(windows.last)do #以下、遷移先の内容
          expect(page).to have_content task.title
          expect(Task.count).to eq 1
          expect(current_path).to eq project_tasks_path(project)
        end
      end

withinメソッド

Capybaraのwithinメソッドは、ページ内の特定のエリアやアクションを指定できます。
within_windowはウィンドウ画面の指定。

確認画面のページ操作したいとき

何かの項目を削除するとき、「本当に削除しますか?」とアラートメッセージがでますが、それの操作は以下のようにします。

 #許可するとき
page.driver.browser.switch_to.alert.accept 

 #拒否するとき
page.driver.browser.switch_to.alert.dismiss

ApplicationHelperで定義したメソッドをRSpecで使いたいとき

何も考えず使おうとしたら、使えませんでした。私はこういうところをよく忘れるので注意します。
当たり前ですが、includeで読み込む必要があります。
今回は、systemspecファイルでrequire 'rails_helper'しているので、spec/rails_helper.rb内でapplication_helper.rbを読み込む設定をします。

config.include ApplicationHelper #追加

これで、ApplicationHelperで定義したメソッドshort_timeRspecでも使用できます。

it 'Taskを編集した場合、一覧画面で編集後の内容が表示されること' do
        fill_in 'Deadline', with: Time.current #今の時刻にdeadlineを更新する。
        click_button 'Update Task'
        click_link 'Back'
        expect(find('.task_list')).to have_content(short_time(task.reload.deadline)) #ここ
        expect(current_path).to eq project_tasks_path(project)
end

Updateのテストがうまくいかない。値が更新されないとき

上のコードの解説です。
最初、short_time(task.deadline)としたら、更新前の日時しか取得できなかった。更新出来てないってこと?
謎だったけど、その場しのぎでTime.currentにしてしまいました。
そしてちゃんと調べたら、ドンピシャな記事がありました。
DBの値が更新されても、インスタンスの値は更新されない。task.reload.deadlineとする。
これでテストが通りました。

rspecでupdateのテストを通せない初心者が疑うべきこと - Qiita

findメソッド

Capybaraのfindメソッドは特定の要素を指定できます。
さきのコード例では、find('.task_list')で、viewで定義しているclass = "task_list"を指定しています。

strftimeメソッド

Rubyのメソッドです。

時刻を format 文字列に従って文字列に変換した結果を返します。
Time#strftime (Ruby 2.7.0 リファレンスマニュアル)

以下のように使います。

expect(page).to have_content(Time.current.strftime('%Y-%m-%d'))

FactoryBotのtraitを使う

属性をいろいろ指定して定義したいとき、traitを使います。
テスト内で何度も同じ属性を指定して呼び出していると、コードの重複が生じてしまいます。
traitを使えばスッキリとした見た目になります。
また、添付ファイルを予めセットすることもできます。(やり方は『everyday Rails』P174 )

#trait定義前
let!(:task) {create(:task, project_id: project.id, status: :done, completion_date: Time.current.yesterday)}

#trait定義後
let!(:task) { create(:task, :done) }
FactoryBot.define do
  factory :task do
    sequence(:title, "title_1")
    status { rand(2) }
    from = Date.parse("2019/08/01")
    to   = Date.parse("2019/12/31")
    deadline { Random.rand(from..to) }
    association :project

    trait :done do #ここ
      status { :done }
      completion_date { Time.current.yesterday }
    end
  end
end

Capybaraのメソッドについて

公式は例もあって分かりやすい

GitHub - teamcapybara/capybara: Acceptance test framework for web applications