Nokogiri Error: undefined method `radiobutton_with' - Why? - ruby

I try to access a form using mechanize (Ruby).
On my form I have a gorup of Radiobuttons.
So I want to check one of them.
I wrote:
target_form = (page/:form).find{ |elem| elem['id'] == 'formid'}
target_form.radiobutton_with(:name => "radiobuttonname")[2].check
In this line I want to check the radiobutton with the value of 2.
But in this line, I get an error:
: undefined method `radiobutton_with' for #<Nokogiri::XML::Element:0x9b86ea> (NoMethodError)

The problem occured because using a Mechanize page as a Nokogiri document (by calling the / method, or search, or xpath, etc.) returns Nokogiri elements, not Mechanize elements with their special methods.
As noted in the comments, you can be sure to get a Mechanize::Form by using the form_with method to find your form instead.
Sometimes, however, you can find the element you want with Nokogiri but not with Mechanize. For example, consider a page with a <select> element that is not inside a <form>. Since there is no form, you can't use the Mechanize field_with method to find the select and get a Mechanize::Form::SelectList instance.
If you have a Nokogiri element and you want the Mechanize equivalent, you can create it by passing the Nokogiri element to the constructor. For example:
sel = Mechanize::Form::SelectList.new( page.at_xpath('//select[#name="city"]') )
In your case where you had a Nokogiri::XML::Element and wanted a Mechanize::Form:
# Find the xml element
target_form = (page/:form).find{ |elem| elem['id'] == 'formid'}
target_form = Mechanize::Form.new( target_form )
P.S. The first line above is more simply achieved by target_form = page.at_css('#formid').

Related

How to count number of matches using page object?

My application has a list and it's size changes very regularly. So I need to get the li count before starting the test cases. So this is how I used to get the count
b.lis(:xpath => "//ul[#id='global_nav']/li[contains(#id, 'nav-')]").count
Now I need to achieve this in page object way. I declared the list in my page file as below.
list_item(:global_nav_count, :xpath => "//ul[#id='global_nav']/li[contains(#id, 'nav-')]")
If I try to get count as below
page.global_nav_count_element.count
It returns method not found error. Can any one suggest any solution to achieve this in page object way ?
The list_item accessor is similar to Watir's li method in that it returns the first matching element. If you want a collection of elements, you need to tell the page object.
The accessor for a collection of li elements is list_items (note the plural):
list_items(:global_nav_count, :xpath => "//ul[#id='global_nav']/li[contains(#id, 'nav-')]")
The method created to access the collection is also pluralized:
page.global_nav_count_elements.count

Can't compare expected result for <nobr> tag

