Dowling
Dowling

Reputation: 33

collection_select not populating in rspec test with Capybara using FactoryGirl

I am trying to test selecting a value from a collection_select element with capybara and for some reason, the data to populate the collection_select isn't there when running the rspec, but it is when running the rails app.

Example:

html definition

<%= form_for(@notification) do |f| %>

    <%= f.label :device, "Select a Device to notify:" %>
    <%= f.collection_select :device_id, Device.all, :id, :device_guid, prompt: true %>

<% end %>

rspec definition

describe "NotificationPages" do

  subject { page }

  let(:device) { FactoryGirl.create(:device) }
  let(:notification) { FactoryGirl.create(:notification, device: device) }

  describe "new notification" do
    before { visit new_notification_path }

    let(:submit) { "Create Notification" }

    describe "with valid information" do
      before do
        select(device.device_guid, from: 'notification_device_id')
        fill_in "Message", with: "I am notifying you."
      end

      it "should create a notification" do
        expect { click_button submit }.to change(Notification, :count).by(1)
      end
    end
  end
end

When running the test, I get the following error message:

Capybara::ElementNotFound: cannot select option, no option with text 'device_guid' in select box 'notification_device_id'

It looks like the Device.all call in the collection_select isn't returning anything during the test. Any ideas as to what I am doing wrong?

Thanks, Perry

Upvotes: 1

Views: 1427

Answers (2)

user172810
user172810

Reputation: 61

A better way to force early evaluation of the let is to use !, like this:

let!(:device) { FactoryGirl.create(:device) }

that way you don't need the extra line of code.

Upvotes: 4

fgp
fgp

Reputation: 428

At the moment you visit new_notification_path there is no device in the database. This happens because let is lazy-evaluated, so the method it defines is called the first time you invoke it, which in your test happens only when you execute the select(device.device_guid ...) statement.

To make sure the device is created before you visit the path, you can just call 'device' in your before block.

before do
  device
  visit new_notification_path
end

Upvotes: 1

Related Questions