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...>
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:
^ 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:
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:
Have you tried the when present, to wait for the button (You could also make it wait for a certain div to )
As for explicit waiting
or a better way as to not waste time
Just use
Then you can wait for it.
A potential answer is in your stacktrace.
Using Webdriver RC and C# I find this is the most effective way to make the driver wait:
You are using
wait
asWebDriver
function, but it isn't. Try this