Testing view helpers: how do I specify a controller? - ruby-on-rails

Consider, for example, the following code:
class ViewHelpersTest < ActionView::TestCase
should 'generate tag with correct parameters' do
assert_equal theme_stylesheet_link_tag('style', :media => 'print'),
'<link href="/themes/default/stylesheets/style.css" media="print" rel="stylesheet" type="text/css" />'
end
end
current_theme_stylesheet_tag is a view helper that creates a stylesheet link tag that points to a css file located inside the current theme's directory. The current theme can be retrieved by calling ApplicationController::current_theme.
So, I need to provide a valid controller instance, which brings me to my question:
How exactly do I specify the controller to be used when testing view helpers in Rails 3?
Also, if there is a better way to express this test, please let me know. I have little experience with testing.

I'm not a big fan of testing helpers, but if you do it's best to approach it as a unit test, so you want to isolate the method from dependencies. In this case, instead of trying to create a controller object, you can just create a mock object and stub the necessary method call.
In RSpec this might work like so, assuming your current_theme method just returns a string:
describe ViewHelper do
it "should generate tag with correct parameters" do
ApplicationController = double(:current_theme=>"A string")
helper.my_helper_method("argument").should == "A string"
end
end
When the helper method executes ApplicationController::current_theme, it uses the stub instead of the actual method, so there's no need to instantiate a controller, or even to require the controller code.

I'm not the testing expert but I wonder if that should be a controller test instead of a view test. For example, Rails Guides describes view tests as "asserting the presence of key HTML elements and their content."
If you're setting the theme in the controller, can you test it there?

Related

How to test that a view helper renders a partial?

Say I want to render different partials depending on an instance variable from the controller. I put the logic in a helper method, that looks something like:
def display_my_partial(foo)
foo == bar ? render(partial_x) : render(partial_y)
end
and in the view I call (using Slim):
= display_my_partial(#foo)
What should my test look like? I tried something like:
expect(display_my_partial(foo)).to render(partial: 'partial_x')
but got:
NoMethodError:
undefined method `matches?' for #<ActiveSupport::SafeBuffer:0x007ffb490aba80>
My example is a bit more complicated, as my partials are in a nested namespace. I had to experiment a little with just usind render 'partial_x' vs render partial: 'namespace/model/partial_x' to get it working in the specs, but finally I got the above mentioned error.
So how would you test this?
Where are you testing it in? Make sure render_views is called.
In any case, do you really care it's rendering that partial? What if the file name is changed, or you decide to change the implementation using html helpers instead. None of this matters to the output. I would personally assert the output instead. Depending on how complex the output is you could do it in a view test or just simple unit tests.
HTH,

Dynamic method call in routes spec

I am testing simple get requests for my routes using rspec in my Rails 3.2 application. Since all are get requests, and all just have different action names which are similar to the views' names, it would be really repetitive to manually write a different test for each get request.
Instead, I wanted to come up with something like this:
%(action_1 action_2 action_3 action_4).each do |action|
it "routes to the #{action} page" do
get("liver_diseases#{action}_path").should route_to("liver_diseases##{action}")
end
end
It fails at this pseudocode: get("liver_diseases_#{action}_path")
So what I need to do is a dynamic method call - but for what I have found out, that would involve .send(:method_name), for which I need to know the class name. And I couldn't find that.
What do I need to do for this method call to work?
that would involve .send(:method_name), for which I need to know the
class name
When the receiver is missing, it's always self. In the context of a controller example, self should be a controller instance. So you should be able to get that path with:
send "liver_diseases_#{action}_path"
which should be equivalent to:
controller.send "liver_diseases_#{action}_path"

Custom Controller variable in application.html

User Story:
Action for Facebook that has open graph object.
For this I need to modify the tag defined in application.html
Problem:
The logic would need to be defined in helpers or the application_controller
From my understanding this is not clean.
Question:
I want to pass variables directly into the application.html view.
Preferably pass those variables from a custom controller into the application.html. This way I can still utilize the rails routing system to only pass those variables when I am on the facebook action.
The common mechanism for passing variables in to the view is to create instance variables in your controller as these are ported over automatically.
This is the standard approach if it is almost certain they will be used. For things that may not be used, create a helper method that will take care of providing them.
This is the difference between doing this:
def show
#facebook_graph = ...
end
And this in a helper:
def facebook_graph
...
end

RoR: defining a class inside a view helper file

I have a view helper file, app/helpers/analysis_helper.rb, whose toplevel methods I've been using in various view files. Works fine. I then defined an AnalysisSummary class inside analysis_helper.rb to package up some view-specific functionality.
However, when I try to instantiate an AnalysisSummary in a view file, I get the error:
uninitialized constant ActionView::CompiledTemplates::AnalysisSummary
Perhaps Rails is telling me that I shouldn't be defining a class inside a helper file? If so, where would you suggest parking AnalysisSummary? It's not a controller, it's not a model...
Thanks.
In Railscasts #213 (Revised) (subscribers only link, alas), Ryan Bates provides an example of how (and why) you might include a class within a helper. The basic gist is this:
# app/helpers/calendar_helper.rb
module CalendarHelper
def calendar(date = Date.today)
Calendar.new(self, date).render
end
class Calendar
def render
# Calendar, render thyself
end
# ... additional methods called by #render
end
end
To those opposed to classes within helpers, what do you make of Ryan's choice? Helpers are for generating markup, right? So if all the logic within class pertains to rendering (rather complicated) HTML, I would think that what it does (as opposed to what it is) makes it appropriate for inclusion in a helper.
Why does it need to be a class? Why not just a collection of methods? That's what a helper is: a collection of helpful methods. Business logic does not belong in helpers. You can place your code in a module within the helper file if you want to give some more structure and organization, though.
You can put classes in app/models without it having to be an ActiveRecord class, but you should seriously consider what the purpose of your class is before you place it there.
If it concerns only rendering the view, and not accessing data directly, it belongs in the view or a view helper.
You can call the class by explicitely mentioning the helper name
ApplicationHelper::AnalysisSummary.new
But I dont think it is a good idea to have classes in helpers.
It's a module then :) Definately do not define classes inside helpers. Jsut use a simple module to do the job.

Rails helper for views and controllers?

I know there are ways to make helpers available to controllers, but that this is generally bad form. How should the following be re-worked to avoid this?
I have a Contacts helper called "fullname" that combines a contact's first and last names.
A layout partial called subheader is rendered in the application layout, and contains this code:
<section id="subheader"><%= #subheader %></section>
The controllers set the value of #subheader.
The issue is that I often want "fullname" in #subheader. But this means accessing the helper from the controller. Should this fullname method reside somewhere else?
With something like fullname I usually just define a method on the model itself.
If the fullname method did some type of HTML formatting then I would keep those parts inside a helper.
Since the title of your question might attract viewers looking for a different answer, I'm going to answer the question of "can I use rails helpers in my controllers"? There are legitimate uses for this, so here's the cleanest way to do so:
In the helpers file, wrap the code you want to access in a model like so:
module HelperModuleName
[helper code here]
end
Wrapping only the code you need to use in your controllers (as opposed to including all helpers using include ApplicationHelper) is a good idea because it reduces the possibility for method name clashes and forces you to be more deliberate about your choice to use helpers in controllers.
Now include the module in your application_controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery
include HelperModuleName
end

Resources