テスト環境でsorceryを使用したユーザーログイン機能を使用したとき、Userクラスのインスタンスメソッドでハマった話
概要
テスト環境でsorceryを使用してログイン機能を追加した時、user.password
で詰まった話。
失敗時のコード
以下のような、ユーザーが正常にログインできるかのテストコードを作成した時、テストに失敗した。
# spec/factories/users.rb FactoryBot.define do factory :user do sequence(:email) { |n| "user_#{n}@example.com" } password { 'password' } password_confirmation { 'password' } end end
# spec/system/usersessions_spec.rb require 'rails_helper' RSpec.describe "UserSessions", type: :system do let(:user) { create(:user) } describe 'ログイン前' do context 'フォームの入力値が正常' do before do visit root_path click_link "Login" fill_in "Email", with: user.email fill_in "Password", with: user.password click_button "Login" end it 'ログイン処理が成功する' do expect(current_path).to eq root_path expect(page).to have_content "Tasks" expect(page).to have_content "Login successful" end end end end
テストに失敗した時のスクリーンショットを見ると、ログインに成功してなかったみたいなのでclick_button
の上にbinding.irb
を挟んでuser.email
とuser.password
を確認してみると、以下のようにuser.password
でnilが返っていた。
irb(#<RSpec::ExampleGroups::UserSessions::Nested::Nested:0x00007f85a4104d08>):001:0> user.email => "user_1@example.com" irb(#<RSpec::ExampleGroups::UserSessions::Nested::Nested:0x00007f85a4104d08>):002:0> user.password => nil
原因
何故こうなったかを調べると、usersテーブルにpassword
カラムが存在してないことが原因みたい。
sorceryを使用してログイン機能を追加する場合、usersテーブルにはcrypted_password
カラムが存在して、仮想的な属性であるpassword
とpassword_confirmation
を元にcrypted_password
カラムを作成している。なのでuser.password
とuser.password_confirmation
を指定してuser.create
を実行すると、user.crypted_password
が作成されてデータベースに保存されるが、仮想的な属性であるpassword
とpassword_confirmation
は無くなるみたいである。
今回の場合だとFactoryBot.create(:user)
を使用すると、FactoryBot
で指定したpassword
とpassword_confirmation
を値を元にuser.crypted_password
を作成するのでuser.password
とuser.password_confirmation
は存在しなくなる(nilになる)。よって、ログインに失敗したようである。
解決方法
なので、今回のようにあらかじめ作成しておいたユーザーデータをもとにログインを検証するテストを作成する場合、fill_in "Password"の箇所をFactoryBotでpasswordに指定した"password"を直に書くことでうまくテストが通るようになった。
fill_in "Password", with: user.password => fill_in "Password", with: "password"