There is a nobr tag with some text:
<nobr>+380</nobr>
I have described it in page-object:
elements(:txtCode, :nobr, :xpath => "//td[#id='phone_prefix']/nobr")
I need to check its value and I use following expectation:
expect(page.txtCode.text).to eql('+380')
But I'm getting the following error:
undefined method `txtCode' for #<Page:0x3071d30>
How do i describe this nobr element to bring the expect() to work?
You're defining an element collection instead of an element because you're using elements instead of element. The only method that creates on your page object is txtCode_elements. Use element instead.
element(:txtCode, :nobr, :xpath => "//td[#id='phone_prefix']/nobr")
You can read more about element collections from this blog post by Justin Ko: https://jkotests.wordpress.com/2013/06/24/defining-element-collections-using-the-page-objects-gem/

Posting data on website using Mechanize Nokogiri Selenium

I need to post data on a website through a program.
To achieve this I am using Mechanize Nokogiri and Selenium.
Here's my code :
def aeiexport
# first Mechanize is submitting the form to identify yourself on the website
agent = Mechanize.new
agent.get("https://www.glou.com")
form_login_AEI = agent.page.forms.first
form_login_AEI.util_vlogin = "42"
form_login_AEI.util_vpassword = "666"
# this is suppose to submit the form I think
page_compet_list = agent.submit(form_login_AEI, form_login_AEI.buttons.first)
#to be able to scrap the page you end up on after submitting form
body = page_compet_list.body
html_body = Nokogiri::HTML(body)
#tds give back an array of td
tds = html_body.css('.L1').xpath("//table/tbody/tr[position()>1]/td")
# Checking my array of td with some condition
tds.each do |td|
link = td.children.first # Select the first children
if link.html = "2015 32 92 0076 012"
# Only consider the html part of the link, if matched follow the previous link
previous_td = td.previous
previous_url = previous_td.children.first.href
#following the link contained in previous_url
page_selected_compet = agent.get(previous_url)
# to be able to scrap the page I end up on
body = page_selected_compet.body
html_body = Nokogiri::HTML(body)
joueur_access = html_body.search('#tabs0head2 a')
# clicking on the link
joueur_access.click
rechercher_par_numéro_de_licence = html_body.css('.L1').xpath("//table/tbody/tr/td[1]/a[1]")
pure_link_rechercher_par_numéro_de_licence = rechercher_par_numéro_de_licence['href']
#following pure_link_rechercher_par_numéro_de_licence
page_submit_licence = agent.get(pure_link_rechercher_par_numéro_de_licence)
body_submit_licence = page_submit_licence.body
html_body = Nokogiri::HTML(body_submit_licence)
#posting my data in the right field
form.field_with(:name => 'lic_cno[0]') == "9511681"
1) So far what do you think about this code, Do you think there is an error in there
2) This part is the one I am really not sure about : I have posted my data in the right field but now I need to submit it. The problem is that the button I need to click is like this:
<input type="button" class="button" onclick="dispatchAndSubmit(document.JoueurRechercheForm, 'rechercher');" value="Rechercher">
it triggers a javascript function onclick. I am triying Selenium to trigger the click event. Then I end up on another page, where I need to click a few more times.. I tried this:
driver.find_element(:value=> 'Rechercher').click
driver.find_element(:name=> 'sel').click
driver.find_element(:value=> 'Sélectionner').click
driver.find_element(:value=> 'Inscrire').click
But so far I have not succeeded in posting the data.
Could you please tell me if selenium will enable me to do what I need to do. If can I do it ?
At a glance your code can use less indentation and more white space/empty lines to separate the internal logic of AEIexport (which should be changed to aei_export since Ruby uses snake case for method names. You can find more recommendations on how to style ruby code here).
Besides the style of your code, an error I found at the beginning of your method is using an undefined variable page when defining form_login_AEI.
For your second question, I'm not familiar with Selenium; however since it does use a real web browser it can handle JavaScript. Watir is another possible solution.
An alternative would be to view the page source (i.e. in Firebug) and understand what the JavaScript on the page does. Then use Mechanize to follow the link manually.

Parsing element text with capybara-webkit

I'm new to Ruby and Capybara and I'm trying to use capybara-webkit to scrape a website. All of the data I'm interested in lies in td tags with certain properties.
Where form is a particular form element I'm looking at, the following code works:
form.all('td').detect do |td|
if td['valign'] == 'top' && td['nowrap'] != 'nowrap'
print "#{td.text}\n"
end
end
The contents of all of the td elements I'm interested in are printed out correctly. However, when I try to then parse the text with a regex:
form.all('td').detect do |td|
if td['valign'] == 'top' && td['nowrap'] != 'nowrap'
print "#{td.text}\n"
val1, val2 = td.match(/(\d)(\d)/).captures # The real regex is more complex
end
end
...suddenly only the first td element is read/parsed. I've tried even just pushing each td.text value into an array for later parsing, but the same thing occurs. I've even tried making a clone of the td.text string and operating on that—no luck. There doesn't seem to be any sort of timeout on the page that would change the HTML elements. Absolutely no clue what could be causing this.
Any thoughts?

How to retrieve the nokogiri processing instruction attributes?

I am parsing the XML using Nokogiri.
I am able to retrieve the stylesheets. But not the attributes of each stylesheet.
1.9.2p320 :112 >style = xml.xpath('//processing-instruction("xml-stylesheet")').first
=> #<Nokogiri::XML::ProcessingInstruction:0x5459b2e name="xml-stylesheet">
style.name
=> "xml-stylesheet"
style.content
=> "type=\"text/xsl\" href=\"CDA.xsl\""
Is there any easy way to get the type, href attributes values?
OR
Only way is to parse the content(style.content) of the processing instruction ?
I solved this problem by following instruction in below answer.
Can Nokogiri search for "?xml-stylesheet" tags?
Added new to_element method to Nokogiri::XML::ProcessingInstruction class
class Nokogiri::XML::ProcessingInstruction
def to_element
document.parse("<#{name} #{content}/>")
end
end
style = xml.xpath('//processing-instruction("xml-stylesheet")').first
element = style.to_element
To retrieve the href attribute value
element.attribute('href').value
Cannot you do that?
style.content.attribute['type'] # or attr['type'] I am not sure
style.content.attribute['href'] # or attr['href'] I am not sure
Check this question How to access attributes using Nokogiri .

Resources