Part 1: Introduction to Maven…

Apache Maven is one important tool that we will be using in creating every single Selenium project from here. In short its a software project management and comprehension tool. It allows the developer to automate the process of creating the initial folder structure for Java application, performing the compilation, testing, packaging and deploying the final product. It is implemented in Java which makes it platform-independent. Java is also the best work environment for Maven. Some of the key feature of Maven are:

  • Convention over Configuration: Maven uses Convention over Configuration which means developers are not required to create build process themselves. Maven provides sensible default behavior for projects.
  • Dependency management: Maven encourages the use of a central repository of JARs and other dependencies. Maven comes with a mechanism to download any JARs required for building your project from a central JAR repository.
  • Repository: Project dependencies can be downloaded from local file system, from Internet or public repositories like Maven Central.
  • Extensible via plug-ins: The Maven build system is extensible via plug-ins, which allows to keep the Maven core small. The Maven core does for example not know how to compile Java source code, this is handled by the compiler plug-in.

We have to go through following topics like Maven Lifecycle, POM and Super POM, Standard Directory Layout, Repositories, Dependency mechanism, Plugins etc. to gain more knowledge on Maven. Complete Maven documentation is placed in Apache Maven Documentation .

Download and Install Maven

The first step is to download and install Maven in your machine. We need to follow below steps for installing Maven.

  1. Before installing Maven, we have to ensure that JDK is already installed in our machine and path is also set. All the steps for installing JDK is mentioned in Installing Java Development Kit… and setting path is mentioned in Setting up Environment Variables….
  2. Open Browser and navigate to Google. Type in “Maven download” and go to downloads page in maven.apache website. Direct link to Maven download page Maven Download.
  3. Click on the Binary zip archive link to start the download in the local machine. This is same for Windows and Mac machines.

    Click Maven zip link to start download
  4. Once download is complete in the local Downloads folder of our machine, we have to move the ‘apache-maven-3.5.0’ folder to a location which is consistent with other applications. For Mac machine, we can copy and paste the folder in your home folder, e.g. ‘/Users/sejijohn’ location. We can also use the Terminal in Mac to move the folder from Downloads to home folder. We can use the below command in Terminal to move the ‘apache-maven-3.5.0’ folder to Home. This command will require password authentication.
    --sudo mv source_folder destination_folder--
    sudo mv /Users/sejijohn/Downloads/apache-maven-3.5.0/ /Users/sejijohn
    

    For Windows machine, we can paste the ‘apache-maven-3.5.0’ folder inside C Drive ‘Program Files/Apache’ folder.

  5. Next step is to set the environment variables for Maven. For Mac OS, Open Terminal and type in the following command  “vim .bash_profile” and then type ‘i’ to insert into the VIM Editor. We need to set M2_Home and MAVEN_HOME variables and then update existing PATH variable. Type in below commands in the VIM editor.
    --Set up M2_HOME--
    export M2_HOME=/Users/sejijohn/apache-maven-3.3.9
    
    --Set up MAVEN_HOME--
    export MAVEN_HOME=/Users/sejijohn/apache-maven-3.3.9
    
    --Append existing PATH--
    export PATH=$PATH:/Users/sejijohn/apache-maven-3.3.9/bin
    
    MAC Terminal

    To Save the entires in VIM Editor, hit Escape, type in: “:wq + Enter”.
    To Quit without saving the editor, hit Escape, type in “:q!”. To save the entries in .bash_profile, use below command.

    --Save the entries in .bash_profile--
    source .bash_profile
  6. For Windows OS, type “advanced system settings” in the search box (beside the Windows start button), click View advanced system settings. Select Advance tab and click Environment Variables button. To run maven from command line in Windows we have to set MAVEN_HOME, M2_HOME and PATH variables. In System variables, add a new ‘MAVEN_HOME’ variable and point it to the Maven folder inside C Drive and that is “C:\Program Files\Apache\apache-maven-3.5.0”. Add another variable ‘M2_HOME’ and point it to same Maven location in C Drive.

    Notice MAVEN_HOME and M2_HOME pointing to same location where Apache Maven folder placed.
  7. We need to update the PATH variable.For that we have to point it to bin folder inside Apache Maven folder.

    Notice PATH is updated to add the Maven bin folder
  8. Once the environment variables settings are completed, next step is to verify if the maven installation is successful. For that go to Mac Terminal or Windows Command Prompt and type in ‘mvn -version‘. If Maven installation is successful, we will see the below message.
    mvn -version in Terminal Mac OS

    With this we have completed the steps to install and configure Maven in Windows and Mac machines. In the next post we will create a sample Maven Project using Eclipse. Till then, Happy Learning!

