Selenium WebDriver: Wait for document.readyState - ruby

what's wrong here? I wanna to wait with the next task until my page is completely loaded.
Problem: No errors, but the Driver doesn't wait :-(
# wait for page load
wait2 = Selenium::WebDriver::Wait.new(:timeout => 20) # seconds
count = 0
begin
raise("maximum attempt crossed #{count} times") if count > 3
wait2.until {
self.getDriver.execute_script("return document.readyState;") == "complete"
}
rescue Timeout::Error
count +=1
retry
end
#do sth

I would handle the issue as below :
wait = Selenium::WebDriver::Wait.new(:timeout => 20) # seconds
count = 0
begin
raise("maximum attempt crossed #{count} times") if count > 3
# if the page having title 'page_title' is not loaded within 20 seconds
# time out error will be thrown,which will be handled by the rescue clause.
wait.until { driver.title == 'page_title' }
rescue Timeout::Error
count +=1
retry
end

This seems to be working for me.
DEFAULT_TIMEOUT = 10
def wait_for_page_to_load(options = {})
options[:timeout] ||= DEFAULT_TIMEOUT
wait = Selenium::WebDriver::Wait.new(options)
wait.until {current_driver.execute_script('var browserState = document.readyState; return browserState;') == "complete" }
end

Related

What is the correct way to terminate all threads that are 'sub' to main

I am running multiple threads, and when one of the threads sets the global function '$trade_executed' to true I want it to kill all other threads and remove them from the global '$threads' array.
Then I restart the thread creation process.
Below is a simplified version of my codebase.
3 Threads are created and it looks like 2 threads are deleted but a third thread stays. (for reasons unknown)
Ideally this script would never print '2' or '3' because it would always trigger at '1' minute and kill all threads and reset.
*
thr.exit is preferred. I don't want any code pushed from other threads with a thr.join after $trade_executed is set
require 'thread'
class Finnean
def initialize
#lock = Mutex.new
end
def digger(minute)
sleep(minute * 60)
coco(minute)
end
def coco(minute)
#lock.synchronize {
puts "coco #{minute}"
$threads.each do |thr|
next if thr == Thread.current
thr.exit
end
$trade_executed = true
Thread.current.exit
}
end
end
minutes = [1, 2, 3]
$threads = Array.new
$trade_executed = false
abc = Finnean.new
def start_threads(minutes, abc)
minutes.each do |minute|
$threads << Thread.new {abc.digger(minute)}
puts minute
end
end
start_threads(minutes, abc)
while true
if $trade_executed != false then
count = 0
$threads.map! do |thr|
count += 1
puts "#{thr} & #{thr.status}"
thr.exit
$threads.delete(thr)
puts "Iteration #{count}"
end
count = 0
$threads.each do |thr|
count += 1
puts "#{thr}" ##{thr.status}
puts "Threads Still Left: #{count}"
end
$trade_executed = false
abc = Finnean.new
start_threads(minutes, abc)
end
end
Why not make a thread killer that you keep locked up until the first one finishes:
# Create two variables that can be passed in to the Thread.new block closure
threads = [ ]
killer = nil
# Create 10 threads, each of which waits a random amount of time before waking up the thread killer
10.times do |n|
threads << Thread.new do
sleep(rand(2..25))
puts "Thread #{n} finished!"
killer.wakeup
end
end
# Define a thread killer that will call `kill` on all threads, then `join`
killer = Thread.new(threads) do
Thread.stop
threads.each do |thread|
puts "Killing #{thread}"
thread.kill
thread.join
end
end
# The killer will run last, so wait for that to finish
killer.join
You can't force a thread to exit, but you can kill it. That generates an exception you could rescue and deal with as necessary.

How do I pass in code to functions?

