I'm trying to write spec for inherited_resources controller. I decided to mock all integration with the database using rspec's mock_model. Unfortunately I can't write spec for create and update action because I'm getting the following error: https://gist.github.com/936947
Can someone help me with this issue?
I was having the same issue using flexmock.
the cause is that it does not use the update_attributes method to make the routing decision. It checks the resource.errors to see whether it is empty.
So to get it to respond properly, we will need to mock out the errors method as well.
Here is the pertinent code #line 248 in lib/inherited_resources/base_helpers.rb
def respond_with_dual_blocks(object, options, &block) #:nodoc:
args = (with_chain(object) << options)
case block.try(:arity)
when 2
respond_with(*args) do |responder|
blank_slate = InheritedResources::BlankSlate.new
if object.errors.empty?
block.call(responder, blank_slate)
else
block.call(blank_slate, responder)
end
end
when 1
respond_with(*args, &block)
else
options[:location] = block.call if block
respond_with(*args)
end
end
The failure messages are about the inability to access named routes from inside the controller, so I'm not sure that this has anything to do with mock_model. Have you tried the same examples using real models?
Related
I'm trying to use expect_to_receive rspec expectation but without any luck. My controller specs file looks like that:
it 'resolves an end behaviour' do
expect_any_instance_of(Job).to receive(:resolve_end_behaviour)
post :callback, #params
end
And my controller method:
def callback
#video = JobVideo.find(params['body']['id'].to_i)
if !#video.is_ready
#video.job.resolve_end_behaviour
#video.update_attribute(:is_ready, true)
end
render json: { success: true }
end
And running rspec gives me:
Exactly one instance should have received the following message(s) but didn't: resolve_end_behaviour
I'm sure that this method is called cause is_ready column is beeing updated. Can anyone give me any clues on why is that happening and what can i do about it? Thanks in advance.
Env:
rails 4
rspec 3
Your test is expecting resolve_end_behaviour to be called with two arguments, you are calling it with no arguments.
I recently upgraded a Ruby on Rails project from rspec-core / rspec-rails 2.10.1 to 2.14. Now (as I feared) a lot of tests are failing, but just because some methods have been changed. I have already fixed deprecations (stub! -> stub, mock -> double) but there are some more. One important method I use everywhere is something I picked up here: https://www.ruby-forum.com/topic/126993 to stub association methods:
module RSpec
module Mocks
module Mock
def stub_association!(association_name, methods_to_be_stubbed = {})
mock_association = RSpec::Mocks::Mock.new(association_name.to_s)
methods_to_be_stubbed.each do |method, return_value|
mock_association.stub(method).and_return(return_value)
end
self.stub(association_name).and_return(mock_association)
end
end
end
end
Now this throws the following error message:
Failure/Error: #foo.stub_association!(:children, :sorted => [])
Double "Foo_1910" received unexpected message :stub_association! with (:children, {:sorted=>[]})
I expect the module names above have changed, but I couldn't figure out how exactly. Any hints would be appreciated.
Secondly, I used code like this to stub controller methods:
112) ApplicationHelper admin_link_to not logged in: should output nothing
Failure/Error: stub(:authenticate_with_http_basic).and_return nil
Stub :authenticate_with_http_basic received unexpected message :and_return with (nil)
where the controller method is this
def admin_link_to(...)
return link_to(...) if logged_in? and current_user.has_role?(:admin)
end
and logged_in? calls authenticate_with_http_basic do |login, password| ....
Similarly I used to stub request to serve fake request objects to the controller or helper being tested.
How can I do this in rspec-rails 2.14?
Update
It seems that apart from renaming Mock to TestDouble (neede for the stub_association!call above) I just needed to put controller or helper in front of my stub(...) calls, depending on what is being tested. So
stub(:authenticate_with_http_basic).and_return nil
becomes
helper.stub(:authenticate_with_http_basic).and_return nil
For most cases, this works fine. Renaming Mock to TestDouble was only half the cake though - I still cannot use my stub_association! method on real objects, only on mocks (or doubles, as they are now called).
So I'm 80% there. Anybody up for the last 20%? :)
I'm using the rails-footnotes gem in my Rails 3.2 applications, but I can't seem to get the footnotes to register the existence of any partials: it always shows a zero partial count.
To be able to know how many and what partials are being displayed on a view easily like this is, I think, immensely useful, so I would really like to get this working (the rest works great), but I'm not sure what the problem is and am hoping someone else has had the same problem and was able to resolve it. Is there a setting I've potentially missed?
I don't think it's relevant, but I'm using OSX 10.6.8 and had some issues getting the gem to work with Sublime Text 2 properly, but they did get resolved (details in this StackOverflow answer).
Update:
It seems that the issue only exists for haml templates, as I am getting expected output for erb templates. It would seem that only erb templates are counted/recognized...?
Update 2:
#DonHopkins' answer below got all my Haml templates to register with Rails Footnotes. I put it in my config file as follows:
config/initializers/rails_footnotes.rb
if defined?(Footnotes) && Rails.env.development?
Footnotes.run! # first of all
Footnotes::Notes::LogNote::LoggingExtensions.module_eval do
def add(*args, &block)
super
logged_message = args[2] + "\n"
Footnotes::Notes::LogNote.log(logged_message)
logged_message
end
end
# ... other init code
Footnotes::Filter.prefix = 'subl://open?url=file://%s&line=%d&column=%d'
end
I had a similar problem, although I am using erb templates, not haml. I fixed it with a monkey patch to rails-footnotes.
Looking at the rails-footnotes code (version 3.7.9), it looked to me like the problem is in this method:
module Footnotes
module Notes
class LogNote < AbstractNote
...
module LoggingExtensions
def add(*args, &block)
logged_message = super
Footnotes::Notes::LogNote.log(logged_message)
logged_message
end
end
...
end
end
end
The add method is assuming that super returns the message that is being logged, but in my testing super was returning a boolean value. To solve the problem, I created a file called footnotes_patch.rb with the following:
Footnotes::Notes::LogNote::LoggingExtensions.module_eval do
def add(*args, &block)
super
logged_message = args[2] + "\n"
Footnotes::Notes::LogNote.log(logged_message)
logged_message
end
end
If you want to try the solution, put that file in config/initializers, then restart your application.
I have a ruby gem, poirot, which enables the use of mustache templates in Rails. The template handler I have was extending from ActionView::Template::Handler, however this appears to be deprecated in Rails 3.1.
I have re-factored the handler to comply with the deprecation warnings. In doing this I am now unable to pass locals, or the view context, to the template. I can't seem to find out how to get this working with Rails 3.1.
module Poirot
class Handler
attr_reader :template
def initialize(template)
#template = template
end
def self.call(template, *args)
self.new(template).call
end
def call
view_path = "#{template.virtual_path}_view"
abs_view_path = Rails.root.join('app/views', view_path)
view_class = begin
view_path.classify.constantize
rescue NameError => e
Poirot::View
end
"#{view_class}.new(self, '#{template.source.gsub(/'/, "\\\\'")}').render.html_safe"
end
end
end
In my code above for the handler I get passed the template, which is an instance of ActionView::Template. But I'm not sure how to get the view context, which should include the locals etc
Can someone point me in the right direction?
Okay I have a solution, I'm not sure it is the best, it feels a little hacky to me!
In my view class I have managed to get access to the locals by doing the following:
locals = view_context.send(:view_renderer).send(:_partial_renderer).instance_variable_get("#locals") || {}
This feels a little messy as both view_renderer and _partial_renderer are private, and there is no proper accessor to the locals ivar.
I'm still hoping there is a better way to do this!
I spent about 4 hours investigating source code to find a solution, and now it's seems very simple:
just add "local_assigns" where you are want to eval it and use.
For example:
"#{view_class}.new(self, '#{template.source.gsub(/'/, "\\\\'")}', local_assigns).render.html_safe"
this string will be evaluted inside the module context - ActionView::CompiledTemplates and local_assigns will be accessible there.
I am trying to write an rspec test for a controller that accesses a
model Group.
#request.env['HTTP_REFERER'] = group_url(#mock_group) ### Line 49
I get this:
NoMethodError in 'ActsController responding to create should redirect to :back'
You have a nil object when you didn't expect it!
The error occurred while evaluating nil.rewrite
/Library/Ruby/Gems/1.8/gems/actionpack-2.1.0/lib/action_controller/base.rb:621:in `url_for'
(eval):17:in `group_url'
/Library/Ruby/Gems/1.8/gems/actionpack-2.1.0/lib/action_controller/test_process.rb:464:in `send!'
/Library/Ruby/Gems/1.8/gems/actionpack-2.1.0/lib/action_controller/test_process.rb:464:in `method_missing'
This line in url_for is the problem; specfically #url is nil.
#url.rewrite(rewrite_options(options))
And it seems that #url is initialized here:
def initialize_current_url
#url = UrlRewriter.new(request, params.clone)
end
This happens because url_for depends on stuff that's initialized during request processing. I assume your test looks something like this:
it "should do whatever when referrer is group thing" do
#request.env["HTTP_REFERER"] = url_for(#mock_group)
get :some_action
"something".should == "something"
end
url_for fails because it happens before the get. The easiest way to resolve the problem is to hard-code the URL in your test (i.e. change url\_for(#mock\_group) to "http://test.host/group/1"). The other option is to figure out how to get #controller to initialize #url before you call url_for. I think I've done that before, but I don't have the code around any more and it involved digging through action_controller's code.
Look at this. I think it is relevant.
http://jakescruggs.blogspot.com/2008/11/if-you-use-mocha-and-rspec-then-read.html