I work with simple rails 4.1.0
app and do not use devise. I'm testing application controller:
class ApplicationController < ActionController::Base
protected
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def signed_in?
!!current_user
end
helper_method :current_user, :signed_in?
def current_user=(user)
@current_user = user
session[:user_id] = user.try :id
end
# want to test this method
def authenticate_user!
render nothing: true, status: :unauthorized unless current_user
end
end
I have a problem with authenticate_user!
method. Full spec see here. Method Spec:
describe 'authenticate_user!' do
context 'when user logged in' do
before { subject.send(:current_user=, create(:user)) }
it 'do nothing' do
expect(subject.send(:authenticate_user!)).to eq nil
end
end
context 'when user not logged in' do
controller do
before_action :authenticate_user!
def custom
render :text => 'response'
end
end
before do
subject.send(:current_user=, nil)
routes.draw { get 'custom' => 'anonymous#custom' }
get :custom
end
it 'returns unauthorized status' do
expect(response).to be_nil
end
# before do
# subject.send(:current_user=, nil)
# subject.send(:authenticate_user!)
# end
#
# it { render status: :unauthorized }
# it 'renders nothing' do
# expect(response).to be_nil
# end
end
end
It works when user logged in, but when there is no one I tried 2 methods: anonymous controller and simply tried to call this method (commented here). Also i tried to inherit TestApplicationController
from ApplicationController
and the result the same as with anonymous controller. So in this case error is next:
Failure/Error: expect(response).to be_nil
expected: nil
got: #<ActionController::TestResponse:0x007fc03b158580 @mon_owner=nil, @mon_count=0, @mon_mutex=#<Mutex:0x007fc03b0e3938>, @stream=#<ActionDispatch::Response::Buffer:0x007fc03b08bc10 @response=#<ActionController::TestResponse:0x007fc03b158580 ...>, @buf=[" "], @closed=false>, @header={"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"1; mode=block", ....
So it returns some response despite that current_user
set to nil and there is before_action :authenticate_user!
in controller. I guess it ignores it.
In case of
before do
subject.send(:current_user=, nil)
subject.send(:authenticate_user!)
end
it { render status: :unauthorized }
it 'renders nothing' do
expect(response).to be_nil
end
Error is next:
Failure/Error: subject.send(:authenticate_user!)
Module::DelegationError:
ActionController::RackDelegation#status= delegated to @_response.status=, but @_response is nil: #<ApplicationController:0x007fe854c592b8 @_action_has_layout=true, @_routes=nil, @_headers={"Content-Type"=>"text/html"}, @_status=200, @_request=#<ActionController::TestRequest:0x007fe854c78c80 @env={"rack.version"=>[1, 2], "rack.input"=>#<StringIO:0x007fe8544fbf98>, "rack.errors"=>#<StringIO:0x007fe8544f0080>, "rack.multithread"=>true, "rack.multiprocess"=>true, "rack.run_once"=>false, "REQUEST_METHOD"=>"GET", "SERVER_NAME"=>"example.org", "SERVER_PORT"=>"80",
It has no response object to set status.
Also, in this case:
controller do
# before_action :authenticate_user!
def custom
authenticate_user!
render :text => 'response'
end
end
The error is different:
Failure/Error: render :text => 'response'
AbstractController::DoubleRenderError:
Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
So, render works, but 2 times, and it throws an error.
I found a lot of variety similar tests, but mostly it was devise and methods which i perform.
Thanks for help.