Search code examples
ruby-on-railsruby-on-rails-4rspec-rails

Rspec Custom view testing


This is my rspec for view

require 'rails_helper'
RSpec.describe "expense_notifies/index", type: :view do
  before(:each) do
    assign(:expense_notifies, [
      ExpenseNotify.create!(:user_id => 1),
      ExpenseNotify.create!(:user_id => 2)
    ])
  end

  it "renders a list of expense_notifies" do
    render
  end
end

This is the index action in expense_notifies_controller.rb

def index
    @expense_notifies = ExpenseNotify.all.includes(:user)
end

This is my view index.html.erb

<% @expense_notifies.each do |expense_notify| %>
<%= expense_notify.user.first_name %> <%=expense_notify.user.last_name%>
<%end%>

Everytime I run rspec spec/views/expense_notifies/index.html.erb_spec.rb

Failure/Error: <%= expense_notify.user.first_name %> <%=expense_notify.user.last_name%>

     ActionView::Template::Error:
       undefined method `first_name' for nil:NilClass

The expense_notify.rb model

class ExpenseNotify < ActiveRecord::Base
  belongs_to :user
  validates_presence_of :user_id
end

How do I get the test to pass?


Solution

  • You should not hardcode the IDs for assignment. You can never make sure that objects with a particular set of IDs exist for every run of RSpecs in your database.

    Instead create User objects and use user.id:

    require 'rails_helper'
    
    RSpec.describe "expense_notifies/index", type: :view do
      let(:user_1) { User.create! }
      let(:user_2) { User.create! }
    
      before(:each) do
        assign(:expense_notifies, [
          ExpenseNotify.create!(user_id: user_1.id),
          ExpenseNotify.create!(user_id: user_2.id)
        ])
      end
    end
    

    See the use of let in RSpecs.

    Another suggestion, you could use factory_bot to create User and ExpenseNotify objects in test environment.