使用Rspec测试Devise时,“setup_controller_for_warden”错误中的“未定义方法`env'为nil:NilClass”

问题描述 投票:36回答:10

我正在尝试使用factorygirl创建用户创建一个注销流程规范,然后使用Devise的sign_in方法对用户进行身份验证,然后使用capybara单击“注销”链接。

当我运行规范时,我得到(在我看来是什么)一个奇怪的错误:

Failures:

  1) Sign out flow successfully redirects to the welcome index (root)
     Failure/Error: Unable to find matching line from backtrace
     NoMethodError:
       undefined method `env' for nil:NilClass
     # /home/vagrant/.rvm/gems/ruby-2.0.0-p576/gems/devise-3.4.1/lib/devise/test_helpers.rb:24:in `setup_controller_for_warden'

Finished in 0.00226 seconds (files took 3.32 seconds to load)
1 example, 1 failure

这是规格:

require 'rails_helper'

describe "Sign out flow" do

  include Devise::TestHelpers

  describe "successfully" do
    it "redirects to the welcome index (root)" do
      user = create(:user)
      sign_in user


      within '.user-info' do
        click_link 'Sign Out'
      end

      expect(current_path).to eq root_path
    end
  end
end

还有我的user.rb工厂:

FactoryGirl.define do
  factory :user do
    name "Fake User"
    sequence(:email, 100) { |n| "person#{n}@example.com" }
    password "helloworld"
    password_confirmation "helloworld"
    confirmed_at Time.now
  end
end

该错误似乎只是从include Devise::TestHelpers行触发,因为我已经尝试评论规范的整个内容并仍然得到相同的错误。

我认为Devise测试助手可以开箱即用;我错过了一些配置吗?谢谢。

ruby-on-rails-4 rspec devise capybara factory-bot
10个回答
20
投票

显然Devise::TestHelpers和集成测试存在问题,所以也许这就是问题所在。

https://github.com/plataformatec/devise(在自述文件,问题等中提到;也见相关的SO问题):

这些助手不适用于由Capybara或Webrat驱动的集成测试。它们仅用于功能测试。相反,填写表单或在会话中明确设置用户;


2
投票

为了完整起见,使用Rails 5和RSpec时,我在使用最新的帮助程序时遇到了类似的问题,因为它们需要在不用作超类时用类型显式设置。

因此,如果您发现自己在模型测试中遇到错误,那么很可能没有设置类型。

这是我在spec_helper中使用的内容:

  config.include Devise::Test::ControllerHelpers, type: :controller
  config.include Devise::Test::ControllerHelpers, type: :view
  config.include Devise::Test::IntegrationHelpers, type: :feature

我知道文档确实提到了这一点,但是有时候你可能会遇到一个较旧的博客,它会给你一个较旧的方法,或者从较旧的设置升级,接下来你知道会发生这种情况。


39
投票

在Rails 5中,你必须包括Devise::Test::IntegrationHelpers而不是Devise::Test::ControllerHelpers

# rails_helper.rb
config.include Devise::Test::IntegrationHelpers, type: :feature

看更多:


18
投票

FWIW似乎已经修复了问题,但是在没有充分阅读文档之后我遇到了问题。

这是我们的代码:

RSpec.configure do |config|
  ...  
  config.include Devise::TestHelpers
  ...
end

这意味着每个测试都将包括测试助手,包括模型。这对我们来说是个问题。我们是否应该仔细阅读文档,我们会注意到Devise建议将其限制为只有控制器:

RSpec.configure do |config|
  ...  
  config.include Devise::TestHelpers, type: :controller
  ...
end

这解决了我们的问题。所有测试通过:)


11
投票

这是我的解决方案:

class ActiveSupport::TestCase
  # all the normal stuff
end

class ActionController::TestCase
  include Devise::TestHelpers    
end

8
投票

我在rails 5上遇到了同样的错误。这是我的解决方案

spec/rails_helper.rb

RSpec.configure do |config|
  config.include Devise::TestHelpers, type: :controller
  config.include Devise::TestHelpers, type: :view
  config.include Warden::Test::Helpers
end

spec/controllers/your_controller_spec.rb

RSpec.describe YourController, type: :controller do
  before(:all) do
  user = FactoryGirl.create(:user)
  login_as user, scope: :user
end

it "#index" do
  get "index"
  expect(response).to render_template(:index)
  expect(response).to have_http_status(200)
end

$ rspec --tag focus

Run options: include {:focus=>true}
DashboardController
#index
Finished in 3.9 seconds (files took 3.5 seconds to load)
1 example, 0 failures

7
投票

像其他人已经说过的那样,你包括了Devise::TestHelpers。这是为了testing controllers。如果您仍想在集成测试中自动登录测试用户,请查看官方Devise Instructions on using it with Capybara


与Capybara一起使用Devise

基本上,您需要做的是首先启用Warden的测试模式:

include Warden::Test::Helpers
Warden.test_mode!

然后,(创建并)登录您的用户:

user = FactoryGirl.create(:user)
login_as(user, scope: :user)

Example:

# spec/features/survey_spec.rb
require 'rails_helper'

feature 'survey app' do
    include Warden::Test::Helpers

    let(:user)   { create(:user) }
    let(:survey) { create(:survey_with_questions) }

    before do
        # Sign the User in
        Warden.test_mode!
        login_as(user, scope: user)
    end

    it 'renders the survey' do
        visit survey_show_path(survey)
        expect(page).to have_content(survey.title)
    end
end

2
投票

我的Devise版本是4.2.0所以我只是包括在内

config.include Devise::Test::ControllerHelpers, type: :controller

在我的rails帮助文件中。

或者,您可以在规范中使用相同的

include Devise::Test::ControllerHelpers

2
投票

Rails 5 / Devise(4.2.0)的正确语法是

RSpec.configure do |config|
  config.include Devise::Test::ControllerHelpers, :type => :controller
end
  • Devise::TestHelpers已被弃用,因此请使用Devise::Test::ControllerHelpers
  • :type => :controller - 仅限制控制器而不是模型。

2
投票

我在尝试使用前钩子中的sign_in用户时遇到了这个问题:

before(:context) do
  create(:skill, name: 'Google Maps API'.downcase)
  user = create(:user)
  sign_in user
end

sign_in放在前钩内导致:

Failure/Error: sign_in user

 NoMethodError:
   undefined method `env' for nil:NilClass

但将它放在一个示例中工作正常:

shared_examples_for('an authenticated resource.') do
  describe 'An authenticated request' do
    it "responds with HTTP status OK" do
      user = create(:user)
      sign_in user
      make_request
      expect(response).to have_http_status(:ok)
    end
  end
end

但是这可以改进,将sign_in放入before(:example)也可以工作:

context 'allow search by keyword' do
  let!(:skill){ create(:skill, name: 'Google Maps API'.downcase) }
  let!(:user) { create(:user) }

  before(:example) { sign_in user }

  it 'finds matching records' do
    get :search, name: "Google Maps API", format: :json
    expect(assigns(:skills).size).to be(1)
  end
  it 'finds records that start with keyword'
  it 'finds records that end with keyword'
  it 'finds records that contains keyword'
end
© www.soinside.com 2019 - 2024. All rights reserved.