This is a spec for a very typical controller with a before_filter
which redirects to login page when a not-logged-in user (a.k.a. a guest) tries to access /projects/new
.
describe ProjectsController do
(...)
describe "GET new" do
context 'when not logged in' do
before { sign_in_nobody }
context 'creating project' do
before { get :new }
it 'denies access' do
expect(response).to be_redirect
end
end
end
end
end
I have specced all possible outcomes of accessing :index
, :show
and :new
for guests, users, admins and superadmins. I didn't have any problems using neither logged or guest users, admins or not – but this is actually the first time this spec touched an action that involves Devise's before_filter :autheticate_user!
and it fails miserably at that.
As you might already suspect – the spec doesn't even reach expect(response).to be_redirect
, it throws a hissy fit before:
Failures:
1) ProjectsController GET new when not logged in creating project denies access
Failure/Error: get :new
ArgumentError:
uncaught throw :warden
# ./spec/controllers/projects_controller_spec.rb:344:in `block (5 levels) in <top (required)>'
I've searched for an answer to question: "how to properly test for unauthenticated (guest) users with rspec and devise", but everyone only talks about having problem with actually logging users in devise for RSpec to use. A problem which I solved thusly:
#spec/support/devise_authenticators.rb
include Devise::TestHelpers
def sign_in_nobody
@request.env["devise.mapping"] = Devise.mappings[:user]
sign_in User.new
end
def sign_in_user
@request.env["devise.mapping"] = Devise.mappings[:user]
sign_in FactoryGirl.create(:user)
end
However it's not the logging in that fails here, it's the "being not logged". So far I got absolutely nothing and I know people HAVE to test those scenarios somehow.
Right now I'm using a walkaround:
before { sign_in_nobody }
context 'creating project' do
it 'denies access' do
expect{ get :new }.to raise_exception("uncaught throw :warden")
end
end
But even tho it's practically correct (uncaught throw :warden
happens only when authenticate_user!
fails so it can be used as an expectation) in theory it feels really dirty.
Any ideas how to do it properly?
(...Maybe I shouldn't be testing this at all, seeing as how the correctness of before_filter authenticate_user!
is Devise's responsibility not mine?)
It should just work. I just spent a while fixing the same problem, and it turned out we had a test helper that overrides process
for controller tests. Devise also overrides it to catch :warden
so I just needed to include Devise::TestHelpers
before including the default params module.
For an example of what I'm talking about when I say we overrode process
, see this answer which describes how to set default params to include format: json
So the lesson is that uncaught throw :warden
happens when authenticate_user!
fails.
So figure out why your the user's authentication is a failing, and you'll have solved your problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With