Capybara and Cucumber cannot find checkboxes even with unique ID - ruby-on-rails

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.

Related

How can I put an "add new" link in a collection_select field in Rails

I want to build a sales_opportunity in my Rails app. The sales_opportunity belongs_to a User and also to a Company. The code works fine as it currently stands, and the form permits a user to select a company to link the sales_opportunity with based on a collection of companies that are pre-defined in the database. What I want is the ability to have a field in the collection_select drop down menu that has "add new company" and takes the user to the companies/new page. At the moment the sales_opportunity cannot be submitted unless a user has previously added companies to his Organization (User belongs_to Organization, Company belongs_to Organization).
The code for the field is as follows:
<div class="form-group">
<%= f.label :company_id, :class => "col-md-4 control-label" %>
<div class ="col-md-8">
<%= f.collection_select :company_id, #user.organization.companies(:company_name), :id, :company_name %>
</div>
</div>
Is there a way I can add a link to this dropdown that will enable the user to add a company to the list if none exists (or if the company he wants to add doesn't exist in the list already)?
The only way I can think to overcome this is for an if statement that has a link to a button to add a company if none exist - but this doesn't cover the scenario where companies are in the database but not the one the user wants.
Any ideas?
You can do this using JavaScript but it will take a bit of work. You question is quite broad so I haven't included any code but I've outlined the basic steps as a starting point.
1) You'll need to add a JavaScript event handler to watch the dropdown, when the 'add new' option is selected it will trigger an Ajax request.
2) The Ajax request will render the create action (a modal box would be nice for the user).
3) When the user submits the form it will update via Ajax.
4) Reload the dropdown via Ajax to display the new company.
As you can see, most of the complexity is on the JS side rather than Rails :)

How to read values from multiple checkbox in ruby-on-rails

How to read values from checkbox in rails.
Suppose I have brands and products.Under brands table, I have 3 brands say nike,reebok and puma. When none of the check box is selected It should display all the products say shirts,trousers,skirts. If nike brand is selected then should display onlt nike related products.Also user should have access to select more than 1 brands and we should able to display corresponding product details.
Conceptually what you are doing is a lot like creating a form that acts as a search engine (Ryan Bates does great screen casts and can help get you if you get lost http://railscasts.com/episodes/37-simple-search-form). Instead of entering text, the form uses checkboxes to create an array of brands the user wants to see.
First Create the form
<%= form_tag your_path_here_path, method: :get do %>
<%= label_tag :Nike %>
<%= check_box_tag 'brands[]', '1' #assuming 1 is the id of the Nike brand%>
<%= label_tag :Reebok %>
<%= check_box_tag 'brands[]', '2'%>
<%= label_tag :Puma %>
<%= check_box_tag 'brands[]', '3'%>
<%= submit_tag 'Get Products'%>
<%- end %>
Then in the controller processing this request search for the products that match brands in the form like this
Products.where('brand_id IN (?)', params[:brands])
To go a bit further. People use JS for these types of problems so that as the user checks different brands the products will automatically reload on the page without the user having to hit a submit button.
This could be accomplished by writing a JQuery function that listens to check events on your brands checkboxes and then
1) makes an Ajax call in the background to get all the relevant
products
2) Removes all the products you don't currently need on the page
3) Shows all the new products.
If you don't know any JQuery this project could be an interesting way to get started learning. Again, railscasts can help http://railscasts.com/episodes/136-jquery

Show and hide based on user role in rails

I have the following code in my home.html.erb file;
<!-- if seeker is logged in show button "Grab it" -->
<% if user_signed_in? %>
<div class="grabit alignright">
<small>want to work on this?</small>
<!-- if seeker is not logged in, show him the output text of "Sign in to work on this job" -->
<% else %>
<small>are you a guru? want to work on this? Sign up.</small>
<% end %>
</div>
Now as you can see I'm trying to have Seeker as a user role. Depending if that type of user with that type of role is signed in or not, different content is shown.
I have Devise + CanCan installed. Now very new to this and I've looked all over to see how to do this. I will have "Users" with normal roles of users and "Seekers" with seeker role. Using the above code only shows when a user is signed in, but not a seeker.
Is it as simple as seekers_signed_in? that I should be using? compare to user_signed_in? I've generated the Devise views for both Users and Seekers and Admins. Admins will be able to delete, update, etc. for users and seekers. Users post items and Seekers grab them.
Can anyone help?
You don't have to create Users& Seekers (two devise models), instead you can create only one model as common and call it User, then add as many roles as you need.
I recommend using this gem for easy roles configuration,
Then in your home.html.erb you simply do the following:
<!-- if seeker is logged in show button "Grab it" -->
<% if user_signed_in? && current_user.is_seeker? %>
<div class="grabit alignright">
<small>want to work on this?</small>
<!-- if seeker is not logged in, show him the output text of "Sign in to work on this job" -->
<% else if !user_signed_in?%>
<small>are you a guru? want to work on this? Sign up.</small>
<% else%>
<small>You are not a seeker, you need to be a seeker!</small>
<% end %>
</div>
CanCan is used at Controller level, so the above approach is easy and direct for your case.
I hope this will help.

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.

How to make the 'I fill in' step in Cucumber find a field w/o defining the label?

I am starting with Cucumber and I am running this simple scenario:
Scenario: Creating a project
Given I go to the new project page
And I fill in "Name" with "xxx"
...
The new project form is already in place and looks like this:
<% form_for (#project) do |f| %>
<%= f.text_field :name %>
...
<% end %>
As you can see I haven't defined a label (don't need one). The problem is that cucumber doesn't find the field:
Given I go to the new project page
And I fill in "Name" with "I need something" #
features/step_definitions/web_steps.rb:68
cannot fill in, no text field, text area or password field with id,
name, or label 'Name' found
(Capybara::ElementNotFound)
However it finds it if I add the label. I find it a little bit suspicious that it can't match the name I gave with the appropriate text field.
What is wrong?
Thank you
Try changing your cucumber feature to read:
Scenario: Creating a project
Given I go to the new project page
And I fill in "project_name" with "xxx"
Or...
Scenario: Creating a project
Given I go to the new project page
And I fill in "project[name]" with "xxx"
The reason this is failing is because if you have no label, capybara (which cucumber uses) looks for the ID or name attribute of the field. As apneadiving mentions, you can check these values by looking at the source of the generated file. You'll see something like:
<input id="project_name" name="project[name]" type="text">
The name of your textfield is by default:
project[name]
Actually it follows the rule:
object[field]
You should look at your dom and check it.
Edit:
Jus FYI, It's weird to see:
<% form_for (#project) do |f| %>
instead of:
<%= form_for (#project) do |f| %>
I had the same problem and I fixed it by simply changing
<% form_for ... %>
to
<%= for_for ... %>
The addition of the '=' enables the display of the form fields, which allows Capybara to correctly identify it.

Resources