Advanced HTML Reports…

TestNG default reports are not very attractive and they are very basic. In this post we will use an advanced HTML Report called Extent Report. We will use this reporting to create our own custom report. Below is a snapshot on how our custom report will look like.

Extent Reports

To save time and effort we will be using already created Java Project ‘NewTourPageFactory‘ from our previous post Working with Page Factory…. We will add an additional class for our reporting and also update some existing classes. Below is the snapshot of the project structure of ‘NewTourPageFactory‘.

NewTourPageFactory Project Structure
  1. To start with Extent Reporting, first task is to download the Jar. Go to Google and type in “Extent Report jar download”. Click on the maven repository link to download the Jar or else you can go directly to Extent Report Jar download link to download the Jar. Here we will be using version 2.40.2.
  2. Extent reports jar has a dependency with freemarker jar. So this too need to be downloaded. Here we are using ‘freemarker-2.3.23’ version.
  3. Once both Jars are downloaded to the local folder, the next step is to add them into our Java Project. Right Click on the project name and click Properties. Click on Java Build Path -> Add External Jars. Go to the local folder where ‘extentreports-2.40.2’ and ‘freemarker-2.3.23’ are saved. Add Jars and click OK to close the window. Once complete, we will see them inside ‘Referenced Libraries‘.

    Extent Report Jars
  4. The next step is to create one Extent Report Reports class. This class will contain all the required methods for starting the test, logging the test status and ending the test. Right click on ‘com.selenium.util‘ package and click New -> Class. Name the class file as ‘Reports‘.

    Reports class
  5. Copy and paste the below code into the Reports class.
    package com.selenium.util;
    
    import com.relevantcodes.extentreports.ExtentReports;
    import com.relevantcodes.extentreports.ExtentTest;
    import com.relevantcodes.extentreports.LogStatus;
    
    public class Reports {
    
    	public static ExtentReports extent;
    	public static ExtentTest test;
    
    	// Start Test Case
    	public void startTest(String testCaseName) {
    
    		/*Create ExtentReports object passing location and report name as argument. Notice a new Result Log folder will be created inside project and the report name will be TestReport.html*/
    		extent = new ExtentReports(System.getProperty("user.dir") + "/RESULT_LOG" + "/TestReport.html");
    
    		// Add details to our report
    		extent.addSystemInfo("Selenium Version", "3.0.1").addSystemInfo("Environment", "QA");
    
    		// Create ExtentTest passing test case name and description
    		test = extent.startTest(testCaseName, "Our First Test Report");
    	}
    
    	// Log Test status, Test name and Test details
    	public void logStatus(LogStatus testStatus, String testStepName, String testDetails) {
    
    		// Log test status
    		test.log(testStatus, testStepName, testDetails);
    	}
    
    	// Capture screenshot and log into report
    	public void screenshotLog(LogStatus logStatus, String testStepName, String screenShotPath) {
    
    		// Attach screenshots
    		test.log(logStatus, testStepName + test.addScreenCapture(screenShotPath));
    	}
    
    	// End Test Case
    	public void endTest() {
    
    		// End test
    		extent.endTest(test);
    		extent.flush();
    		extent.close();
    	}
    }
    
  6. Next steps is to add the logging information into our test steps. For that we will add few steps into our page object class. Here we will be updating ‘HomePage’ class inside ‘com.selenium.pages‘ package.

    HomePage class
  7. Replace the existing code of ‘HomePage’ class with below code.
    package com.selenium.pages;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.support.FindBy;
    import com.relevantcodes.extentreports.LogStatus;
    import com.selenium.util.Log;
    import com.selenium.util.Reports;
    
    public class HomePage {
    	// Declare WebDriver
    	WebDriver driver;
    	Reports reports;
    	// Element Locators for username textbox
    	@FindBy(name = "userName")
    	private WebElement userName;
    
    	// Element Locators for password textbox
    	@FindBy(name = "password")
    	private WebElement password;
    
    	// Element Locators for login button
    	@FindBy(name = "login")
    	private WebElement login;
    
    	// Constructor. Driver Initialization
    	public HomePage(WebDriver driver) {
    		this.driver = driver;
    		reports = new Reports();
    
    	}
    
    	// Login method. Notice there is no return type
    	public void loginUser(String uname, String pwd) {
    		// Enter username
    		userName.sendKeys(uname);
    		// Log4j logging
    		Log.info("HomePage.loginUser - username entered");
    
    		// Extent Reprot Logging. Enter Log status for HTML report
    		reports.logStatus(LogStatus.PASS, "Enter user name", "User name entered" + " <span class='label success'> Success</span>");
    		// Enter password
    		password.sendKeys(pwd);
    		// Log4j logging
    		Log.info("HomePage.loginUser - password entered");
    
    		// Extent Reprot Logging. Enter Log status for HTML report
    		reports.logStatus(LogStatus.PASS, "Enter password", "Password entered" + " <span class='label success'>Success</span>");
    		// Click Login button
    		login.click();
    		// Log4j logging
    		Log.info("HomePage.loginUser - login button clicked");
    
    		// Extent Reprot Logging. Enter Log status for HTML report
    		reports.logStatus(LogStatus.PASS, "Click Login","Login button clicked" + " <span class='label success'> Success</span>");
    	}
    }
    
  8. In the above code, notice that we created an object of Reports class and used its methods for logging test status. We can log different test status like LogStatus.PASS, LogStatus.FAIL, LogStatus.ERROR etc based on our test.
  9. We can take same approach for other page object classes. However in this post we will be updating only the ‘HomePage’ class.
  10. Before logging the log status in extent report, we need to start the test. This will be done in the TestNG test case.

    BookFlight class – TestNG test case
  11. We will update the ‘BookFlight’ class inside ‘com.selenium.testcase‘ package with below code.
    package com.selenium.testcase;
    
    import org.testng.annotations.Test;
    import com.selenium.pages.BookFlightPage;
    import com.selenium.pages.FlightConfirmationPage;
    import com.selenium.pages.FlightFinderPage;
    import com.selenium.pages.HomePage;
    import com.selenium.pages.SelectFlightPage;
    import com.selenium.util.Log;
    import com.selenium.util.Reports;
    import org.testng.annotations.BeforeMethod;
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import org.apache.log4j.xml.DOMConfigurator;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.support.PageFactory;
    import org.testng.annotations.AfterMethod;
    import org.testng.annotations.DataProvider;
    import org.testng.annotations.BeforeTest;
    
    public class BookFlight {
    
    	WebDriver driver;
    	HomePage homePage;
    	FlightFinderPage flightFinderPage;
    	SelectFlightPage selectFlightPage;
    	BookFlightPage bookFlightPage;
    	FlightConfirmationPage flightConfirmationPage;
    	Reports reports;
    
    	// Test Case
    	@Test(dataProvider = "newTourData")
    	public void bookFlight(String uname, String pwd, String departFrom, String departDate, String fname, String lname,
    			String ccNum) {
    
    		/*
    		 * Test case logic.
    		 * 
    		 */
    		Log.startTestCase("Test Case bookFlight");
    		Log.info("BookFlight.bookFlight - Home Page Opens");
    		homePage.loginUser(uname, pwd);
    		Log.info("BookFlight.bookFlight - Flight Finder Page Opens");
    		flightFinderPage.findFlights(departFrom, departDate);
    		Log.info("BookFlight.bookFlight - Select Flight Page Opens");
    		selectFlightPage.reserveFlight();
    		Log.info("BookFlight.bookFlight - Book Flight Page Opens");
    		bookFlightPage.bookFlight(fname, lname, ccNum);
    		Log.info("BookFlight.bookFlight - Flight Confirmation Page Opens");
    		flightConfirmationPage.clickLogOut();
    		Log.endTestCase("Test Case bookFlight");
    
    	}
    
    	// Driver and Page Objects Initialization
    	@BeforeMethod
    	public void beforeMethod() {
    		// Initialize driver
    		driver = new ChromeDriver();
    		Log.info("BookFlight.beforeMethod - Chrome Driver Intialized");
    		// Page Factory Initialization for all page objects
    		homePage = PageFactory.initElements(driver, HomePage.class);
    		flightFinderPage = PageFactory.initElements(driver, FlightFinderPage.class);
    		selectFlightPage = PageFactory.initElements(driver, SelectFlightPage.class);
    		bookFlightPage = PageFactory.initElements(driver, BookFlightPage.class);
    		flightConfirmationPage = PageFactory.initElements(driver, FlightConfirmationPage.class);
    		Log.info("BookFlight.beforeMethod - Page Factory intialization complete");
    
    		// Start Extent Report
    		reports.startTest("Book Flight");
    
    		// Nvaigate to URL
    		driver.get("http://newtours.demoaut.com");
    		Log.info("BookFlight.beforeMethod - open New Tour URL");
    
    		// Maximize window
    		// driver.manage().window().maximize();
    		Log.info("BookFlight.beforeMethod - Browser maximized");
    
    	}
    
    	// Driver closure
    	@AfterMethod
    	public void afterMethod() {
    
    		// End Extent Report
    		reports.endTest();
    
    		// Close and quit the driver to close the Browser
    		driver.close();
    		driver.quit();
    		Log.info("BookFlight.afterMethod - Browser closed");
    	}
    
    	// Create test data
    	@DataProvider
    	public Object[][] newTourData() {
    		return new Object[][] { { "demo", "demo", "London", "7", "john", "Doe", "56465465" } };
    	}
    
    	// Setting System property
    	@BeforeTest
    	public void beforeTest() {
    		// Set System Property for driver location
    		System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + "/Chrome/chromedriver");
    		SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
    		SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    		// Set System Property for log file location
    		System.setProperty("logfoldername", sdf1.format(Calendar.getInstance().getTime()));
    		System.setProperty("logfilename", sdf2.format(Calendar.getInstance().getTime()) + "-LOG");
    
    		Log.info("BookFlight.beforeTest - System property setting complete");
    		DOMConfigurator.configure("src/log4j.xml");
    		Log.info("BookFlight.beforeTest - XML config complete");
    
    		// Create Extent Report object
    		reports = new Reports();
    	}
    }
    
  12. Notice that in the above code, we are creating a Reports object inside ‘@BeforeTest‘ method, starting the test inside ‘@BeforeMethod‘ and ending the test inside ‘@AfterMethod‘.
  13. Final step is to execute our TestNG test case. Right click on ‘BookFlight’ class and click Run As -> TestNG Test.

    TestNG Test
  14. After successful execution, a new folder named ‘RESULT_LOG’ will be created inside our project and the Extent Report will be placed in this folder. This is because, inside ‘startTest‘ method of Reports class, we are creating an Extent Report object by passing the location as argument.
    /*Create ExtentReports object passing location and report name as
    argument. Notice a new Result Log folder will be created inside
    project and the report name will be TestReport.html*/
    extent = new ExtentReports(System.getProperty("user.dir") + "/RESULT_LOG" + "/TestReport.html");
    
  15. Right click on ‘TestReport.html’ to open on web browser. Below is the snapshots on how our test report will look like.
    Book Flight Extent Report Page 1

    Book Flight Extent Report Page 2
  16. Notice that all the log status that we entered in ‘HomePage’ class are displayed in the HTML report.

