How do I read text from non visible elements with Watir (Ruby)? - ruby

There is a div on a page that is not visible but has some value I want to capture. Calling text on it returns me an empty string.
How do I get the value displayed without having to deal with the raw html? Can I force .text to return me the actual value regardless of the visiblity of the text in the browser?
irb(main):1341:0> d.first.visible?
=> false
irb(main):1344:0> d.first.html
=> "<div class=\"day\">7</div>"
irb(main):1345:0> d.first.text
=> ""
PS: There are many many divs (the page is caching response and display them accordingly). I considered changing all the display:none in the page or clicking to make them visible but I'd prefer to avoid this if possible.
If not possible a solution with changing all the display none would be the preferred work around.
PPS: Damned, I tried to overload the visible? method in the Watir::Element class to always return true, but that didn't do the trick.
irb(main):1502:0> d.first.visible?
=> true
irb(main):1504:0> d.first.text
=> ""

For the newer versions of Watir, there is now an Element#text_content method that does the below JavaScript work for you.
e = d.first
e.text_content
#=> "7"
For Old Versions of Watir (Original Answer):
You can use JavaScript to get this.
e = d.first
browser.execute_script('return arguments[0].textContent', e)
#=> "7"
Note that this would only work for Mozilla-like browsers. For IE-like browsers, you would need to use innerText. Though if you are using watir-classic it would simply be d.first.innerText (ie no execute_script required).
Using attribute_value:
Turns out you can make it simpler by using the attribute_value method. Seems it can get the same attribute values as javascript.
d.first.attribute_value('textContent')
#=> "7"
Using inner_html
If the element only includes text nodes (ie no elements), you can also use inner_html:
d.first.inner_html
#=> "7"

Try using the execute_script method do change the value of "visible" to visible. Something like document.getElementById('id').style.visibility = 'visible' assuming it has an ID. If it does not you can always ask the devs to put a test-id on the element (or just do it yourself).

Related

Watir WebDriver select list without standard html

Just started using Watir-WebDriver, came across website with and facing an problem.
1) Goto "https://www.smiles.com.br/home"
2) How to get/set values to drop down selections like selecting number of adults in "Adulto"
Selection list initially is hidden but when clicked on the text field it become visible in browser.
But when I tried using to click and check its existence it returning false
1) b.text_field(:id => "inputOrigin").click
2) irb(main):049:0> b.a(:id => 'yui_patched_v3_11_0_1_1467245841395_1777').exist?
=> false
Since its not actually a selection list, how do I set values?
Thanks in advance.
The ID is dynamic so it changes every time. It looks like it might be based on the time, but this should be sufficiently unique:
b.link(id: /^yui_patched_v3_11_0_1_/)
After clicking on <input id="inputOrigin">, you need to perform another click to trigger the "dropdown" list. Otherwise, you'll get a element not visible error. You could do something like this:
require 'watir-webdriver'
b = Watir::Browser.new :chrome
b.goto('https://www.smiles.com.br/home')
b.text_field(:id => "inputOrigin").when_present.click
b.div(:id => "dk_container_qtdAdult").when_present.click #trigger "dropdown" menu
b.div(:class => "adult").link(:text => "02").when_present.click
# b.div(:class => "adult").link(:data_dk_dropdown_value => "02").click #an alternative
Once selected, you can get the option using the .text method:
puts b.div(:id => "dk_container_qtdAdult").link(:class => "dk_toggle dk_label").text
Lastly, you could use regex locators, but you might have more success by trying to identify more discrete (and--ideally--unique) page elements.

Get the actual value of a boolean attribute

