3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

deviseのメール認証機能を利用している場合のRequestSpecでハマった話

Last updated at Posted at 2021-02-16

タイトルのとおりですが、deviseのメール認証機能を使用したアプリで、RequestSpecでテストを行った際にハマりました

概要

  1. Railsでdeviseのメール認証機能を使用したアプリを作成しました。
  2. 特定の値を持つインスタンスは、特定のページに遷移できない処理を行いたかったので、Punditというgemを使いました。
  3. 2のテストをするため、RequestSpecでテストコードを記述しましたが、期待した結果が出力されず、ハマりました

前提条件

  • Ruby 2.6.5
  • Rails 5.2.4

テーブル構成

全ては記述してませんが、テーブル構成はこんな感じです。
Punditというgemを使い、以下のとおりアクセス制限をしました。
materialstatuslearningの時は、materialの編集画面(materials/:id/edit)に、アクセスできる設定
materialstatuscompleteの時は、materialの編集画面(materials/:id/edit)に、アクセスできない設定

db/schema.rb
create_table "users", force: :cascade do |t|
    t.string "name", null: false
    t.string "email", default: "", null: false
end

create_table "materials", force: :cascade do |t|
    t.string "title", null: false
    t.bigint "user_id"
    # material_modelでenum status: { learning: 0, complete: 1 }と定義してます。
    t.integer "status", default: 0, null: false 
end

実行したこと

1.まず、こちらの記事を参考に、下記のとおり記述しました。

FactoryBotを記述

spec/factories/users.rb
FactoryBot.define do
  factory :user do
    id { 1 }
    name { 'sample' }
    email { 'sample@example.com' }
  end
end
spec/factories/materials.rb
FactoryBot.define do
  factory :material do
    id { 1 }
    title { 'test1' }
    status { 'learning' }
  end
end

deviseのhelperメソッドを呼び出せるように設定

spec/rails_helper.rb
RSpec.configure do |config|
  # 下記コードを追加しました
  config.include Devise::Test::IntegrationHelpers, type: :request
end

下記のとおりRequestSpecを記述

spec/request/materials_spec.rb
require 'rails_helper'

RSpec.describe 'Materials', type: :request do
  let(:user) { FactoryBot.create(:user) }
  let(:learning_material) { FactoryBot.create(:material, user: user) }
  let(:complete_material) { FactoryBot.create(:material, id: 2, status: 'complete', user: user) }

  describe 'GET /materials/:id/edit' do
    before do
      sign_in(user) # deviseのsign_inメソッド利用し、ログイン処理をする
    end
    it 'materialがlearningの場合、リクエストは成功する' do
      get edit_material_path(learning_material)
      expect(response.status).to eq 200
    end
  end
end

2.spec/request/materials_spec.rbを実行!しかし、想定の結果にならず・・・

materials_spec.rbの結果、response.status302でした。
302は、リダイレクトされた際のHTTPステータスコードです。
実際にアプリを動かした際には、成功しているのになぜだろう??

3.原因の調査

binding.irbでテストを止めて、responseの中身を見てみました。
その結果、下記の気になる情報が見つかりました。

@buf=["<html><body>You are being <a href=\"http://www.example.com/users/sign_in\">redirected</a>.</body></html>"]
{"alert"=>"メールアドレスの本人確認が必要です。"}
  • users/sign_inはlogin画面のURL。login画面にredirectされてる。
  • メール認証無しでloginしようとした際のアラートが表示されている。
アカウント作成後のメール認証ができていない!!!ということが発覚しました。

4.対応

userアカウント作成後のメール認証を行うために、deviseのconfirmメソッドを使用しました。
下記が最終的なコードです。テストも成功しました。

spec/request/materials_spec.rb
require 'rails_helper'

RSpec.describe 'Materials', type: :request do
  let(:user) { FactoryBot.create(:user) }
  let(:learning_material) { FactoryBot.create(:material, user: user) }
  let(:complete_material) { FactoryBot.create(:material, id: 2, status: 'complete', user: user) }

  describe 'GET /materials/:id/edit' do
    before do
      user.confirm # devise:メール認証機能(サインインの前に認証必要)
      sign_in(user) # deviseのsign_inメソッド利用し、ログイン処理をする
    end
    it 'materialがlearningの場合、リクエストは成功する' do
      get edit_material_path(learning_material)
      expect(response.status).to eq 200
    end
  end
end

参考URL

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?