ruby-on-railsrubyrspec

Modify rails session data for rspec test


I'm writing rspecs for my ruby on rails application, and I'm using google for my authentication. I had my specs all setup fine before I added auth, but now I need some way to test an authenticated user. Here is what one of my specs looks like.

require 'rails_helper'

RSpec.describe 'Test', type: :request do
  it 'should return 200' do
    get '/test'
    expect(response).to have_http_status(:ok)
  end
end

This is failing with a 401 as it rightfully should be.

I need to add the authentication information into the session variable so the controller can recognize that the user is logged in, but there doesn't seem to be a way to modify the session variable from rspec. I guess I could make a test google account and setup some helpers that would log me into a real google account, but it seems like there should be a better way to write tests. I've seen a couple of examples online, but most seem to be for older versions of rails.

I'm on Rails 7.0.4.3 and ruby 3.2.2

Edit: It occurs to me that I should probably include my auth code.

class ApplicationController < ActionController::Base
  before_action :require_auth

  private

  def require_auth
    user_id = session[:user_id]

    if !user_id.present?
      head :unauthorized
    else
      @auth_user = User.find(user_id)

      if !@auth_user.present?
        head :unauthorized
      end
    end
  end
end


Solution

  • As far as I know there is no way of easily modifying session variables in the test setup for RSpec request specs unless you add the rack_session_access gem or a similar solution.

    One approach is to just mock the auth_user object in the tests that require a logged in user.

    class ApplicationController < ActionController::Base
      before_action :require_auth
    
      private
    
      def auth_user
        @auth_user ||= User.find_by(id: session[:user_id])
      end
    
      def require_auth
        head(:unauthorized) unless auth_user.present?
      end
    end
    
    # spec/support/test_macros.rb
    module TestMacros
      def log_in(user)
        allow_any_instance_of(ApplicationController).to receive(:auth_user).and_return(user)
      end
    end
    
    # spec/rails_helper.rb
    RSpec.configure do |config|
      config.include(TestMacros)
    end
    
    it 'should return 200' do
      user = # create or fabricate user
      log_in(user)
      get '/test'
      expect(response).to have_http_status(:ok)
    end