Capybara: Select an option by value not text - ruby

For the HTML
<select id="date">
<option value="20120904">Tue 4 Sep 2012</option>
<option value="20120905">Wed 5 Sep 2012</option>
<option value="20120906">Thu 6 Sep 2012</option>
</select>
I have the following Capybara Ruby code:
select "20120905", :from => "date"
But this errors with:
cannot select option, no option with text '20120905' in select box 'date' (Capybara::ElementNotFound)
However, if I do
select "Wed 5 Sep 2012", :from => "date"
It's ok.
Is it possible to select an option in Capybara by Value not Text?
Thanks

This will work to select an option by value:
find("option[value='20120905']").click
To maintain the scope of the selector you could wrap it in a within block as such:
within '#date' do
find("option[value='20120905']").click
end

With Poltergeist as driver I can't click on an option like suggested in some of the other options above, instead you can do the following:
page.find_by_id('date').find("option[value='20120905']").select_option

I wrote a helper method:
def select_by_value(id, value)
option_xpath = "//*[#id='#{id}']/option[#value='#{value}']"
option = find(:xpath, option_xpath).text
select(option, :from => id)
end
Save in a .rb file in spec/support/
Example use:
before do
select_by_value 'some_field_id', 'value'
click_button 'Submit'
end

You can also achieve it by doing the following:
find_by_id('date').find("option[value='20120905']").click

That helper method is pretty clever. I would change it just a little bit:
def select_by_value(id, value)
option_xpath = "//*[#id='#{id}']/option[#value='#{value}']"
find(:xpath, option_xpath).click
end
or just:
find(:xpath, "//select[#id='date']/option[#value='20120904']").click

In my case I have a few options with same text, that's the reason why I need select by value. Combining a few answers together I've found the best solution for me:
def select_by_value(id, value)
option_xpath = "//*[#id='#{id}']/option[#value='#{value}']"
find(:xpath, option_xpath).select_option
end

Click using find_field works fine:
find_field("date").find("option[value='20120905']").click

You could also use capybara-ui which will look first to match the text, then to match the value.
# define your form widget, in this case in a role
class UserRole < Capybara::UI::Role
form :my_form do
select :my_select, 'my_select'
end
end
# then just submit your form params via #submit
role = UserRole.new
role.submit :my_form, my_select: '20120905'
See more about capybara-ui forms here.

In case of not visible field, try this
find("#date", visible: false).find("option[value='20120905']").click
Or with scope as:
within '#date', visible: false do
find("option[value='20120905']").click
end

You're setting the value.
find(selector).set(value)

Related

Insert value in a text field using Ruby - watir/selenium

I am trying to insert a number in the 'Mine Id' using Ruby - Watir/Selenium
Somehow the field <input> field is not being recognized as a text box and hence I am unable to enter values through the code.
The id 'inputdrs' is used multiple times on the same page.
Any suggestions how to achieve it.
The URL is this
http://www.msha.gov/drs/drshome.htm
The below don't work:
#browser.text_field(:id => /inputdrs/, :index => 2).set("3607277")
browser.text_field(:name, "inputdrs").set("3607277")
Thank you for your help
require 'watir-webdriver'
$browser = Watir::Browser.start "http://www.msha.gov/drs/drshome.htm"
a = 0
b = $browser.text_fields.length
while a < b
$browser.text_fields[a].set a
a += 1
end
This will put the value of a in each text field on this page. I REALLY drew out the loop so you can see whats going on. This isn't as dynamic as you would like it, but if the page has the same amount of text_fields you should be fine.
OR you can do something like..
$browser.text_field(:name => "MineId").select
$browser.send_keys "hello"
Problem
The html of the Mine ID field is:
<input size="8" maxlength="8" name="MineId" onclick="this.value='';" id="inputdrs" align="middle" type="number">
The line:
#browser.text_field(:id => /inputdrs/, :index => 2).set("3607277")
Will fail because it is inputting into the wrong text field. If you get all of the text fields with that id:
browser.text_fields(:id => 'inputdrs').collect(&:name)
#=> ["q", "MineId", "OperSearch", "MineName", "CntctrId", "CntCtrSearch", "Controller"]
You can see it is the second field. However, because Watir is using a 0-based index, you actually get the OperSearch field. This would have worked by using an :index => 1 instead.
The line:
browser.text_field(:name, "inputdrs").set("3607277")
Will fail because the "inputdrs" is the value of the id attribute and not the name attribute.
Solution
Given that the id attribute value is not unique for this page, you should probably not use it for locating. Instead, use something unique, such as the name attribute.
browser.text_field(:name => "MineId").set("3607277")

Entering text into tinymce using webdriver, ruby and variables

