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

前端 未结 6 586
情书的邮戳
情书的邮戳 2020-12-04 08:43

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 stat

相关标签:
6条回答
  • 2020-12-04 09:28

    I found this link very helpful https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)

    0 讨论(0)
  • 2020-12-04 09:29

    I used a slightly different approach, using the Warden::Test::Helpers.

    In my spec/support/macros.rb I added:

    module RequestMacros
      include Warden::Test::Helpers
    
      # for use in request specs
      def sign_in_as_a_user
        @user ||= FactoryGirl.create :confirmed_user
        login_as @user
      end
    end
    

    And then included that in RSpec's config in spec_helper.rb:

    RSpec.configure do |config|
      config.include RequestMacros, :type => :request
    end
    

    And then in the request specs themselves:

    describe "index" do
      it "redirects to home page" do
        sign_in_as_a_user 
        visit "/url"
        page.should_not have_content 'content'
      end
    end
    

    In contrast to the post_via_redirect user_session_path method, this actually works and allows me to use current_user in before_filters, for example.

    0 讨论(0)
  • 2020-12-04 09:40

    @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)

    0 讨论(0)
  • 2020-12-04 09:46

    Ah, so close. This does the trick - I was missing the proper parameter form, and the redirecting.

    post_via_redirect user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
    
    0 讨论(0)
  • 2020-12-04 09:46

    You can create a macro (/spec/support/controller_macros.rb) and write something like :

    module ControllerMacros
      def login_user
        before(:each) do
          @request.env["devise.mapping"] = :user
          @user = Factory(:user)
          sign_in @user
        end
      end
    end
    

    You can also include any CanCan attributes you want. Then, in your spec :

    describe YourController do
        login_user
    
        it "should ..." do
    
        end
    
    0 讨论(0)
  • 2020-12-04 09:49

    As of mid 2017, we have one more, in my opinion better opprotunity to integrate devise in our Rspecs. We are able to utilize stub authentization with helper method sign in defined as described below:

    module ControllerHelpers
        def sign_in(user = double('user'))
          if user.nil?
            allow(request.env['warden']).to receive(:authenticate!).and_throw(:warden, {:scope => :user})
            allow(controller).to receive(:current_user).and_return(nil)
          else
            allow(request.env['warden']).to receive(:authenticate!).and_return(user)
            allow(controller).to receive(:current_user).and_return(user)
          end
        end
      end
    

    You should also append in spec_helper.rb or rails_helper.rb reference to newly created file:

    require 'support/controller_helpers'
      ...
      RSpec.configure do |config|
        ...
        config.include Devise::TestHelpers, :type => :controller
        config.include ControllerHelpers, :type => :controller
        ...
      end
    

    Then in method just place at the beginning of the method body sign_in for context for authenticated user and you are all set. Up to date details can be found in devise docs here

    0 讨论(0)
提交回复
热议问题