はじめに
devise_token_authのログイン機能が開発し終わったので現在RSpecでテストを書いているのですが、"メール認証済みでないとログインできない"というテストを書くことができたので、備忘録として残そうと思います。
sessions_spec.rbで何をテストするか
devise_token_authで設定をすればアカウント作成時にメールで本認証を行わないとログインができない機能を実装することができます。
この"sessions_spec.rb"は、ログイン機能を担当しているので"メールが送信できているか?"などのテストではなくシンプルに、
・認証が済んでいればそのアカウントはログインできる
・認証ができていなければそのアカウントはログインできない
という2点が問題なく動作していることをテストで確認できればOKという考えになりました。
アカウントを作成する箇所のテストについては、registrations_spec.rbで記述します。
(その他パスワードやメールアドレスが間違っている場合はログインできない等のテストは書いていますが、認証とは関係ないので省略しています)
どうやって認証の状態を制御するか
結論から述べると"confirmed_at"に日付を入れることにより、認証済みか未認証かを制御することができます。
メール認証が完了(認証メール内にあるリンクを開くこと)でconfirmed_atに値が入り、認証済みかどうか判断しているようです。
最初に作成されるDBテーブルのカラム内にもちゃんとありますね。
class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[6.1]
def change
create_table(:users) do |t|
## Required
t.string :provider, :null => false, :default => "email"
t.string :uid, :null => false, :default => ""
#省略
## Confirmable
t.string :confirmation_token
t.datetime :confirmed_at #=>これ!!
t.datetime :confirmation_sent_at
t.string :unconfirmed_email # Only if using reconfirmable
#省略
end
end
結論
そのため下記のように、confirmed_atに値がある場合/ない場合のuserデータを作成してそれぞれテストを行えばOKです。
RSpec.describe "Api::V1::Auth::Sessions", type: :request do
let(:current_user) { create(:user, confirmed_at: Date.today) }
describe "POST /api/v1/auth/sign_in" do
context "認証時みでメールアドレス、パスワードが正しい場合" do
let(:params) { { email: current_user.email, password: current_user.password } }
it "ログインが成功すること" do
post api_v1_user_session_path, params: params
expect(response.headers["uid"]).to be_present
expect(response.headers["access-token"]).to be_present
expect(response.headers["client"]).to be_present
expect(response).to have_http_status(200)
end
end
context "未認証でメールアドレス、パスワードが正しい場合" do
let(:no_confirmed_current_user) { create(:user, confirmed_at: "") }
let(:params) { { email: no_confirmed_current_user.email, password: no_confirmed_current_user.password } }
it "ログインが失敗すること" do
post api_v1_user_session_path, params: params
res = JSON.parse(response.body)
expect(res["errors"]).to include("A confirmation email was sent to your account at '#{no_confirmed_current_user.email}'. You must follow the instructions in the email before your account can be activated")
expect(response).to have_http_status(401)
end
end
end
end
テストも無事通りました。
コンテナ名:/サービス名 # bundle exec rspec ./spec/requests/api/v1/auth/sessions_spec.rb
.....
Finished in 0.57591 seconds (files took 3.55 seconds to load)
5 examples, 0 failures
【余談】エラーメッセージはどこにあるのか
いろんなrspecを参考にしながらも、response.bodyのエラーメッセージとかどこのこと言ってんねん!と密かに思っていた時期があったので、一応どこにあるか画像に残そうと思います。
(何を写しちゃだめかわからなくて不安なので、一応不要そうな箇所は隠しました。)
終わりに
テストを書くために必要な準備は、どんなロジックで実装しているのか、もしくはされているのかの理解だと強く感じました。
gemを使って機能を作ってる時は理解してないとなんとなくで機能が作れちゃったりすると思うので、ちゃんとソースコードを読むことが大事だなぁとも感じました。