Entent Reports help us in creating beautiful looking test reports. They are very easy to implement and also provide valuable information about our test. Hope this post is useful in creating some good looking reports. Many more to follow. Till then, Happy Learning!

Additional Information:

While logging the Extent Report status we have used some HTML code inside ‘HomePage’ class.

// Extent Reprot Logging. Enter Log status for HTML report
reports.logStatus(LogStatus.PASS, "Enter user name",
	"User name entered" + " <span class='label success'>Success</span>");

The span class helps us in providing some meaningful logs and messages into our test report. Some more labels are also available for use.

"<span class='fail label'>Fail</span>"
"<span class='warning label'>Warning</span>"
"<span class='info label'>Info</span>"
"<span class='skip label'>Skip</span>"

 

Advanced Selenium topics…

In this post we will be focusing on some advanced topics in Selenium.

Selenium WebDriver Wait commands:

This is one of the most used commands. Most of the times the code executes much faster than the web page navigation. If not synchronized, then the test case execution will fail. To overcome this, we use different Wait commands to slow our execution. Each of these commands have their own purpose:

  • Implicit Wait: Implicit waits are used to provide a user specified waiting time between each consecutive test step/command across the entire test script. This means Implicit waits will be in place for the entire time the browser is open and is applicable to search for elements also. Once set, the implicit wait is set for the life of the WebDriver object instance. Below is the code for Implicit Wait.
  • // Initialize Chrome WebDriver
    WebDriver driver = new ChromeDriver();
    
    // Setting Implicit Wait for 10 seconds
    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    
    // Navigate to Google Website
    driver.get("http://www.google.com");
    
    //Maximize browser window
    driver.manage().window().maximize();
    
    //Relative XPath for the text box
    driver.findElement(By.xpath("//input[@id='lst-ib']")).sendKeys("selenium");
  • Explicit Wait: Explicit waits are used to stop the execution till the time a particular condition or Expected Condition is met or the maximum time has elapsed before throwing an “ElementNotVisibleException” exception. Explicit wait applies for specified element only. WebDriverWait by default calls the ExpectedCondition every 500 milliseconds until it returns successfully. Below is the code for Explicit Wait.
    / Initialize Chrome WebDriver
    WebDriver driver = new ChromeDriver();
    
    // Setting Implicit Wait for 10 seconds
    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    
    // Navigate to Google Website
    driver.get("http://www.google.com");
    
    //Maximize browser window
    driver.manage().window().maximize();
    
    //Relative XPath for the text box
    driver.findElement(By.xpath("//input[@id='lst-ib']")).sendKeys("selenium");
    
    /* Setting Explicit Wait 10 seconds for Search icon button to be Clickable */
    WebDriverWait wait = new WebDriverWait(driver, 10);
    WebElement searchElement = wait.until(ExpectedConditions.elementToBeClickable(By.id("_fZl")));
    
    //Once searchElement is clickable
    searchElement.click();
    
  • Fluent Wait: Fluent wait is another type of Explicit wait and you can define polling and ignore the exception to continue with script execution in case element is not found. Using Fluent wait we can define the frequency with which Fluent Wait has to check the conditions defined, ignore specific types of exception waiting such as NoSuchElementExceptions while searching for an element and set maximum amount of time to wait for a condition.
    /* Waiting 30 seconds for an element to be present on the page, checking */
    // for its presence once every 5 seconds.
    public void waitForElement(By by) {
     new FluentWait(driver)
     .withTimeout(30, TimeUnit.SECONDS)
     .pollingEvery(5, TimeUnit.SECONDS)
     .ignoring(NoSuchElementException.class)
     .until(new ExpectedCondition() {
         @Override
         public Boolean apply(WebDriver driver) {
         WebElement element = driver.findElement(by);
         if (element == null)
           return false;
         else {
    	    System.out.println("WebElement found");
    	    return true;
    	 }
            }
          });
    }
    
  • Page Load Timeout: Page Load Timeout sets the amount of time to wait for a page load to complete before throwing an error. If the timeout is negative, page loads can be indefinite.
    driver.manage().timeouts().pageLoadTimeout(30, SECONDS);
    

