ruby-on-railstestingruby-on-rails-7pundit

Rails controller test defining current user


I'm having a small issue with testing in Rails 7 (API mode). I try to set the current user manually in my test, this way, when the server resolve the route/method and controller, it checks for authentication, which is skipped in testing environment, and then returns what its supposed to return. Unfortunaly, the User.current is reset somehow and I'm not sure why and where. I do not have other method that is called before reaching the controller.

require 'test_helper'
class ThingControllerTest < ActionDispatch::IntegrationTest

  test "call method my_method" do
    me = users(:me)
    User.current = me
    get("/api/users/#{me.id}/do-the-thing")
    assert_response :success
  end

end
class ApplicationController < ActionController::Base

  before_action do |c|
    authenticate_user
  end

  def authenticate_user
    return User.current if Rails.env.test?
    # lots of stuff going on otherwise
  end

end
class ThingController < ApplicationController
  # GET /users/:id/do-the-thing
  def the_thing
    user = User.find(params[:id])
    if (User.current != user) # User.current is nil here
      render json: {}, status: 500
      return
    end
    render json: {}, status: 200
  end

end

I tried setting manually the current user but it seems like when it lands in the authenticate_user, the User.current is already nil. Thanks !


Solution

  • Found a workaround, I made an AuthHelper module for my controller tests, this way my ApplicationController::authenticate_user has no longer the weird condition for the Rails environment.

    # test/test_helpers/auth_helper.rb
    module AuthHelper
    
      def headers_jwt_auth(user)
        iat = Time.now
        exp = iat + 4.hours
        payload = {iat: iat.to_i, exp: exp.to_i, some_other_stuff: nil}
        secret = Rails.application.credentials.jwt_secret
        return { Authorization: JWT.encode(payload, secret, 'HS256') }   
      end
    
    end
    

    and

    #  test/controllers/thing_controller_test.rb
    require 'test_helper'
    require "test_helpers/auth_helper"
    
    class ThingControllerTest < ActionDispatch::IntegrationTest
    
      include AuthHelper
      
      test "call method my_method" do
        me = users(:me)
        User.current = me
        get("/api/users/#{me.id}/do-the-thing",  headers: headers_jwt_auth(User.current))
        assert_response :success
      end
    
    end