Sunday, 13 August 2017

Selenium Core Extensions (User-Extensions.js)

To understand extensions, lets first understand the three pillars of selenium IDE
  1. Action: What operation you are performing on UI Screen
    Selenium Core Extensions (User-Extensions.js)
  2. Assessors/Assertion: What verification you do on data you get from UI
Selenium Core Extensions (User-Extensions.js)
  1. Locator Strategy: How can we find the element in UI.
Selenium Core Extensions (User-Extensions.js)
Now, Selenium IDE has a very mature library with plenty of Actions, Assertion/Assessors and Locator Strategies.
But sometimes we need to add some more functionality to it for our project requirements. In that situation, we can expand this library by adding our custom extensions. These custom extensions are called 'User Extension'.
For example, we need an Action which can convert the text to upper case before filling it in a web element. You cannot find this Action in the default Action library. In such case you can create your own 'User Extension'. In this tutorial, we will learn how to create user extension to convert Text to Upper Case

Requirement to create Selenium user extension:

To create user extension for Selenium IDE, we need to know the basic concept of JavaScript and Java Script prototype object concept.
Selenium Core Extensions (User-Extensions.js)
To create your user extension, you need to create Java script methods and add them to the selenium object prototype and PageBot object prototype.

How Selenium IDE recognizes User Extension?

After adding of User Extension to Selenium IDE when we start Selenium IDE, all of these extensions in javascript prototype get loaded, and Selenium IDE recognizes them by their name.

How to Create User Extension

Step 1) Action- all actions are started by "do", i.e. if the action is for upper case text than its name will be doTextUpperCase. When we add this action method in Selenium IDE, Selenium IDE will itself create a wait method for this action. So in this case when we create doTextUpperCase action, Selenium IDE will create a corresponding wait function as TextUpperCaseAndWait. It can accept two parameters
Example: Upper Case Text Action
Selenium.prototype.doTextUpperCase = function(locator, text) {
     // Here findElement is itself capable to handle all type of locator(xpath,css,name,id,className), We just need to pass the locator text
     var element = this.page().findElement(locator);
      
     // Create the text to type
     text = text.toUpperCase();
      
     // Replace the element text with the new text
     this.page().replaceText(element, text);
    };
Step 2) Assessors/Assertion- All assessors registered in selenium object prototype will be prefixed
by "get" or "is" Ex. getValueFromCompoundTable , isValueFromCompoundTable .It can accept two parameters, one for target and other for value field in test case.
Selenium Core Extensions (User-Extensions.js)
For each Assessor, there will be corresponding verification functions prefixed by "verify," "assert" and the wait function prefix by "waitFor"
    
Example: For Upper Case Text assessors
    
Selenium.prototype.assertTextUpperCase = function(locator, text) {
     // All locator-strategies are automatically handled by "findElement"
     var element = this.page().findElement(locator);
      
     // Create the text to verify
     text = text.toUpperCase();
      
     // Get the actual element value
     var actualValue = element.value;
    
     // Make sure the actual value matches the expected
     Assert.matches(expectedValue, actualValue);
    };
    
    Selenium.prototype.isTextEqual = function(locator, text) {
     return this.getText(locator).value===text;
    };
    
    Selenium.prototype.getTextValue = function(locator, text) {
     return this.getText(locator).value;
    };
Step 3) Locator strategy- If we wish to create our own function to locate an element then
    we need to extend PageBot prototype with a function with prefix "locateElementBy."
    It will take two parameters, first will be the locator string and second will be the document
    where it needs to be searched.
    
Example: For Upper Case Text Locator
    
// The "inDocument" is a document you are searching.
    PageBot.prototype.locateElementByUpperCase = function(text, inDocument) {
     // Create the text to search for
     var expectedValue = text.toUpperCase();
      
     // Loop through all elements, looking for ones that have
     // a value === our expected value
     var allElements = inDocument.getElementsByTagName("*");
// This star '*' is a kind of regular expression it will go through every element (in HTML DOM every element surely have a tag name like<body>,<a>,<h1>,<table>,<tr>,<td> etc. ). Here our motive is to find an element which matched with the Upper Case text we have passed so we will search it with all elements and when we get match we will have the correct web element.
     for (var i = 0; i < allElements.length; i++) {
     var testElement = allElements[i];
     if (testElement.innerHTML && testElement.innerHTML === expectedValue) {
     return testElement;
     }
     }
     return null;
    };

