I'm new to Rspec
and Capybara
. The error I'm getting is Navigation from homepage Visit Gallery
Failure/Error: visit root_path
NoMethodError:undefined method 'testimonials' for nil:NilClass
I tried let two different ways in order to define a variable in the spec. I've added both of them so I can get feedback on what I'm doing wrong.
class WelcomeController < ApplicationController
def index
@event = Event.last
@event.testimonials.first ? @latest_testimonial = @event.testimonials.first.id : @latest_testimonial = nil
end
end
feature 'Navigation from homepage' do
before :each do
visit root_path
find('#nav-menu').find('h1').click #opens up navigation bar
end
scenario 'Visit Gallery' do
find('#nav-gallery').find('.no_bar').click
let(:event) {Event.last} #1st attempt at solving Rspec error.
let(:event) {mock_model(Event, id: 3, name: "Jack & Jill", date: "2004-06-10", created_at: "2014-03-10 02:57:45", updated_at: "2014-03-10 02:57:45")} #2nd attempt at solving Rspec error.
controller.stub(:event)
expect(page).to have_css 'img.photos'
end
end
The other answer is correct - here is essentially the same content in simpler (or maybe just more drawn out by explaining things you already know) terms.
The first thing your test does is execute the before
block, which visits root_path
, presumably calling the index
action on WelcomeController
. The first thing that method does does is call Event.last
, which returns nil
, because your test database is empty so there is no last record to return. Then when you call testimonials
on @event
, you get the error you see because @event
is nil
.
To remedy this, you need to create an Event
record in the database before you navigate to the root_path
and call the index
action. One way to do that would be to add this line before visit root_path
:
Event.create(name: "Jack & Jill" [...])
That will create a record in the database, so Event.last
will return something.
You would also get rid of both let
statements and the controller.stub
thing. Those are unnecessary now (and had other problems anyway). That should be enough to get that code to at least run.
In practice, you won't find just creating records like I've shown here to be a sustainable approach - that's where factories (with a tool like FactoryGirl) or mocks/stubs come in. Then you use let
to define those items just once in your before
block, and still limit the overhead consumed by creating them to those subsequent tests where they are actually used.
Regardless, the main point is that the setup of objects (and records if needed) needs to be done before you start triggering controller actions that assume those objects exist.