Saturday, May 11, 2013

Wait in Selenium WebDriver

There are many types of waits in selenium WebDriver.
  1. Thread.sleep()
  2. Implicit Wait
  3. WebDriver Wait
  4. Wait for the Ajax call
  5. Wait for the page to load
1. Thread.sleep()

Here we can't predict the exact required wait time. With this we may need to wait for some extra seconds which decreases performances. These extra seconds became more when we execute multiple tests which increases the overhead. This wait is not recommended and we should not use this in our test.

2. Implicit Wait

This is the wait provided by WebDriver which is used, in general, for waiting for an element. This is recommended and we can use it. For example,
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
When we use this statement, the WebDriver waits for the element(on which next action is performed) till 30 seconds if that is not available immediately. After the timeout period, if the element is not available, it throws NoSuchElementException.
Use of this at the beginning of each test is very profitable and a best practice.
3. WebDriver Wait

This wait waits for a condition. This is also recommended and we can use it. This checks the condition in every 500 milliseconds until it returns true or the timeout. For example,
WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(xpath)));
Here the condition is "ExpectedConditions.presenceOfElementLocated(By.xpath(xpath))" and this condition is checked in every 500 milliseconds until it is timed out by the timeout specified in timeOutInSeconds.

WebDriver wait is an explicit wait. You can refer here for more about implicit and explicit waits.


4. Wait for the AJAX call to complete

This is also recommended and very useful when we need to wait for some elements on the web page which is updating upon ajax calls.
You can refer the my post "Wait For Ajax call" for how to use this.

5. Wait for page to load

This is also recommended and very useful when you need to wait for a web page to load completely.
You can refer the my post "Wait for Page to load" for how to use this.

Friday, May 10, 2013

Wait for AJAX call to complete in WebDriver

Sometimes in our web application only part of the web page gets loaded upon certain actions, at that time actually an ajax call happens and depending upon the ajax response the page part loads. So in this case we need to wait till the ajax call is completed to test anything on that part of the webpage, if you don't want to do that by waiting for a specific element to be available. Below is the code that waits till the ajax calls completed:
/**
 * Waits until there are no more active ajax connection and until the
 * specified timeoutInSeconds is timeout
 * 
 * @param timeoutInSeconds
 */
public void waitForAjax(long timeoutInSeconds) {
 log.info("Checking active ajax calls by calling jquery.active");
 try {
  if (driver instanceof JavascriptExecutor) {
   JavascriptExecutor jsDriver = (JavascriptExecutor) driver;

   for (int i = 0; i < timeoutInSeconds; i++) {
    Object numberOfAjaxConnections = jsDriver
      .executeScript("return jQuery.active");
    // return should be a number
    if (numberOfAjaxConnections instanceof Long) {
     Long n = (Long) numberOfAjaxConnections;
     log.info("Number of active jquery ajax calls: " + n);
     if (n.longValue() == 0L)
      break;
    }
    Thread.sleep(1000);// 1 second sleep
   }
  } else {
   log.error("Web driver: " + driver
     + " cannot execute javascript");
  }
 } catch (Exception e) {
  log.error("Failed to wait for ajax response: " + e);
 }
}
In this code snippet we are checking the number of active Ajax connections by executing the javascript code jQuery.active then depending upon the result we are waiting for the ajax calls to complete until the timeout specified in timeoutInSeconds paameter

Wait for page to load in WebDriver

Unlike Selenium RC(selenium 1) have waitForPageToLoad method to wait until the page to load, WebDriver(selenium 2) doesn't have any method in the API to wait until the page to load. Here is a way to wait until the page elements load properly.
/**
 * Waits for a page to load for timeOutInSeconds number of
 * seconds.
 * 
 * @param timeOutInSeconds
 */
public void waitForPageToLoad(long timeOutInSeconds) {
 ExpectedCondition expectation = new ExpectedCondition() {
  public Boolean apply(WebDriver driver) {
   return ((JavascriptExecutor) driver).executeScript(
     "return document.readyState").equals("complete");
  }
 };
 try {
  log.info("Waiting for page to load...");
  WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
  wait.until(expectation);
 } catch (Throwable error) {
  log.error("Timeout waiting for Page Load Request to complete after "
    + timeOutInSeconds + " seconds");
  Assert.assertFalse(true,
    "Timeout waiting for Page Load Request to complete.");
 }
}
Here we are checking for the "complete" loading state of the web page by JavascriptExecutor and until that we are waiting till the timeout period specified in timeOutInSeconds parameter.