Keyboard and Mouse Actions:

Using Actions class we can emulate complex user gestures. Sometimes we need to perform a ‘mouse hover’ action on a web site or we need to perform chain of actions like going to menu, and then from there to sub menu etc.. Sometimes we may need to do a drag and drop on a web site. All of these actions are possible using Actions class.

  • Mouse Hover: Using Actions class we can do a mouse hover on any links in web page. Below is the code:
    //Create actions object and pass WebDriver
    Actions actions = new Actions(driver);
    
    //Get the WebElement for Mouse Hover
    WebElement mainMenu =driver.findElement(By.id("nav-menuitem-1-link"));
    
    //Perform the mouse hover
    //Use build().perform() to complete the action
    action.moveToElement(mainMenu).build().perform();
    
  • Click Sub Menu inside Menu: Actions class can also be used to click sub menu inside main menu where the main menu appears only when we do a mouser hover.
    //Create actions object and pass WebDriver
    Actions actions = new Actions(driver);
    
    //Get the WebElement for Main Menu
    WebElement mainMenu =driver.findElement(By.id("nav-menuitem-1-link"));
    
    //Move to Main Menu do mouse hover
    action.moveToElement(mainMenu);
    
    //Get the WebElement for Sub Menu
    //Sub Menu will be displayed inside Menu
    WebElement subMenu = driver.findElement(By.linkText("Best price search"));
    
    //Use the actions object to move to sub menu and click
    //Use build().perform() to complete the action
    actions.moveToElement(subMenu).click().build().perform();
    
  • Drag and Drop: Using Actions class we can perform drag and drop a web element. This can be done either by providing the source and target elements or by providing source elements and x, y coordinates for the destination. Below is the sample code for performing drag and drop:
    //Create actions object and pass WebDriver
    Actions actions = new Actions(driver);
    
    //Source Element
    WebElement dragElement =driver.findElement(By.id("draggable"));
    
    //Target Element
    WebElement dropElement =driver.findElement(By.id("droppable"));
    
    //Use the actions object to perform drag and drop using source target elements
    actions.dragAndDrop(dragElement, dropElement).perform();
    
    //Use the actions object to perform drag and drop using x, y coordinates
    actions.dragAndDropBy(mainMenu, 300, 200).perform();
    
  • Double Click: Using Actions class we can perform double click on an element. Below sample code is for performing double click:
    //Create actions object and pass WebDriver
    Actions actions = new Actions(driver);
    
    //Get the WebElement for Main Menu
    WebElement mainMenu =driver.findElement(By.id("nav-menuitem-1-link"));
    
    //Use the actions object to perform double click on Main Menu
    actions.doubleClick(mainMenu);
    
  • Right Click: Using Actions class we can also perform right click on an element.
    //Create actions object and pass WebDriver
    Actions actions = new Actions(driver);
    
    //Get the WebElement for Main Menu
    WebElement mainMenu =driver.findElement(By.id("nav-menuitem-1-link"));
    
    //Use contextClick method do right click on Main Menu
    actions.contextClick(mainMenu);
    
  • Click, Hold and Move: This can be performed by click and hold a web element and then drag it to required location. Below is the set of code to perform the action:
    /Create actions object and pass WebDriver
    Actions actions = new Actions(driver);
    
    //Source Element
    WebElement dragElement =driver.findElement(By.id("draggable"));
    
    //Target Element
    WebElement dropElement =driver.findElement(By.id("droppable"));
    
    /* Use actions object to click and hold the source element 
    and move to target element and release source element.
    Use build().perform() to complete the action. */
    actions.clickAndHold(mainMenu).moveToElement(subMenu).release(mainMenu).build().perform();

    The same commands can be used for resizing the window. However we have to provide x, y coordinates of the resized window. In this case we have to select ‘moveByOffset’ method instead of ‘moveToElement’.

    //Resize a window to x, y coordinates
    actions.clickAndHold(mainMenu).moveByOffset(100, 100).release(mainMenu).build().perform();
    
  • Sliders: There are some web elements in a web page, which can be moved sideways or up and down like the volume or equalizer bars etc. These kind of movements can also be controlled using Actions class.
    //Slide horizontally to forward direction. Note y coordinate is 0. 
    actions.clickAndHold(sliderElement).moveByOffset(100, 0).release(sliderElement).build().perform();
    
    //Slide horizontally to backward direction. Note y coordinate is 0. 
    actions.clickAndHold(sliderElement).moveByOffset(-100, 0).release(sliderElement).build().perform();
    
  • Key Down/Up: keyDown performs a modifier key press, doesn’t release the modifier key. Subsequent interactions may assume it’s kept pressed. keyUp performs a key release. Below is the same code for performing keyDown and keyUp:
    //Perform key press control a and then delete
    action.keyDown(Keys.CONTROL).sendKeys("a").keyUp(Keys.CONTROL).sendKeys(Keys.DELETE).perform(); 
    

