環境
- macOS 10.14.5
- ruby 2.5.5
- rails 5.2.3
はじめに
RailsチュートリアルのテストをRSpecで書いていた時にあることに気づきました。
featureテストではsessionが使えない!?
Railsチュートリアル8章のテストでis_logged_in?というユーザーがログイン中かどうかを論理値で返すテスト用ヘルパーを紹介していました。
# テストユーザーがログイン中の場合にtrueを返す
def is_logged_in?
!session[:user_id].nil?
end
なので同様にspec/support/test_helper.rb
に記述してfeatureテストでヘルパーを使用した。
(ヘルパーを定義する方法はこちらを見るとよいと思います
→ マクロ(ヘルパーメソッド)を定義してフィーチャースペックのユーザー切替えを楽に行う
)
module TestHelper
def is_logged_in?
!session[:user_id].nil?
end
end
require 'rails_helper'
RSpec.feature "UsersSignups", type: :feature do
feature "valid signup information" do
before do
visit signup_path
fill_in "Name", with: "Example User"
fill_in "Email", with: "user@example.com"
fill_in "Password", with: "password"
fill_in "Confirmation", with: "password"
end
scenario "add users count" do
expect {
click_button "Create my account"
expect(page).to have_current_path user_path(User.last)
}.to change(User, :count).by(1)
end
scenario "show flash message" do
click_button "Create my account"
expect(page).to have_content "Welcome to the Sample App!"
visit current_path
expect(page).to_not have_content "Welcome to the Sample App!"
end
scenario "login created user" do
click_button "Create my account"
expect(is_logged_in?).to be_truthy #### ここで使用 ####
end
end
feature "invalid signup information" do
before do
visit signup_path
fill_in "Name", with: ""
fill_in "Email", with: "user@invalid"
fill_in "Password", with: "foo"
fill_in "Confirmation", with: "bar"
end
scenario "no difference users count" do
expect {
click_button "Create my account"
expect(page).to have_current_path signup_path
}.to_not change(User, :count)
end
scenario "is show error messages" do
click_button "Create my account"
expect(page).to have_content "Name can't be blank"
expect(page).to have_content "Email is invalid"
expect(page).to have_content "Password is too short"
expect(page).to have_content "Password confirmation doesn't match Password"
end
end
end
するとこんなエラーが、、、
1) UsersSignups valid signup information login created user
Failure/Error: !session[:user_id].nil?
NameError:
undefined local variable or method `session' for #<RSpec::ExampleGroups::UsersSignups::ValidSignupInformation:0x00007fe38a4a3e20>
# ./spec/support/login_macros.rb:3:in `is_logged_in?'
# ./spec/features/users_signup_spec.rb:30:in `block (3 levels) in <top (required)>'
# -e:1:in `<main>'
解決策
どうやら調べてみるとfeatureテスト内ではsesssionが扱えないようで、コントローラーテスト内では使えるみたい。
でもどうにかfeatureテスト内でこのヘルパーを使えるようにする方法はないかと調べていたところある記事を見つけました。
Rails feature testing with logged in user (undefined method 'session')
'rack_session_access'
というgemを使うとfeatureテスト内でもsessionを参照したり、変更したりできるみたいなのでgemのREADMEを参考にセットアップしました。
gem 'rack_session_access' # 追加
$ bundle install # gemをインストール
Rails.application.configure do
:
:
config.middleware.use RackSessionAccess::Middleware # 追加
end
require "rack_session_access/capybara" # 追加
このgemを使うとsessionに値を挿入することもできるらしいが今回は値が入っているかどうかを調べたいだけなので以下のメソッドを記述してRailsチュートリアルに習って論理値を反転。
module TestHelper
def is_logged_in?
!page.get_rack_session_key('user_id').nil? # 変更
end
end
はじめはget_rack_session_key(:user_id)
と修正したがダメだったのでREADEMEを見ると、文字列('user_id'
)を渡さなきゃいけないらしい
まとめ
'rack_session_access'
gemを使うとfeatureスペックでもsessionを扱える!
しかし頻繁にsessionの操作をfeatureスペック内で行わないようなら、ログインしているかどうかをテストする方法は他にもいくらでもあるのでgemをわざわざ入れる必要はないかも。。