Friday, April 05, 2013

Logging application log to a log file(by File Appender)

To log your application log to a log file by using log4j, you have to go through the following steps:
  1. Download latest jar of log4j.jar and add it to your project classpath.
  2. Create a log4j.properties file inside your source directory to define properties of your logger.
  3. To log your application log to a log file, you need to add the following code in the log4j.properties
  4.  
    #################################################################
    #####     Application Logs to be printed in the log file    #####
    #################################################################
     
    log4j.rootLogger= WARN, FILE_APPENDER
    
    # test appender  daily rolling logs format
    log4j.appender.FILE_APPENDER=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.FILE_APPENDER.File=logs/autoLog.log
    log4j.appender.FILE_APPENDER.DatePattern='.'yyyy-MM-dd
    log4j.appender.FILE_APPENDER.layout=org.apache.log4j.PatternLayout
    log4j.appender.FILE_APPENDER.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p (%F:%M:%L) - %m%n
    
    # test appender  daily rolling logs for packages
    log4j.logger.com.myorg=DEBUG
    log4j.logger.com.myorg.core.util=FILE_APPENDER
    log4j.logger.com.myorg.core.page=FILE_APPENDER
    
  5. To know the usage of logger see the below code:
    //In ConfigUtil.java
    private static Logger log = Logger.getLogger(ConfigUtil.class);
    // The below line is called inside static block
    log.info("Properties file loaded at '" + configLoc + "'");
    
    //In BasePage.java
    protected static Logger log = Logger.getLogger(BasePage.class);
    // The below line is called inside setTimeout() method
    log.info("The timeout value is set to " + timeoutSeconds + " seconds.");
    
    //In DriverManager.java
    private static Logger log = Logger.getLogger(DriverManager.class);
    // The below line is called inside static block
    log.info("Driver location is set to '" + driverLoc + "'");
    
  6. You will get your application log in the log file(which you have specified in your log4j.properties, in this example i have specified "logs/autoLog.log" file) as shown in the below sample:
     
    2013-09-05 12:36:04  INFO (ConfigUtil.java::39) - Properties file loaded at '/Users/aksahu/MySpace/Web_Workspace/KnowledgeBase/config/config.properties'
    2013-09-05 12:36:04  INFO (BasePage.java:setTimeout:155) - The timeout value is set to 60 seconds.
    2013-09-05 12:36:04  INFO (DriverManager.java::54) - Driver location is set to '/Users/aksahu/MySpace/Web_Workspace/CoreDriver/drivers/'
    2013-09-05 12:36:04  INFO (DriverManager.java:getDriver:85) - initializing 'chrome' driver...
    2013-09-05 12:36:15  INFO (BasePage.java:windowMaximize:101) - Maximizing the browser window.
    2013-09-05 12:36:17  INFO (BasePage.java:openUrl:86) - Openning the url 'http://knowledgebase-wiki.appspot.com/' in the browser...
    2013-09-05 12:36:23  INFO (BasePage.java:waitForPageToLoad:956) - Waiting for page to load...
    2013-09-05 12:36:23  INFO (BasePage.java:typeByID:195) - Entering text 'java' to the element specified by id 'searchField'
    2013-09-05 12:36:23  INFO (BasePage.java:clickByID:258) - Clicking on the element specified by id 'resultDiv0'
    2013-09-05 12:36:23  INFO (BasePage.java:waitForElementLocatedByXpath:848) - Waiting for the element specified by xpath '//a[contains(text(),'[Go to page]')]'
    2013-09-05 12:36:23  INFO (BasePage.java:clickByXpath:238) - Clicking on the element specified by xpath '//a[contains(text(),'[Go to page]')]'
    2013-09-05 12:36:24  INFO (BasePage.java:waitForPageToLoad:956) - Waiting for page to load...
    2013-09-05 12:36:24  INFO (BasePage.java:isTextPresent:807) - Checking for the text 'Installing Java' in the page
    2013-09-05 12:36:24  INFO (BasePage.java:isTextPresent:807) - Checking for the text 'java' in the page
    2013-09-05 12:36:24  INFO (BasePage.java:quitBrowser:582) - Closing all the instances of the browser 'chrome'
    