How to use newly created core extension?

  1. Go to Selenium IDE
    Click on Options -> Options…
Selenium Core Extensions (User-Extensions.js)
  1. In General section select the location of the newly created Selenium Core Extension
    Selenium Core Extensions (User-Extensions.js)
  2. Click OK and restart Selenium IDE
Selenium Core Extensions (User-Extensions.js)
  1. You will find the extension in the command list
Selenium Core Extensions (User-Extensions.js)

Here is a list of popular extensions/plug-in used in Selenium IDE

NamePurpose
FavoritesTo mark a test suite as favorite and execute them in one click
Flex Pilot XFor Flex based automation
FlexMonkiumFor Adobe Flex based recording and playback Testing in Selenium IDE
File LoggingFor saving logs in a file
Flow ControlTo control test execution flow
Highlight ElementsTo highlight a web control
Implicit WaitTo wait for an element for certain time limit
ScreenShot on FailTake a screenshot on failure
Test ResultsSave test case result for a test suite in one click
You can get these all and many more from SeleniumHQ official site's download section
http://docs.seleniumhq.org/download/
Summary:
  • There is three part of Selenium IDE, Action, Assessors/Assertion, Locator strategy.
  • User extension is created, when Selenium IDE is not fulfilling the current requirement.
  • To create user extension it is required to add javascript to selenium's object prototype.
  • After creation of extension, it is required to add it in Selenium IDE and restart IDE.

XPath Contains, Sibling, Ancestor Functions in Selenium WebDriver

If a simple XPath is not able to find a complicated web element for our test script, we need to use the functions from XPath 1.0 library. With the combination of these functions, we can create more specific XPath. Let's discuss a 3 such functions –
  1. Contains
  2. Sibiling
  3. Ancestor
Let's study them in detail -
Contains: By using 'contains' function in XPath, we can extract all the elements which matches a particular text value.
Ex. Here we are searching an anchor .contains text as 'SAP M'.
"//h4/a[contains(text(),'SAP M)']"
XPath Contains, Sibling, Ancestor Functions in Selenium WebDriver
Sibling: Using sibling keyword, we can fetch a web element on the which is related to some other element.
Example: Here on the basis of sibling element of 'a' we are finding 'h4'
"//div[@class='canvas- graph']//a[@href='/accounting.html'][i[@class='icon-usd']]/following-sibling::h4"
XPath Contains, Sibling, Ancestor Functions in Selenium WebDriver
Ancestor: To find an element on the basis of the parent element we can use ancestor attribute of XPath.
XPath Contains, Sibling, Ancestor Functions in Selenium WebDriver
Lets understand these 3 functions using an example –
Test Steps
Note: Since the date of creation of tutorial the Homepage of Guru99 has been updated so use the demo site instead to run tests
  1. Go to http://demo.guru99.com/selenium/guru99home/
  2. In the section 'A few of our most popular courses', search all Web Elements which are sibling of a WebElement whose text is 'SELENIUM'
  3. We will find element using contains , ancestor and sibling function
    XPath Contains, Sibling, Ancestor Functions in Selenium WebDriver

USING Contains and Sibling

import java.util.List;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.Test;

public class SiblingAndParentInXpath {

    @Test

    public void testSiblingAndParentInXpath(){

     WebDriver driver;
     String driverPath = "C:\\geckodriver.exe";
     System.setProperty("webdriver.firefox.marionette", driverPath);
        driver = new FirefoxDriver();        
        
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.get("http://demo.guru99.com/selenium/guru99home/");

        //Search element inside 'Popular course' which are sibling of control 'SELENIUM' ,Here first we will find a h2 whose text is ''A few of our most popular courses' ,then we move to its parent element which is a 'div' , inside this div we will find a link whose text is 'SELENIUM' then at last we will find all of the sibling elements of this link('SELENIUM')
        List >WebElement< dateBox = driver.findElements(By.xpath("//h2[contains(text(),'A few of our most popular courses')]/parent::div//div[//a[text()='SELENIUM']]/following-sibling::div[@class='rt-grid-2 rt-omega']"));

        //Print all the which are sibling of the the element named as 'SELENIUM' in 'Popular course'
        for (WebElement webElement : dateBox) {
            System.out.println(webElement.getText());
        }     

        driver.close();
    }
}
Output will be like:
XPath Contains, Sibling, Ancestor Functions in Selenium WebDriver

Using Ancestor function