Handeling Frames:

Frames are nothing but HTML code embedded inside another HTML code. They are defined inside <iframe></iframe> tags in HTML. Using this tag we can identify if the inspected object is inside a frame. We can get the frames details using firebug add on in Firefox browser.

Notice the list of iframes available in the web page

Sometimes in order to access the objects inside the frames, we have to switch the Web Driver to the frame where the web elements are located. Below is the sample code for accessing the frames in different ways:

        /* Three ways of navigating the web driver to frame.
         * 1. Using index number
         * 2. Using String Name or ID
         * 3. Using Web Element
         */
        
	/* Switch to frame using index number. 
	 * This is not reliable as the index number varies with different browsers */
	driver.switchTo().frame(0);

	//Access the web element inside the frame
	driver.findElement(By.id("nav-menuitem-1-link")).click();
				
	/* Switch to frame using ID or Name. 
	 * Frame id = google_ads_iframe_/55875582/WMUS/homepage_0
	 */
	driver.switchTo().frame("google_ads_iframe_/55875582/WMUS/homepage_0");

	//Access the web element inside the frame
	driver.findElement(By.id("nav-menuitem-1-link")).click();
				
	//Identify the frame element first
	WebElement frameOne = driver.findElement(By.id("google_ads_iframe_/55875582/WMUS/homepage_0"));

	//Pass the frame details to web driver
	driver.switchTo().frame(frameOne);

	//Access the web element inside the frame
	driver.findElement(By.id("nav-menuitem-1-link")).click();

