Capybara Not Finding Form Fields - ruby-on-rails

I was trying Capybara for the first time and having trouble with it finding my form. I'm using Rspec, Capybara, Rails 3.2.8, and Twitter Bootstrap.
In my test, I had:
before do
choose "Residential"
choose "Storage"
fill_in "Customer Location", with: 30082
fill_in "datepicker", with: 2012-12-02
fill_in "Email", with: "jesse#test.com"
fill_in "Phone", with: "555-555-5555"
end
And was getting the error:
Failure/Error: choose "Residential"
Capybara::ElementNotFound:
cannot choose field, no radio button with id, name, or label 'Residential' found
In my form, I had (excerpt):
<%= quote.radio_button :customer_type, "Residential"%>
<%= quote.label "Residential", class:"radio inline" %>
When I fired up the server, I could see the form and Firebug showed that I had a label named "Residential" associated with the form element.
After searching for the problem and finding this post: Capybara not finding form elements (among others), I couldn't figure out why it wasn't working.

I ultimately went back to Capybara's Rubydocs ( http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Actions ) and found the section on the "Choose" method.
I didn't dive deep into the documentation, but I saw that it was looking for a "locator" in the :radio_button and so tried associating one directly.
I thus changed my form to (notice I added "id" to the form element):
<%= quote.radio_button :customer_type, "Residential", id:"Residential"%>
<%= quote.label "Residential", class:"radio inline" %>
and that portion of the test passed! I repeated with each of my form elements and everything performed as expected.
Hope this is useful to someone else.

Related

Capybara and Cucumber cannot find checkboxes even with unique ID

I have been encountering a problem when running cucumber to test the functionality of some of my checkboxes. The checkboxes are located on the edit profile page for users and allow users to check off their interests. However, every time I run cucumber it says that it is unable to find the checkbox. But this does not happen for all of the checkboxes on the page, only the checkboxes for the interests. Originally we thought that it was because the checkboxes did not have unique IDs, but now we have updated the checkboxes to have unique ids and they still cannot be found by capybara and cucumber.
The view code looks like this:
<% #interests.each do |interest| %>
<div class="form-group">
<%= label_tag 'interests', interest.name, class: 'col-sm-2 control-label' %>
<div class="col-sm-6">
<%= check_box_tag 'interests[]', interest.id, resource.interest_ids.include?(interest.id), {class: 'form-control', id: "interest_#{interest.id}"} %>
</div>
</div>
<% end %>
The step definition is:
When /^(?:|I )check "([^"]*)"$/ do |field|
check(field)
end
The feature look like this:
Feature: Edit Profile as a User
As a BoardBank User
So I can keep my info up to date
I want to be able to edit my profile
Background:
Given I login as a User
And I am on the home page
Scenario: Edit profile
When I follow "Profile"
And I follow "Edit Profile"
And I fill in "user_firstname" with "User"
And I fill in "user_lastname" with "Joe"
And I fill in "user_address" with "123 userville"
And I fill in "user_city" with "Userton"
And I select "Alabama" from "user_state"
And I fill in "user_zipcode" with "90210"
And I fill in "user_phonenumber" with "555-555-5555"
And I select "Bachelors" from "user_education"
And I fill in "user_areaofstudy" with "Magic"
And I check "interest_2"
And I check "user_previous_experience"
And I fill in "user_current_password" with "password"
And I press "Update"
Then I should see "Your account has been updated successfully."
And I should be on the homepage
When I run cucumber this is what happens:
And I check "interest_2" #features/step_definitions/web_steps.rb:89
Unable to find checkbox "interest_2" (Capybara::ElementNotFound)
./features/step_definitions/web_steps.rb:90:in `/^(?:|I )check "([^"]*)"$/'
features/edit_profile.feature:23:in `And I check "interest_2"'
We think that it must be an issue with the view code and how the checkboxes are appearing on the page, but we could not find any solution to this issue when searching.
Try the find the checkboxes in this way:
within('.form-group') do
page.find('input[type=checkbox]').set(true)
end
If you use chrome, you can inspect the element and copy the css or xpath. That helps me a lot. Also, if you use the pry gem, I sometimes set js: true on capybara, so I can see what's going on in the browser, then walk through step by step until I get what I want. For me, it's way easier to do it that way.