We can achieve the same functionality with the help of a function 'ancestor' as well.
Now suppose we need to Search All elements in 'Popular course' section with the help of ancestor of the anchor whose text is 'SELENIUM'
Here our xpath query will be like
"//div[.//a[text()='SELENIUM']]/ancestor::div[@class='rt-grid-2 rt-omega']/following-sibling::div"

Complete Code

import java.util.List;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.Test;

public class AncestorInXpath{

@Test

    public void testAncestorInXpath(){

        WebDriver driver = new FirefoxDriver();             
  driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.get("http://demo.guru99.com/selenium/guru99home/");

        //Search All elements in 'Popular course' section 
  //with the help of ancestor of the anchor whose text is 'SELENIUM'

        List<WebElement> dateBox = driver.findElements(By.xpath("//div[.//a[text()='SELENIUM']]/ancestor::div[@class='rt-grid-2 rt-omega']/following-sibling::div"));

        //Print all the which are sibling of the element named as 'SELENIUM' in 'Popular course'

        for (WebElement webElement : dateBox) {
            System.out.println(webElement.getText());
        }
     
        driver.quit();
    }
}
   
Output will look like-
XPath Contains, Sibling, Ancestor Functions in Selenium WebDriver
Summary:
  • There are some situation when regular xpath cannot be used to find element. In these situation we need different functions from xpath query.
  • There some important xpath functions like contains, parent, ancestors, following-sibling etc.
  • With the help of these functions we can create complex xpath expressions.

How to Take Screenshot in Selenium WebDriver

Screenshots are desirable for bug analysis. Selenium can automatically take screenshots during execution. You need to type cast WebDriver instance to TakesScreenshot.
How to Take Screenshot in Selenium WebDriver
Taking Screenshot in Selenium is a 3 Step process
Step 1) Convert web driver object to TakeScreenshot
TakesScreenshot scrShot =((TakesScreenshot)webdriver);
Step 2) Call getScreenshotAs method to create image file
File SrcFile=scrShot.getScreenshotAs(OutputType.FILE);
Step 3) Copy file to Desired Location
Example: In this example we will take screenshot of http://demo.guru99.com/V4/ & save it as C:/Test.png
package Guru99TakeScreenshot;

import java.io.File;

import org.apache.commons.io.FileUtils;

import org.openqa.selenium.OutputType;

import org.openqa.selenium.TakesScreenshot;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.firefox.FirefoxDriver;

import org.testng.annotations.Test;

public class Guru99TakeScreenshot {

    @Test

    public void testGuru99TakeScreenShot() throws Exception{

  WebDriver driver ;
     System.setProperty("webdriver.firefox.marionette","C:\\geckodriver.exe");
     driver = new FirefoxDriver();

        //goto url

        driver.get("http://demo.guru99.com/V4/");

        //Call take screenshot function

        this.takeSnapShot(driver, "c://test.png") ;     

    }

    /**

     * This function will take screenshot

     * @param webdriver

     * @param fileWithPath

     * @throws Exception

     */

    public static void takeSnapShot(WebDriver webdriver,String fileWithPath) throws Exception{

        //Convert web driver object to TakeScreenshot

        TakesScreenshot scrShot =((TakesScreenshot)webdriver);

        //Call getScreenshotAs method to create image file

                File SrcFile=scrShot.getScreenshotAs(OutputType.FILE);

            //Move image file to new destination

                File DestFile=new File(fileWithPath);

                //Copy file at destination

                FileUtils.copyFile(SrcFile, DestFile);

    }

}

Page Object Model (POM) & Page Factory in Selenium: Complete Tutorial

Before we learn about Page Object Model, let's understand -

Why POM?

Starting an UI Automation in Selenium WebDriver is NOT a tough task. You just need to find elements, perform operations on it.
Consider this simple script to login into a website
Page Object Model (POM) & Page Factory in Selenium: Complete Tutorial
As you can observe, all we are doing is finding elements and filling values for those elements.
This is a small script. Script maintenance looks easy. But with time test suite will grow. As you add more and more lines to your code, things become tough.
The chief problem with script maintenance is that if 10 different scripts are using the same page element, with any change in that element, you need to change all 10 scripts. This is time consuming and error prone.
A better approach to script maintenance is to create a separate class file which would find web elements, fill them or verify them. This class can be reused in all the scripts using that element. In future, if there is a change in the web element, we need to make the change in just 1 class file and not 10 different scripts.
This approach is called Page Object Model(POM). It helps make the code more readable, maintainable, and reusable.
     Page Object Model (POM) & Page Factory in Selenium: Complete Tutorial

