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,
Related
I have this action
class SearchesController < ApplicationController
...
def results
#users = User.search(params[:name], params[:gender])
render 'user_results'
end
...
The problem is rails is running back through this code again for when it renders my user_results.css.erb which is giving unsuspecting results as the params appear not to be available and I dont want to run back through the code again anyway.
I tried to cache the #users variable by doing #users ||= User.search(params... but it runs back through the code anyway and my search method which is giving different results than when it first runs through for the user_results.html.erb when the params are available.
How can I solve this?
Why are you running this code from user_results.css.erb at all? Is it necessary? Because this is a code smell to me. If you need to render custom CSS here then simply use a separate action, don't call it results call it user_results and the two calls will be separate.
The thing to remember is that there are actually 2 different web requests, one to the HTML and one to the CSS. They could be called individually in some cases, not necessarily tied together for all browsers, and that is why this is a code smell to me is you're blurring the lines between the two in your controller.
For more clarity, try adding this to your method:
logger.info "#{request.format}"
You could also enable/disable things based on the format:
if request.format.html?
If you are doing something like assigning a different color to each user in your CSS, then I would just move that into your HTML as an inline <style> block, and then you won't need any sort of caching. I'm 99% sure caching is not the right thing here.
I want to have a user menu in my layouts/application.html.erb. In future, I plan to move it to a partial layouts/_user_menu.html.erb.
How should I start, write tests for this menu just in application.html.erb_spec.rb, and then as refactoring to move it to partial, leaving all tests in application.html.erb_spec.rb?
Or write its separate test _user_menu.html.erb_spec.rb? In this case, how can I test application.html.erb to render this partial? I don't thinks its good idea to use html selectors here, and think about something like in my application.html.erb_spec.rb:
expect(view).to render_partial 'user_menu'
Please try this
response.should render_template(:partial => 'partial_name')
I have a partial that is being shared between a few different views, and a mailer template. This partial should attempt to use the user's session to store some state information if possible.
Determining if the session exists seems to be a bit of a problem. Within the partial, calling defined?(session) always seems to yield true during a mail render (is this a bug?), but attempting to access "session" in any way yields an "undefined method" exception.
As of now, I'm having my mailer use a #for_mailer instance variable to signal this partial to render differently, but this doesn't seem very elegant. Is there some simple way for the partial to figure out whether or not it's being rendered by a mailer, as opposed to being rendered in the context of a web request?
I would also create two partials for this but here is an alternative solution as well.
Assuming that it is coming from a different controller and action, you could check the params[:controller] and params[:action].
If you end up doing this more than a few times, you will probably end up with more code than just rewriting the partial. What do you want to be different between the two presentations?
I'm working on a functional test that needs to assert that a certain XHTML tag is present in a certain set of controllers. I'm basically doing this:
class ApplicationControllerTest < ActionController::TestCase
def setup
#controller = ApplicationController.new
end
# [...]
def test_foo_bar_and_baz_include_stylesheet
[FooController, BarController, BazController].each do |controller|
#controller = controller.new
get :show
assert_select 'head > link[rel="stylesheet"]'
end
end
end
The problem is that not all controllers have a :show action. What I need to do is ask either the controller or the routing configuration for the controller's default action and call get with that.
Update: Joseph Silvashy was right: I ended up separating my controller gets out into separate test cases. Solving the "default" route problem was bad enough, until I discovered that some of my routes had conditions attached, and I would have to parse them to craft the correct get call. And finally, Rails functional tests don't deal very well with calling get multiple times in the same test case, especially when that those calls are hitting multiple controllers. :(
I think the lesson here is one that we all know by heart but sometimes is hard to accept: if the code looks hairy, you're probably doing it wrong. ;)
Controllers don't have a "default" view or action, additionally actions can be named anything you want, they don't have to be the standard index, show, new, etc...
I'll probably have to :get the appropriate action for each controller you want to test. It's likely each test will be different down the road anyhow, even though right now they all have the same requirement, I think it makes sense to write one for each action regardless.
try to use the respond_to function: http://www.ruby-doc.org/core/classes/Object.html#M001005
to check if a method exitst.
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?