Thursday, October 18, 2012

WebDriver - Take Screenshots on Test Case Fail.

There are two way you can achieve this if you are using TestNG as you unit testing framework. Refer the following blog post to see how to do this using TestNG.
http://qtp-help.blogspot.in/2010/07/testng-take-screenshot-of-failed-test.html

Below we will discuss how to do the same thing using WebDriver listeners. Webdriver has a WebDriverEventListener interface which you can implement and override the particular listener you want. WebDriverEventListener interface has onException method which is being called whenever a WebDriver exception occurs, So we will override this method and will write down the code to take screenshot in it.

WebDriverEventListenerDemo.java
you need to implement all the methods of the WebDriverEventListener class, here I haven't show that to make code looks small.
import java.io.*;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.support.events.WebDriverEventListener;

/***
 * Implements WebDriverEventListener and overrides onException method
 * @author Gaurang
 * 
 */
public class WebDriverEventListenerDemo implements WebDriverEventListener {
 @Override
 public void onException(Throwable exception, WebDriver driver) {
  File screenShot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
  try {
   FileUtils.copyFile(screenShot, new File("c:\\tmp\\exception.png"));
  } catch (IOException e) {
   e.printStackTrace();
  }
  
 }
}
TestWithEvenRegistered.java
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.events.EventFiringWebDriver;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

/***
 * Class registers the Event listern class we created 
 * @author gshah
 *
 */
public class TestWithEvenRegistered {
 
 WebDriver driver = new FirefoxDriver();
 EventFiringWebDriver eventFiringWebDriver;
 @BeforeClass
 public void setup() {
  eventFiringWebDriver = new EventFiringWebDriver(driver);
  eventFiringWebDriver.register(new WebDriverEventListenerDemo());
  eventFiringWebDriver.get("http://google.com");
  
 }
 
 /**
  * "qq" is wrong element id and so NoElementFound Exception will 
  * be generated, which will call our overridden method of WebDriverEventListenerDemo
  * class and will take the screenshot. 
  */
 @Test
 public void test(){
  eventFiringWebDriver.navigate().to("http://google.com");
  eventFiringWebDriver.findElement(By.name("qq"));
  
 }
}

Monday, October 8, 2012

WebDriver - Selecting from CSS dropdown

In last few years the web designing has advanced too much. And for better look and feel people sometimes uses CSS to overwrite basic HTML component like editbox, dropdown, checkbox. It doesn't create any problem until you try to Automate it, but the moment you think to automate it started giving problem.
The biggest problem is, tools specifically selenium doesn't identify them as a proper element. For example, "All Categories" dropdown on flipcart.com.

If you will see it's code it is not standard HTML dropdown box, you wouldn't be able to find any select tag. And so the following code would fail.
@Test
 public void selectCSSDropDown(){
  driver.get("http://flipcart.com");
  Select catagoryDropDown = new Select(driver.findElement(By.className("fk-menu-selector")));
  catagoryDropDown.selectByVisibleText("Cameras");
 }
It will give you error somewhat like blow:
org.openqa.selenium.support.ui.UnexpectedTagNameException: Element should have been "select" but was "a"
There are two workarounds to this.
  1. Click on the Dropdown and then click on the item you want to select 
     However using this you will be able to select by index only and not by visible text
    @Test
    public void selectCssDropDownUsingCSS() {
    
     driver.get("http://flipcart.com");
     driver.findElement(By.className("fk-menu-selector")).click();
     driver.findElement(By.cssSelector("div#fk-mI li:nth-child(5)")).click();
    
    }
  2. Through JavaScript
    You are lucky if your website if using JavaScript function to select an item, that way we can directly call those JavaScript functions as mention below
    @Test
    public void selectCssDropDownUsingJavaScript(){
     driver.get("http://flipcart.com");
     JavascriptExecutor js = (JavascriptExecutor) driver;
     js.executeScript("selectMItem('Cameras', 'cameras')");
    }

