はじめに
サインイン機能の勉強のために、サインイン機能をdeviseを使わないで自作したところ、テストで大変苦労したので、学んだことを以下に記します。
今回は、system specとrequest specでテストを記載し、多くのところで使いまわせるよう、これらの処理を別ファイルに書き出しました。
実行環境は以下の通りです。
- Rails 5.2.4.2
- Rspec 4.0.1
- capybara 3.33.0
サインイン画面について
emailとパスワードでサインインできるフォームを作っています。画像は参考画像です。
基本のサインインメソッド
サインインメソッドをsystem specとrequest specとでそれぞれ表すと下記のようになります。今回は、あるショップに所属しているスタッフを作成し、そのスタッフのメールアドレスとパスワードでサインインをします。
system spec
let!(:shop) { FactoryBot.create(:shop) }
let!(:user) { FactoryBot.create(:staff, shop_id: shop.id ) }
before do
visit login_path
fill_in "E-mail", with: user.email
fill_in "Password", with: user.password
click_button 'LOGIN'
end
request spec
let!(:shop) { FactoryBot.create(:shop) }
let!(:user) { FactoryBot.create(:staff, shop_id: shop.id ) }
before do
session_params = { session: { email: user.email, password: user.password } }
post "/login", params: session_params
end
共通事項をまとめる(1) shared_context
まずは、letで従業員を定義している2行が、両者で重複していたので、それをshared_context
を用いて、別ファイルに書き出します。
RSpec.shared_context "user_setup" do
let!(:shop) { FactoryBot.create(:shop) }
let!(:user) { FactoryBot.create(:staff, shop_id: shop.id ) }
end
この時、spec\rails_helper.rb
内にある、以下の行のコメントアウトを外し、spec\support
内のファイルやディレクトリをすべて読み込めるようにしておきます。
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
こちらの設定で、spec内では以下のように記述することで、ユーザーのセットアップができるようになります。
# 任意のspecファイル内
include_context "user_setup"
共通事項をまとめる(2) module
system specとrequest specの共通処理もそれぞれモジュールにまとめることで、いろいろなところで使いまわすことができます。今回作成したファイルは以下の通りです。
system spec
module SignInModule
def sign_in_as(user)
visit login_path
fill_in "E-mail", with: user.email
fill_in "Password", with: user.password
click_button 'LOGIN'
end
end
なお、この時、ファイル名とモジュール名は一致させる必要があるようです。例えば、SignInModule
なら、sign_in_module.rb
というファイル名にする必要があります。
▼参考サイト
https://relishapp.com/rspec/rspec-core/v/3-0/docs/helper-methods/define-helper-methods-in-a-module
request spec
module SignInRequestModule
def sign_in_request_as(user)
session_params = { session: { email: user.email, password: user.password } }
post "/login", params: session_params
end
end
rails_helper.rb への記載
このとき、spec\rails_helper.rb
には、以下のように記入します。(明示的に読み込むことを記載しないと、読み込めませんでした…。)
RSpec.configure do |config|
# 中略
config.include SignInModule
config.include SignInRequestModule
end
このあたりもう少しDRYにかけそうなので、方法がわかったら追記したいです。
specファイルでの使い方
上記のように記載することで、specファイルではこちらの方法で、それぞれサインインメソッドを呼び出すことができます。
# 任意のsystem specファイル
include_context "user_setup"
before do
sign_in_as(user)
end
# 任意のrequest specファイル
include_context "user_setup"
before do
sign_in_request_as(user)
end
まとめ&参考サイト
devise使わないでログイン機能を実装してやる!と頑張って作り始めたのですが、deviseはいろいろなところで手間を簡略化してくれていることがわかりました。これからはdeviseとうまく付き合っていきたいと思います。
一方で、サインインの仕組みにも詳しくなったので、エンジニアとしてのスキルアップはできたと思います。
今回参考にした情報はこちら。
Define helper methods in a module
Request Specを使おう
What is the proper way to sign in as a user in an rspec request spec, without devise?
rails5 can't access session in ActionDispatch::IntegrationTest