Once we are done with all the task in a particular frame we have to switch back to the main page. This is very important otherwise the Web Driver will always continue in current frame. Below is the sample code to switch back to main page.

//Switching back to main page
driver.switchTo().parentFrame();

Handeling Multiple Windows:

Sometimes when clicking on a web element, a new tab is opened in the browser. What if we want to move the focus of the Web Driver from the parent page to newly opened page? Using Selenium we can handle multiple windows.

The code works by first identifying the parent window ID and then by getting the Set (java.util package) of opened window IDs. Note that window IDs are unique thats why we are using Set. To switch to child window we will use the iterator method of Set. Below is the sample method to switch to child window and then return the driver.

public WebDriver getChildWindow(WebDriver driver) {

     // getWindowHandle method will return the current id of the window
     String parentWindow = driver.getWindowHandle();

     // Get the set of ids of open windows
     Set setWindow = driver.getWindowHandles();

     // Create iterator object
     Iterator getWindow = setWindow.iterator();

     // Navigate to child window and return driver
     while (getWindow.hasNext()) {
	String childWindow = getWindow.next();
			
	// If childWindow!=parentWindow
	if (!childWindow.equalsIgnoreCase(parentWindow)) {
				
		//Switch to child window
		driver.switchTo().window(childWindow);
		return driver;
		}
	}
	return null;
}