What is POM?

  • Page Object Model is a design pattern to create Object Repository for web UI elements.
  • Under this model, for each web page in the application, there should be corresponding page class.
  • This Page class will find the WebElements of that web page and also contains Page methods which perform operations on those WebElements.
  • Name of these methods should be given as per the task they are performing, i.e., if a loader is waiting for the payment gateway to appear, POM method name can be waitForPaymentScreenDisplay().
Page Object Model (POM) & Page Factory in Selenium: Complete Tutorial

Advantages of POM

  1. Page Object Patten says operations and flows in the UI should be separated from verification. This concept makes our code cleaner and easy to understand.
  2. The Second benefit is the object repository is independent of test cases, so we can use the same object repository for a different purpose with different tools. For example, we can integrate POM with TestNG/JUnit for functional Testing and at the same time with JBehave/Cucumber for acceptance testing.
  3. Code becomes less and optimized because of the reusable page methods in the POM classes.
  4. Methods get more realistic names which can be easily mapped with the operation happening in UI. i.e. if after clicking on the button we land on the home page, the method name will be like 'gotoHomePage()'.    

How to implement POM?

Simple POM:
It's the basic structure of Page object model (POM) where all Web Elements of the AUT and the method that operate on these Web Elements are maintained inside a class file.A task like verification should be separate as part of Test methods.    
Page Object Model (POM) & Page Factory in Selenium: Complete Tutorial
Complete Example
TestCase: Go to Guru99 Demo Site.
Step 1) Go to Guru99 Demo SitePage Object Model (POM) & Page Factory in Selenium: Complete Tutorial
Step 2) In home page check text "Guru99 Bank" is presentPage Object Model (POM) & Page Factory in Selenium: Complete Tutorial
Step 3) Login into applicationPage Object Model (POM) & Page Factory in Selenium: Complete Tutorial
Step 4) Verify that the Home page contains text as "Manger Id: demo"Page Object Model (POM) & Page Factory in Selenium: Complete Tutorial
Here are we are dealing with 2 pages
  1. Login Page
  2. Home Page (shown once you login)
Accordingly, we create 2 POM classes
Guru99 Login page POM
package pages;

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

public class Guru99Login {

    WebDriver driver;

    By user99GuruName = By.name("uid");

    By password99Guru = By.name("password");

    By titleText =By.className("barone");

    By login = By.name("btnLogin");

    

    public Guru99Login(WebDriver driver){

        this.driver = driver;

    }

    //Set user name in textbox

    public void setUserName(String strUserName){

        driver.findElement(user99GuruName).sendKeys(strUserName);

    }

    

    //Set password in password textbox

    public void setPassword(String strPassword){

         driver.findElement(password99Guru).sendKeys(strPassword);

    }

    

    //Click on login button

    public void clickLogin(){

            driver.findElement(login).click();

    }

    

    //Get the title of Login Page

    public String getLoginTitle(){

     return    driver.findElement(titleText).getText();

    }

    /**

     * This POM method will be exposed in test case to login in the application

     * @param strUserName

     * @param strPasword

     * @return

     */

    public void loginToGuru99(String strUserName,String strPasword){

        //Fill user name

        this.setUserName(strUserName);

        //Fill password

        this.setPassword(strPasword);

        //Click Login button

        this.clickLogin();        

        

    }

}
Guru99 Home Page POM
package pages;

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

public class Guru99HomePage {

    WebDriver driver;

    By homePageUserName = By.xpath("//table//tr[@class='heading3']");

    

    public Guru99HomePage(WebDriver driver){

        this.driver = driver;

    }

    

    //Get the User name from Home Page

        public String getHomePageDashboardUserName(){

         return    driver.findElement(homePageUserName).getText();

        }

}
Guru99 Simple POM Test case
package test;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.firefox.FirefoxDriver;

import org.testng.Assert;

import org.testng.annotations.BeforeTest;

import org.testng.annotations.Test;

import pages.Guru99HomePage;

import pages.Guru99Login;

public class Test99GuruLogin {

    WebDriver driver;

    Guru99Login objLogin;

    Guru99HomePage objHomePage;

    

    @BeforeTest

    public void setup(){

        driver = new FirefoxDriver();

        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

        driver.get("http://demo.guru99.com/V4/");

    }

