Selenium webdriver ruby: Unable to read text value some times - ruby

Scenario:
There is a text in my webpage
I am using xpath to locate it
myxpath=//table[#id='table44']/tbody/tr[1]/td[1]/span[2]
I am trying to get it value using
value=driver.find_element(:xpath, myxpath).text
But problem is :sometimes it gets value & sometime it doesn't
& i am not able to understand the cause of this problem
Any alternative that i can try ?

You can write using explicit wait.
my_xpath = "//table[#id='table44']/tbody/tr[1]/td[1]/span[2]"
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
element = wait.until { driver.find_element(:xpath, my_xpath) }
puts element.text

Related

Ruby: get web elements inside the Shadow-Root DOM

I'm new to Ruby automation test using cucumber and selenium-webdriver.
I received the source code automation from another guy. The way he find element on page some thing looks like:
element(:error_message) { browser.elements(class: 'input-invalidate') }
Now I need to access the element inside a ShadowRoot, did some researches but could not get answer for the Ruby code.
Below picture is an example, I'd like to get the div tag with id="maincontainer" inside that shadowroot, anyone can help please?
Thanks you
This is now supported in Selenium 4.0, here's a working example:
driver.get('http://watir.com/examples/shadow_dom.html')
shadow_host = driver.find_element(id: 'shadow_host')
shadow_root = shadow_host.shadow_root
shadow_content = shadow_root.find_element(id: 'shadow_content')
Also verify that you have selenium devtools gem installed, and at least chrome v96 with newest chromedriver
This will work like Titus pointed out when locating element with Selenium
browser = Watir::Browser.new
browser.goto "http://watir.com/examples/shadow_dom.html"
shadow_host = browser.driver.find_element(id: 'shadow_host')
shadow_root = shadow_host.shadow_root
shadow_content = shadow_root.find_element(id: 'shadow_content')
You can also locate element with Watir and then call shadow_root on underlying Selenium element
shadow_host = browser.div(id: 'shadow_host') #Watir::Div
shadow_root = shadow_host.wd.shadow_root
edit: this should also work in theory - converting ShadowRoot to Watir element, but it breaks afterwards.
browser.goto "http://watir.com/examples/shadow_dom.html"
shadow_host = browser.div(id: 'shadow_host') #Watir::Div
shadow_root = shadow_host.wd.shadow_root #Selenium::WebDriver::ShadowRoot
watir_shadow = browser.div(element: shadow_root) #Watir::Div
watir_shadow.divs.count #undefined method `keys' for nil:NilClass
I might be doing something wrong :) best to ask #titusfortner
/watirs/watir-7.1.0/lib/watir/locators/element/selector_builder.rb:73:in `merge_scope?'
/watirs/watir-7.1.0/lib/watir/locators/element/selector_builder.rb:50:in `normalize_selector'
/watirs/watir-7.1.0/lib/watir/locators/element/selector_builder.rb:28:in `build'
/watirs/watir-7.1.0/lib/watir/element_collection.rb:47:in `build'
/watirs/watir-7.1.0/lib/watir/element_collection.rb:18:in `initialize'
/watirs/watir-7.1.0/lib/watir/container.rb:28:in `new'
/watirs/watir-7.1.0/lib/watir/container.rb:28:in `elements'

Scroll automation appium

I'm doing an automation in Ruby and Appium on mobile, and I need to access a card that is out of range, and I'm using all possible methods and it just happens error ... Does anyone have a solution? I need to down the Recycler view all the way down
Edit:
code
class AuditoriaController
def initialize
#util = UtilMethods.new
#objects = PageAuditoria.new
main = MenuPrincipal.new
#menus = main.menus
#tela_principal = main.tela_principal
#objects_auditoria = #objects.tela_auditoria
end
def acessar_auditoria
data_sync = find_element(:xpath, #tela_principal[:msg_sincronizacao]).text
data_sync.slice!("Última atualização: ")
t = Time.now
while(t.strftime("%d/%m/%Y %H:%M:%S") != data_sync)
btn_sync = find_element(:xpath, #tela_principal[:view_sync])
btn_sync.click
break;
end
list = find_element(:xpath, #tela_principal[:lista])
list.scrollIntoView()
#menu_auditoria = find_element(:xpath, #menus[:menu_auditoria])
#if(menu_auditoria)
# #util.logger("ACHEI AUDITORIA")
#end
end
First get the element(that is card)
Then add the below code
browser.execute_script('arguments[0].scrollIntoView();', card);
Hope it will help you. If you need any more information just comment here
EDIT:
JavascriptExecutor jse = (JavascriptExecutor)driver;
jse.execute_script('arguments[0].scrollIntoView();', card)
Here driver is the driver you are using for automation that is appium driver. Here card is the element that you want to get and scroll upto it.
In ruby:
def scroll_to_element(element)
#driverAppium.execute_script('mobile: scroll', name: element.name)
end
This will scroll to the element which you are looking for even if it is offscreen. You should be able to modify for use with Java.
scroll_to_exact(elementname) should do the job for you! This will scroll to through the elements until the specified is visible. This is in Appium_lib for ruby

Launching browser windows from Ruby command prompt

I've got this code below. What I'd like it to do is launch each of the search queries I've specified into browser windows, instead of listing the search results as it's currently written to do. But I'm a beginner and having a difficult time finding documentation on this. Is it possible?
The issue is the actual list of search_criteria I will be using is actually 40 terms long and I need to do it for dozens and dozens of cities - which is why I was looking to automate the search process.
If it's not possible to launch each query as a browser window (or better tabs in a browser window) is there a way to specify each URL that results in some systematic way so as to be called by Ruby from command prompt to launch as a browser window?
require "google-search"
search_criteria = ["makers", "makerspaces", "fablabs", "smartlabs"]
#City name
search_1 = search_criteria.map do |noun|
"#{noun} new york city"
end
#City acronym 1
search_2 = search_criteria.map do |noun|
"#{noun} new york"
end
#City acronym 2
search_3 = search_criteria.map do |noun|
"#{noun} nyc"
end
#Replace "search_1" for other acronyms
search_1.each do |query|
puts "Just one moment please! I am searching for #{query}"
Google::Search::Web.new do |search|
search.query = query
search.size = :large
end.each { |item| puts item.title }
end
search_criteria = ["makers", "makerspaces", "fablabs", "smartlabs"]
names = ["new+york+city", "new+york", "nyc"]
query_strings = names.map do |name|
"#{name}+#{search_criteria.join('+')}"
end
urls = query_strings.map do |q|
"google.com/search?q=" + q
end
cmd_line = urls.join(' ')
Then you pass cmd_line to the Google Chrom executable via the system() call. On Mac OS X it would be like this:
system("/Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome --url #{cmd_line}")
Chrome will then open each url in the string passed to it in it's own tab in a new window.
If you are using Windows you will have to find where the chrome.exe executable is buried, and in Linux you would just find the chrome binary to call it. Everything before the last part of ...Chrome --url #{cmd_line}") is just the path to the executable, which is buried inside the "Google Chrome.app" container on OS X.

Selenium-Webdriver Ruby --> How to wait for images to be fully loaded after click

I am very new to Ruby and Selenium-Webdriver, so please, help :)
I am trying to open email campaign , sent to my inbox, that has images and take a screenshot in the firefox. But i can not make it wait until images is fully loaded. Once i click on 'Show images' , screenshot is already taken , but image is not loaded at that time. How can i pause the script and take screenshot some time later, after all images is displayed?
Please, help :(
Bellow is my script:
enter code here
require 'selenium-webdriver'
browser = Selenium::WebDriver.for :firefox
#==========================================================================================
wait = browser.manage.timeouts.implicit_wait = 15
#==========================================================================================
url = 'https://login.yahoo.com/config/login_verify2?.intl=us&.src=ym'
# Open browser (firefox)
browser.navigate.to url
browser.find_element(:id, 'username').send_keys "some yahoo id"
browser.find_element(:id, 'passwd').send_key "some password"
browser.find_element(:id, ".save").click
browser.find_element(:id, "inbox-label").click
browser.find_element(:xpath, "//div[#class='subj']").click
browser.find_element(:xpath, "//a[#title='Display blocked images']").click
result_page_title = browser.find_element(:tag_name, 'title')
puts "Title of the page: \t\t: #{result_page_title.text}"
browser.save_screenshot "1.jpg"
You can use Implicit Wait and Explicit Wait to wait for a particular Web Element until it appears in the page. The wait period you can define and that is depends upon the application.
Explicit Wait:
An explicit waits is code you define to wait for a certain condition to occur before proceeding further in the code. If the condition achieved it will terminate the wait and proceed the further steps.
Code:
WebDriverWait wait = new WebDriverWait(driver,30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(strEdit)));
Or
WebElement myDynamicElement = (new WebDriverWait(driver, 30))
.until(new ExpectedCondition<WebElement>(){
#Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("myDynamicElement"));
}});
This waits up to 30 seconds before throwing a TimeoutException or if it finds the element will return it in 0 - 30 seconds. WebDriverWait by default calls the ExpectedCondition every 500 milliseconds until it returns successfully. A successful return is for ExpectedCondition type is Boolean return true or not null return value for all other ExpectedCondition types.
You can use ExpectedConditions class as you need for the application.
Implicit Wait:
An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available
Code:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
One thing to keep in mind is that once the implicit wait is set - it will remain for the life of the WebDriver object instance
For more info use this link http://seleniumhq.org/docs/04_webdriver_advanced.jsp
The above code is in Java. Change as your language need.
Ruby code from the docs (click on the 'ruby' button):
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
begin
element = wait.until { driver.find_element(:id => "some-dynamic-element") }
ensure
driver.quit
end
Which works for me
To add to the above answer, here is how I use implicit and explicit wait in Ruby.
Implicit Wait
I pass this option to Selenium::WebDriver after initializing with a couple of lines like this:
browser = Selenium::WebDriver.for :firefox
browser.manage.timeouts.implicit_wait = 10
Just replace "10" with the number of seconds you'd like the browser to wait for page refreshes and other such events.
Explicit Wait
There are two steps to declaring an explicit wait in Selenium. First you set the timeout period by declaring a wait object, and then you invoke the wait with Selenium::Webdriver's .until method. It would look something like this, in your example:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { browser.find_element(:xpath, "//path/to/picture").displayed? }
This would tell the Webdriver to wait a maximum of 10 seconds for the picture element to be displayed. You can also use .enabled? if the element you're waiting for is an interactive element - this is especially useful when you're working with Ajax-based input forms.
You can also declare an explicit wait period at the start of your script, and then reference the object again whenever you need it. There's no need to redeclare it unless you want to set a new timeout. Personally, I like to keep the wait.until wrapped in a method, because I know I'm going to reference it repeatedly. Something like:
def wait_for_element_present( how_long=5, how, what )
wait_for_it = Selenium::WebDriver::Wait.new(:timeout => how_long )
wait_for_it.until { #browser.find_element(how, what) }
end
(I find it's easier to just declare browser as an instance variable so that you don't have to pass it to the method each time, but that part's up to you, I guess?)
ExpectedConditions isn't supported yet in the Ruby Selenium bindings. This snippet below does the same thing as ExpectedConditions.elementToBeClickable — clickable just means "visible" and "enabled".
element = wait_for_clickable_element(:xpath => xpath)
def wait_for_clickable_element(locator)
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
element = wait.until { #driver.find_element(locator) }
wait.until { element.displayed? }
wait.until { element.enabled? }
return element
end

How can I measure the length of a long string in Ruby? SciTE and command prompt aren't working.

I've written a program that measures my typing speed. As part of this, I need it to count how many characters I've typed. I did that with
text = gets.chomp
puts text.length.to_s
Unfortunately, I can't get this working for a long string.
In the SciTE editor, .length doesn't work properly, so instead of giving me the length of the string, it gives me the character count of everything I've typed, including corrected mistakes - if I typo "Hrello" and correct it to "Hello", it'll still return 6 instead of 5.
I googled this, and the suggested fix was to run the program from the command prompt instead. In the command prompt, .length works fine, but it turned out that I can't type in more than 264 characters.
So I tried to put a GUI on the program with Shoes:
Shoes.app :width => 300, :height => 300 do
button "Start." do
text = ask "Type here."
para text.length.to_s
end
end
and discovered that Shoes' input box has an even shorter character limit.
I'm running Windows 7, Ruby 1.9.2, SciTe version 2.29 and Shoes Policeman Revision 1514.
How can I run this program so it'll correctly measure the length of a really long string? I'd be happy with any solution that fixes the command prompt or Shoes character limit, the SciTE bug, or just a suggestion for a different way to execute ruby programs where this will work.
I'd be happy with [...] a suggestion for a different way to execute ruby programs where this will work.
What about a simple web app? Here is a simple Sinatra app that accomplishes exactly what you have asked with a very large character limit.
require 'sinatra'
get '/' do
%{<html>
<body>
<form method="post">
<textarea name="typed"></textarea>
<input type="submit">
</form>
</body>
</html>
}
end
post '/' do
"You typed #{params['typed'].length} characters."
end
To run the app you can use something as simple as ruby sinatra_example.rb to use a built-in web server. Or, you can deploy this app using any of several web servers.
If you need timers this should be easy to accomplish through javascript and include in the form submit.
Ok, your question is not accurately titled, but lets see:
There is a very broad number of options of using command prompt, and you should consider running a simple script in ruby on it.
On command line from windows, try typing ruby C:/path_to_folder_program/program.rb
If it won`t execute, you can find on ruby folder some executable called ruby and should, from command prompt on that path, run it like above.
But let me ask you, why ruby? Other more accessible and user-friendly programming languages, like javascript would behave better and would be easier to make your program accessible.
- EDIT -
Seems shoes can handle more chars, use edit_box instead of ask:
In Shoes:
Shoes.app do
#txt = edit_box
button("How many"){ alert(#txt.text.size) }
end
Anyway, before trying shoes I did the exercise with that I knew, here it is:
In javascript:
<script>
function start_stop(){
var txt = document.getElementById('txt');
var btn = document.getElementById('btn');
if( txt.disabled ){
txt.value = '';
txt.disabled = false;
btn.value = 'Stop';
txt.focus();
startTime = new Date().getSeconds();
} else {
txt.disabled = true;
btn.value = 'Start again';
timeNow = new Date().getSeconds();
alert(txt.value.length + " characters in " + (timeNow - startTime) + " seconds.");
}
}
</script>
<input type='button' id='btn' onclick='start_stop()' value='Start'>
<textarea id='txt' rows='8' cols='80' disabled></textarea>
In Ruby using Qt: (replicating the same idea as in the javascript one)
require 'Qt'
class MyWidget < Qt::Widget
slots :start_stop
def initialize
super
setFixedSize(400, 120)
#btn = Qt::PushButton.new("Start")
#txt = Qt::TextEdit.new ; #txt.readOnly = true
vbox = Qt::VBoxLayout.new
vbox.addWidget #btn
vbox.addWidget #txt
setLayout vbox
connect(#btn, SIGNAL("clicked()"), self, SLOT(:start_stop))
end
def start_stop
if #txt.readOnly
#txt.plainText = ''
#txt.readOnly = false
#btn.text = "Stop"
#txt.setFocus
#startTime = Time.now
else
#txt.readOnly = true
#btn.text = "Start again (#{#txt.plainText.size} chars #{(Time.now - #startTime).to_i} in seconds)"
end
end
end
app = Qt::Application.new(ARGV)
widget = MyWidget.new
widget.show
app.exec

Resources