SelectList with Mechanize in Ruby - ruby

I'm trying to set the value of a select list using Mechanize with Ruby. I can navigate to the page with the select list, grab the form using the .form method, and find the select list.
report_form =page.form('form1')
pp report_form.field_with(:name => "report_type")
Correctly returns the right object.
However, I'm still unable to set the value of this field! I've tried:
report_form.field_with(:name => "report_type").options.first.select
report_form.field_with(:name => "report_type").options[1].select
report_form.field_with(:name => "report_type").value = "Foo"
But when I then do:
pp report_form.field_with(:name => "report_type")
The value field is still empty.
Is there something I'm missing? Tips? Tricks? Better Mechanize docs than what live at http://mechanize.rubyforge.org?
Thanks!
Edit: The relevant HTML is:
The relevant HTML is:
<TD>
<select id="report_type" name="report_type">
<option value="Foo1">Opt 1</option>
<option value="Foo2">Opt 2</option>
<option value="Foo3">Opt 3</option>
</select></TD>

Try this
report_form.field_with(:name => "report_type").option_with(:value => "Foo").click
# now report_form.field_With(:name => "report_type").value should bee "Foo"
(via 1, 2)

It's usually good enough to do:
report_form["report_type"] = "Foo"

i ran into this same issue, nothing works for me either, but id like to clarify that im able to set the value to anything besides select options.
report_form.field_with(:name => "report_type").value = "Foo1"
report_form["report_type"]
=> "Foo1"
report_form.field_with(:name => "report_type").value
=> "Foo1"
report_form.field_with(:name => "report_type")
=> [selectlist:0x7c08ada type: name: "report_type" value: []]
after submiting the form, the select is treated as empty, however if i do
report_form.field_with(:name => "report_type").value = "anything not in the options"
report_form.field_with(:name => "report_type")
=> [selectlist:0x7c08ada type: name: "report_type" value: ["anything not in the options"]]

Foo is not in the select list, i think if you change it to Foo1 (or the others) it should work!?

It actually turned out to be a bug in the Mechanize gem. Make sure you're using v 0.6.0 or newer.

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")

Ruby's Mechanize balks when selecting a radio button (maybe because its name is capitalized) but Perl's WWW::Mechanize works fine

I'm trying to submit a form with Ruby's Mechanize gem. This form has a set of radio buttons named "KeywordType". The individual buttons are named something like rdoAny, rdoAll and rdoPhrase. With Perl's WWW:Mechanize it works just fine:
my $result = $agent->submit_form(
form_number => 1,
fields => {
txtKeywords => 'foo bar baz',
lstLocationCode => '2100',
lstONETMajorGroup => '0',
KeywordType => 'rdoAny'
},
button => 'btnSearch'
);
but Ruby balks when I do this:
result = page.form_with(:id => 'frmSearch') do |field|
field.txtKeywords = 'foo bar baz'
field.lstLocationCode = '2100'
field.lstONETMajorGroup = '0'
field.KeywordType = 'rdoAny'
end.submit
This throws the error
"undefined method `KeywordType=' for #<Mechanize::Form:0x00000001c896e0> (NoMethodError)".
I've tried leaving out the KeywordType field, but then I just get sent back to the same page with no obvious error message. I've also tried doing things like field.radiobuttons.second.check and field.radiobuttons_with(:name => "KeywordType") to no avail.
And on a side note, is whatever's going on because Ruby sees a capitalized radiobutton name and thinks it's a constant?
Thanks.
Does this work?
field['KeywordType'] = 'rdoAny'
Edit: Oh, and I think you missed a part here:
result = page.form_with(:id => 'frmSearch') do |field|
should be (I think):
result = page.form_with(:id => 'frmSearch').fields.each do |field|
Gaah. The outdated version gremlin strikes again. "gem update mechanize" is now at least showing me the values for the two dropdowns.

Capybara: Select an option by value not text

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)

Override id on a ruby object (created using OpenStruct)