Sunday, October 7, 2012

Webdriver - Page Object Pattern

What I am going to discuss here is Page Object Pattern with Page Factory for Webdriver. Let's not talk much about theory and let's see how to implement it. let's take one scenario and see how we can automate it without and with Page Object Pattern Scenario:
  1. Open http://newtours.demoaut.com/ site 
  2. Login to the site. 
  3. Log out. Now if we are not using any design patten the testcase will look like below
@Test
public void testLogin() {
 driver.findElement(By.id("userName")).clear();
 driver.findElement(By.id("userName")).sendKeys("testuser33");
 
 driver.findElement(By.id("password")).clear();
 driver.findElement(By.id("password")).sendKeys("password123");
 
 driver.findElement(By.id("login")).click();
 
 driver.findElement(By.linkText("SIGN-OFF")).click();

}
Now let's see how the code will look like if we will have to use the Page Object Pattern with Page Factory. LoginPage.java - contains Login page web elements and functions

package Pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;

public class LoginPage {
 
 final WebDriver driver;
 
 @FindBy(how = How.NAME, using = "userName")
 private WebElement usernameEditbox;
 
 @FindBy(how = How.NAME, using = "password")
 private WebElement passwordEditbox;
 
 @FindBy(how = How.NAME, using = "login")
 private WebElement singinButton;

 public LoginPage(WebDriver driver) {
  this.driver = driver;
 }

 public void enterUsername(String login) {
  usernameEditbox.clear();
  usernameEditbox.sendKeys(login);
 }

 public void enterPassword(String password) {
  passwordEditbox.clear();
  passwordEditbox.sendKeys(password);
 }

 public void clickSigninButton() {
  singinButton.click();
 }

 public FindFlightPage login(String login, String password) {
  enterUsername(login);
  enterPassword(password);
  clickSigninButton();
  return PageFactory.initElements(driver, FindFlightPage.class);
 }
}

FindFlightPage.java - contains Find Flight page web elements and functions
package Pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;

public class FindFlightPage {

 final WebDriver driver;
 
 public FindFlightPage(WebDriver driver) {
  this.driver = driver;
 }
 
 @FindBy(how = How.LINK_TEXT, using="SIGN-OFF")
 private WebElement signOff;
 
 public LoginPage singOff(){
  signOff.click();  
  return PageFactory.initElements(driver, LoginPage.class);
 }
}

LoginTest.java  - Actual class which contains tests for login page
package Tests;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.PageFactory;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import Pages.FindFlightPage;
import Pages.LoginPage;

public class LoginTest {

 WebDriver driver;
 private static String login = "testuser33";
 private static String pass = "password123";

 @BeforeClass
 public void setUp() throws Exception {
  driver = new FirefoxDriver();
  driver.get("http://newtours.demoaut.com/mercuryreservation.php");
 }

 @Test
 public void testLogin() {
 
  LoginPage loginPage = PageFactory.initElements(driver, LoginPage.class);
  FindFlightPage findPage = loginPage.login(login, pass);
  
  loginPage = findPage.singOff();
 }
 
 @AfterClass
 public void tearDown() throws Exception {
  driver.quit();
 }
}

Wednesday, March 7, 2012

WebDriver - Dynamic Table

Scenario: Sometimes we have a dynamic table, in which neither the number of rows, or the order is constant. And in such case if you have to verify and particular values from the table you can use the following technique.

Assumption: Following table is dynamic table, which can have any number of rows and order or the records may also change every time you load.

Names Designationsalary
GaurangConfused45000
AjayTeam Lead50000
BinoyQA40000
SantoshProject Manager100000

TestCase: Verify the Salary of Gaurang from the above table.

/**
 * @author Gaurang Shah
 * Purpose: To demonstrate how to verify Dynamic Table in Selenium 
 */
import static org.junit.Assert.*;

import java.util.List;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

public class WebDriverTable {
 public static WebDriver driver;

