Skip to content

Stub views in controller specs #37

Closed
carhartl opened this Issue Jun 3, 2011 · 13 comments

5 participants

@carhartl
carhartl commented Jun 3, 2011

I am using RSpec and in my controller specs I noticed that rabl views are still being rendered - usually rendering views with a template are stubbed in such examples ("By default, controller specs stub views with a template that renders an empty string instead of the views in the app." [1]).

I hacked that back into my specs manually with

ActionView::Template::Handlers::Rabl.stub(:call).and_return('')

Just wondering if there is a better way? Could this also be a bug on RSpec side, i.e. shouldn't it hook into the template renderers itself automatically, given it is possible?

Thanks again!

[1] http://relishapp.com/rspec/rspec-rails/v/2-6/dir/controller-specs/views-are-stubbed-by-default

@rwilcox
rwilcox commented Sep 30, 2011

+1 I see this bug tooo

@radar
radar commented Mar 27, 2012

Don't you want to assert that when you're making that controller request that the response contains the correct template? Why would you not want to do that?

@rwilcox
rwilcox commented Mar 27, 2012

I would argue that since stubbing views is the default behavior of rspec-rails, that rabl should make sure it works for that default case.

I waffle back and forth on "view specs are a great idea! Test your view in isolation!"... and "View specs are a horrible idea, because you need to remember to test your views along with everything, and the view you forget to test will be the one that throws an error...". And I know you can turn render_views on for a context...

@databyte
Collaborator
databyte commented Apr 6, 2012

The problem with stubbing the view is that most of us then use Cucumber to test the actual "use" of the views. That doesn't work really well in the case of JSON output IMHO.

I use json_spec and verify the output in RSpec. I can't handle the wordy Cuke tests show in the json_spec's README to test output. To me, the specifics of my JSON output is a unit test (= spec) and testing the use of the JSON output within my application is a true integration test (= cuke).

In other words, I use RSpec to test controllers and RABL and Cucumber for view usage and browser like stuff.

I can look into requiring render_views to work but I'm just curious how you guys test the output.

@databyte databyte was assigned Apr 6, 2012
@agibralter

I'm having the same issue here. I was confused as to whether it's rspec-rails or rabl that is the issue. Following the code with debugger, through both haml and rabl, it seems like the issue with rabl is that even with render_views turned off the compiled rabl template gets executed while the haml template gets compiled but not executed. In either case, I feel like rspec-rails should cut off the templates at a higher level than it is doing now... but maybe I'm wrong and rabl should be tweaked?

Here is the issue I posted in rspec-rails: rspec/rspec-rails#565

@databyte
Collaborator

I'll look at it later tonight but at first glance, RSpec is substituting the view_path on the controller such that it finds their empty template instead of the proper one.

Rabl itself does the template lookup here: https://github.com/nesquena/rabl/blob/master/lib/rabl/partials.rb#L66

Eventually it calls context_scope.lookup_context.find which, when you look at the Rails source, is basically used in the same way - to find the file within the view_path. I'll have to dig into a project that I have that uses rspec to see what's possible.

I'd hate to make a change to Rspec to support this change but if Haml is having the same results, maybe some common pattern can evolve so that any template renderer works.

@agibralter

Hmm in my specs that's never getting called -- that seems to only be used for partial rendering within rabl.

@agibralter

Ok, so I tracked it down:

Basically, RSpec stubs out templates to seem empty rather than stubbing out the whole rendering process. It does this so Rails properly handles formats/mime-types/etc. and seeing if templates are missing. When this code runs:

def self.call(template)
  source = if template.source.empty?
    File.read(template.identifier)
  else # use source
    template.source
  end

  %{ ::Rabl::Engine.new(#{source.inspect}).
      render(self, assigns.merge(local_assigns)) }
end # call

rabl sees an "empty" source and re-loads it from the file system. I'm not sure where the change should happen here. On the one hand, rspec-rails could accomodate template engines that don't like blank source code. On the other, rabl could maybe be refactored... but I think that would be harder than making a simple change to rspec-rails. I left my thoughts in the rspec-rails chain... but if anyone else has thoughts I would love to hear them!

@agibralter

(continue from the rspec-rails thread)

@databyte -- that commit replaced something that would have also been trouble:

def compile(template)
  %{
    ::Rabl::Engine.new(#{File.read(template.identifier).inspect}).render(self, assigns.merge(local_assigns))
  }
end

I guess it could be: ::Rabl::Engine.new(#{template.source.inspect}).render(self, assigns.merge(local_assigns)) instead. But I wonder if that breaks anything in Rails 2.x?

@databyte
Collaborator

Rails 2.x uses a different template read and the used of source = template.source is how ERB does it. See:

https://github.com/rails/rails/blob/3-2-stable/actionpack/lib/action_view/template/handlers/erb.rb#L81

Give me a min to run a full spec suite on an app that I have that uses Rabl to make sure everything is still clean.

@agibralter

Cool -- I commented on issue #35. It turns out @mrinterweb was using rspec without render_views so the source was empty for good reason. It's a bit nuts that that pull request was merged for very much the wrong reasons. It should definitely be template.source :)

@agibralter

And thank you for your help with this! Had me pulling my hair out all day. I'm used to testing my controller in isolation, so when I introduced rabl for a lot of my json stuff today, I couldn't figure out why things were not going as expected. At least I have a very intimate understanding of the Rails template system now :).

(Btw -- we met at a NYC ruby meet up a while back, no?)

@databyte databyte added a commit that closed this issue Jun 21, 2012
@databyte databyte [fixes #37] Don't load template source from file
This resolves an issue whereby RSpec was intentionally
not loading the template source unless you called
render_views. The force load of templates from source
was introduced in Issue #35.
e7be8be
@databyte databyte closed this in e7be8be Jun 21, 2012
@databyte
Collaborator

That should fix it and my tests that previously didn't use render_views but needed to are now breaking as they should.

I believe we may have met though there was a time I went to a lot of them. Are you going to GoRuCo?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.