3
votes

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?

3
You're probably getting the timeout on explicit waits, for example on "wait_until_present", "when_present" methods (default timeout is 30 seconds there). Without the code that raise timeout error, this question is meaningless.p0deje

3 Answers

5
votes

It depends exactly what you mean by 'timeout'. AFAIK there are three different definitions of timeout commonly discussed when talking about Watir-Webdriver:

  1. How long does the browser wait for a page to load?
  2. 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
  3. 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
3
votes

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)
1
votes

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.