It depends on if you want to actually test your authentication too on every request. If that is the case, you need to set a valid auth headers for that user, like this:
RSpec.describe 'Api::V1::Articles', type: :request do
let(:user) { FactoryBot.create :user }
let(:auth_header) { { 'Authorization' => "TOKEN#{user.generate_bearer_token}" } }
describe 'POST /create' do
context "with valid user params" do
let(:articles_params) { {article:{ name: "art1" } }}
it 'creates a new article' do
expect {
post "/api/v1/posts/1/articles", params: articles_params, headers: auth_header
}.to change(Article, :count).by(1)
end
end
end
end
Note that you need to change "TOKEN#{user.generate_bearer_token}"
in the third line of the above example with an implementation from your application to generate a valid bearer token for the given user.
Or you can decide to not care about how authentication is implemented, and mock the whole authentication logic in the test. Then you have, of course, to test the authentication logic in other places to ensure the implementation actually works in general.
To mock the implementation, I would first move parts of the authenticate_action
method into a class method in the user model or a class in the Auth
namespace and then just call that one method in authenticate_action
:
# in app/models/user.rb
def self.find_by_bearer_token(token)
id = Auth::TokenValidator.call(token).result
User.find(id) if id
end
# in your application_controller
def authenticate_action
@user = User.find_by_bearer_token(bearer_token)
render json: 400, status: :unauthorized unless @user
end
With such a class method, it is much easier to mock that method in the test and return whatever user you want to use for the spec:
RSpec.describe 'Api::V1::Articles', type: :request do
let(:user) { FactoryBot.create :user }
before { allow(User).to receive(:find_by_bearer_token).and_return(user) }
describe 'POST /create' do
context "with valid user params" do
let(:articles_params) { {article:{ name: "art1" } }}
it 'creates a new article' do
expect {
post "/api/v1/posts/1/articles", params: articles_params
}.to change(Article, :count).by(1)
end
end
end
end