how to stub or mock authlogic current_user in view specs - ruby-on-rails-3

i am trying to write some views specs for my rails app, but i stumble on this error:
ActionView::Template::Error:
undefined local variable or method `current_user' for #<#<Class:0x007fa47d2612d0>:0x007fa47e267710>
Here is how i wrote my view spec :
describe "/newsletters/index.html.erb" do
include NewslettersHelper
include Authlogic::TestCase
def current_user(stubs = {})
#current_user ||= mock_model(User, stubs)
end
def user_session(stubs = {}, user_stubs = {})
#current_user_session ||= mock_model(UserSession, {:user => current_user(user_stubs)}.merge(stubs))
end
def login(session_stubs = {}, user_stubs = {})
UserSession.stub!(:find).and_return(user_session(session_stubs, user_stubs))
end
def logout
#user_session = nil
end
context "without a logged-in user" do
before(:each) do
activate_authlogic
logout()
assigns[:newsletters] = #newsletters = [ mock_model(Newsletter, :titre => "value for titre",
:sommaire => "value for sommaire", :content => "value for content") ]
end
it "renders a list of newsletters" do
# pending("find how to mock authlogic current user in views spec")
render
rendered.should have_selector("tr>td") do |row|
row.should have_content("value for titre")
end
rendered.should have_selector("tr>td") do |row|
row.should have_content("value for sommaire")
end
rendered.should have_selector("tr>td") do |row|
row.should have_content("value for content")
end
end
end

Try controller.stub(:current_user) { mock_model(User) } I think it should help

The view spec is an isolated context so you need to stub the current_user method in the view context.
view.stub(:current_user).and_return(mock_model(User))
For further reading on the view spec I suggest you the view spec page on relish

None of the answers worked for me (using rspec 3.9 here), as I was getting errors like #<#<Class:0x007fb9ca387dc8> does not implement: current_user, trying to stub the view or controller objects, so I had to do it like:
before do
controller.singleton_class.class_eval do
# Just defining methods to being stubbed later
def current_user; end
def current_account; end
helper_method :current_user, :current_account
end
allow(controller).to receive(:current_user).and_return(user)
allow(controller).to receive(:current_account).and_return(account)
end
not the prettiest solution, but it worked.

Related

Access session in Helper file ? Rails 3

how to get session in helper file?
UserHelper.rb
module UsersHelper
def self.auth login, password
user = Users.where("firstname = :firstname AND password = :password", {:firstname => login, :password => password})
if user != []
return true
else
return false
end
end
def self.is_auth? level
puts #session
user = Users.where("firstname = :firstname AND password = :password", {:firstname => #session[:firstname], :password => #session[:password]})
if user != []
return true
else
return false
end
end
end
Admin_controller.rb
class AdminController < ApplicationController
include Rails.application.routes.url_helpers
def initialization
#session = session
end
def index
#session = session
if UsersHelper.is_auth?(2)
render :text => "ssssss"
end
end
def auth
if params[:send] != nil
if UsersHelper.auth params[:firstname], params[:password]
session[:firstname] = params[:firstname]
session[:password] = params[:password]
redirect_to :action => "index"
else
#error = 1
end
end
end
def exit
session.delete(:firstname)
session.delete(:password)
render :json => session
end
end
Error
undefined method `[]' for nil:NilClass
app/helpers/users_helper.rb:13:in `is_auth?'
app/controllers/admin_controller.rb:8:in `index'
Only Controller can access session.
So, in a nutshell, if you are going to use this method in Controllers only like what is you case, you can define it as ApplicationController's method. Or define it a module and include it in AppplicationController.
class ApplicationController < ActionController::Base
def auth
end
def is_auth?
end
end
If you want to use the method in both controller and view, just declare them as helper_method
class ApplicationController < ActionController::Base
helper_method :auth, :is_auth?
def auth
end
def is_auth?
end
end
Ref: http://apidock.com/rails/ActionController/Helpers/ClassMethods/helper_method
Another note: In my opinion it's really not worth the time to build auth system from scratch by yourself. The functionalities are not easy but quite general. There are well baked gems such as Devise, Authlogic. Better to use them.

Stubbing out save methodin rails with rspec

I have the following action in my controller:
def create
#user = current_user
#vin = #user.vins.new(params[:vin])
if #vin.save
# waiting for implementation
logger.debug("here we are")
else
redirect_to(vins_path)
end
end
I'd like to test with with rspec. However, I want to stub out the save operation to simulate a failure:
it "should send user to vins_path if there is a problem creating the VIN" do
#vin.stub!(:save).and_return(false)
post 'create', :vin => { :name => "Test 1", :vin => "test" }
response.should redirect_to(vins_path)
end
However, the stub doesn't seem to work as the save operation is always successful. What am I doing wrong?
Thanks
Try this:
Vin.any_instance.stub(:save).and_return(false)