Testing fields added dynamically by cocoon using rspec and capybara

I was wondering whether anybody tests fields that were dynamically added by cocoon?
It's a great little time saver but all of the fields that are added dynamically have really long numerics added to the ID and name. This means that I have to skip testing that requires more than one (set of) field(s) on the page.
Afaik you could test for two things:
that the dynamic addition of the nested elements works
creating elements, filling it in and storing them in the database
So assume the relevant part of your view looks like this (default example):
#tasks
= f.semantic_fields_for :tasks do |task|
= render 'task_fields', :f => task
.links
= link_to_add_association 'add task', f, :tasks
and your nested element looks like
.nested-fields
= f.input :description
= f.input :done, :as => :boolean
= link_to_remove_association "remove task", f
So normally you give it a class, i normally just test the count of elements on the page.
So if one element is already there, creating a new element, the count should be two. This you could test with
find("#tasks .nested-fields").count.should == 2
Filling in the newly added nested element, you could use the :last-child css selector
find("#tasks .nested-fields:last-child input#description").set("something")
How names and id are formed, are close to rails internals, so i try to stay away of those.
Maybe using Capybara finders all, first and the selector input. Something like this:
visit new_resource_path
click_link "Add a Nested Resource"
first("input[name='nested_resource[name]']").set("Nested Resource")
click_button "submit"
Or
visit new_resource_path
click_link "Add a Nested Resource"
click_link "Add a Nested resource"
all("input[name='nested_resource[name]']").each do |input|
input.set("Nested Resource")
end
click_button "submit
This is only an approach, I've never worked with cocoon. This is however, a form to test dynamic inputs.
Strange.
i have in the form (haml):
= link_to_add_association f, :staff_phases, class: :button, id: 'add-staff-phase-link' do
%i.fas.fa-plus
and in my test
click_link 'add-staff-phase-link'
save_and_open_page
the click_link works but i can see no added association.
if i, then on the opened page, click the link by mouse, the cocoon-link works and adds a association
It might be common knowledge, but sharing this as it worked for me when dealing with a nested attribute that requires a select instead of a text input. I find all instances of my select fields, then pick the select field I want to updated with my preferred option like below:
page.find_all('select[id^="model_model_nested_attributes_"]')[2].select("preferred_option")
A possible alternate that I just used is to dynamically update the label of each added form field (using the technique mentioned in https://github.com/nathanvda/cocoon/issues/374) and now my Cucumber/Capybara tests can easily insert text into the different multiple form fields distinguishing them via the different labels they have.
Full details on what I did in this PR https://github.com/AgileVentures/WebsiteOne/pull/1818

Capybara + Selenium: save_and_open_page shows button, but capybara can't find it

My capybara test includes these lines:
click_button "SHARE"
fill_in 'Email Address', :with => #user_two.email
save_and_open_page
click_button 'CONFIRM'
the share button would make a modal visible. Filling in the email address text box of this modal seems to go off without a hitch, but I receive the following error for the button
Capybara::ElementNotFound:
Unable to find button "CONFIRM"
However, when I save_and_open_page, the button is visible.
I've tried switching to
page.find("#id-of-button").click
but Capybara can't find that either.
It's interesting to note the save_and_open_page shows me a page where the field for email hasn't been filled in.
I think I might be missing something basic about how save_and_open_page works because if that is the page Capybara is seeing in its totality then these errors make no sense to me...
edit: Modal view code
.title.aaux
Title
.content
.line-separator
#intro
Enter Email:
= form_for(patient, url: {controller: "dashboard/patients", action: "share_with_user"}, method: :post, html: {id: "share-patient-form"}) do |f|
%fieldset.bordered
= f.text_field :share_user_email, placeholder: "Email Address", class: "aaux form-control"
.line-separator
#button-row
%button.btn.btn-success.aaux.pull-right#confirm-share-patient{type: "submit"}
CONFIRM
%button.btn.btn-cancel.aaux.pull-right#close-modal-share-patient
CANCEL
edit: source code generated for button
<button type="submit" id="confirm-share-patient-button" class="btn btn-success aaux pull-right">
CONFIRM
</button>
I changed from selenium webdrive to capybara-webkit, and the issue no longer occurred.

Why isn't Capybara filling in these form elements?

I have been trying to set up Capybara to test a form but I keep getting the error
cannot fill in, no text field, text area or password field with id, name, or label 'Name' found
Here is what I have in my view:
<%= form_for(#user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
...
<%= f.submit "Create Account", class: "btn btn-large btn-primary" %>
<% end %>
which renders the following html:
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" size="30" type="text" />
So it seems like it should be finding the field based on the label.
Here is what my user_pages_test.rb file has (I am using Test::Unit and shoulda-context):
context "sign up page" do
should "add user to database when fields are filled in" do
fill_in "Name", with: "Bubbles"
...
click_button "Create Account"
end
end
Here is what I've tried so far:
1) changing the call to fill_in to match the id with fill_in "user_name", with: "Bubbles"
2) changing the call to fill_in to page.fill_in "Name", with: "Bubbles" to match the example in the documentation
3) changing the view to manually add the id "Name" with <%= f.text_field :name, id: "Name" %> (this answer)
4) changing the call to get sign_up_path to get "/sign_up" (in case it was an issue with the routing)
All these still give me the same error, which makes me think that the page isn't being loaded correctly for some reason. However, I have a different (passing) test in the same context that asserts the page has the correct title, so I know the page does get loaded correctly (in the setup).
Based on this (and according to this answer), it seems like the problem might just be that the fill_in method isn't waiting for the page to load before trying to access the fields. According to this suggestion, I added the line puts page.body in my test to see that the HTML was being loaded completely before it was trying to fill in the fields, and got the following output:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
So, I was pretty sure that fill_in just wasn't waiting for the page to load. I then tried
5) changing the Capybara.default_wait_time according to this answer, but this had no effect. I tried setting it in the ActionDispatch::IntegrationTest class in the test_helper file (where Capybara is included), and also in the test itself.
Then I tried adding puts page.body in the passing test (both before and after it asserts the correct title), and I got the same output. THEN, I found this answer, and finally got the console to print out the page's HTML. I tried one more thing to get Capybara to fill in the fields:
6) changed the call to fill_in to say #response.fill_in, since #response seems to do what I thought the page variable was supposed to do.
So, I have two questions about this:
1) What does the page variable actually refer to? The doctype declaration for my app is just <!DOCTYPE html>, so I have no idea where it gets the old one from.
2) Why isn't Capybara able to find/fill_in these fields?
You need to use the visit method to get the page object setup properly. The capybara documentation indicates that '/' is visited by default and if you want to visit some other page you need to do an explicit call. It may also be helpful to read a bit about the difference between visit and get.

