ruby-on-railsrspecruby-on-rails-4rspec2authlogic

Rails4 + Authlogic + rspec


Using Rails 4, I am having issues getting Authlogic to see my faked UserSession.

I have set up pages#whoami to render the current user's email address, as a simplistic test.

class PagesController < ApplicationController
  # before_filter :require_user

  def whoami
    render :text => current_user.try(:email) || 'anonymous'
  end
end

in spec/spec_helper.rb:

require "authlogic/test_case"
include Authlogic::TestCase

and my rspec test:

require 'spec_helper'

describe '/whoami' do
  setup :activate_authlogic

  it "should tell me who I am" do
    user = FactoryGirl.create(:user)
    user.should be_valid

    session = UserSession.create(user)
    session.should be_valid

    get '/whoami'
    response.body.should == user.email
  end
end

I updated my application controller to show the current session:

  def require_user
    unless current_user
raise "Current User Session is: #{ current_user_session.inspect}"
    store_location
    flash[:notice] = "You must be logged in to access this page"
    redirect_to new_user_session_url
    return false
  end
end

With before_filter :require_user commented, I correctly get "anonymous". When I uncomment it, I see that my user session is nil. I tried looking through the authlogic code but got lost in Authlogic::Session:Persistence::InstanceMethods#persisting?

I'm trying to debug. Here's where I am so far.

Here, we try to set Authlogic::Session::Base.controller to the test's mock controller: https://github.com/binarylogic/authlogic/blob/master/lib/authlogic/test_case.rb#L109

in my spec, I see that @controller is a Authlogic::TestCase::MockController

and in my spec, I see that Authlogic::Session::Base.controller is set to that Mock Controller.

However, I then check this:

class ApplicationController < ActionController::Base
  ...

  def current_user_session
    raise Authlogic::Session::Base.controller.inspect
    ...
  end
end

and I see Authlogic::ControllerAdapters::RailsAdapter ... so somehow the controller is being set but isn't persisting. I'm wondering whether this has to do with the switch from Rails3 to Rails4?

Any insight into this would be appreciated.

Gem versions for those who are interested: gem rspec-core (2.14.5) gem authlogic (3.3.0) gem rails (4.0.0)


Solution

  • Per https://stackoverflow.com/a/5803121, a request spec is just a thin wrapper around ActionDispatch::IntegrationTest. As such, there is no direct access to the session, unlike a normal controller spec.

    Due to this, it isn't directly possible to log a user in directly with AuthLogic, which does rely on the session and cookies:

    It first authenticates, then it sets up the proper session values and cookies to persist the session.

    For request/integration/api/feature specs, a request directly to the login path will be necessary to set the proper session / cookies behind the scenes. The integration session will then be sent back (just like a normal web request) with the proper values.

    To make life easier you can add a helper method, which you can include for request/integration/api/feature specs:

    # spec/support/auth_logic_helpers.rb
    module Authlogic
      module TestHelper
        # You can call this anything you want, I chose this name as it was similar
        # to how AuthLogic calls it's objects and methods
        def create_user_session(user)
          # Assuming you have this defined in your routes, otherwise just use:
          #   '/your_login_path'
          post user_session_path, login: user.login, password: user.password
        end
      end
    end
    
    # Make this available to just the request and feature specs
    RSpec.configure do |config|
      config.include Authlogic::TestHelper, type: :request
      config.include Authlogic::TestHelper, type: :feature
    end