I'm using webdriver and Ruby...
So I was able to write text into a tinymce field using the script below. However on the last line, driver.execute... I would like to change the static value 'bob' to be the value of the variable being passed, parValue. I've tried few modifications to the driver.execute_script line, but I continue to get errors. In other words, I don't know javascript and I am unable to find a way to do this.
I've tried replacing the code and use sendkeys, but that does not print anything to my tinymce box. Is there a way to use the value being passed in from parValue and replace 'bob'?
def enterValues(driver,parField,parValue)
tinymce_frame = driver.find_element(:id => parField)
driver.switch_to.default_content
driver.switch_to.frame(tinymce_frame)
editor_body = driver.find_element(:tag_name => 'body')
driver.execute_script("arguments[0].innerHTML = 'bob'", editor_body)
end
this seems kind of simple so I'm worried I might be misunderstanding but you could use ruby's string interpolation to replace bob with parvalue:
def enterValues(driver,parField,parValue)
tinymce_frame = driver.find_element(:id => parField)
driver.switch_to.default_content
driver.switch_to.frame(tinymce_frame)
editor_body = driver.find_element(:tag_name => 'body')
driver.execute_script("arguments[0].innerHTML = '#{parValue}'", editor_body)
end

How do I use a method in a simple_form input without submitting it in the form?

Ok, this should be on here already somewhere, but I can't find it.
I'm building a form with simple_form, and I'm using a dummy radio select input which values are based on a method (named 'simple?') in my 'Price' model. The methods looks if some attributes are used and returns false if they are. This way I can hide the advanced inputs in my form if they are not used.
I want to use simple_form so the method is connected to the right object because more prices can be made (and created) in the same form.
I use the radio buttons (and javascript) so users can still unhide the advanced fields.
Problem is when I submit the form, the form including the :simple? method is submitted, which returns errors because it is just a method.
Question is: How do I make sure the ':simple?' value for the is not submitted through the form, but is initiated to the right value? Or is there a smarter way of doing this?
form.haml
= f.input :simple?, as: :radio, label: "Simple price?"
price.rb
def simple?
true unless advanced?
end
def advanced?
specific_days? || period_id? || description? || begin_time? || end_time?
end
Thanks for any feedback!
If you rename simple? to is_simple you can implement a virtual attribute in your model
def is_simple
true unless advanced?
end
def is_simple= _ignored
# NOOP
end
def advanced?
specific_days? || period_id? || description? || begin_time? || end_time?
end
and then use :is_simple in your form
= f.input :is_simple, as: :radio, label: "Simple price?"
The renaming is necessary because def simple?= will lead to a syntax-error.

How to change the values in textbox using capybara?

For example the text box is having the value 10
I need to change the value to 20
while I am using the below Capybara command,
fill_in "#{ID}", :with => "20"
the value is not getting changed ... instead its appended as 1020.
Give me your suggestions.
I've had to use javascript to do this. I wrote a separate step to clear the field before changing the value.
page.execute_script("$('#{field_id}').val('');")
I believe the correct syntax is
fill_in "ID", :with => "20"

How do I get an array of check boxes in haml?

I have an array of strings, called #theModels, in a routine implemented as part of a Sinatra server. These models are options for the user to select, and are obtained by the back end (the idea being, as new models are added, then the front end code should not change).
I'm using haml to render html.
How can I enumerate each element in the list of #theModels such that each element is a checkbox? And how can I obtain which checkboxes the user has selected?
I see that just putting
= #theModels
will give me the list of strings contained in #theModels, but without spacing or the like, and certainly not in checkboxes. I've found this question that appears to be similar, but my haml-fu isn't good enough to convert that into what I need.
UPDATE:
These are options associated with a file upload, such that now the code looks like:
%form{:action=>"/Upload",:method=>"post",:enctype=>"multipart/form-data"}
- #theModelHash.each do |key,value|
%br
%input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
=key
%input{:type=>"file",:name=>"file"}
%input{:type=>"submit",:value=>"Upload"}
Problem is, that puts a file upload button on each option, instead of at the end. I only want one submit button in the end; should I have two forms that both report their results when the 'Upload' button is pressed?
UPDATE2:
After a moment's thought, the above can be modified to:
Thanks!
%form{:action=>"/Upload",:method=>"post",:enctype=>"multipart/form-data"}
- #theModelHash.each do |key,value|
%br
%input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
=key
%form{:action=>"/Upload",:method=>"post",:enctype=>"multipart/form-data"}
%input{:type=>"file",:name=>"file"}
%input{:type=>"submit",:value=>"Upload"}
And that appears to do what I want.
I think you should send the content as an hash instead.
This will give you the opportunity to set initial values in the form.
The hash #params will give you the result.
E.g. {"oranges"=>"1"}
#app.haml
%form{:method => 'post', :action => "/"}
- #models.each do |key,value|
%br
%input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
=key
%input{:type => :submit, :value => "Save"}
#app.rb
require 'sinatra'
require 'haml'
get '/' do
#models = {"oranges" => true, "bananas" => false}
haml :app
end
post '/' do
#params.inspect
end
The link you provided linked to a rails solution where you have a function returning the proper html.
You can define this function yourself:
Input: key, value
Output: %input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
def check_box(key, value)
...
end
and call it in haml with
=check_box(key,value)

Resources