何をしたか
firebase-auth-railsというgemを使ったプロジェクトを作成したのですが、テストコード(rspec)で認証が通らないため、それを解決した方法を備忘録的に書きました。
事象
例えば下記のようなcontrollerがあったとします。
before_action :authenticate_user
で認証が通らないと401エラーになります。
class Api::BooksController < Api::ApplicationController
include Firebase::Auth::Authenticable
before_action :authenticate_user
def create
@book = Book.new(title: params[:title])
if @book.save
render json: { book: @book }
else
render json: { error: @book.errors.messages }, status: :internal_server_error
end
end
end
このcontrollerのテストコードを書いてみます。
headerのAuthorization
には適当な値を入れています。
今回はAuthorizationの値は任意で問題ない想定です。
require 'rails_helper'
RSpec.describe Api::BooksController, type: :request do
describe '#create' do
let (:headers) {
{
'Content-Type': 'application/json',
Authorization: "Bearer token"
}
}
it 'return 200' do
post api_books_path, params: { title: 'タイトル' }.to_json, headers: headers
expect(response).to have_http_status 200
end
end
end
上記のテストコードはテストが通りません。
before_action :authenticate_user
で認証が通らないためです。
そのため上記のテストコードでテストが通るように諸々追加します。
解決方法
spec/support
配下にfirebase_stub.rb
を作成
Firebase::Auth::Authenticable
のauthenticate_entity
というメソッドが引数で指定したuserを返すようなstubを作成します。
Firebase::Auth::Authenticable
module FirebaseStub
def stub_firebase(user)
allow_any_instance_of(Firebase::Auth::Authenticable).to receive(:authenticate_entity).and_return(user)
end
end
spec/rails_helper.rb
にFirebaseStub
を追加
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
# ...略
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
# ...略
RSpec.configure do |config|
# ...略
config.include FirebaseStub
end
最後に先ほどのテストコードにstub_firebase
をbeforeで実行するよう追加します。
userはここではFactoryBotで予め定義されている前提で書きました。
require 'rails_helper'
RSpec.describe Api::BooksController, type: :request do
describe '#create' do
let (:headers) {
{
'Content-Type': 'application/json',
Authorization: "Bearer token"
}
}
+ let(:user) { FactoryBot.create(:user) }
+ before { stub_firebase(user) }
it 'return 200' do
post api_books_path, params: { title: 'タイトル' }.to_json, headers: headers
expect(response).to have_http_status 200
end
end
end
以上の設定によってテストコードで認証が通るかと思います。
また、current_user
を使うと、stub_firebaseの引数のuserが取得できます。
今回はtokenの値を一切使わなかったため、もっといい書き方があるかと思いますが、自分はこう解決しました。