Thursday, July 28, 2011

WebDriver First look

WebDriver has been for a while but never get a chance to look at it. finally today I downloaded the webdriver and executed the simple testcase. Let's see how to configure webdriver for java.

First download the selenium-java-2.2.0.zip (version may differ) from http://code.google.com/p/selenium/downloads/list

The first thing you will notice when you will extract this zip is, too much JAR files, too much as compared to only two in selenium RC.

Now create the simple java project in eclipse. Put all the extracted JAR files in the buildpath of the project.

Copy and paste the following code and run using Junit. (you don't require to run any selenium server)

package Tests;

import static org.junit.Assert.assertTrue;

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;
/**
 * 
 * @author Gaurang
 *
 */
public class GoogleTest  {

 public static WebDriver driver;
 @BeforeClass
 public static void setup(){
 // Create a new instance of the Firefox driver
        driver = new FirefoxDriver();
        
        // And now use this to visit Google
        driver.get("http://www.google.com");
 }
 
 @AfterClass
 public static void tearDown(){
        //Close the browser
        driver.quit();

 }
 @Test
 public void testSearch() throws InterruptedException {
        // Find the text input element by its name
        WebElement element = driver.findElement(By.name("q"));
        // Enter something to search for
        element.sendKeys("Cheese!");
        //driver.findElement(By.name("btnG")).click();
        // Now submit the form. WebDriver will find the form for us from the element
        element.submit();
        // Check the title of the page
        System.out.println("Page title is: " + driver.getTitle());
        Thread.sleep(3000);
        assertTrue(driver.getTitle().contains("cheese!"));
  }
}

To run the webdriver testcase in Internet Explorer
replace the driver = new FirefoxDriver(); line from the setup() method with following line.
driver = new InternetExplorerDriver();

To run the webdriver testcase in Opera
replace the driver = new FirefoxDriver(); line from the setup() method with following line.
driver = new OperaDriver();

To run the Webdriver testcase in Chrome
Download the chrome driver form the below URL
Download Chrome driver

Now extract the zip file and set the path of executable in PATH variable.

replace the driver = new FirefoxDriver(); line from the setup() method with following line.

driver = new ChromeDriver();

Selenium - Handle Alert and Confirmbox

Handling alertbox.
Alertbox is special kind of modal dialog created though JavaScript. As it's modal dialog box the things in the parent window will not be accessible until close it.

selenium has getAlert()  method to handle javascript alertbox, It will click on the OK button of the alertbox and will return the text of the alertbox to verify. However Selenium fails to identify the alertbox if it has appeared through page load event. ( i.e. should not appeared when you navigate to some page or when refresh it).

Handle Alertbox at page load event
selenium is not able to indentify the dialogs appeard at the pageload event. look at this.
So I tried to click on the OK button with AutoIt script. I make the Autoit script, not a big, it's just three lines of code and tested it with both the browser and it did well. But when I call the same script (exe) from my testcase it fails to indentify the alertbox and my testcase failed. I am still finding out why the hell this is happening.
Following is the script to handle alertbox appeard at body load event.
AutoItSetOption("WinTitleMatchMode","2")

WinWait($CmdLine[1])
$title = WinGetTitle($CmdLine[1]) ; retrives whole window title
MsgBox(0,"",$title)
WinActivate($title)
WinClose($title); 


Confirmbox
Confirm box is a kind of alertbox with OK and Cancel button as compared to only OK button in alerbox.
Selenium provides following APIs to handle this.
chooseOkOnNextConfirmation() - This will click on the OK button if the confirm box appears after executing the very next step.
chooseCancelOnNextConfirmation() - This will click on the cancel button if the confirm box appears after executing the very next step.

You need to write down any of the above functions (depends on you requirement, ofcourse) just before the step which opens the confirmbox.
/**
 * @author Gaurang Shah
 * Purpose: To handle Confirm box.
 * Email: gaurangnshah@gmail.com
 */
import org.testng.annotations.*;
import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;

public class Handle_Alert {
private Selenium selenium;


@BeforeClass
public void startSelenium() {
selenium = new DefaultSelenium("localhost", 4444, "*chrome", "http://gaurangnshah.googlepages.com/");
selenium.start();

}

@AfterClass(alwaysRun=true)
public void stopSelenium() {
this.selenium.stop();
}

@Test
public void handleAlert() throws Exception{
selenium.open("selenium_test");
selenium.click("Alert");
String a = selenium.getAlert();
System.out.println(a);
}

@Test
public void handleConfirmBox() throws Exception {
selenium.open("selenium_test");
selenium.chooseCancelOnNextConfirmation();
selenium.click("Confirm");
}
}
Download above file

Watir - Setup and TearDown

In Test/Unit framework setup and teardown method invokes before and after each and every tests but sometimes we require to call setup method before test method of the class and teardown method after the last test method of the class.

After searching so much on the internet i found this

In the following example setup and teardown method will be called before and after each and every test.
beforeClass method will be called before the first test method executes.
afterClass method will be called after the last test method executes.

require 'test/unit'

class TestSuite < Test::Unit::TestCase

  def setup
    p 'setup'
  end

  def teardown
    p 'teardown'
  end

  def test1
    p 'test1'
  end

  def test2
    p 'test2'
  end

  def self.suite
    s = super
    def s.beforeClass
      p 'suite_setup'
    end

    def s.afterClass
      p 'suite_teardown'
    end

    def s.run(*args)
      beforeClass
      super
      afterClass
    end
    s
  end
end

Tuesday, July 26, 2011

WATIR: Parameterization with Excel

Ruby has already a functionality under win32ole package to make your test data-driven.
It has functions to read and write data from and to cell. if you need to read the data from a column and 10th row the code will the something like below.
value = worksheet.Range("a10").Value

However the problem with above code is, when we use that in automation we need to remember what data does "a" column contains, is it username or password or error messages and which scenario does 10th row contain, valid or invalid ?

To get rid of all this question i have write the excel class which will read the data based on given column name(data field name) and row name(scenario name).

The excel file we will access should look like below, where first row should contain data field names and first column should contain scenario names.

Following is the excel class which will read the data based on given data field name and scenario name
Excel.rb
require 'win32ole'

=begin
Purpose: Class to read Excel file given the column name and scenario name
Author:  Gaurang Shah
=end

class Excel

  @@map = Array["a","b","c","d","e","f","g","h","i","j","k","l","m","o","p","q","r","s","t","u","v","w","x","y","z"]
  #provide the path of the EXCEL file.. i.e. c:/demo.xls
  #Provide the worksheet number if you have multiple worksheets
  #If you will not provide the worksheet number by default it will take 1
  def initialize(path, workSheetNumber=1)
    @path=path
    @workSheetNumber=workSheetNumber
  end

  def openExcel
    # puts "inside excel"
    @excel = WIN32OLE::new("excel.Application")

    @workbook = @excel.Workbooks.Open("#{File.dirname(__FILE__)}/#{@path}")

    @worksheet = @workbook.WorkSheets(@workSheetNumber)
    # just to make sure macros are executed, if your sheet doesn't have macros you can skip this step.
    @worksheet.Select

    column = @worksheet.range("a1:a100").Value
    index=0
    while(column[index].to_s != "") do
      index = index+1
    end

    @scenarios = Array.new(index)
    for i in(0...index)do
      @scenarios[i] = column[i]
    end
  end

  #Returns the EXCEL cell value based on provided ScenarioName and columnName
  def getValue(scenarioName,columnName)

    openExcel()
    #get the first line of excel
    columnNames = @worksheet.Rows(1).value[0]

    #Find out the total number of columns
    name=0
    while(columnNames[name+=1] != columnName) do
    end
    #puts name

    begin
      colData = @worksheet.Range("#{@@map[name]}1:#{@@map[name]}100").Value
    rescue
      return "Data Not Found: Invalid Column"
    end

    totalScenarios  = @scenarios.length
    for index in(0..totalScenarios) do
      if(@scenarios[index].to_s == scenarioName) then
        break;
      end
    end

    if(index >= totalScenarios) then
      return "Data Not Found: Invalid Scenario"
    end
    index+=1;

    value = @worksheet.range("#{@@map[name]}#{index}").value
    @workbook.close
    @excel.Quit

    if(value.nil?) then
      return ""
    end
    return value
  end
end

Following is the sample test which will use the excel class to make test data-driven(parametrized)
DemoTest.rb
require 'test/unit'
require 'rubygems'
require 'watir'
require 'Excel'

class DemoTest < Test::Unit::TestCase
  def setup
    @browser = Watir::Browser.new
    @browser.goto("http://gmail.com")
    @browser.maximize
  end

  def test_gmail
    readExcel = Excel.new("gmail.xls")
    puts readExcel.getValue("noPassword","username")
    @browser.text_field(:id,"Email").set(readExcel.getValue("noPassword","username"))
    @browser.text_field(:id,"Passwd").set(readExcel.getValue("noPassword","password"))
    @browser.button(:id,"signIn").click()
    assert((@browser.text.include? "Enter your password."),"Verify Error Messages")
  end

  def teardown
    @browser.close()
  end
end

Friday, July 15, 2011

WATIR - HTML Report

I was just evaluating WATIR for one of our project and stuck for some time when it came to report.
There are ci_reporter gem which generates xml reports, but we required HTML reports. There are various XSL files available on internet which we can use to generate HTML reports out of this XML, I tried that but the reports were not good. We wanted something like generated through ReportNG or Junit.

So I did the trick, I generated JUnit HTML reports from this WATIR XML report file using junitreport ANT Task.
So let's see how to do it.

First you need to install ci_reporter. use the following command to install it.
gem install ci_reporter

require 'test/unit/testcase'
require 'rubygems'
require 'funfx'
require 'ci/reporter/rake/test_unit_loader.rb'


class Demo < Test::Unit::TestCase
 
  def test_first
      assert(true,"PASS");
  end

  def test_second
      assert(false,"Fail");
  end

end  
When you will run the above code it will generate the XML report under test\report folder. Now to generate the HTML report from this XML file, save the following file as build.xml where your above test file is located.
<project name="Report" default="generateReport" basedir=".">
<property name="report.dir" value="test\reports" />
<target name="generateReport">
 <junitreport todir="${report.dir}">
  <fileset dir="${report.dir}">
    <include name="*.xml" />
  </fileset>
  <report format="noframes" todir="${report.dir}" />
 </junitreport>
 </target>
</project>

Now run the following command from command line.

ANT

But before you run this command ANT need to be installed on your system. Download and install the ANT from following location.
http://ant.apache.org/bindownload.cgi

Following is the screenshot of report.

Thursday, July 14, 2011

Selenium with Regular Expression

import static org.junit.Assert.assertTrue;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;


public class SeleniumWithRegex {
 static Selenium selenium;
 @BeforeClass
 public static void setUp() throws Exception {
  selenium = new DefaultSelenium("localhost", 2323, "*chrome", "http://qtp-help.blogspot.com");
  selenium.start();
 }
 /**
  * Verify Text using regular expression
  * @throws InterruptedException
  */
 @Test
 public void verifyText() throws InterruptedException {
  selenium.open("/2010/10/selenium-checkbox-example.html");
  assertTrue(selenium.isTextPresent("regexp:.*gaurang00.*"));
 }
 
 /**
  * Click on button using regular expression
  * @throws InterruptedException
  */
 @Test
 public void testButton() throws InterruptedException {
  selenium.allowNativeXpath("false");
  selenium.click("//input[matches(@id,'Gaurang.*')]");
 }
 
 /**
  * Click on link using regular expression
  * @throws InterruptedException
  */
 @Test
 public void testLink() throws InterruptedException {
   selenium.click("link=regexp:gaurang.*");

 }
 
 @AfterClass
 public static void tearDown(){
  selenium.close();
  selenium.stop();
 }
}