To switch back to parent window:

//Switch to parent window
driver.switchTo().window(parentWindow);

Handeling Date Pickers:

Some web sites does not allow users to directly enter the date in text field. In those cases, the user need to select a date from the Calendar pop up. Below is one example of one such web site where the ‘Depart’ text box is non editable.

Date Picker

Although different web sites have their own implementation of date pickers, below sample code can be used in most cases.

// Setting System properties
System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + "/Chrome/chromedriver");

// Initialize WebDriver
WebDriver driver = new ChromeDriver();

// Maximize browser window
driver.manage().window().maximize();

// Navigate to Test Website
driver.get("https://www.skyscanner.com/");

// Click on Date Field present in web page
driver.findElement(By.id("js-depart-input")).click();

// In Calendar click next icon to select next month
driver.findElement(By.xpath("//div[@class='calendar-info-bar datepicker_clearfix']/button[2]")).click();

// Select 05/16/2017 date from Calendar
driver.findElement(By.xpath("//table[@data-month='2017-05']/tbody/tr[3]/td[@data-id='2017-05-16']")).click();

// Verify the date in Date text box
String departDate = driver.findElement(By.id("js-depart-input")).getAttribute("data-date");

if (departDate.equals("2017-05-16")) {
	System.out.println("PASS");
   }