 @BeforeClass
 public static void setup() {
  // Create a new instance of the Firefox driver
  driver = new FirefoxDriver();
  driver.get("http://qtp-help.blogspot.in/2012/02/selenium-verify-table.html");
 }

 @AfterClass
 public static void tearDown() {
  // Close the browser
  driver.quit();
 }

 @Test
 public void testDynamicTable() throws InterruptedException {

  String salary = "0";
  List<WebElement> totalRows = driver.findElements(By
    .xpath("//table[@name='salaryTable']/tbody/tr"));

  for (int row = 1; row <= totalRows.size(); row++) {
   // Fetch the text of first column (name)
   String name = driver.findElement(By.xpath("//table[@name='salaryTable']/tbody/tr["+row+"]/td[1]")).getText();

   // If name matches gaurang fetch the text of third column (salary)
   if (name.equalsIgnoreCase("gaurang")) {
    salary = driver.findElement(By.xpath("//table[@name='salaryTable']/tbody/tr["+row+"]/td[3]")).getText();
   }
  }

  System.out.println(salary);
  assertEquals("Verify Salary", "45000", salary);
 }
}


Thursday, March 1, 2012

Selenium - Firefox with Custom Profile

There are few scenarios where we require to run Firefox with custom profile, I will cover the scenarios in my upcoming posts, however let me post how to run Selenium with Custom Firefox profile.
First you require to create a custom Firefox profile. Let's see how to create.

  1. Open the run menu and type following command
    Firefox -ProfileManager
  2. It will open the below dialog box, Click on "Create Profile" Click on "Next" 
  3. From below dialog box On below dialog click on "Choose Folder" first and then choose the folder where you want to save you custom profile, and then click "Finish" button. 
Now your custom profile has created. To run Selenium with custom profile, you need to start selenium RC and need to provide the path where your custom profile is stored as mention below
java -jar selenium-server-standalone-2.19.0.jar -firefoxProfileTemplate "d:\Gaurang\Selenium\Custom_Profile"

Friday, February 24, 2012

Selenium - Verify Table

Scenario: Sometimes we have a dynamic table, in which neither the number of rows, or the order is constant. And in such case if you have to verify and particular values from the table you can use the following technique.

Assumption: Following table is dynamic table, which can have any number of rows and order or the records may also change every time you load.

Names Designationsalary
GaurangConfused45000
AjayTeam Lead50000
BinoyQA40000
SantoshProject Manager100000

TestCase: Verify the Salary of Gaurang from the above table.

/**
 * @author Gaurang Shah
 * Purpose: To demonstrate how to verify Dynamic Table in Selenium 
 */

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;
import static org.junit.Assert.*;
public class SeleniumTable {
 public static Selenium selenium;
 @BeforeClass
 public static void setUp() throws Exception {
  selenium = new DefaultSelenium("localhost", 4444, "*chrome", "http://qtp-help.blogspot.in");
  selenium.start();
  selenium.windowMaximize();
 }
 
 @Test
 public void ItrateTable(){
  int salary = 0;
  selenium.open("/2012/02/selenium-verify-table.html");
  
  //Find out how many rows this table has.
  int totalRows=selenium.getXpathCount("//table[@name='salaryTable']/tbody/tr").intValue();
  
  for(int row=1; row<=totalRows; row++){
   //Find the row whose first column has name as Gaurang
   String name = selenium.getText("//table[@name='salaryTable']/tbody/tr["+row+"]/td[1]");
   if(name.equalsIgnoreCase("gaurang")){
    //When you find row get the value of third column of that table.
    salary = Integer.valueOf(selenium.getText("//table[@name='salaryTable']/tbody/tr["+row+"]/td[3]"));
   }
  }
  System.out.println("salary="+salary);
  assertEquals("Verify Salary", 45000,salary);
 }
 
 @AfterClass
 public static void tearDown() throws Exception {
  selenium.stop();
 }
}