I have this piece of code that executes a series of commands and keep retrying until it reaches MAX_RETRIES. I don't want to repeat this over and over again for different commands. Is there an elegant way of doing so?
retries = 0
ex = true
MAX_RETRIES = 10
while(retries <= MAX_RETRIES and ex)
begin
#MY CODE HERE
ex = false
rescue
ex = true
end
retries = retries + 1
end
Something like this?
execute_with_retries do
#CODE HERE
end
execute_with_retries do
#DIFFERENT CODE HERE
end
Define a function and execute the block
def execute_with_retries
retries = 0
ex = true
max_retries = 10
while(retries <= max_retries and ex)
begin
yield
ex = false
rescue
ex = true
end
retries = retries + 1
end
end
execute_with_retries { puts "hello" }
execute_with_retries { puts 1/0 }
I renamed one of your variable and you can read here why.
It's also worth noting that something like this exists in Ruby and you can read about it here.
MAX_RETRIES = 10
def execute_with_retries(meth)
retries = 0
ex = true
while(retries <= MAX_RETRIES and ex)
begin
public_send(meth)
ex = false
rescue
ex = true
end
retries = retries + 1
end
retries
end
require 'time.h'
def meth
sleep(1)
puts "Time.now in m = #{Time.now}"
puts Time.now - #start < 5 ? "cat"/9 : "dog"
end
#start = Time.now
#=> 2017-12-30 13:39:20 -0800
execute_with_retries(:meth)
Time.now in m = 2017-12-30 13:39:21 -0800
Time.now in m = 2017-12-30 13:39:22 -0800
Time.now in m = 2017-12-30 13:39:23 -0800
Time.now in m = 2017-12-30 13:39:24 -0800
Time.now in m = 2017-12-30 13:39:25 -0800
"dog"
#=> 5

Continue script if it doesn't find element

I am waiting for a page to load in Selenium like this:
wait.until {
comp = driver.find_element(:xpath, "//span[contains(text(), 'New Page']")
if comp.displayed?
myVal= "Passed"
end
}
If the new page doesn't load, it gives me a timeout error and the script does not continue. How can I make it continue if the element is not found?
Here's an example modified from a project:
require 'logger'
logger = Logger.new('logfile.log')
begin
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
comp = driver.find_element(:xpath, "//span[contains(text(), 'New Page']")
if comp.displayed?
myVal = "Passed"
end
}
rescue => e
# log error
logger.error "ERROR! => #{e}"
end
# continue with whatevs

