Jake Scruggs

writes ruby/wears crazy shirts

So in a previous post I complained about not being able to mock/stub a partial from within a partial, but with Peter Ryan and Mike Ward's help we got it all figured out.
Normally in your test(spec) you call a partial like this:

  
render :partial => 'partial_name',
locals => {:page_variable => mock_page_variable }

But if you want to intercept all or some calls to render with partial, them you can't do that. But what you can do is call a partial like so:
  
render '_partial_name'

If you need some locals you can stub them out like so:
  
@controller.template.stub!(:page_variable).
and_return(mock_page_variable)
render '_partial_name'

So if I wanted to stub out all calls to render, and assert that the string "Blargh" appears on the page, it would look a little something like this:
  
@controller.template.stub!(:render)
@controller.template.stub!(:page_variable).
and_return(mock_page_variable)
render '_partial_name'

response.body.should include("Blargh")

Now why does that work while "render :partial =>..." does not? I, uh, really don't know. Ideas?

4 comments :

Chris said...

Are you sure this method works? How does stubbing out render not make the subsequent call to render impotent?

Chris said...

If anyone else happens upon this post, refer to the following thread on how to pass locals into the containing partial (i.e., how to get by without passing :locals to the render method):

http://rubyforge.org/pipermail/rspec-users/2007-April/001224.html

Jake Scruggs said...

Yep it works, we totally use code just like this to test lots of our partials.
And why doesn't the stub of render stop the later call to render? I don't know. I was asking you, the blogoshpere, to help me out with that.
Btw this all works with RSpec 0.8.2 and Rails 1.2.2 if that helps. (or shoot me an email if you're still stuck)

David Chelimsky said...

The #render that you call in the example gets called on a controller, not on the template. That's why they don't conflict.

FYI - I'm adding a #template method to view examples. That'll be available next release, so you can just say:

template.should_receive(:render).
with({:partial => 'form'})