I have the span:
<span disabled="disabled">Edit Member</span>
When I try to get the value of the disabled attribute:
page.in_iframe(:id => 'MembersAreaFrame') do |frame|
expect(page.span_element(:xpath => "//span[text()='Edit Member']", :frame => frame).attribute('disabled')).to eq("disabled")
end
I get:
expected: "disabled"
got: "true"
How do I get the value of specified attribute instead of a boolean value?
The Page-Object gem's attribute method does not do any formatting of the attribute value. It simply returns what is returned from Selenium-WebDriver (or Watir-Webdriver).
In the case of boolean attributes, this means that true or false will be returned. From the Selenium-WebDriver#attribute documentation:
The following are deemed to be “boolean” attributes, and will return
either “true” or “false”:
async, autofocus, autoplay, checked, compact, complete, controls,
declare, defaultchecked, defaultselected, defer, disabled, draggable,
ended, formnovalidate, hidden, indeterminate, iscontenteditable,
ismap, itemscope, loop, multiple, muted, nohref, noresize, noshade,
novalidate, nowrap, open, paused, pubdate, readonly, required,
reversed, scoped, seamless, seeking, selected, spellcheck, truespeed,
willvalidate
As you can see, the "disabled" attribute is included in this list and thus returns a boolean.
If you really want to check the actual attribute value, you will have to parse the HTML. Unless the HTML is simple, I would suggest using Nokogiri (or other HTML parser) rather than writing your own. In Nokogiri:
require 'nokogiri'
# Get the HTML of the span
span_html = page.in_iframe(:id => 'MembersAreaFrame') do |frame|
page.span_element(:xpath => "//span[text()='Edit Member']", :frame => frame).html
end
# Parse the span
doc = Nokogiri::HTML.fragment(span_html)
root_element = doc.at_css('*')
# Check the disabled attribute of the root element (ie the span)
expect(root_element['disabled']).to eq("disabled")

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.

Capture selected value from list using webdriver and Ruby

I'm using selenium webdriver with ruby. I've written a script that will fill in a form. One field is a dropdown list. What I would like to do is capture the value I selected in the list.
For example: If I had a list of cars and I selected Honda I would like to capture the value in the field (Honda) and place it in a variable for me to use later.
I hope I'm making sense.
You can use below code select list items:
cars_select = driver.find_element(:id=> "cars_list")
//use id of your dropdownlist
options = cars_select.find_elements(:tag_name=>"option")
options.each do |el|
if (el.value == "Honda")
el.select()
var selected_car = el.value;
break
end
end
If you are selecting from dropdown with:
browser.select_list(id: 'some_id').option(text: 'some_value').select
Then you can store that value in a variable, like below:
var1=browser.select_list(id: 'some_id').option(text: 'some_value').value
Hope this will work. If not, then provide your dropdown part html, and explain more. I am using watir-webdriver, try if this work for selenium-webdriver.

Clear input field and enter new info using Watir? (Ruby, Watir)

Pretty positive you have to use .clear, or maybe not as it doesn't seem to be working for me, maybe i'm just implementing it wrong I'm unsure.
Example:
browser.div(:id => "formLib1").clear.type("input", "hi")
Can anyone tell me how to simply clear a field then enter in a new string?
Assuming we are talking about a text field (ie you are not trying to clear/input a div tag), the .set() and .value= methods automatically clear the text field before inputting the value.
So one of the following would work:
browser.text_field(:id, 'yourid').set('hi')
browser.text_field(:id, 'yourid').value = 'hi'
Note that it is usually preferred to use .set since .value= does not fire events.
I had a similar issue, and, for some reason, .set() and .value= were not available/working for the element.
The element was a Watir::Input:
browser.input(:id => "formLib1").to_subtype.clear
after clearing the field I was able to enter text.
browser.input(:id => "formLib1").send_keys "hi"
I had a similar issue, and, for some reason, .set() and .value= were not available for the element.
The element was a Watir::HTMLElement:
[2] pry(#<Object>)> field.class
=> Watir::HTMLElement
field.methods.grep /^(set|clear)$/
=> []
I resorted to sending the backspace key until the value of the field was "":
count = 0
while field.value != "" && count < 50
field.send_keys(:backspace)
count += 1
end
field.send_keys "hi"

Resources