Rspec NoMethodError: undefined method `call', yet everything works via rails console

I'm a rails/rspec newb trying to learn. I've setup the following data model (excerpt)
t.string :foo
t.string :bar
t.date :future_date
and I have a web form to create these entries associated with a user, similar to the microposts in this rails tutorial. The web form looks like this (excerpt):
<%= f.label :foo %>
<%= f.text_field :foo %>
<%= f.label :bar %>
<%= f.text_field :bar %>
<%= f.date_select :future_date %>
with a button, "Create", that initiates the post. Everything seems to work fine via rails console; the web form displays correctly, the entries are created correctly, the database is being populated correctly. However, when I run rspec I get
NoMethodError:
undefined method `call' for #<RSpec::Expectations::ExpectationTarget:0x0000000492b7c0>
Here is the relevant request spec (excerpt):
it "should not create a foobar" do
expect { click_button "Create" }.should_not change(Foobar, :count)
end
In other words, click "Create" with no info filled in. I have a similar example later with info filled in but nearly the same click_button that also throws this error (should change .by(1)). I have similar click_button tests working fine for the user creation portion (nothing/something entered) which, other than future_date, is very similar. That, plus something I ran across in my endless googling, leads me to believe the date is somehow to blame, perhaps an inconsistency in versions or something. Especially since in actual use everything is working fine. This is with ruby 1.9.3, Rails 3.2.6, and Rspec 2.11.1. Any insight is very much appreciated.
In RSpec >= 2.11 you should use to method instead of should
expect { click_button "Create" }.to_not change(Foobar, :count)
That should say...
it "should not create a foobar" do
lambda { click_button "Create" }.should_not change(Foobar, :count)
end
... so lambda, not expect.

Resources