syntax error, unexpected keyword_end, expecting '}' [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have gotten this syntax error message:
/usr/src/check_in/lib/check_in.rb:105: syntax error, unexpected keyword_end, expecting '}'
class CheckIn < Adhearsion::CallController
def run
answer
#play 'welcome.wav' # "Welcome to the PSG check in application."
logger.info "#{call.from.to_s} called at #{time.now.to_s}"
if verify_phone(call.from) == false # If it's not a site phone
logger.info "Number not recognised, routing to Ops"
#play 'not_site_phone.wav' # "Number not recognized."
#dial(sip:number) # Dial operations
hangup
else
user = verify_uid # Checks the User Id
end
if to_check_out?(user.uid)
check_out(user.uid)
else
update_shift(user.uid)
#play 'thank_you.wav'
end
end
def verify_uid
count = 1 # Generic count variable
input = ask 'enter_uid.wav', :limit => 5, :timeout => 5.seconds #takes user ID as DTMF
while (count <= 3 ) # Tracks the number of attempts
if User.find_by_uid(input.response) == nil # If user.find doesn't return anything
logger.info "Invalid user ID. ID entered = #{input.response} Attepmt = #{count}"
input = ask "please_try_again.wav", :limit => 5, :timeout => 10.seconds
count += 1 # Get user to try again
elsif count == 3
play "try_again_later.wav" #"Please try you again later"
logger.info "Tries exceeded, played try again later."
hangup
else
#user = User.find_by_uid(input) # Assigns the user variable to return.
logger.info "User ID: #{#user.uid} is valid"
return #user
end
end
end
def verify_phone(caller_id)
if Sites.find_by_site_phone(caller_id) != nil
return true
else
return false
end
end
def update_shift (user_id)
#user = User.find_by_uid(user_id) # Grabs the user object
if (#user.checked_in?) # If the user is already checked in assign the relevant attributes
#user.time_olc = time.now
#user.num_ci += 1
#user.check_in.create_check_in(:site_id => #user.site_id, uid => #user.uid, :time => time.now)
logger.info "#{#user.uid} checked in at #{#user.time_olc}"
else # Otherwise set all the attributes for the shift
#user.update_attributes(:checked_in? => true, :time_in => time.now, :time_olc => time.now, :num_ci => 1, :site_id => #user.site.find_by_site_phone(call.from))
#user.check_in.create_check_in(:site_id => #user.site_id, uid => #user.uid, :time => time.now)
logger.info "#{#user.uid} punched in at #{#user.time_in}"
end
end
def to_check_out?(user_id) # Method to see if the user has reached check out
#user = User.find_by_uid(user_id)
num_of_ci = #user.num_ci + #user.num_notifications
if (num_of_ci >= #user.site.shift_len)
return true
else
return false
end
end
def check_out!(user_id)
#user = User.find_by_uid(user_id)
input = ask 'check_out?.wav', :limit => 1, :timeout => 5.seconds
if (input == 1)
update(#user.uid)
else
#user.time_out = time.now
#user.time_olc = time.now
#user.update_attributes(:checked_in => false)
end
report_for_user(uid)
end
def secure
count = 1
play 'secure.wav'
sec = 5.times.map {Random.rand(0..9)
result = ask %w"#{sec[0]}, #{sec[1]}, #{sec[2]}, #{sec[3]}, #{sec[4]}", :limit => 5, :timeout => 5.seconds
while (count <= 3)
if (sec.join == result.response)
logger.info "Check in valid"
return true
elsif (count < 3)
result = ask 'please_try_again.wav', :limit => 5, :timeout => 5.seconds
else
play 'try_again_later.wav'
hangup
end
end
end
def report_for_user(user_id)
#user = Users.find_by_uid(user_id)
report = file.open("/report/#{user_id}-#{#user.site_id}-#{date.current}",w)
user_check_ins = #user.check_in.all
report.write("Time, Site ID, User ID")
user_check_ins.each do |check_in|
report.write("#{user.check_in.time}, #{user.check_in.site_id}, #{user.checkin.uid}")
check_in.destroy
end
end
def notify
foo = Users.all
foo.each do |user|
if user.checked_in?
t1 = Time.now #sets a time place holder
t2 = user.time_olc
convert_time = (t1.hour * 60 * 60) + (t1.min * 60) + t1.sec
convert_tolc = (t2.hour * 60 * 60) + (t2.min * 60) + t1.sec
if ((convert_time - convert_tolc)/60 > 75)
user.num_notification += 1
a = user.uid.to_s
logger.info "#{user.uid} hasn't checked in this hour"
# Adhearsion::OutboundCall.originate '+tel: Mobile' :from => ' ' do
# answer
# play a[0], a[1], a[2], a[3], a[4], 'has_not_checked_in.wav'
# hangup
# end
end
end
end
end
end
In this method you have opened one curly bracket '{' but not closed it.
def secure
count = 1
play 'secure.wav'
sec = 5.times.map {Random.rand(0..9)
result = ask %w"#{sec[0]}, #{sec[1]}, #{sec[2]}, #{sec[3]}, #{sec[4]}", :limit => 5, :timeout => 5.seconds
while (count <= 3)
if (sec.join == result.response)
logger.info "Check in valid"
return true
elsif (count < 3)
result = ask 'please_try_again.wav', :limit => 5, :timeout => 5.seconds
else
play 'try_again_later.wav'
hangup
end
end
end
you are missing a closing brace in secure method at the following line
sec = 5.times.map {Random.rand(0..9)

How to get a stopwatch program running?

I borrowed some code from a site, but I don't know how to get it to display.
class Stopwatch
def start
#accumulated = 0 unless #accumulated
#elapsed = 0
#start = Time.now
#mybutton.configure('text' => 'Stop')
#mybutton.command { stop }
#timer.start
end
def stop
#mybutton.configure('text' => 'Start')
#mybutton.command { start }
#timer.stop
#accumulated += #elapsed
end
def reset
stop
#accumulated, #elapsed = 0, 0
#mylabel.configure('text' => '00:00:00.00.000')
end
def tick
#elapsed = Time.now - #start
time = #accumulated + #elapsed
h = sprintf('%02i', (time.to_i / 3600))
m = sprintf('%02i', ((time.to_i % 3600) / 60))
s = sprintf('%02i', (time.to_i % 60))
mt = sprintf('%02i', ((time - time.to_i)*100).to_i)
ms = sprintf('%04i', ((time - time.to_i)*10000).to_i)
ms[0..0]=''
newtime = "#{h}:#{m}:#{s}.#{mt}.#{ms}"
#mylabel.configure('text' => newtime)
end
end
How would I go about getting this running?
Thanks
Based upon the additional code rkneufeld posted, this class requires a timer that is specific to Tk. To do it on the console, you could just create a loop that calls tick over and over. Of course, you have to remove all the code that was related to the GUI:
class Stopwatch
def start
#accumulated = 0 unless #accumulated
#elapsed = 0
#start = Time.now
# #mybutton.configure('text' => 'Stop')
# #mybutton.command { stop }
# #timer.start
end
def stop
# #mybutton.configure('text' => 'Start')
# #mybutton.command { start }
# #timer.stop
#accumulated += #elapsed
end
def reset
stop
#accumulated, #elapsed = 0, 0
# #mylabel.configure('text' => '00:00:00.00.000')
end
def tick
#elapsed = Time.now - #start
time = #accumulated + #elapsed
h = sprintf('%02i', (time.to_i / 3600))
m = sprintf('%02i', ((time.to_i % 3600) / 60))
s = sprintf('%02i', (time.to_i % 60))
mt = sprintf('%02i', ((time - time.to_i)*100).to_i)
ms = sprintf('%04i', ((time - time.to_i)*10000).to_i)
ms[0..0]=''
newtime = "#{h}:#{m}:#{s}.#{mt}.#{ms}"
# #mylabel.configure('text' => newtime)
end
end
watch = Stopwatch.new
watch.start
1000000.times do
puts watch.tick
end
You'll end up with output like this:
00:00:00.00.000
00:00:00.00.000
00:00:00.00.000
...
00:00:00.00.000
00:00:00.00.000
00:00:00.01.160
00:00:00.01.160
...
Not particularly useful, but there it is. Now, if you're looking to do something similar in Shoes, try this tutorial that is very similar.
I believe you have found the example on this site
I'm repeating what is already on the site but you are missing:
require 'tk'
as well as initialization code:
def initialize
root = TkRoot.new { title 'Tk Stopwatch' }
menu_spec = [
[
['Program'],
['Start', lambda { start } ],
['Stop', lambda { stop } ],
['Exit', lambda { exit } ]
],
[
['Reset'], ['Reset Stopwatch', lambda { reset } ]
]
]
#menubar = TkMenubar.new(root, menu_spec, 'tearoff' => false)
#menubar.pack('fill'=>'x', 'side'=>'top')
#myfont = TkFont.new('size' => 16, 'weight' => 'bold')
#mylabel = TkLabel.new(root)
#mylabel.configure('text' => '00:00:00.0', 'font' => #myfont)
#mylabel.pack('padx' => 10, 'pady' => 10)
#mybutton = TkButton.new(root)
#mybutton.configure('text' => 'Start')
#mybutton.command { start }
#mybutton.pack('side'=>'left', 'fill' => 'both')
#timer = TkAfter.new(1, -1, proc { tick })
Tk.mainloop
end
end
Stopwatch.new
I would suggest reading through the rest of the site to understand what is all going on.
I was searching for a quick and dirty stop watch class to avoid coding such and came upon the site where the original code was posted and this site as well.
In the end, I modified the code until it met what I think that I was originally searching for.
In case anyone is interested, the version that I have ended up thus far with is as follows (albeit that I have yet to apply it in the application that I am currently updating and for which I want to make use of such functionality).
# REFERENCES
# 1. http://stackoverflow.com/questions/858970/how-to-get-a-stopwatch-program-running
# 2. http://codeidol.com/other/rubyckbk/User-Interface/Creating-a-GUI-Application-with-Tk/
# 3. http://books.google.com.au/books?id=bJkznhZBG6gC&pg=PA806&lpg=PA806&dq=ruby+stopwatch+class&source=bl&ots=AlH2e7oWWJ&sig=KLFR-qvNfBfD8WMrUEbVqMbN_4o&hl=en&ei=WRjOTbbNNo2-uwOkiZGwCg&sa=X&oi=book_result&ct=result&resnum=8&ved=0CEsQ6AEwBw#v=onepage&q=ruby%20stopwatch%20class&f=false
# 4. http://4loc.wordpress.com/2008/09/24/formatting-dates-and-floats-in-ruby/
module Utilities
class StopWatch
def new()
#watch_start_time = nil #Time (in seconds) when the stop watch was started (i.e. the start() method was called).
#lap_start_time = nil #Time (in seconds) when the current lap started.
end #def new
def start()
myCurrentTime = Time.now() #Current time in (fractional) seconds since the Epoch (January 1, 1970 00:00 UTC)
if (!running?) then
#watch_start_time = myCurrentTime
#lap_start_time = #watch_start_time
end #if
myCurrentTime - #watch_start_time;
end #def start
def lap_time_seconds()
myCurrentTime = Time.now()
myLapTimeSeconds = myCurrentTime - #lap_start_time
#lap_start_time = myCurrentTime
myLapTimeSeconds
end #def lap_time_seconds
def stop()
myTotalSecondsElapsed = Time.now() - #watch_start_time
#watch_start_time = nil
myTotalSecondsElapsed
end #def stop
def running?()
!#watch_start_time.nil?
end #def
end #class StopWatch
end #module Utilities
def kill_time(aRepeatCount)
aRepeatCount.times do
#just killing time
end #do
end #def kill_time
elapsed_time_format_string = '%.3f'
myStopWatch = Utilities::StopWatch.new()
puts 'total time elapsed: ' + elapsed_time_format_string % myStopWatch.start() + ' seconds'
kill_time(10000000)
puts 'lap time: ' + elapsed_time_format_string % myStopWatch.lap_time_seconds() + ' seconds'
kill_time(20000000)
puts 'lap time: ' + elapsed_time_format_string % myStopWatch.lap_time_seconds() + ' seconds'
kill_time(30000000)
puts 'lap time: ' + elapsed_time_format_string % myStopWatch.lap_time_seconds() + ' seconds'
puts 'total time elapsed: ' + elapsed_time_format_string % myStopWatch.stop() + ' seconds'
Simple stopwatch script:
# pass the number of seconds as the parameter
seconds = eval(ARGV[0]).to_i
start_time = Time.now
loop do
elapsed = Time.now - start_time
print "\e[D" * 17
print "\033[K"
if elapsed > seconds
puts "Time's up!"
exit
end
print Time.at(seconds - elapsed).utc.strftime('%H:%M:%S.%3N')
sleep(0.05)
end
Run like this in your terminal (to mark a lap, just tap enter):
# 10 is the number of seconds
ruby script.rb 10
# you can even do this:
ruby script.rb "20*60" # 20 minutes

Resources