可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
Apparently there are issues with Devise::TestHelpers and integration testing, so perhaps that's the problem here.
https://github.com/plataformatec/devise (mentioned in README, Issues, etc.; also see related SO questions):
These helpers are not going to work for integration tests driven by Capybara or Webrat. They are meant to be used with functional tests only. Instead, fill in the form or explicitly set the user in session;
回答2:
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:
FWIW it seems like the issues have been fixed, however I ran into the issue after not reading the documentation well enough.
This was our code:
RSpec.configure do |config| ... config.include Devise::TestHelpers ... end
This means every test will include the test helpers, including models. This wound up being the issue for us. Should we have read the documentation closer we would have noticed Devise suggests limiting it to only controllers with:
RSpec.configure do |config| ... config.include Devise::TestHelpers, type: :controller ... end
This solved the issue for us. All tests passing :)
回答4:
Here's my solution:
class ActiveSupport::TestCase # all the normal stuff end class ActionController::TestCase include Devise::TestHelpers end
回答5:
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
回答6:
I meet the same error on rails 5. Here's my solution
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:
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
回答8:
The correct syntax for Rails 5 / Devise (4.2.0) is
RSpec.configure do |config| config.include Devise::Test::ControllerHelpers, :type => :controller end
Devise::TestHelpers are deprecated so use Devise::Test::ControllerHelpers :type => :controller - to limit only for controllers and not models for example.
回答9:
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
回答10:
For the sake of being complete, with Rails 5 and RSpec I have run into similar issues when using the latest helpers, as they need to be set explicitly with the type when not used as a superclass.
So if you find yourself receiving there errors in your model tests there's a pretty good chance the type is not set.
Here's what I use in the spec_helper:
config.include Devise::Test::ControllerHelpers, type: :controllers config.include Devise::Test::ControllerHelpers, type: :view config.include Devise::Test::IntegrationHelpers, type: :feature
I know that the docs do mention this, but there are times when you may run across an older blog that gives you an older approach, or upgrading from an older setup, and next thing you know this happens.