简体   繁体   English

如何使用 RSpec 和 Devise/CanCan 进行集成测试?

[英]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? 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.这是这个问题的答案中的伪建议: Stubbing authentication in request spec ,但我一辈子都无法让它与 devise 一起工作。 CanCan is receiving a nil User when checking Ability, which doesn't have the correct permissions, naturally. CanCan 在检查没有正确权限的能力时自然会收到一个 nil 用户。

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.在集成规范中无法访问 controller,所以我不能存根 current_user,但我想做这样的事情。

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目前最好的方法是: http://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara

@pschuegr's own answer got me across the line. @pschuegr 自己的回答让我越界了。 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):为了完整起见,我所做的就是让我轻松设置请求规范和 controller 规范(使用 FactoryGirl 创建用户实例):

in /spec/support/sign_in_support.rb:在 /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)同样,在 controller 规范中使用 'signed_in_as_valid_user'

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

I used a slightly different approach, using the Warden::Test::Helpers.我使用了一种稍微不同的方法,使用 Warden::Test::Helpers。

In my spec/support/macros.rb I added:在我的 spec/support/macros.rb 我添加了:

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:然后将其包含在 spec_helper.rb 中的 RSpec 配置中:

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.post_via_redirect user_session_path方法相比,这实际上是有效的,并且允许我在 before_filters 中使用 current_user,例如。

As of mid 2017, we have one more, in my opinion better opprotunity to integrate devise in our Rspecs.截至 2017 年中期,我们还有一个更好的机会将 devise 集成到我们的 Rspec 中。 We are able to utilize stub authentization with helper method sign in defined as described below:我们可以使用带有帮助方法sign in存根验证,如下所述:

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:您还应该 append 在spec_helper.rbrails_helper.rb参考新创建的文件:

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.然后在方法中,只需将方法体sign_in放在方法的开头,以获得经过身份验证的用户的上下文,就可以了。 Up to date details can be found in devise docs here最新的详细信息可以在 devise 文档中找到

You can create a macro (/spec/support/controller_macros.rb) and write something like:您可以创建一个宏 (/spec/support/controller_macros.rb) 并编写如下内容:

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.您还可以包含所需的任何 CanCan 属性。 Then, in your spec:然后,在您的规范中:

describe YourController do
    login_user

    it "should ..." do

    end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM