Search code examples
ruby-on-railsrspecdevisecancan

How to do integration testing with RSpec and Devise/CanCan?


If I have a Devise model User, of which only those users with role :admin are allowed to view a certain url, how can I write an RSpec integration test to check that the status returns 200 for that url?

def login(user)
  post user_session_path, :email => user.email, :password => 'password'
end

This was pseudo-suggested in the answer to this question: Stubbing authentication in request spec, but I can't for the life of me get it to work with devise. CanCan is receiving a nil User when checking Ability, which doesn't have the correct permissions, naturally.

There's no access to the controller in integration specs, so I can't stub current_user, but I'd like to do something like this.

describe "GET /users" do
  it "should be able to get" do
    clear_users_and_add_admin #does what it says...
    login(admin)
    get users_path
    response.status.should be(200)
  end
end

NOTE!!!: all this has changed since the question was asked. The current best way to do this is here: http://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara


Solution

  • @pschuegr's own answer got me across the line. For completeness, this is what I did that gets me easily set up for both request specs and controller specs (using FactoryGirl for creating the user instance):

    in /spec/support/sign_in_support.rb:

    #module for helping controller specs
    module ValidUserHelper
      def signed_in_as_a_valid_user
        @user ||= FactoryGirl.create :user
        sign_in @user # method from devise:TestHelpers
      end
    end
    
    # module for helping request specs
    module ValidUserRequestHelper
    
      # for use in request specs
      def sign_in_as_a_valid_user
        @user ||= FactoryGirl.create :user
        post_via_redirect user_session_path, 'user[email]' => @user.email, 'user[password]' => @user.password
      end
    end
    
    RSpec.configure do |config|
      config.include ValidUserHelper, :type => :controller
      config.include ValidUserRequestHelper, :type => :request
    end
    

    Then in request spec:

    describe "GET /things" do
      it "test access to things, works with a signed in user" do
        sign_in_as_a_valid_user
        get things_path
        response.status.should be(200)
      end
    end
    
    describe "GET /things" do
      it "test access to things, does not work without a signed in user" do
        get things_path
        response.status.should be(302) # redirect to sign in page
      end
    end
    

    and similarly, use 'signed_in_as_valid_user' in controller specs (which wraps Devise::TestHelpers sign_in method with a user from FactoryGirl)