    /**

     * This test case will login in http://demo.guru99.com/V4/

     * Verify login page title as guru99 bank

     * Login to application

     * Verify the home page using Dashboard message

     */

    @Test(priority=0)

    public void test_Home_Page_Appear_Correct(){

        //Create Login Page object

    objLogin = new Guru99Login(driver);

    //Verify login page title

    String loginPageTitle = objLogin.getLoginTitle();

    Assert.assertTrue(loginPageTitle.toLowerCase().contains("guru99 bank"));

    //login to application

    objLogin.loginToGuru99("mgr123", "mgr!23");

    // go the next page

    objHomePage = new Guru99HomePage(driver);

    //Verify home page

    Assert.assertTrue(objHomePage.getHomePageDashboardUserName().toLowerCase().contains("manger id : mgr123"));

    }

What is Page Factory?

Page Factory is an inbuilt Page Object Model concept for Selenium WebDriver but it is very optimized.
Here as well, we follow the concept of separation of Page Object Repository and Test Methods. Additionally, with the help of PageFactory class, we use annotations @FindBy to find WebElement. We use initElements method to initialize web elements
Page Object Model (POM) & Page Factory in Selenium: Complete Tutorial
@FindBy can accept tagName, partialLinkText, name, linkText, id, css, className, xpath as attributes.
Let's look at the same example as above using Page Factory
Guru99 Login page with Page Factory
package PageFactory;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

import org.openqa.selenium.support.FindBy;

import org.openqa.selenium.support.PageFactory;

public class Guru99Login {

    /**

     * All WebElements are identified by @FindBy annotation

     */

    WebDriver driver;

    @FindBy(name="uid")

    WebElement user99GuruName;

    

    @FindBy(name="password")

    WebElement password99Guru;

    

    @FindBy(className="barone")

    WebElement titleText;

    

    @FindBy(name="btnLogin")

    WebElement login;

    

    public Guru99Login(WebDriver driver){

        this.driver = driver;

        //This initElements method will create all WebElements

        PageFactory.initElements(driver, this);

    }

    //Set user name in textbox

    public void setUserName(String strUserName){

        user99GuruName.sendKeys(strUserName);

        

    }

    

    //Set password in password textbox

    public void setPassword(String strPassword){

    password99Guru.sendKeys(strPassword);

    }

    

    //Click on login button

    public void clickLogin(){

            login.click();

    }

    

    //Get the title of Login Page

    public String getLoginTitle(){

     return    titleText.getText();

    }

    /**

     * This POM method will be exposed in test case to login in the application

     * @param strUserName

     * @param strPasword

     * @return

     */

    public void loginToGuru99(String strUserName,String strPasword){

        //Fill user name

        this.setUserName(strUserName);

        //Fill password

        this.setPassword(strPasword);

        //Click Login button

        this.clickLogin();

                

    }

}
Guru99 Home Page with Page Factory
package PageFactory;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

import org.openqa.selenium.support.FindBy;

import org.openqa.selenium.support.PageFactory;

public class Guru99HomePage {

    WebDriver driver;

    @FindBy(xpath="//table//tr[@class='heading3']")

    WebElement homePageUserName;

    

    public Guru99HomePage(WebDriver driver){

        this.driver = driver;

        //This initElements method will create all WebElements

        PageFactory.initElements(driver, this);

    }

    

    //Get the User name from Home Page

        public String getHomePageDashboardUserName(){

         return    homePageUserName.getText();

        }

}

Guru99 TestCase with Page Factory concept

    
package test;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.firefox.FirefoxDriver;

import org.testng.Assert;

import org.testng.annotations.BeforeTest;

import org.testng.annotations.Test;

import PageFactory.Guru99HomePage;

import PageFactory.Guru99Login;

public class Test99GuruLoginWithPageFactory {

    WebDriver driver;

    Guru99Login objLogin;

    Guru99HomePage objHomePage;

    

    @BeforeTest

    public void setup(){

        driver = new FirefoxDriver();

        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

        driver.get("http://demo.guru99.com/V4/");

    }

    /**

     * This test go to http://demo.guru99.com/V4/

     * Verify login page title as guru99 bank

     * Login to application

     * Verify the home page using Dashboard message

     */

    @Test(priority=0)