I want to convert a hash to an object using OpenStruct that has an id property, however the resultant object#id returns the native object id, e.g.
test = OpenStruct.new({:id => 666})
test.id # => 70262018230400
Is there anyway to override this? As at the moment my workaround isn't so pretty.
OpenStruct uses a combination of define_method calls inside an unless self.respond_to?(name) check and method_missing. This means if the property name conflicts with the name of any existing method on the object then you will encounter this problem.
tokland's answer if good but another alternative is to undefine the id method e.g.
test.instance_eval('undef id')
You could also incorporate this into your own customised version of OpenStruct e.g.
class OpenStruct2 < OpenStruct
undef id
end
irb(main):009:0> test2 = OpenStruct2.new({:id => 666})
=> #<OpenStruct2 id=666>
irb(main):010:0> test2.id
=> 666
This was the classical workaround, I'd be also glad to hear a better way:
>> OpenStruct.send(:define_method, :id) { #table[:id] }
=> #<Proc:0x00007fbd43798990#(irb):1>
>> OpenStruct.new(:id => 666).id
=> 666
I've switched to using Hashery and the BasicStruct (renamed version of OpenObject in latest version, 1.4) as that allows me to do this:
x = BasicStruct.new({:id => 666, :sub => BasicStruct.new({:foo => 'bar', :id => 777})})
x.id # => 666
x.sub.id # => 777
x.sub.foo # => "bar"

Firewatir: Firewatir dynamic drop down issue

I am having any issue with selecting any item from the drop down. Below is the HTML from our site. The HTML looks like this
<div class="x-form-field-wrap x-trigger-wrap-focus"
id="ext-gen157" style="width: 170px;"><input type="hidden"
id="parentEntity" name="parentEntity" value=""><input type="text"
id="cmbParentEntityId" autocomplete="off" size="24" class="
x-form-text x-form-field x-form-focus" style="width: 145px;">
<img class="x-form-trigger x-form-arrow-trigger"
src="../ext/resources/images/default/s.gif" id="ext-gen158"></div>
So I have created a watir code which looks like this:
#browser.text_field(:id,"cmbParentEntityId").set("1")
which search for all the accounts starting with 1.Once the value is set to 1, the drop down is showing only accounts starting with 1. Below is the HTML code from the drop down
<div class="x-combo-list-inner" id="ext-gen336" style="width:
248px; overflow: auto; height: 40px;"><div class="x-combo-list-item
x-combo-selected">10_12_2010</div><div
class="x-combo-list-item ">10_13_2010</div></div>
Based on the above code I have created the Watir code
#browser.div(:class => "x-combo-list-inner", :text => "10_12_2010").click
But nothing is happening, I have searched the web but couldn't find any answers, I really appreciate that if anyone can help me to point to right direction.
Thanks
What do you mean that nothing is happening? If i try the code provided by you, then i'll get an expected UnknownObjectException:
irb(main):003:0> b.div(:class => "x-combo-list-inner", :text => "10_12_2010").click
Watir::Exception::UnknownObjectException: Unable to locate element, using {:class=>"x-combo-list-inner", :text=>"10_12_2010"}
from c:/Ruby/lib/ruby/gems/1.8/gems/watir-1.6.6/lib/watir/element.rb:57:in `assert_exists'
from c:/Ruby/lib/ruby/gems/1.8/gems/watir-1.6.6/lib/watir/element.rb:315:in `enabled?'
from c:/Ruby/lib/ruby/gems/1.8/gems/watir-1.6.6/lib/watir/element.rb:62:in `assert_enabled'
from c:/Ruby/lib/ruby/gems/1.8/gems/watir-1.6.6/lib/watir/element.rb:259:in `click!'
from c:/Ruby/lib/ruby/gems/1.8/gems/watir-1.6.6/lib/watir/element.rb:229:in `click'
from (irb):3
That is because you're trying to find a div element with a class of "x-combo-list-inner" and a text of "10_12_2010". There isn't such an element. See this:
irb(main):007:0> b.div(:class => "x-combo-list-inner").text
=> "10_12_2010\r\n10_13_2010"
Text of "x-combo-list-inner" includes texts for every child element. You could search for that particular child element like this:
irb(main):008:0> b.div(:class => "x-combo-list-inner").div(:text => "10_12_2010").html
=> "\r\n<DIV class=\"x-combo-list-item
x-combo-selected\">10_12_2010</DIV>"
Or with regexps:
irb(main):009:0> b.div(:class => "x-combo-list-inner", :text => /10_12_2010/).text
=> "10_12_2010\r\n10_13_2010"
And when it comes to clicking then you have to know which exact div you need to click - is it the first one, or the second one. Also, if nothing happens then you have to find out what JavaScript events are binded to these elements exactly and then fire events manually:
irb(main):010:0> div = b.div(:class => "x-combo-list-inner").div(:text => "10_12_2010")
=> #<Watir::Div:0x5846088 located=false how={:text=>"10_12_2010"} what=nil>
irb(main):013:0> div.fire_event("onmousedown")
=> nil
irb(main):014:0> div.fire_event("onmouseup")
=> nil
My guess is that some JavaScript event should be explicitly fired. See How to find out which JavaScript events fired?

Resources