How to get a Selenium/Ruby bot to wait before performing an action?

I'm building a Selenium/Ruby web bot that clicks on elements. The problem is, sometimes there isn't enough time for the page to load before the bot decides it can't find the element.

What's the Ruby way to get Selenium to wait before performing an action? I would prefer explicit waiting, but I'm fine with implicit waiting too.


I tried to use the wait.until method:

require "selenium-webdriver"
require "nokogiri"
driver = Selenium::WebDriver.for :chrome
wait = Selenium::WebDriver::Wait.new(:timeout => 15)
driver.navigate.to "http://google.com"
driver.wait.until.find_element(:class, "gb_P").click

But I'm getting the following error:

Undefined method 'wait' for <Selenium::WebDriver>

I also tried:

require "watir-webdriver/wait"
...
driver.find_element(:class, "gb_P").wait_until.click

but that's also giving me an undefined method error:

undefined method `when_present' for #<Selenium::WebDriver...>

Answers


You are using wait as WebDriver function, but it isn't. Try this

element = wait.until { driver.find_element(:class => "gb_P") }
element.click

Have you tried the when present, to wait for the button (You could also make it wait for a certain div to )

require "watir-webdriver/wait"
driver.button(:class => 'gb_P').when_present.click

As for explicit waiting

sleep *seconds*

or a better way as to not waste time

sleep *seconds* until driver.element(:id/class/etc, 'value').exists?

Okay. This answer has been asked many times in many different contexts. So I just want to answer it here once and for all.

There are three ways this can be done. And each is useful in certain contexts.

First, you can use an EXPLICIT wait. This has nothing to do with whether the page loads or not. It simply tells the script to wait. In other words, if your page loads in 11 seconds and your explicit wait is 10 seconds, the clickable element still won't be available. You can work around this inefficiency by using an expected condition. See, e.g., the Selenium manpages:

require 'selenium-webdriver'

driver = Selenium::WebDriver.for :firefox
driver.get "http://google.com"

wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
begin
  element = wait.until { driver.find_element(:class => "gb_P") }
ensure
  driver.quit
end

^ This will wait either: 10 seconds OR until the element is found.

Second, you can use an implicit wait. This is very similar to the explicit wait with expected condition. However, where the explicit waits applies to the element being queried, implicit wait applies to the WebDriver Object. In other words, if your script only uses a single webdriver, it will wait either: the implicit wait time for EVERY element OR until each element is found (until failure). For example:

require 'selenium-webdriver'

driver = Selenium::WebDriver.for :firefox
driver.manage.timeouts.implicit_wait = 10 # seconds

driver.get "http://google.com"
element = driver.find_element(:class => "gb_P")

Third, you can call a Javascript function to click the page. The advantage of this is that once the page's Javascript loads, the item will be clickable and you don't have to actually wait for the page to render. A lot of time when you're "waiting for the page" you're actually waiting on the client side for the rendering engine to construct the page. You can bypass that process by simply clicking the underlying element before the page is actually rendered.

The drawback of this is that it doesn't mirror an actual human clicking the page. For example, if the button you want to click is hidden by a popup. Selenium won't allow you to click it, but a JS function will.

You can use this method by doing:

click = driver.execute_script("document.getElementsByClassName('gb_P')[0].click();")

A potential answer is in your stacktrace.

driver.element(:class, "gb_P").when_present.click

Using Webdriver RC and C# I find this is the most effective way to make the driver wait:

Task.Delay(1000).Wait();

Just use

sleep(number_of_seconds)

Then you can wait for it.


You can also simply use sleep(#) this will cause it to wait, and depending on your editor you can see which variations you can use so instead of seconds you can go to something lower or higher, in Ruby you don't even have to declare it.

Just type sleep and a number in the parenthesis and you should see it stop for that amount of time in seconds, others note why this is a solution that might not be optimal, but if you only need it to wait for a bit on a page that will never take that long it's great one line code to use.


Need Your Help

Automatic refreshing images in php application

javascript php jquery ajax

I have been writing some rest application in PHP. The application download an image by the REST from the server and return html code to adding the one to the webpage. This is a sample of php code (...

Can I do a INSERT using select from another DB with the same table name

sql sql-server sql-server-2008 tsql vbscript

I have a person table (sqlServer 2008r2) and are using .vbs and .bat files to sync some data from a table called person in database A to database B.