Rspecテスト内でdevise token authをつかってユーザログイン・認証するのはどうするんだ!?
Deviseのやり方はたくさんあるのですがdevise token authは探すのに苦労したので、私と同じ状況に陥っている方のためにこの記事を残しておきます。
やりたいこと
下記の様に、BooksControllerにcreateメソッドがあり、createメソッドを実行するにはユーザが認証が必須(authenticate_user!)だとします。
class BooksController < ApplicationController
before_action :authenticate_user!
def create
book = Book.new(book_params)
if book.save
render json: { status: 'SUCCESS', data: book }
else
render json: { status: 'ERROR', data: book.errors }
end
end
def book_params
params.require(:book).permit(:name, :category, :author, :price)
end
end
Rspecテストでユーザ認証を実装せずに書くと下記の様な感じになりますが・・・
require 'rails_helper'
RSpec.describe 'BooksAPI', type: :request do
describe 'POST /books/create' do
it '本を新規登録する' do
params = {
book: {
name: "Rspecがよくわかる本",
author: "豊田桃子",
category: "プログラミング",
price: 1400
}
}
post books_path, params: params
expect(response).to have_http_status :ok
end
end
end
もちろんauthenticate_user!が通らないので、expected the response to have status code :ok (200) but it was :unauthorized (401)というエラーが返ってきます。
BooksAPI
POST books/create
本を新規登録する (FAILED - 1)
Failures:
1) BooksAPI POST books/create 本を新規登録する
Failure/Error: expect(response).to have_http_status :ok
expected the response to have status code :ok (200) but it was :unauthorized (401)
# ./spec/requests/books_spec.rb:17:in `block (3 levels) in <top (required)>'
Finished in 0.14515 seconds (files took 3.38 seconds to load)
1 example, 1 failure
ということでdevise token authを使ってtokenベースで認証を行っている場合のRspecでのテストの書き方を解説したいと思います。
手順
- ヘルパーモジュールを作り
sign_inメソッドを実装する - ヘルパーモジュールをRspecで読み込む
- テストでヘルパーモジュールを使って
sign_inする
ヘルパーモジュールを作りsign_inメソッドを実装する
libディレクトリ直下にauthorization_spec_helper.rbという名前のファイルを作成します。下記のコードを貼り付けます。
module AuthorizationSpecHelper
def sign_in(user)
post "/auth/sign_in/",
params: { email: user[:email], password: user[:password] },
as: :json
response.headers.slice('client', 'access-token', 'uid')
end
end
userを使ってdevise_token_authのPOSTメソッドにてサインイン後、responseとして返ってきたclient、access-token、uidを返すヘルパーメソッドです。
ヘルパーモジュールをRspecで読み込む
ヘルパーモジュールをRspecで使える様にするために下記の一文を追加します。
RSpec.configure do |config|
# ....
# ....
config.include AuthorizationSpecHelper, type: :request
end
テストでヘルパーモジュールを使ってsign_inする
これでヘルパーモジュールを使う準備ができました。あとはbooks_spec.rbを修正していくだけです。
require 'rails_helper'
RSpec.describe 'BooksAPI', type: :request do
describe 'POST books/create' do
it '本を新規登録する' do
# 下記の2行を追加する
# DBに下記user情報のuserが存在している前提
user = { email: "momoko@test.com", password: "123456" }
auth_tokens = sign_in(user)
params = {
book: {
name: "Rspecがよくわかる本",
author: "豊田桃子",
category: "プログラミング",
price: 1400
}
}
# headersを追加
post books_path, params: params, headers: auth_tokens
expect(response).to have_http_status :ok
end
end
end
これで再度テストを実行してみると・・・・通った!!!
BooksAPI
POST books/create
本を新規登録する
Finished in 0.7509 seconds (files took 4.08 seconds to load)
1 example, 0 failures
これでもOK
require 'rails_helper'
RSpec.describe 'BooksAPI', type: :request do
describe 'POST books/create' do
let(:user) { { email: "momoko@test.com", password: "123456" } }
let(:auth_tokens) { sign_in(user) }
it '本を新規登録する' do
params = {
book: {
name: "Rspecがよくわかる本",
author: "豊田桃子",
category: "プログラミング",
price: 1400
}
}
post books_path, params: params, headers: auth_tokens
expect(response).to have_http_status :ok
end
end
end
調べるまでが大変でしたが、実装自体はとても簡単でした。お役に立てれば嬉しいです!