    public void test_Home_Page_Appear_Correct(){

        //Create Login Page object

    objLogin = new Guru99Login(driver);

    //Verify login page title

    String loginPageTitle = objLogin.getLoginTitle();

    Assert.assertTrue(loginPageTitle.toLowerCase().contains("guru99 bank"));

    //login to application

    objLogin.loginToGuru99("mgr123", "mgr!23");

    // go the next page

    objHomePage = new Guru99HomePage(driver);

    //Verify home page

    Assert.assertTrue(objHomePage.getHomePageDashboardUserName().toLowerCase().contains("manger id : mgr123"));

    }

    

}
Complete Project Structure will look like the diagram:
Page Object Model (POM) & Page Factory in Selenium: Complete Tutorial

AjaxElementLocatorFactory

    One of the key advantages of using Page Factory pattern is AjaxElementLocatorFactory Class.
It is working on lazy loading concept, i.e. a timeout for a WebElement will be assigned to the Object page class with the help of AjaxElementLocatorFactory .
Here, when an operation is performed on an element the wait for its visibility starts from that moment only. If the element is not found in the given time interval, test case execution will throw 'NoSuchElementException' exception.
Page Object Model (POM) & Page Factory in Selenium: Complete Tutorial

Summary

  1. Page Object Model is an Object Repository design pattern in Selenium WebDriver.
  2. POM creates our testing code maintainable, reusable.
  3. Page Factory is an optimized way to create object repository in POM concept.
  4. AjaxElementLocatorFactory is a lazy load concept in Page Factory pattern to identify WebElements only when they are used in any operation.

Selenium Framework: Keyword Driven & Hybrid

What is Selenium Framework?

Selenium Framework is a code structure that helps to make code maintenance easy. Without frameworks, we will place the “code” as well as “data” in the same place which is neither re-usable nor readable. Using Frameworks, produce beneficial outcomes like increased code re-usage, higher portability, reduced script maintenance cost, higher code readability, etc.
There are mainly three type of frameworks created by Selenium WebDriver to automate manual test cases
  • Data Driven Test Framework
  • Keyword Driven Test Framework
  • Hybrid Test Framework
Selenium Framework: Keyword Driven & Hybrid

Data Driven Test Framework

In data driven framework all of our test data is generated from some external files like Excel, CSV, XML or some database table. We already learned about Data Driven Testing in our previous tutorial

Keyword Driven Test Framework:

In keyword driven test framework, all the operations and instructions are written in some external file like Excel worksheet. Here is how the complete framework looks like
Selenium Framework: Keyword Driven & Hybrid
As you can see it's a 5 step framework. Let's study it stepwise in detail
Step 1)
  • The driver script Execute.java will call ReadGuru99ExcelFile.java
  • ReadGuru99ExcelFile.java has POI script to read data from an Excel
Step 2)
  • ReadGuru99ExcelFile.java will read data from TestCase.xlsx
  • Here is how the sheet looks like-
Selenium Framework: Keyword Driven & Hybrid
  • According to the keywords written in Excel file, the framework will perform the operation on UI.
  • For example, we need to click a button 'Login.' Correspondingly, our Excel will have a keyword 'Click.' Now the AUT can have hundreds of button on a page, to identify a Login button, in Excel we will input Object Name as loginButton & object type as a name (see highlighted the row in above image). The Object Type could be Xpath, name CSS or any other value
Step 3) ReadGuru99ExcelFile.java will pass this data to the driver script Execute.java
Step 4)
  • For all of our UI web elements, we need to create an object repository where we will place their element locator (like Xpath, name, CSS path, class name etc.)
Selenium Framework: Keyword Driven & Hybrid
  • Execute.java (our driver script) will read the entire Object Repository and store it in a variable
  • To read this object repository, we need a ReadObject class which has a getObjectRepository method to read it.
    Selenium Framework: Keyword Driven & Hybrid
NOTE: You may think why do we need to create an object repository. The answer helps in code maintenance. For example, we are using the button with name = btnlogin in 10 different test cases. In future, the developer decides to change the name from btnlogin to submit. You will have to make a change in all the 10 test cases. In the case of an object repository, you will make the change just once in the repository.
Step 5)
  • The driver will pass the data from Excel & Object Repository to UIOperation class
  • UIOperation class has functions to perform actions corresponding to keywords like CLICK, SETTEXT etc… mentioned in the excel
  • UIOperation class is a Java class which has the actual implementation of the code to perform operations on web elements
