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

发布于 2024-11-04 08:33:34 字数 914 浏览 1 评论 0原文

如果我有一个 Devise 模型用户,其中只有具有 :admin 角色的用户才可以查看某个 url,我如何编写 RSpec 集成测试来检查该 url 的状态是否返回 200?

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

这是在这个问题的答案中伪建议的:请求规范中的存根身份验证,但我一生都无法让它与设计一起工作。 CanCan 在检查能力时收到一个 nil User,这自然没有正确的权限。

集成规范中无法访问控制器,因此我无法存根 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

注意!!!:自从提出问题以来,这一切都发生了变化。目前最好的方法是在这里: http:// /github.com/plataformatec/devise/wiki/How-To:-用水豚测试

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

夏夜暖风 2024-11-11 08:33:51

我使用了稍微不同的方法,使用 Warden::Test::Helpers。

在我的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

然后将其包含在spec_helper.rb中的RSpec配置中:

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

然后在请求规范本身中:

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

post_via_redirect user_session_path方法相比,这实际上是有效的例如,允许我在 before_filters 中使用 current_user 。

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.

往昔成烟 2024-11-11 08:33:51

您可以创建一个宏 (/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

您还可以包含所需的任何 CanCan 属性。然后,在您的规范中:

describe YourController do
    login_user

    it "should ..." do

    end

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
你是我的挚爱i 2024-11-11 08:33:51

截至 2017 年中期,我认为我们还有一个更好的机会将设备集成到我们的 Rspec 中。我们可以通过辅助方法 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

您还应该附加在 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

然后在方法中,只需将 sign_in 放在方法主体的开头,作为经过身份验证的用户的上下文,一切就都准备好了。最新详细信息可以在设计文档 这里

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

烟若柳尘 2024-11-11 08:33:50

@pschuegr 自己的回答让我越线了。为了完整起见,我所做的可以轻松设置请求规范和控制器规范(使用 FactoryGirl 创建用户实例):

在 /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

然后在请求规范中:

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

类似地,使用控制器规范中的“signed_in_as_valid_user”(使用来自 FactoryGirl 的用户包装 Devise::TestHelpers Sign_in 方法)

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

小霸王臭丫头 2024-11-11 08:33:50

啊,这么近。这确实有效 - 我缺少正确的参数形式和重定向。

post_via_redirect user_session_path, 'user[email]' => user.email, 'user[password]' => user.password

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文