Scroll the Web Page:

For scrolling the web page up or down we can use the below code.

// Initialize WebDriver
WebDriver driver = new FirefoxDriver();

//Create JavascriptExecutor object
JavascriptExecutor jse = (JavascriptExecutor)driver;

//Page down by 400 px
jse.executeScript("scroll(0,400)");

//Scroll for a element
jse.executeScript("arguments[0].scrollIntoView(true);", webElement);

//Scroll Up using negative y coordinate
jse.executeScript("scroll(0,-400)");

Similarly scrolling sideways can be done by changing the x coordinates.

Take Screenshot of full page:

It is very important to take screenshots when we execute a test script. Taking a screenshot also help us to debug or analyze any failed cases. Below code can be used for taking a screenshot for the entire page. Notice that we need to import ‘org.apache.commons.io.FileUtils‘ and ‘import org.openqa.selenium.TakesScreenshot‘ packages. Also in the below code we are saving the screenshot image inside Project/IMAGE folder. The image file will be named as ‘fileName.jpg’.

//Take a screenshot
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
   try {
	   FileUtils.copyFile(scrFile, new File(System.getProperty("user.dir")+"/IMAGES" + "/fileName" + ".jpg"));
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

Take Screenshot of Web Element:

Sometimes we don’t require a screenshot of an entire web page, instead what if we just need the screenshot of the object or the web element. This can be done by first taking the screenshot of the entire page and then cropping the web element using its coordinates. Below code can be used for taking a screenshot of a web element.

// Capture the Web Element
WebElement element = driver.findElement(By.name("elementName"));

//Get Height and Width of the Web Element
int eleWidth = element.getSize().getWidth();
int eleHeight = element.getSize().getHeight();

// Create a rectangle using Width, Height and element location
Rectangle rect = new Rectangle(eleWidth, eleHeight);

/* Used selenium Point class to get x y coordinates of Image element to
 * get location(x y coordinates) of the element */
Point point = element.getLocation();
int xcord = point.getX();
int ycord = point.getY();

// Capture entire page screenshot as buffer.
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);

// Reading full image screenshot.
BufferedImage fullImg = ImageIO.read(scrFile);
  
//Cut Image using height, width and x y coordinates parameters.
BufferedImage dest = img.getSubimage(xcord, ycord, eleWidth, eleHeight);
ImageIO.write(dest, "png", scrFile);
  
//Used FileUtils class of apache.commons.io.
//Save Image screenshot in Project/Images folder 
FileUtils.copyFile(scrFile, new File(System.getProperty("user.dir")+"/IMAGES"+ "/fileName" + ".png"));

In case if we are scrolling the web page, we need to make following changes.

//Page down by 400 px
((JavascriptExecutor)driver).executeScript("scroll(0,400)");

//Cut Image using height, width and x y coordinates parameters.
BufferedImage dest = img.getSubimage(xcord, ycord - 400, eleWidth, eleHeight);
ImageIO.write(dest, "png", scrFile);

With this we came to an end on some of the advanced topics in Selenium. Some of the topics are commonly used across all Selenium scripts. Many more interesting topics to follow. Till then, Happy Learning!