Logging application log in the Console(by Console Appender)

To log your application log in the console by using log4j, you have to go through the following steps:
  1. Download latest jar of log4j.jar and add it to your project classpath.
  2. Create a log4j.properties file inside your source directory to define properties of your logger.
  3. To log your application log in the console, you need to add the following code in the log4j.properties
  4.  
    ################################################################
    #####     Application Logs to be printed in the console    #####
    ################################################################
     
    log4j.rootLogger= WARN, CONSOLE_APPENDER
    
    # console appender format
    log4j.appender.CONSOLE_APPENDER=org.apache.log4j.ConsoleAppender
    log4j.appender.CONSOLE_APPENDER.layout=org.apache.log4j.PatternLayout
    log4j.appender.CONSOLE_APPENDER.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p (%F:%M:%L) - %m%n
    
    # console appender for packages
    log4j.logger.com.myorg=DEBUG
    log4j.logger.com.myorg.core.util=CONSOLE_APPENDER
    log4j.logger.com.myorg.core.page=CONSOLE_APPENDER
    
  5. To know the usage of logger see the below code:
    //In ConfigUtil.java
    private static Logger log = Logger.getLogger(ConfigUtil.class);
    // The below line is called inside static block
    log.info("Properties file loaded at '" + configLoc + "'");
    
    //In BasePage.java
    protected static Logger log = Logger.getLogger(BasePage.class);
    // The below line is called inside setTimeout() method
    log.info("The timeout value is set to " + timeoutSeconds + " seconds.");
    
    //In DriverManager.java
    private static Logger log = Logger.getLogger(DriverManager.class);
    // The below line is called inside static block
    log.info("Driver location is set to '" + driverLoc + "'");
    
  6. You will get your application log as shown in the below example:
     
    [TestNG] Running:
      /private/var/folders/cl/34rlg3ns31g8w4jktmpkc2440000gn/T/testng-eclipse--1656210619/testng-customsuite.xml
    
    2013-09-05 12:58:03  INFO (ConfigUtil.java::39) - Properties file loaded at '/Users/ashwin/MySpace/Web_Workspace/KnowledgeBase/config/config.properties'
    2013-09-05 12:58:03  INFO (BasePage.java:setTimeout:155) - The timeout value is set to 60 seconds.
    2013-09-05 12:58:03  INFO (DriverManager.java::54) - Driver location is set to '/Users/ashwin/MySpace/Web_Workspace/CoreDriver/drivers/'
    2013-09-05 12:58:03  INFO (DriverManager.java:getDriver:85) - initializing 'chrome' driver...
    2013-09-05 12:58:09  INFO (BasePage.java:windowMaximize:101) - Maximizing the browser window.
    2013-09-05 12:58:12  INFO (BasePage.java:openUrl:86) - Openning the url 'http://knowledgebase-wiki.appspot.com/' in the browser...
    2013-09-05 12:58:18  INFO (BasePage.java:waitForPageToLoad:956) - Waiting for page to load...
    2013-09-05 12:58:18  INFO (BasePage.java:typeByID:195) - Entering text 'java' to the element specified by id 'searchField'
    2013-09-05 12:58:19  INFO (BasePage.java:clickByID:258) - Clicking on the element specified by id 'resultDiv0'
    2013-09-05 12:58:19  INFO (BasePage.java:waitForElementLocatedByXpath:848) - Waiting for the element specified by xpath '//a[contains(text(),'[Go to page]')]'
    2013-09-05 12:58:19  INFO (BasePage.java:clickByXpath:238) - Clicking on the element specified by xpath '//a[contains(text(),'[Go to page]')]'
    2013-09-05 12:58:19  INFO (BasePage.java:waitForPageToLoad:956) - Waiting for page to load...
    2013-09-05 12:58:19  INFO (BasePage.java:isTextPresent:807) - Checking for the text 'Installing Java' in the page
    2013-09-05 12:58:19  INFO (BasePage.java:isTextPresent:807) - Checking for the text 'java' in the page
    2013-09-05 12:58:19  INFO (BasePage.java:quitBrowser:582) - Closing all the instances of the browser 'chrome'
    PASSED: testJavaModule
            Verifies the Java Module form Knowledge base
    
    ===============================================
        Default test
        Tests run: 1, Failures: 0, Skips: 0
    ===============================================