RSpecではインスタンス変数を使う代わりに、letを使うことが出来ます。
このletをインスタンス変数のようなものだとあやふやな認識をしていた為、以下のコードを書いてしまっていました。
test_spec.rb
require 'rails_helper'
# before内にletを書いている
describe 'ログイン', type: :system do
before do
let(:user_a) { FactoryBot.create(:user) }
visit login_path
fill_in 'Email', with: user_a.email
fill_in 'Password', with: password
click_button 'Login'
end
context 'ログイン成功' do
before do
let(:password) { user_a.password }
end
it '成功時のflashが表示される' do
expect(page).to have_css('div', class: 'alert-success')
end
end
context 'ログイン失敗' do
before do
let(:password) { 'badpassword' }
end
it '失敗時のflashが表示される' do
expect(page).to have_css('div', class: 'alert-danger')
end
end
end
このテストを実行すると以下のエラー文が出てきます。
Failure/Error: let(:user_a) { FactoryBot.create(:user) }
let
is not available from within an example (e.g. anit
block) or from >constructs that run in the scope of an example (e.g.before
,let
, etc). It is >only available on an example group (e.g. adescribe
orcontext
block).
letはdescribe
かcontext
の中でしか使えないよ!というお叱りを受けました。
インスタンス変数の代わりにletを使うサンプルが多いですが、letは変数とは違うのでbefore
やit
の中では使えません。
上記のプログラムは、以下のように書き換えると正常に実行できます。
test_spec.rb
require 'rails_helper'
# letをbeforeの外で定義している
describe 'ログイン', type: :system do
let(:user_a) { FactoryBot.create(:user) }
before do
visit login_path
fill_in 'Email', with: user_a.email
fill_in 'Password', with: password
click_button 'Login'
end
context 'ログイン成功' do
let(:password) { user_a.password }
it '成功時のflashが表示される' do
expect(page).to have_css('div', class: 'alert-success')
end
end
context 'ログイン失敗' do
let(:password) { 'badpassword' }
it '失敗時のflashが表示される' do
expect(page).to have_css('div', class: 'alert-danger')
end
end
end