Watir implicit_wait doesn't seem to work - watir

We are currently using watir-webdriver (0.6.2) with firefox to run acceptance tests.
Our tests take a long time to run, and often fail with timeout errors.
We wanted to decrease the timeout time, for them to fail faster.
We tried:
browser = Watir::Browser.new("firefox")
browser.driver.manage.timeouts.implicit_wait=3
However, we are still experiencing 30s timeouts.
We couldn't find any documentation or question regarding this issue. Does anyone know how to configure Watir waiting timeouts properly?

It depends exactly what you mean by 'timeout'. AFAIK there are three different definitions of timeout commonly discussed when talking about Watir-Webdriver:
How long does the browser wait for a page to load?
How long does Watir-Webdriver explicitly wait before considering an element 'not present' or 'not visible' when told to wait via the '.when_present' function
How long does Watir-Webdriver implicitly wait for an object to appear before considering an element 'not present' or 'not visible' (when not waiting via explicitly call see #2)
#1: Page load
Justin Ko is right that you can set page load timeout as described if your goal is to modify that, though it looks like the canonical way to do that is to set the client timeout before creating the browser and passing it to the browser on creation:
client = Selenium::WebDriver::Remote::Http::Default.new
client.timeout = 180 # seconds – default is 60
b = Watir::Browser.new :firefox, :http_client => client
- Alistair Scott, 'How do I change the page load Timeouts in Watir-Webdriver'
#2: Explicit timeout
But I think #p0deje is right in saying you are experiencing explicit timeouts, though it's not possible to say for sure without seeing your code. In the below I experienced the explicit declaration overriding the implicit (I am unsure if that's intentional):
b = Watir::Browser.new :firefox
b.driver.manage.timeouts.implicit_wait = 3
puts Time.now #=> 2013-11-14 16:24:12 +0000
begin
browser.link(:id => 'someIdThatIsNotThere').when_present.click
rescue => e
puts e #=> timed out after 30 seconds, waiting for {:id=>"someIdThatIsNotThere", :tag_name=>"a"} to become present
end
puts Time.now #=> 2013-11-14 16:24:43 +0000
Watir-Webdriver will wait 30 seconds before failure by default thanks to 'when_present'. Alternatively you can say 'when_present(10)' to alter the default and wait 10 seconds. (Watir-Webdriver > Watir::Wait#when_present.) I can not divine any way to do this globally. Unless you find such a thing - and please tell me if you do - it must be done on each call. :( Edit: Fellow answerer Justin Ko gave me the answer as to how to do what I described above. Edit 2: #jarib added this to Watir, per #justinko in the linked answer: "Update: This monkey patch has been merged into watir-webdriver and so will no longer be needed in watir-webdriver v0.6.5. You will be able to set the timeout using: Watir.default_timeout = 90"
#3 Implicit timeout
The code you provided sets the time Watir-Webdriver will wait for any element to be come present without you explicitly saying so:
b = Watir::Browser.new :firefox
b.driver.manage.timeouts.implicit_wait = 3
puts Time.now #=> 2013-11-14 16:28:33 +0000
begin
browser.link(:id => 'someIdThatIsNotThere').when_present.click
rescue => e
puts e #=> unable to locate element, using {:id=>"someIdThatIsNotThere", :tag_name=>"a"}
end
puts Time.now #=> 2013-11-14 16:28:39 +0000

The implicit_wait is the amount of time selenium-webdriver tries to find an element before timing out. The default is 0 seconds. By changing it to "3", you are actually increasing the amount of time that it will wait.
I am guessing that you actually want to change the timeout for waiting for the page to load (rather than for finding an element). This can be done with:
browser.driver.manage.timeouts.page_load = 3
For example, we can say to only wait 0 seconds when loading Google:
require 'watir-webdriver'
browser = Watir::Browser.new :firefox
browser.driver.manage.timeouts.page_load = 0
browser.goto 'www.google.ca'
#=> Timed out waiting for page load. (Selenium::WebDriver::Error::TimeOutError)

Update: Since Watir 6.5, the default timeout is configurable using
Watir.default_timeout = 3
We experienced the same issue and chose to override Watir methods involving timeouts, namely
Watir::Wait.until { ... }
Watir::Wait.while { ... }
object.when_present.set
object.wait_until_present
object.wait_while_present
Here is the code, you can put it in your spec_helper.rb if using rspec
# method wrapping technique adapted from https://stackoverflow.com/a/4471202/177665
def override_timeout(method_name, new_timeout = 3)
if singleton_methods.include?(method_name)
old_method = singleton_class.instance_method(method_name)
define_singleton_method(method_name) do |timeout = new_timeout, *args, &block|
old_method.bind(self).(timeout, *args, &block)
end
else
old_method = instance_method(method_name)
define_method(method_name) do |timeout = new_timeout, *args, &block|
old_method.bind(self).(timeout, *args, &block)
end
end
end
# override default Watir timeout from 30 seconds to 3 seconds
module Watir
module Wait
override_timeout(:until)
override_timeout(:while)
end
module EventuallyPresent
override_timeout(:when_present, 5) # 5 secs here
override_timeout(:wait_until_present)
override_timeout(:wait_while_present)
end
end
We used answer from https://stackoverflow.com/a/4471202/177665 to get it working.

Related

How to break out of loop when URL read is taking too long

Hi I have the following code to skip the particular URL if it is taking too long to read.
timeout = 30
loop begins below for different urlz {
timeout_start = time.time()
webpage = urlopen(urlz[i]).read()
if time.time() > timeout_start + timeout:
continue}
My question is; wont the program execute the line of code "webpage = urlopen(urlz[i]).read()" before moving down to check the if condition? In that case I think it wont detect if the page is taking too long (more than 30 seconds to read). I basically want to skip this URL and move on to the next one if the program is stuck for 30 seconds (i.e. we have run into a problem when reading this particular URL).
The urlopen() function has a timeout method inbuilt:
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
So in your code:
timeout = 30
loop begins below for different urlz {
try:
webpage = urlopen(urlz[i], timeout=timeout).read()
}

Why does my code stuck after speak function?

I try to create a Voice Assistant on python3
This is my function Speak (with pyttsx):
def speak(what):
print("Gosha: " + what)
speak_engine.say( what )
speak_engine.runAndWait()
speak_engine.stop()
in the main body it works fine, but in function execute_cmd, after Speak function my code stucks.
One part of execute_cmd:
def execute_cmd(cmd, voice):
global finished
finished = False
#import debug
if cmd == 'ctime':
now = datetime.datetime.now()
hours = str(now.hour)
minutes = str(now.minute)
if (now.minute < 10): minutes = '0' + minutes
speak("Now " + hours + ":" + minutes)
finished = True
finished will never True
This happens anywhere in the function
pls help me
(sorry for my eng, I'm from Russia)
UPD: I debugged my code and noticed, my code get stuck on speak_engine.runAndWait()
I know, many people have same problem, but their solutions didn't help me
I'm not sure I understand you problem. What exactly do you mean by your code getting "Stuck"? Since you said that your finished variable will never be False, I assume that the code runs through and doesn't get stuck. My best guess is that your code simply doesn't produce sound.
If that's the case, I could imagine it's due to the previous loop still being active. So maybe try adding the following to your speak() function:
ef speak(what):
print("Gosha: " + what)
try:
speak_engine.endLoop()
except Exception as e:
pass
speak_engine.say( what )
speak_engine.runAndWait()
speak_engine.stop()

Creating loops to update a label in app jar

I'm trying to make a countdown timer in appJar and have a label that shows how much time is remaining until the end of the allotted amount of time. I've looked at the guides on appJar's website a fair amount and know of the two ways that they say you can create loops with their library. You can use .registerevent(function) or .after(delay_ms, function, *args). I've tried both of these ways and can't get either to work. I haven't managed to figure out how to get the .after function to work and every time I try to use the .registerevent function something doesn't work. My current issue is that I can get the function to run but it isn't actually working. That is, it says the block of code is running but the GUI ins't updating
Here are the specific lines of code in question
def introduction_bill(x):
global time_remaining, time_allotted
time_remaining = 120
time_allotted = 120
app.removeAllWidgets()
print("ran 'introduction_bill'")
app.addLabel('timer', 'Time remaining: 2:00')
app.addButtons(['start timer','update'], [start_timer, update_timer])
app.addButton('next introduction', next_introduction)
....
def update_timer():
global time_remaining, current_function
current_function = 'update timer'
time_remaining = end_time - t.time()
minutes = int(time_remaining // 60)
seconds = round(time_remaining % 60, 2)
app.setLabel('timer', 'Timer remaining: ' + str(minutes) + ':' + str(seconds))
print("ran 'update_timer'")
if time_remaining > -10:
app.registerEvent(update_timer)
def start_timer(x):
print("ran 'start_timer'")
global start_time, end_time
start_time = t.time()
end_time = start_time + time_allotted
update_timer()
And here is the code in its entirety
Keep in mind that I am still a beginner in coding so this code is both incomplete and very rough.
You can achieve what you want with both of the methods you mention.
With registerEvent() you should only call it once, it then takes care of scheduling your function. In your code, you are calling it repeatedly, which won't work.
With after() you have to take care of calling it again and again.
So, with your current code, you're better off using after():
In update_timer() try changing the call to app.registerEvent(update_timer) to be app.after(100, update_timer)
The timer should then update every 0.1 seconds.
However, if you click the Start Timer button again, you'll run into problems, so you might want to disable the button until the timer finishes.

Python - queuing one function

I've just started learning python, but I have problem with my code:
import pifacecad
# listener initialization
cad = pifacecad.PiFaceCAD()
listener = pifacecad.SwitchEventListener(chip=cad)
listener.register(4, pifacecad.IODIR_ON, blowMyMind)
listener.activate()
def blowMyMind(event):
print('some prints...')
time.sleep(4)
print('and the end.')
blowMyMind() will be fired as many times as listener it tells to. That is okay.
My goal is to deactivate listener UNTIL blowMyMind ends. Pifacecad suggest Barrier() to achieve that, at least I think that it was here for that reason(correct me if I'm wrong).
Now it's working as many times as I activate listener event, but It's not like pushing function 99 times at once, but queues it and runs one by one.
With Barriers I think it should look like this:
# Barrier
global end_barrier
end_barrier = Barrier(1)
# listener initialization
listener = pifacecad.SwitchEventListener(chip=cad)
listener.register(4, pifacecad.IODIR_ON, blowMyMind)
listener.activate()
def blowMyMind(event):
global end_barrier
test = end_barrier.wait()
print(test) # returns 0, which should not in about 5 seconds
print('some prints...')
time.sleep(4)
print('and the end.')
The funny part is when I change parties in Barrier initialization it is causing BrokenBarrierError at first listener event.
Actually I think that I completely misunderstood Barrier() I think the problem with it is that all listener events are in one thread instead of their own threads.
It's making me even more confused when I'm reading:
parties The number of threads required to pass the barrier.
from here: https://docs.python.org/3/library/threading.html
My conclusion: when initializing Barrier(X) it would be realeased when there will be X('or less', 'or more'?) number of threads. That sounds VERY stupid :D
I tried to make it that way with no luck:
# listener initialization
global busy
busy = 0
cad = pifacecad.PiFaceCAD()
listener = pifacecad.SwitchEventListener(chip=cad)
listener.register(4, pifacecad.IODIR_ON, blowMyMind)
listener.activate()
def blowMyMind(event):
global busy
if busy == 0:
busy = 1
print('some prints...')
time.sleep(4)
print('and the end.')
busy = 0
else:
return None

Frank Cucumber Test Case Hangs When Using "when I wait" Test

I'm using frank-cucumber to test my iOS app and have run into some problems when my test is of the following form
When I wait to see "OpenButton"
If a UIView with the accessibility label "OpenButton" never shows up, instead of timing out and reporting an error on the test after WAIT_TIMEOUT is hit, cucumber just hangs.
Since I don't see WAIT_TIMEOUT even used in the core_frank_steps.rb I wonder if this is the reason why any test case of the form "When I wait.." will just hang.
Note: core_frank_steps.rb can be found here
# Polls every 0.1s , returns true when element is present
# #param selector [String] Frankly selector e.g. view marked:''
# #param timeout [Int] seconds to wait
def wait_for_element(selector, timeout=10)
#the return value of the yield expression isn't working, so we use a closure
res = nil
wait_until(:timeout => timeout, :message => "Waited for element #{selector} to exist") {
res = element_exists(selector)
}
res
end
The above function helped us get around some of these wait scenarios.

Resources