In a Rails 3.28 application using Devise, I setup a controller that checks whether a user is logged in or not with if user_signed_in?. Once the tests hit this line, I always get a undefined method 'authenticate!' for nil:NilClass error. I wanted to test some code in a scenario that no user is logged in.
I am thinking that I need to setup the tests according to the options specified in the Devise Wiki here, however, all the instructions pertain to rspec.
In particular, I think I need to have the following to work in minitest:
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
end
Has anyone succeded in setting this up to have Devise work with minitest?
Add the following to your minitest_helper.rb file:
class MiniTest::Rails::ActionController::TestCase
include Devise::TestHelpers
end
Related
I want to make sure this link is displayed only when both user values are set:
- if current_user.dms.present? and current_user.dms_id.present?
= link_to "Import Items", "#"
How do I stub out that current_user variable?
Did you make sure you add the helpers for both views and controllers?
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.include Devise::TestHelpers, :type => :view
end
If you are using the Devise Gem for your current_user, have you tried using the Devise Test Helpers (Devise::TestHelpers)? They allow you to sign and in and sign out a user, and therefore access the current_user record in your controller and view specs.
The Devise Wiki has a page on this:
Devise Wiki for TestHelpers
I try to test devise user authentication, the problem I've done everything according to samples, however the code still doesn't work.
spec/support/devise/devise_support.rb
module ValidUserRequestHelper
def sign_in_as_a_valid_user
#user ||= Fabricate(:simple_user)
post_via_redirect user_session_path, 'user[email]' => #user.email, 'user[password]' => #user.password
end
end
RSpec.configure do |config|
config.include ValidUserRequestHelper, :type => :request
end
spec/spec_helper.rb
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
However when I run test, it fails on the calling to `sign_in_as_a_valid_user'
undefined local variable or method `sign_in_as_a_valid_user' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0xc57a0c4>
I don't have idea how to debug this.
The test code is
require 'spec_helper'
describe User do
before do
sign_in_as_a_valid_user
end
...
when you write this in your rspec configuration
RSpec.configure do |config|
config.include ValidUserRequestHelper, :type => :request
end
you tell rspec to only include this helper for request spec. those are typically located in spec/request. deriving from the example of your spec that has describe User in it, i assume that you are writing a model spec, typically located in spec/model. so when running the spec, rspec won't include it for that spec!
if you just remove the :type => :request it will get included everywhere. keep in mind, that there is usually a good reason for this kind of restrictions. for example a helper that only works with a fake browser, like it is done in request specs.
I want to test every route in an application, and learned I should do that in an integration test: Where to test routes in ruby on rails
However I'm getting the following error:
NoMethodError: undefined method `authenticate?' for nil:NilClass
/usr/local/Cellar/ruby/1.9.3-p194/lib/ruby/gems/1.9.1/gems/devise-2.1.2/lib/devise/rails/routes.rb:286:in `block in authenticated'
It's well-mentioned online that you can't use Devise::TestHelpers in integration testing --
Devise Google Group,
Devise Github page
How can I test routes like the following?
# config/routes.rb
devise_for :users
authenticated :user do
root to: 'static#home'
end
root to: 'static#landing'
I am running test unit tests with $ rake test:integration
Devise::TestHelpers work by putting things directly into your session. When running integration tests with Capybara, you don't have access to the server-side session. You just have access to the browser.
In our application, our integration tests use helper methods like this, that interact with Devise through the user interface:
def authenticate(user, password = nil)
password ||= FactoryGirl.attributes_for(:user)[:password]
visit new_user_session_path
fill_in 'email', with: user.email
fill_in 'password', with: password
click_on 'Login'
expect(current_path).to eq welcome_path
end
Integration tests are important for your application work flow. They can tell about your URL definition more clearly.
Check the post by nicholaides, that explains the cause of this error and the solution in Authenticated routes.
Still the problem is:
Devise has its own methods and you can't use Devise::TestHelpers in ruby. So how can you test? Well you need to include the Devise::TestHelpers somehow.
Well, if you're using RSpec, you can put the following inside a file named spec/support/devise.rb:
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
This is specified here.
But wait.......... Again, you can run into this same issue with Test::Unit.
Then?
So, you just need to add the devise test helpers to test/test_helper.rb.
class ActiveSupport::TestCase
include Devise::TestHelpers
end
I am trying to get a previously passing rspec "view spec" to pass after adding Devise's user_signed_in? method to the view template in question. The template looks something like this:
<% if user_signed_in? %>
Welcome back.
<% else %>
Please sign in.
<% endif %>
The view spec that was passing looks something like this:
require "spec_helper"
describe "home/index.html.erb" do
it "asks you to sign in if you are not signed in" do
render
rendered.should have_content('Please sign in.')
end
end
The error it produces after adding the call to user_signed_in? is:
1) home/index.html.erb asks you to sign in if you are not signed in
Failure/Error: render
ActionView::Template::Error:
undefined method `authenticate' for nil:NilClass
# ./app/views/home/index.html.erb:1:in `_app_views_home_index_html_erb__1932916999377371771_70268384974540'
# ./spec/views/home/index.html.erb_spec.rb:6:in `block (2 levels) in <top (required)>'
There are plenty of references to this error around the web, but I have yet to find an answer descriptive enough that I can get my test passing again. I believe the problem has something to do with the view (which is being testing in isolation from any models/controllers) not having some key Devise infrastructure available. Your suggestions are appreciated.
Also, once the test passes, how would I test the other path (user already signed in)? I presume it will be very similar. Thanks.
The error you're receiving is because you need to include the devise test helpers
Generally you'll add this (and you might already have) to spec/support/devise.rb
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
But since you're creating a view spec, you'll want something like this:
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.include Devise::TestHelpers, :type => :view
end
Have a look at Rails Composer, this will guide you through a new rails project creation with options like testing, UI etc..
Create a sample project, cool thing is it will create all the test for you including view testing with devise. Then you can get an idea from those testing specs.
worked for me :D
HTH
My helper code looks like this (and works fine btw):
module ProvidersHelper
def call_to_review(provider)
if user_signed_in? && review = Review.find_by_provider_id_and_user_id(provider.id, current_user.id)
link_to "Edit Your Review", edit_provider_review_path(provider, review), :class => "call_to_review"
else
link_to "Review This Provider", new_provider_review_path(provider), :class => "call_to_review"
end
end
end
Unfortunately, this produces the following error when I run my tests:
undefined method `user_signed_in?' for #<ActionView::Base:0x00000106314640>
# ./app/helpers/providers_helper.rb:3:in `call_to_review'
Clearly the Devise::Controllers::Helpers are not being included in my helpers when rspec is running the test. Any suggestions that might help this work?
Edit: to provide a bit more information, my spec_helper does have this:
config.include Devise::TestHelpers, :type => :controller
config.include Devise::TestHelpers, :type => :view
config.include Devise::TestHelpers, :type => :helper
(Sadly, I couldn't get it to work with :type => [:controller, :view, :helper])
Anyway I believe that these lines add the sign_in(scope, object) (and other) test helpers to your tests. They don't add the helpers that you would actually leverage in your controller / view code.
I think the philosophy of rspec is to test the view/helpers/models in total isolation as much as possible. So in this case, i would stub out the user_signed_in? and returns false or true and my results should change appropriately.
This gives you a clean isolated test.
Are you currently including the test Helpers as suggested in the wiki?
# spec_helper.rb:
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
type would be probably helper in your case.
Maybe try putting this is in a before block?
#request.env["devise.mapping"] = :user
This has not been solved to my satisfaction and probably never will be. I think the best work-around for now is to manually stub helper.current_user and any other Devise methods you use in the helper method you're testing.
Yes, Devise provides these stubbing facilities for controller and view specs. I suspect that it's something about the combination of Devise/Rails/Test::Unit/Rspec that proves this to be difficult for helper specs.
my helper test uses Devise and cancan and works without stubbing anything (but I'm not sure if it is better to actually stub everything).
Here's the gist: https://gist.github.com/shotty01/5317463
i also tried to add user_signed_in? in the helper method and it still was fine.
The following is required:
add to spec_helper.rb:
config.include Devise::TestHelpers, :type => :helper
My spec gems:
rspec (2.10.0)
rspec-core (2.10.1)
rspec-expectations (2.10.0)
rspec-mocks (2.10.1)
rspec-rails (2.10.1)
of course you can sign in without factory girl, you just have to rewrite the ValidUserHelper methods to create a user directly or from fixtures.