How do I emulate logging in for controller tests?

I have a SearchesController that requires a user to be logged in before it will do its thing.
I'd like to write an rspec helper function login to emulate logging in for controller tests. (NB: I will handle integration / requests specs separately.) My attempts so haven't worked: the logged_in? method in ApplicationController returns false.
The question: how do I write the 'login' helper?
Here's the RSpec controller test:
# file: spec/controllers/searches_controller_spec.rb
require 'spec_helper'
require 'controllers_helper'
describe SearchesController do
include ControllersHelper
describe "GET index" do
it 'without login renders login page' do
get :index
response.should redirect_to(login_path)
end
it 'with login finds searches belonging to user' do
me = FactoryGirl.create(:user)
my_searches = FactoryGirl.create_list(:search, 2, :user => me)
not_me = FactoryGirl.create(:user)
not_my_searches = FactoryGirl.create_list(:search, 2, :user => not_me)
login(me) # want to define this in spec/controllers_helper.rb
get :index
assigns(:searches).should =~ my_searches
end
end
end
Here's the Controller:
# file: app/controllers/searches_controller.rb
class SearchesController < ApplicationController
def index
unless logged_in?
redirect_to login_path, :alert => "You must be logged in to access this page."
else
#searches = Search.where(:user_id => current_user.id)
respond_to do |format|
format.html
format.json { render json: #searches }
end
end
end
end
And here's the ApplicationController code. Note that current_user = x has the effect of logging x in, and it's rather simple: it sets #current_user and session[:user_id].
# file: app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
force_ssl
protected
def current_user
#current_user ||= User.find_by_id(session[:user_id])
end
def current_user=(user)
#current_user = user
session[:user_id] = user && user.id
end
def logged_in?
!!#current_user
end
def require_login
unless logged_in?
redirect_to login_path, :alert => "You must be logged in to access this page."
end
end
helper_method :current_user, :logged_in?, :require_login
end
I may have said this before, but if Stack Overflow gave badges answering one's own questions, I'd have a LOT of badges! :)
Okay, to answer this question you need to look at the documentation for ActionController::TestCase. When you do so, you'll find that it sets up bindings for:
#controller
#request
#response
So for the specific controller given in the OP, writing the login method is trivial:
# file: spec/controllers_helper.rb
module ControllersHelper
def login(user)
#controller.send(:current_user=, user)
end
end
(Did I hear someone say RTFM again? I thought so...)

Authlogic Rails 3.1

Which version of authlogic are people using with Rails 3.1.
I have the following entry in my gemfile:
gem 'authlogic', :git => 'https://github.com/AndreasWurm/authlogic.git'
The problem I have is with a piece of code in my base ApplicationController.
def require_no_user
if current_user
store_location
flash[:notice] = "You must be logged out to access this page"
redirect_to :controller => "home", :action => "index"
return false
end
end
def store_location
session[:return_to] = request.request_uri
end
The error I am getting is with the line:
session[:return_to] = request.request_uri
I am getting an error saying:
undefined method `request_uri' for #<ActionDispatch::Request:0x7dadd4d8>
Has Request_uri been removed from ActionDispatch and if so, what is the correct alternative?
The best solution is as said Vadim, using the new methods in ActionDispatch::Request :
You just replace :
def store_location
session[:return_to] = request.request_uri
end
by :
def store_location
session[:return_to] = request.url
end
and it's done !
fullpath will give you url(but without protocol, port, domain) with params
and request.url will give you everything that fullpath skips

Rspec2: response.should render_template("new") after invalid params fails

I am testing a controller in RSpec2 and for both my create and update actions, when passed invalid params, the controller should render either the "new" or "edit" templates respectively. It is doing that, but my test never passes.
describe "with invalid params" do
before(:each) do
User.stub(:new) { mock_user(:valid? => false, :save => false) }
end
it "re-renders the 'new' template" do
post :create, :company_id => mock_company.id
response.should render_template("new")
end
end
Results in this:
re-renders the 'new' template
expecting <"new"> but rendering with <"">
Here is the controller action:
respond_to do |format|
if #user.save
format.html {
flash[:notice] = "#{#user.full_name} was added to #{#company.name}."
redirect_to company_users_url(#company)
}
else
logger.debug #user.errors
format.html{
render :new
}
end
end
This problem also seems to be isolated to this controller. I have almost identical code running another controller and it is fine. I am not sure where the problem could be.
Update:
Here are the two mock methods
def mock_user(stubs={})
#mock_user ||= mock_model(User, stubs).as_null_object
end
def mock_company(stubs={})
(#mock_company ||= mock_model(Company).as_null_object).tap do |company|
company.stub(stubs) unless stubs.empty?
end
end
Turned out it was a problem with stubbing and CanCan. CanCan was loading the resources and uses some different methods than what I thought.