Reputation: 9651
What is the best way to test logic in a rails 3 layout?
Example: when a user signs into my site, if they have not completed the onboarding process I show them an alert at the top of the screen on ALL pages. This logic was placed into the application layout. I simply check the logged in user for a particular key. If the key is NOT present I show the alert. As soon as the key is present (meaning they've completed the onboarding) I DO NOT show the alert.
Currently I'm attempting to do this with a view test, but I'm getting all sorts of ActionView::Template::Error: undefined method
authenticate' for nil:NilClass` errors by including the application layout and I cant seem to test this feature.
I need to make sure I have this under test because if for some reason one of my devs accidentally breaks this feature (view showing up with onboarding is not complete) we need to know immediately upon build.
The code that I'm trying to test in my layout looks like this:
<% if user_signed_in? %>
<% unless current_user.has_completed_onboarding? %>
<div class="alert">
You cannot accept payments from your clients until you set up your payment gateway.
<%= link_to "Set up your", payment_gateway_path %> payment gateway. Its quick, we promise. :)
</div>
<% end %>
<% end %>
I want to make sure that if they onboarding details have NOT been provided that this message will show and if they have been provided, then do not show this message.
Upvotes: 10
Views: 2768
Reputation: 2093
The error you got ActionView::Template::Error: undefined method authenticate for nil:NilClass
is caused by the user_signed_in?
method call in the view. You can handle this by stubbing the user_signed_in?
method in your tests as @shioyama showed in the code.
The following code shows how to stub the user_signed_in?
method and return true
if you wanted the if
statement in your view to be executed or false
if you don't.
view.stub(:user_signed_in?).and_return(true)
Upvotes: 2
Reputation: 27374
You can test your layout just like any other view. Just create a file application.html.erb_spec.rb
(replace erb
by haml
if necessary) in spec/views/layouts/
, and in that file write up your specs as you normally would, e.g.:
require 'spec_helper'
describe 'layouts/application' do
context 'signed-in user' do
before { view.stub(:user_signed_in?) { true } }
context 'completed onboarding' do
before do
user = double('user')
user.stub(:has_completed_onboarding?) { false }
assign(:current_user, user)
end
it "should display alert" do
render
rendered.should have_selector('.alert')
end
end
...
end
context 'signed-out user' do
...
end
...
end
I do this with one of my apps and it works no problem, so I don't see why it wouldn't work for your case as well.
Upvotes: 14