I have a few views that use current_user
when rendering. I was unable how to get these tests how to work properly until last night. Here is the secret sauce that worked for me
First add this to spec/rails_helpers.rb
config.include Devise::Test::ControllerHelpers, type: :view
Then your test should look something like this
require 'rails_helper' RSpec.describe "things/index", type: :view do before do sign_in create(:user) #This logs us in as non-admin assign(:things, [ create(:thing, name: 'Foo'), create(:thing, name: 'Bar') ]) end it "renders a list of things" do render expect(rendered).to match /Foo/ expect(rendered).to match /Bar/ end it "doesn't show link to edit or destroy the things" do render expect(rendered).not_to match /Edit/ expect(rendered).not_to match /Destroy/ end context "as an admin" do before do sign_in create(:user, :admin) end it "shows edit and delete" do render expect(rendered).to match /Edit/ expect(rendered).to match /Destroy/ end end end
The important bit is the sign_in create(:user)
or sign_in create(:user, :admin)
. In my app these are created from a factorybot factory with an admin trait that looks like this.
factory :user do email { Faker::Internet.email } password { "password"} password_confirmation { "password" } user_type { 'free' } trait :admin do user_type { 'admin' } end end
Just for completeness this is what the index view looks like
<h1 class="subtitle is-1">Things</h1> <table> <thead> <tr> <th>Name</th> <th colspan="3"></th> </tr> </thead> <tbody> <% @things.each do |thing| %> <tr> <td><%= link_to thing.name, thing %></td> <% if current_user.user_type == 'admin' || meal.user == current_user%> <td><%= link_to 'Edit', edit_thing_path(thing) %></td> <% else %> <td></td> <% end %> <% if current_user.user_type == 'admin' || thing.user == current_user%> <td><%= link_to 'Destroy', thing, method: :delete, data: { confirm: 'Are you sure?' } %></td> <% else %> <td></td> <% end %> </tr> <% end %> </tbody> </table> <br> <%= link_to 'New Thing', new_thing_path %>