“undefined method `env' for nil:NilClass” in &

2019-01-23 10:29发布

I'm trying to create a spec for a sign out flow by using factorygirl to create a user and then use Devise's sign_in method to authenticate the user, then use capybara to click the "Sign Out" link.

I'm getting (what seems to me to be) a strange error when I run the spec:

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

Here's the spec:

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

And my user.rb factory:

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

The error seems to be triggered simply from the line include Devise::TestHelpers, as I've tried commenting out the entire content of the spec and still get the same error.

I thought the Devise test helpers would work out of the box; did I miss some configuration? Thanks.

10条回答
该账号已被封号
2楼-- · 2019-01-23 11:22

In Rails 5 you must include Devise::Test::IntegrationHelpers instead Devise::Test::ControllerHelpers:

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

See more:

查看更多
放荡不羁爱自由
3楼-- · 2019-01-23 11:24

My Devise version is 4.2.0 so I just included

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

in my rails helper file.

Alternatively you can use the same in your spec as

include Devise::Test::ControllerHelpers
查看更多
干净又极端
4楼-- · 2019-01-23 11:32

Like others have already said, you're including the Devise::TestHelpers. That's for testing controllers. If you'd still like to automatically login a test user in your integration tests, check out the official Devise Instructions on using it with Capybara.


Using Devise with Capybara

Basically, what you need to do is first enable Warden's test mode:

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

Then, (create and) login your user:

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
查看更多
老娘就宠你
5楼-- · 2019-01-23 11:34

I was having this problem when trying to sign_in a user in a before hook:

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

Placing sign_in inside the before hook leads to:

Failure/Error: sign_in user

 NoMethodError:
   undefined method `env' for nil:NilClass

But placing it inside an example works fine:

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

But this can be improved, placing the sign_in into a before(:example) that will also work:

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
查看更多
登录 后发表回答