Selenium Framework: Keyword Driven & Hybrid
The complete project will look like-
Selenium Framework: Keyword Driven & Hybrid
Let's look into an example:
Test Scenario
  • We are executing 2 test cases
  • Test Case 1:
  • Goto http://demo.guru99.com/V4/
  • Enter User ID
  • Enter Password
  • Click Reset
  • Test Case 2:
  • Goto http://demo.guru99.com/V4/
  • Enter User ID
  • Enter Password
  • Click Login

object.properties

url=http://demo.guru99.com/V4/
username=uid
password=password
title=barone
loginButton=btnLogin
resetButton=btnReset

ReadGuru99ExcelFile.java

package excelExportAndFileIO;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ReadGuru99ExcelFile {
    
    public Sheet readExcel(String filePath,String fileName,String sheetName) throws IOException{
    //Create a object of File class to open xlsx file
    File file =    new File(filePath+"\\"+fileName);
    //Create an object of FileInputStream class to read excel file
    FileInputStream inputStream = new FileInputStream(file);
    Workbook guru99Workbook = null;
    //Find the file extension by spliting file name in substing and getting only extension name
    String fileExtensionName = fileName.substring(fileName.indexOf("."));
    //Check condition if the file is xlsx file
    if(fileExtensionName.equals(".xlsx")){
    //If it is xlsx file then create object of XSSFWorkbook class
    guru99Workbook = new XSSFWorkbook(inputStream);
    }
    //Check condition if the file is xls file
    else if(fileExtensionName.equals(".xls")){
        //If it is xls file then create object of XSSFWorkbook class
        guru99Workbook = new HSSFWorkbook(inputStream);
    }
    //Read sheet inside the workbook by its name
    Sheet guru99Sheet = guru99Workbook.getSheet(sheetName);
     return guru99Sheet;    
    }
}

ReadObject.java

package operation;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ReadObject {
    Properties p = new Properties();
    public Properties getObjectRepository() throws IOException{
        //Read object repository file
        InputStream stream = new FileInputStream(new File(System.getProperty("user.dir")+"\\src\\objects\\object.properties"));
        //load all objects
        p.load(stream);
         return p;
    }
    
}

UIOperation.java

package operation;
import java.util.Properties;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class UIOperation {
    WebDriver driver;
    public UIOperation(WebDriver driver){
        this.driver = driver;
    }
    public void perform(Properties p,String operation,String objectName,String objectType,String value) throws Exception{
        System.out.println("");
        switch (operation.toUpperCase()) {
        case "CLICK":
            //Perform click
            driver.findElement(this.getObject(p,objectName,objectType)).click();
            break;
        case "SETTEXT":
            //Set text on control
            driver.findElement(this.getObject(p,objectName,objectType)).sendKeys(value);
            break;
            
        case "GOTOURL":
            //Get url of application
            driver.get(p.getProperty(value));
            break;
        case "GETTEXT":
            //Get text of an element
            driver.findElement(this.getObject(p,objectName,objectType)).getText();
            break;
        default:
            break;
        }
    }
    
    /**
     * Find element BY using object type and value
     * @param p
     * @param objectName
     * @param objectType
     * @return
     * @throws Exception
     */
    private By getObject(Properties p,String objectName,String objectType) throws Exception{
        //Find by xpath
        if(objectType.equalsIgnoreCase("XPATH")){
            
            return By.xpath(p.getProperty(objectName));
        }
        //find by class
        else if(objectType.equalsIgnoreCase("CLASSNAME")){
            
            return By.className(p.getProperty(objectName));
            
        }
        //find by name
        else if(objectType.equalsIgnoreCase("NAME")){
            
            return By.name(p.getProperty(objectName));
            
        }
        //Find by css
        else if(objectType.equalsIgnoreCase("CSS")){
            
            return By.cssSelector(p.getProperty(objectName));
            
        }
        //find by link
        else if(objectType.equalsIgnoreCase("LINK")){
            
            return By.linkText(p.getProperty(objectName));
            
        }
        //find by partial link
        else if(objectType.equalsIgnoreCase("PARTIALLINK")){
            
            return By.partialLinkText(p.getProperty(objectName));
            
        }else
        {
            throw new Exception("Wrong object type");
        }
    }
}

ExecuteTest.java

