RSpecのfeatureテストでsessionを扱う方法


環境


  • macOS 10.14.5

  • ruby 2.5.5

  • rails 5.2.3


はじめに

RailsチュートリアルのテストをRSpecで書いていた時にあることに気づきました。

featureテストではsessionが使えない!?

Railsチュートリアル8章のテストでis_logged_in?というユーザーがログイン中かどうかを論理値で返すテスト用ヘルパーを紹介していました。


test/test_helper.rb

# テストユーザーがログイン中の場合にtrueを返す

def is_logged_in?
!session[:user_id].nil?
end

なので同様にspec/support/test_helper.rbに記述してfeatureテストでヘルパーを使用した。

(ヘルパーを定義する方法はこちらを見るとよいと思います

マクロ(ヘルパーメソッド)を定義してフィーチャースペックのユーザー切替えを楽に行う

)


spec/support/test_helper.rb

module TestHelper

def is_logged_in?
!session[:user_id].nil?
end
end


spec/features/users_signup_spec.rb

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を参考にセットアップしました。


Gemfile

gem 'rack_session_access' # 追加


$ bundle install   # gemをインストール


config/environments/test.rb

Rails.application.configure do

:
:
config.middleware.use RackSessionAccess::Middleware # 追加
end


spec/spec_helper.rb

require "rack_session_access/capybara"   # 追加


このgemを使うとsessionに値を挿入することもできるらしいが今回は値が入っているかどうかを調べたいだけなので以下のメソッドを記述してRailsチュートリアルに習って論理値を反転。


spec/support/test_helper.rb

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をわざわざ入れる必要はないかも。。