Reputation: 5488
I am trying to stub a method on a helper that is defined in my controller. For example:
class ApplicationController < ActionController::Base
def current_user
@current_user ||= authenticated_user_method
end
helper_method :current_user
end
module SomeHelper
def do_something
current_user.call_a_method
end
end
In my Rspec:
describe SomeHelper
it "why cant i stub a helper method?!" do
helper.stub!(:current_user).and_return(@user)
helper.respond_to?(:current_user).should be_true # Fails
helper.do_something # Fails 'no method current_user'
end
end
In spec/support/authentication.rb
module RspecAuthentication
def sign_in(user)
controller.stub!(:current_user).and_return(user)
controller.stub!(:authenticate!).and_return(true)
helper.stub(:current_user).and_return(user) if respond_to?(:helper)
end
end
RSpec.configure do |config|
config.include RspecAuthentication, :type => :controller
config.include RspecAuthentication, :type => :view
config.include RspecAuthentication, :type => :helper
end
I asked a similar question here, but settled on a work around. This strange behavior has creeped up again and I would like to understand why this doesnt work.
UPDATE: I have found that calling controller.stub!(:current_user).and_return(@user)
before helper.stub!(...)
is what is causing this behavior. This is easy enough to fix in spec/support/authentication.rb
, but is this a bug in Rspec? I dont see why it would be expected to not be able to stub a method on a helper if it was already stubbed on a controller.
Upvotes: 29
Views: 27523
Reputation: 51
As of RSpec 3.10, this technique will work:
before do
without_partial_double_verification {
allow(view).to receive(:current_user).and_return(user)
}
end
The without_partial_double_verification
wrapper is needed to avoid a MockExpectationError
unless you have that turned off globally.
Upvotes: 5
Reputation: 471
This worked for me in the case of RSpec 3:
let(:user) { create :user }
helper do
def current_user; end
end
before do
allow(helper).to receive(:current_user).and_return user
end
Upvotes: 3
Reputation: 13972
In RSpec 3.5 RSpec, it seems like helper
is no longer accessible from an it
block. (It will give you the following message:
helper
is not available from within an example (e.g. anit
block) or from constructs that run in the scope of an example (e.g.before
,let
, etc). It is only available on an example group (e.g. adescribe
orcontext
block).
(I can't seem to find any documentation on this change, this is all knowledge gained experimentally).
The key to solving this is knowing that helper methods are instance methods, and that for your own helper methods it's easy to do this:
allow_any_instance_of( SomeHelper ).to receive(:current_user).and_return(user)
This is what finally worked for me
Footnotes/Credit Where Credit Due:
Upvotes: 19
Reputation: 4615
Rspec 3
user = double(image: urlurl)
allow(helper).to receive(:current_user).and_return(user)
expect(helper.get_user_header).to eq("/uploads/user/1/logo.png")
Upvotes: 5
Reputation: 4119
Update to Matthew Ratzloff's answer: You don't need the instance object and stub! has been deprecated
it "why can't I stub a helper method?!" do
helper.stub(:current_user) { user }
expect(helper.do_something).to eq 'something'
end
Edit. The RSpec 3 way to stub!
would be:
allow(helper).to receive(:current_user) { user }
See: https://relishapp.com/rspec/rspec-mocks/v/3-2/docs/
Upvotes: 22
Reputation: 4623
Try this, it worked for me:
describe SomeHelper
before :each do
@helper = Object.new.extend SomeHelper
end
it "why cant i stub a helper method?!" do
@helper.stub!(:current_user).and_return(@user)
# ...
end
end
The first part is based on this reply by the author of RSpec, and the second part is based on this Stack Overflow answer.
Upvotes: 8