package testCases;
import java.util.Properties;
import operation.ReadObject;
import operation.UIOperation;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.Test;
import excelExportAndFileIO.ReadGuru99ExcelFile;
public class ExecuteTest {
@Test
    public void testLogin() throws Exception {
        // TODO Auto-generated method stub
WebDriver webdriver = new FirefoxDriver();
ReadGuru99ExcelFile file = new ReadGuru99ExcelFile();
ReadObject object = new ReadObject();
Properties allObjects = object.getObjectRepository();
UIOperation operation = new UIOperation(webdriver);
//Read keyword sheet
Sheet guru99Sheet = file.readExcel(System.getProperty("user.dir")+"\\","TestCase.xlsx" , "KeywordFramework");
//Find number of rows in excel file
    int rowCount = guru99Sheet.getLastRowNum()-guru99Sheet.getFirstRowNum();
    //Create a loop over all the rows of excel file to read it
    for (int i = 1; i < rowCount+1; i++) {
        //Loop over all the rows
        Row row = guru99Sheet.getRow(i);
        //Check if the first cell contain a value, if yes, That means it is the new testcase name
        if(row.getCell(0).toString().length()==0){
        //Print testcase detail on console
            System.out.println(row.getCell(1).toString()+"----"+ row.getCell(2).toString()+"----"+
            row.getCell(3).toString()+"----"+ row.getCell(4).toString());
        //Call perform function to perform operation on UI
            operation.perform(allObjects, row.getCell(1).toString(), row.getCell(2).toString(),
                row.getCell(3).toString(), row.getCell(4).toString());
     }
        else{
            //Print the new testcase name when it started
                System.out.println("New Testcase->"+row.getCell(0).toString() +" Started");
            }
        }
    }
}
After execution, output will look like -
Selenium Framework: Keyword Driven & Hybrid

Hybrid Test Framework

Hybrid Test framework is a concept where we are using the advantage of both Keyword and Data driven framework.
Here for keywords, we will use Excel files to maintain test cases, and for test data, we can use data, provider of TestNG framework.
Selenium Framework: Keyword Driven & Hybrid
Here in our hybrid framework, we don't need to change anything in Keyword driven framework, here we just need to replace ExecuteTest.java file with HybridExecuteTest.java file.
Selenium Framework: Keyword Driven & Hybrid
This HybridExecuteTest file has all the code for keyword driven with data provider concept.
The complete pictorial representation of hybrid framework will look like
Selenium Framework: Keyword Driven & Hybrid

HybridExecuteTest.java

package testCases;
import java.io.IOException;
import java.util.Properties;
import operation.ReadObject;
import operation.UIOperation;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import excelExportAndFileIO.ReadGuru99ExcelFile;
public class HybridExecuteTest {
    WebDriver webdriver = null;
@Test(dataProvider="hybridData")
    public void testLogin(String testcaseName,String keyword,String objectName,String objectType,String value) throws Exception {
        // TODO Auto-generated method stub
      
    if(testcaseName!=null&&testcaseName.length()!=0){
    webdriver=new FirefoxDriver();
    }
ReadObject object = new ReadObject();
Properties allObjects = object.getObjectRepository();
UIOperation operation = new UIOperation(webdriver);
    //Call perform function to perform operation on UI
            operation.perform(allObjects, keyword, objectName,
                objectType, value);
    
    }
@DataProvider(name="hybridData")
    public Object[][] getDataFromDataprovider() throws IOException{
    Object[][] object = null;
    ReadGuru99ExcelFile file = new ReadGuru99ExcelFile();
//Read keyword sheet
Sheet guru99Sheet = file.readExcel(System.getProperty("user.dir")+"\\","TestCase.xlsx" , "KeywordFramework");
//Find number of rows in excel file
    int rowCount = guru99Sheet.getLastRowNum()-guru99Sheet.getFirstRowNum();
    object = new Object[rowCount][5];
    for (int i = 0; i < rowCount; i++) {
        //Loop over all the rows
        Row row = guru99Sheet.getRow(i+1);
        //Create a loop to print cell values in a row
        for (int j = 0; j < row.getLastCellNum(); j++) {
            //Print excel data in console
            object[i][j] = row.getCell(j).toString();
        }
    }
    System.out.println("");
     return object;    
    }
}

Summary:
  • We can create three types of test framework using Selenium WebDriver.
  • These are Data Driven, Keyword Driven, and Hybrid test framework.
  • We can achieve Data-driven framework using TestNG's data provider.
  • In Keyword driven framework, keywords are written in some external files like excel file and java code will call this file and execute test cases.
  • The hybrid framework is a mix of keyword driven and data driven framework.