Sunday, September 12, 2010

WebDriver Wait is easier after using implicitlyWait()

"WebDriver will wait until the page has fully loaded (that is, the "onload" event has fired) before returning control to your test or script."
The classic example is Javascript starting to run after the page has loaded (onload); while if the website is very "rich", it is always hard for WebDriver to identify some elements by its own blocking API.

Previous solution mentioned/suggested by experts are : Use the Wait class to wait for a specific element to appear:http://groups.google.com/group/webdriver/browse_thread/thread/50c963cd25fb416c/61aae67b8a2560fd?#61aae67b8a2560fd

Here is one example, which i wrapped the presenceOfElementLocated():

 import org.openqa.selenium.By;  
 import org.openqa.selenium.WebDriver;  
 import org.openqa.selenium.WebElement;  
 import org.openqa.selenium.support.ui.WebDriverWait;  
 import com.google.common.base.Function;  
 public class MyWaiter {  
      private WebDriver driver;  
      public MyWaiter(WebDriver driver){  
           this.driver = driver;  
      }  
      public WebElement waitForMe(By locatorname, int timeout){  
           WebDriverWait wait = new WebDriverWait(driver, timeout);  
           return wait.until(MyWaiter.presenceOfElementLocated(locatorname));  
      }  
      public static Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {  
           // TODO Auto-generated method stub  
           return new Function<WebDriver, WebElement>() {  
                @Override  
                public WebElement apply(WebDriver driver) {  
                     return driver.findElement(locator);  
                }  
           };  
      }  
 }  

My test code:
 public static void main(String[] args) {  
           WebDriver driver = new FirefoxDriver();  
           driver.get("http://www.google.com/");  
           MyWaiter myWaiter = new MyWaiter(driver);  
           WebElement search = myWaiter.waitForMe(By.name("btnG"), 10);  
           search.click();  
      }  

This way looks a little bit fussy to me, although it works well.

Now, implicitlyWait() gives tests a "KISS" and most importantly, it did solve the problem.

driver.findElement(By.id("signIn")).click();  
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);  
driver.switchTo().frame("canvas_frame");  
driver.findElement(By.partialLinkText("Buzz")).click();  
driver.findElement(By.linkText("Cheng Chi")).click();  


You may notice that the first sample code using wait.until(), you have to two wait.until() for each link element, otherwise the code will fail; While the second one, you just add one implicitlyWait() in front of the "Buzz" link.
I do not know why, but it shows that implicitlyWait() is a better choice for locating (ajax) elements.

PS: I marked "in front of" as bold above, which means implicitlyWait() is a kind of registration method, you need to tell Webdriver in advance.

1 comment:

  1. So, does this mean that once you do an implicitlyWait once in the code, it will do for all findelement things?

    ReplyDelete