【问题标题】:Testing Sessions in Rails 3 with Rspec & Capybara使用 Rspec 和 Capybara 在 Rails 3 中测试会话
【发布时间】:2023-03-13 09:12:01
【问题描述】:

我正在尝试使用 rspec、factory_girl 和 capybara 编写集成测试。我也安装了黄瓜,但我没有使用它(据我所知)。

我基本上想用我的用户预填充数据库,然后转到我的主页并尝试登录。它应该重定向到 user_path(@user)。

但是,我的 /rspec/requests/ 集成测试中似乎没有保留会话。

我的规范:/rspec/requests/users_spec.rb

require 'spec_helper'

describe "User flow" do

  before(:each) do
    @user = Factory(:user)
  end

  it "should login user" do

    visit("/index")

    fill_in :email, :with => @user.email
    fill_in :password, :with => @user.password
    click_button "Login"
    assert current_path == user_path(@user)
  end
end

返回:

Failures:

  1) User flow should login user
     Failure/Error: assert current_path == user_path(@user)
     <false> is not true.
     # (eval):2:in `send'
     # (eval):2:in `assert'
     # ./spec/requests/users_spec.rb:16

相反,它会重定向到我的 please_login_path - 如果由于任何原因登录失败(或者如果 session[:user_id] 未设置),就会发生这种情况。

如果我尝试放入 session.inspect,它会作为 nil 对象失败。

如果我尝试在控制器测试 (/rspec/controllers/sessions_spec.rb) 中执行此操作,我可以毫无问题地访问会话,并且可以调用 session[:user_id]

【问题讨论】:

  • 我不知道这是否相关,但您应该无法通过键入@user.password 来获取用户密码。这是您的应用程序中的一个安全漏洞。您是否使用纯文本存储密码?
  • 不相关,可能不是安全漏洞。对#password 的调用只返回一个密码,因为它是由工厂在实例变量中设置的。很可能他正在使用 Devise 或类似的东西,不会将密码属性以明文形式保存到数据库中,因此如果该实例变量消失,它将不可用。

标签: ruby-on-rails session rspec capybara


【解决方案1】:

如果您使用的是 Devise,则需要包含 Warden::Test::Helpers(在 spec_helper 的 require 之后是一个好地方),如 in the warden wiki 所述。

对 session 的调用返回 nil,因为 capybara 在作为集成测试运行时不提供对它的访问。

【讨论】:

    【解决方案2】:

    我有同样的问题,虽然填写表格可能是某些人的选择,但我不得不推出自己的身份验证 ruby​​,因为我使用的是第三方身份验证系统(确切地说是 Janrain)......在我的测试我最终使用了这样的东西:

    这是我的 spec/support/test_helpers_and_stuff.rb 中的内容

    module AuthTestHelper
    
      class SessionBackdoorController < ::ApplicationController
        def create
          sign_in User.find(params[:user_id])
          head :ok
        end
      end
    
      begin
        _routes = Rails.application.routes
        _routes.disable_clear_and_finalize = true
        _routes.clear!
        Rails.application.routes_reloader.paths.each{ |path| load(path) }
        _routes.draw do
          # here you can add any route you want
          match "/test_login_backdoor", to: "session_backdoor#create"
        end
        ActiveSupport.on_load(:action_controller) { _routes.finalize! }
      ensure
        _routes.disable_clear_and_finalize = false
      end
    
      def request_signin_as(user)
        visit "/test_login_backdoor?user_id=#{user.id}"
      end
    
      def signin_as(user)
        session[:session_user] = user.id
      end
    
    end
    

    然后在我的请求规范中,使用水豚和硒,我做了以下事情:

    describe "Giveaway Promotion" do
      context "Story: A fan participates in a giveaway", js: :selenium do
        context "as a signed in user" do
    
          before :each do
            @user = Factory(:user)
            request_signin_as @user
          end
    
          it "should be able to participate as an already signed in user" do
            visit giveaway_path
            ....
          end
        end
      end
    end
    

    顺便说一句,在尝试了 this postthis post 的建议解决方案后,我想出了解决方案,但它们都不适合我。 (但他们肯定启发了我的解决方案)

    祝你好运!

    【讨论】:

      【解决方案3】:

      您可能已经从这里继续前进,但我只是在同一个问题上苦苦挣扎。原来这是一个语法问题。我在 :email:password 中使用了符号,而我应该一直使用字符串("email""password")。

      换句话说,尝试改变这个:

      fill_in :email, :with => @user.email
      fill_in :password, :with => @user.password
      

      到这里:

      fill_in "email", :with => @user.email
      fill_in "password", :with => @user.password
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-12
        • 1970-01-01
        相关资源
        最近更新 更多