wardencommunity/warden

request.env['warden'] is nil in Rails controller test

manubo opened this issue · 11 comments

In my controller tests in Rails 4.2.2 (MiniTest), request.env['warden'] is always nil in the tested controller. I include Warden::Test::Helpers into ActiveSupport::TestCase.

# test_helper.rb
class ActiveSupport::TestCase
  include Warden::Test::Helpers
end

I also have Capybara tests, where the issue does not occur. What am I missing?

# controllers/concern/authenticatable.rb
module Authenticatable
  extend ActiveSupport::Concern

  def self.included(base)
    base.helper_method :warden, :current_user, :signed_in?
  end

  def logout(scope = default_scope)
    warden.logout(scope)
  end

  def signed_in?(scope = default_scope)
    !current_user(scope).nil?
  end

  def current_user(scope = default_scope)
    warden.user(scope)
  end

  def warden
    request.env['warden'] # <-- is nil in MiniTest controller tests
  end

  def authenticate!(scope = default_scope)
    warden.authenticate!(scope: scope)
  end

  private

  def default_scope
    warden.config.default_scope
  end
end

# controllers/application_controller.rb
class ApplicationController < ActionController::Base
  include Authenticatable

  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
end

# test/controllers/accounts_controller_test.rb
require 'test_helper'

class AccountsControllerTest < ActionController::TestCase
  setup do
    @account = accounts(:cash)
    login_as users(:john)
  end

  teardown do
    Warden.test_reset!
  end

  test "should get index" do
    get :index
    assert_response :success
    assert_not_nil assigns(:accounts)
  end
end

I realized the middleware stack is not processed by rails in controller tests. Thus, this is not a Warden issue, please ignore my post. I went with this solution.

Ch4s3 commented

Might be good to post @manubo's solution in a wiki to avoid link rot.

@manubo can you test this branch: https://github.com/acaron/warden/tree/fix-test-helpers
Add Warden::Test::Mock and you can call warden to get a valid warden object (remove your current solution to test this). I needed the exact same thing! Tell me if your tests pass because env and app are simulate. The current version 1.2.5 implement this in Warden::Test::Helpers if that is easier for you to test on. It must be changed because it breaks tests for many people who don't need this!

Version 1.2.6 should solve your problem if you add Warden::Test::Mock and call warden.

@acaron I just hit this exact issue. In this solution, do we need to monkey patch Authenticatable#warden to return Warden::Test::Mock#warden instead of request.env['warden']?

Also, I just noticed that this fails if you don't have a :password strategy defined. the proxy raises "Invalid strategy password". I got around it for now by adding a duplicate strategy with a different name, but I don't have immediate suggestions offhand for how to fix that.

@orenmazor you only have to include Warden::Test::Mock and use directly warden instead of request.env['warden']. No monkey patch needed anymore. I don't have have strategy password defined in my tests and it works. Do you have a code sample?

I did, but unfortunately I refactored it out. I'll spin up a sample app for you this weekend.

1v commented

This worked for me:

    @request.env['warden'] = @warden

Controller test helpers for Warden _Kentaro Imai.pdf

Here is a PDF of the article linked in #117 (comment). I had to find it on the wayback machine, so leaving it here in case it disappears.

Controller test helpers for Warden _Kentaro Imai.pdf

Here is a PDF of the article linked in #117 (comment). I had to find it on the wayback machine, so leaving it here in case it disappears.

Nice idea! thanks! here is the same pdf but cleaner (I removed unrelated divs and texts which were covering part of the code):
Controller test helpers for Warden _Kentaro Imai.pdf