Question

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
Was it helpful?

Solution

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.

OTHER TIPS

Event.last is returning nil.

The typical (and easiest) way to do this would be to just create an event in your test, before trying to visit the site, and then your controller will use it. Feature specs should really contain the minimal amount of mocking and stubbing - they represent a real user interacting with the system.

Your stubs are not getting used (and in fact are errors in themselves). This is verified by the fact that your error is coming before they even get set.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top