RailsチュートリアルのテストをRspecで書いてみた[第10章]
はじめに
今回はRspecの学習の一環として、RailsチュートリアルのテストをRspecで書いていきます。
至らない点があるかもしれませんが、その際はコメントにてご指摘をお願いします。
各種バージョン
Ruby 2.7.0
Rails 6.0.3.3
Rspec 3.9
Capybara 3.33.0
Factory_bot_rails 6.1.0
第10章
リスト10.9: 編集の失敗に対するテスト
今回はsystemスペックを使用しました。また、ログインする箇所をサポートモジュールに切り出しています。
spec/support/test_helper.rb ... module SystemHelper def login_as(user) visit login_path fill_in 'Email', with: user.email fill_in 'Password', with: user.password click_button 'Log in' end end RSpec.configure do |config| config.include TestHelper config.include SystemHelper #<= 追加 end
spec/system/users_edit_spec.rb require 'rails_helper' RSpec.describe "UsersEdits", type: :system do let(:user) { FactoryBot.create(:user) } scenario 'it fails edit with wrong information' do login_as(user) click_on 'Setting' fill_in 'Name', with: ' ' fill_in 'Email', with: 'user@invalid' fill_in 'Password', with: 'foo' fill_in 'Confirmation', with: 'bar' click_on 'Save changes' aggregate_failures do expect(current_path).to eq user_path(user) expect(has_css?('.alert-danger')).to be_truthy end end end
リスト10.11: 編集の成功に対するテスト
spec/system/users_edit_spec.rb require 'rails_helper' RSpec.describe "UsersEdits", type: :system do let(:user) { FactoryBot.create(:user) } # 一つ前のテストと重複するコードがあったので、before文に切り出しています。 before do login_as(user) click_on 'Setting' end scenario 'it fails edit with wrong information' do fill_in 'Name', with: ' ' fill_in 'Email', with: 'user@invalid' fill_in 'Password', with: 'foo' fill_in 'Confirmation', with: 'bar' click_on 'Save changes' aggregate_failures do expect(current_path).to eq user_path(user) expect(has_css?('.alert-danger')).to be_truthy end end # ここからが追加したテストです。 scenario 'it succeeds edit with correct information' do fill_in 'Name', with: 'Foo Bar' fill_in 'Email', with: 'foo@bar.com' fill_in 'Password', with: '' fill_in 'Confirmation', with: '' click_on 'Save changes' aggregate_failures do expect(current_path).to eq user_path(user) expect(has_css?('.alert-success')).to be_truthy end end end
また、一応requestスペックも書きました。
spec/requests/users_request_spec.rb require 'rails_helper' RSpec.describe "Users", type: :request do ・・・ describe "PATCH /users/:id" do let(:user) { FactoryBot.create(:user) } it 'succeeds edit with correct information' do patch user_path(user), params: { user: { name: "Foo Bar", email: "foo@bar.com", password: "", password_confirmation: "", } } expect(response).to redirect_to user_path(user) end end end
リスト10.17: テストユーザーでログインする
spec/requests/users_request_spec.rb require 'rails_helper' RSpec.describe "Users", type: :request do ・・・ describe "PATCH /users/:id" do let(:user) { FactoryBot.create(:user) } before { log_in_as(user) } #<= ここを追加しています。 it 'fails edit with wrong information' do patch user_path(user), params: { user: { name: " ", email: "foo@invalid", password: "foo", password_confirmation: "bar", } } expect(response).to have_http_status(200) end it 'succeeds edit with correct information' do patch user_path(user), params: { user: { name: "Foo Bar", email: "foo@bar.com", password: "", password_confirmation: "", } } expect(response).to redirect_to user_path(user) end end end
リスト10.20: editとupdateアクションの保護に対するテスト
spec/requests/users_request_spec.rb require 'rails_helper' RSpec.describe "Users", type: :request do ・・・ describe "before_action: :logged_in_user" do let(:user) { FactoryBot.create(:user) } it 'redirects edit when not logged in' do get edit_user_path(user) expect(response).to redirect_to login_path end it 'redirects update when not logged in' do patch user_path(user), params: { user: { name: user.name, email: user.email, } } expect(response).to redirect_to login_path end end end
リスト10.24: 間違ったユーザーが編集しようとしたときのテスト
spec/requests/users_request_spec.rb require 'rails_helper' RSpec.describe "Users", type: :request do ・・・ describe "before_action: :correct_user" do let(:user) { FactoryBot.create(:user) } let(:other_user) { FactoryBot.create(:user) } before { log_in_as(other_user) } it 'redirects edit when logged in as wrong user' do get edit_user_path(user) expect(response).to redirect_to root_path end it 'redirects update when logged in as wrong user' do patch user_path(user), params: { user: { name: user.name, eemail: user.email, } } expect(response).to redirect_to root_path end end end
リスト10.29: フレンドリーフォワーディングのテスト
spec/requests/sessions_request_spec.rb require 'rails_helper' RSpec.describe "Sessions", type: :request do let(:user) { FactoryBot.create(:user) } ・・・ describe "friendly forwarding" do let(:user) { FactoryBot.create(:user) } it 'succeeds' do get edit_user_path(user) log_in_as(user) expect(response).to redirect_to edit_user_url(user) end end end
リスト10.34: indexアクションのリダイレクトをテストする
spec/requests/users_request_spec.rb require 'rails_helper' RSpec.describe "Users", type: :request do ・・・ describe "GET /users" do it "redirects login when not logged in" do get users_path expect(response).to redirect_to login_url end end end
リスト10.61: 管理者権限の制御をアクションレベルでテストする
FactoryBotで新しく管理者権限をもつテストユーザを作成します。
また、「trait」を使用して重複部を省略しています。
spec/factories/users.rb FactoryBot.define do factory :user do name { "TestUser" } sequence(:email) { |n| "test#{n}@example.com" } password { "foobar" } password_confirmation { "foobar" } # ここから下の文を追加しています。 # FactoryBot.create(:user, :admin)の形で呼び出せます。 trait :admin do admin { true } end end
spec/requests/users_request_spec.rb require 'rails_helper' RSpec.describe "Users", type: :request do ・・・ describe "before_action: :logged_in_user" do let(:user) { FactoryBot.create(:user) } ・・・ it 'redirects delete when not logged in' do delete user_path(user) expect(response).to redirect_to login_url end end ・・・ describe "delete /users/:id" do #「let!」を使用して遅延評価を打ち消しています。(before文と等価) let!(:user) { FactoryBot.create(:user) } let!(:admin_user) { FactoryBot.create(:user, :admin) } it 'fails when not admin' do log_in_as(user) aggregate_failures do expect do delete user_path(admin_user) end.to change(User, :count).by(0) expect(response).to redirect_to root_url end end it 'succeds when user is administrator' do log_in_as(admin_user) aggregate_failures do expect do delete user_path(user) end.to change(User, :count).by(-1) expect(response).to redirect_to users_url end end end end