"неопределенный метод" env "для nil:NilClass" в ошибке "Setup controller for warden" при тестировании устройства с использованием Rspec

Я пытаюсь создать спецификацию для потока выхода, используя 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 будут работать из коробки; я пропустил какую-то конфигурацию? Спасибо.

10 ответов


по-видимому, есть проблемы с Devise::TestHelpers и интеграционное тестирование, так что, возможно, в этом проблема.

https://github.com/plataformatec/devise (упоминается в README, выпусках и т. д.; Также см. связанные вопросы SO):

эти помощники не будут работать для интеграционных тестов, управляемых Capybara или Webrat. Они предназначены для использования только с функциональными пробами. Вместо этого заполните форму или явно укажите пользователя в сеанс;


в Rails 5 Вы должны включить Devise::Test::ControllerHelpers:

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

Посмотреть подробнее:


FWIW похоже, что проблемы были исправлены, однако я столкнулся с проблемой после недостаточно хорошего чтения документации.

Это был наш код:

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

Это означает, что каждый тест будет включать помощников по тестированию, включая модели. Это стало проблемой для нас. Если бы мы прочитали документацию ближе, мы бы заметили, что Devise предлагает ограничить ее только контроллерами с:

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

это решило проблему для нас. Все тесты проходя:)


вот мое решение:

class ActiveSupport::TestCase
  # all the normal stuff
end

class ActionController::TestCase
  include Devise::TestHelpers    
end

как уже говорили другие, вы в том числе Devise::TestHelpers. Это контроллеры тестирования. Если вы все еще хотите автоматически войти в систему тестового пользователя в своих интеграционных тестах, ознакомьтесь с официальным разработать инструкции по его использованию с Capybara.


использование Devise с Capybara

в основном, что вам нужно сделать, это сначала включить тестовый режим Warden:

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

затем (создание и) логин пользователя:

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

пример:

# 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

я встречаю ту же ошибку на 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 / контроллеры / 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

моя версия Devise-4.2.0, поэтому я просто включил

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

в моем файле помощника rails.

в качестве альтернативы вы можете использовать то же самое в своей спецификации как

include Devise::Test::ControllerHelpers

правильный синтаксис для 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 - ограничить только для например, контроллеры, а не модели.

у меня была эта проблема при попытке 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 в A перед (: пример), который также будет работать:

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

чтобы быть полным, с Rails 5 и RSpec я столкнулся с аналогичными проблемами при использовании последних помощников, поскольку они должны быть явно установлены с типом, когда они не используются в качестве суперкласса.

поэтому, если вы обнаружите, что получаете ошибки в тестах модели, есть довольно хороший шанс, что тип не установлен.

вот что я использую в spec_helper:

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

Я знаю, что документы упоминают об этом, но бывают случаи, когда вы можете запустить в более старом блоге, который дает вам более старый подход или обновление из более старой установки, и следующее, что вы знаете, это происходит.