I have literally been bashing my head into the wall this past week trying to figure out how to get RSpec view tests to pass when using Devise. I finally figured it out after a lot of trial and error because there is a particular combination of things you have to have in place to make things work.
First, the what: I added some navigation to a menu bar that only shows up if the user is logged in. It was just:
<nav>
<% if user_logged_in? %>
<%= link_to ...blah... %>
<% end %>
</nav>
The trouble is, I kept getting this error:
Failure/Error: render ActionView::Template::Error: undefined method `authenticate' for nil:NilClass
The first problem was figuring out why Devise’s helpers weren’t being loaded. According to the Devise documentation you should create a spec/support/devise.rb file like:
RSpec.configure do |config| config.include Devise::TestHelpers, :type => :controller end
But what about running view tests? The missing line is:
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.include Devise::TestHelpers, :type => :view
end
Great! But that only solves the missing helpers. What about getting current_user to actually return a user? I tried all sorts of things and spent days searching for the answer and it comes down to stubbing out the helpers … but which object? The answer is on the view itself:
module ApplicationRspecHelpers
def stub_user
@user = double('user')
@user.stub(:id => 100)
view.stub(:user_signed_in? => true)
view.stub(:current_user => @user)
end
end
That works exactly as I want it. So now I can write my view tests like:
require 'spec_helper'
describe 'layouts/application' do
include ApplicationRspecHelpers
describe 'authentication nav' do
context 'when authenticated' do
it 'should have Log Out' do
stub_user
render
rendered.should have_selector('nav a', text: 'Log Out')
end
end
end
end
