Custom Elements in Selenium Webdriver

Selenium WebDriver is highly flexible to extend the features and commands to build a scalable test automation framework.

But Why do we need Custom WebElements in Selenium webdriver ?
Sometimes we may want access few webelement like tables, bootstrap dropdowns and so on, during those time we tend to write the complete code every time, or we call some method to perform operation but in longer run this way doing becomes more and more difficult to handle.

But if we create Custom Webelements helps us to ease the process and as well as narrows down the learning curve.

This tutorial focuses on how to create custom webelements by extending selenium class

Custom WebTable's test table

Website Title Field
Chercher.tech chercher Future Technologies
selenium-webdriver.com Selenium Webdriver Automation Testing
google.com Google Search Engine
facebook.com Facebook Social Media

Custom WebTable in Selenium

WebElement interface in Selenium provides methods to perform operations on the various webelements.

Selenium Webdriver provides helper classes to work with the dropdown element which is formed using select HTML tag. Anyways selenium webdriver doesnot support the tables on webpage or the &table> elements

We will be using methods from the WebElement Interface to perform operations on Webtable, we will be considering the web table is formed using <table>, <tr>, <td> HTML tags.

WebTable Methods :
To access the details of the WebTable we may need implement few methods like:

1. Accept WebTable element
2. Get number of rows
3. Get number of columns
4. Get the size of the table
5. Get all the data from a row
6. Get all the date from column
7. Get the total data
8. Verify Presence of Data
9. Get data from Specific cell
custom-table-selenium-webdriver


1. Accept WebTable Element : We need to accept the table on which we are going to perform the operations. We will be accepting the webtable as parameter for the WebTable() constructor.

Constructor assigns the Webtable element into global non-static varaiable table, we are assignig the value into global as we want to use the value across the class.


										WebElement table;
										// accept the web element (table) as parameter to then constructor
										public WebTable(WebElement wtable) {
											this.table= wtable;
										}
										


2. Get number of Rows : Sometimes user may request for number of rows present in the table, in such cases we should be able to give details. tr tags are used to form the table rows in HTML, so if we can get the number of tr present in our table element then we got our number of rows.

We have subtracted 1 from the total size because all the rows including header are also formed using tr HTML tags, so we subtracted 1 to exclude the headers.We are returning the size to calling method.


										// get the number of rows present
										public int getRowCount(){
											int noOfRows = table.findElements(By.tagName("tr")).size() - 1;
											return noOfRows;
										}
										


3. Get number of Columns : We can give the count of columns present in the table by counting the number of td HTML tags present in the table, tdHTML tags are used to form the cells. We have used xpath //tr[2]/td for find the number of columns, If we use //tr[1] then we may need to use th HTML tags as tr[1] point to headers and header will not have the td tags.


										// get the number of columns present
										public int getColumnCount(){
											int noOfCols = table.findElements(By.xpath("//tr[2]/td")).size();
											return noOfCols;
										}
										


4. Get the size of the table : Few people may expect out WebTable element to give the details about the total size of the table instead of giving number of rows, number of columns seperately. In this case we may need to return the Map of Key Value pairs which contains count of rows and columns.

Instead of creating new method implementation we cab use the getRowCount, getColumnCount to get the row count and column count. This methods returns a Map of values, Map consists String as keys and Integer as Value.


										// get the nuber of rows and columns and return it as Map
										public Map<String, Integer> getTableSize(){
											Map<String, Integer> tableSize = new HashMap<>();
											tableSize.put("rows", getRowCount());
											tableSize.put("columns", getColumnCount());
											return tableSize;
										}
										


5. Get all the data from a Row : Sometimes user may request the WebTable class to get a particular row values, we can get the row values by iterating the all the td HTML elements present under that row.

This method gets the all the td HTML element from a specific row, and iterates those element to store the text from it. We would be adding the text into list, so we can return the list at the end of the method.

We want to exclude the header and xpath index starts from 1, so we are adding +1 to the user passed value. We have throw the throw the exception when user passes 0 as value as all rows starts from 1.


										// get row data and return it as list
										public List rowData(int rowNumber) throws Exception{
											if(rowNumber == 0){
												throw new Exception("Row number starts from 1");
											}
											rowNumber = rowNumber + 1;
											List row = table.findElements(By.xpath("//tr["+rowNumber+"]/td"));
											List rData = new ArrayList<>();
											for (WebElement webElement : row) {
												rData.add(webElement.getText());
											}
											return rData;
										}
										


6. Get all the data from a Column : Similar to a row, user may need the values from a particular column. To get the values from column we need to get all the td HTML elements based on the column number passed in the method.

Inthis case we wo=ill be just iterating only cell, //tr/td avoids the headers so no need perform any action regarding that, but we still have to throw exception when user passes 0.


										// get the column data and return as list
										public List columnData(int columnNumber) throws Exception{
											if(columnNumber == 0){
												throw new Exception("Column number starts from 1");
											}
											List column = table.findElements(By.xpath("//tr/td["+columnNumber+"]"));
											List cData = new ArrayList<>();
											for (WebElement webElement : column) {
												cData.add(webElement.getText());
											}
											return cData;
										}
										


7. Get the total data : When we design a web table in Selenium WebDriver we must be in a position that we should be able to return all the data present in the table in Map format.

All the rows in a HTML table are formed using tr tags, and all the columns are formed using td tags. If there are 10 columns present under row in a webtable, which means there are 10 td tags are present under the tr tag

To get all the data from the table we have to iterate each and every row present under the web table, once we get the rows we must iterate the td tags present under that particular row

Idea of below code is, we have to iterate over all the data present in the table by iterating row by row using loops in selenium webdriver.

1. This method doesnot accept any parameters
2. We have to find how may rows are present exculding the Headers. (we are subtracting one in noOfRows).
3. We have to find the number of columns present, we can use //tr[2]/td xpath to do so.
4. Based one number of rows we have to form outer loop, and based on the number of columns we have to form inner loop.
5. Create a list to accept all the values of rows, we should give ability to user that he/she can to extract only first if she want so. To give such a result we have to use List of Lists.
6. Inside the first loop create another list variable, so when ever it crosses this line it should be created newly
7. Get the text values from inner loop and add it to the 'ro' list
8. After inner loop add the 'ro' list into 'allData' list.
9. return the values of 'allData' List

										// get all the data from the table
										public List getAllData(){
											// get number of rows
											int noOfRows = table.findElements(By.xpath("//tr")).size() -1;
											// get number of columns
											int noOfColumns = table.findElements(By.xpath("//tr[2]/td")).size();
											List allData = new ArrayList<>();
											// iterate over the rows, to ignore the headers we have started the i with '1'
											for (int i = 2; i < noOfRows; i++) {
												// reset the row data every time
												List<String> ro = new ArrayList<>();
												// iterate over columns
												for (int j = 1; j < noOfColumns; j++) {
													// get text from the i th row and j th column
													ro.add(table.findElement(By.xpath("//tr["+i+"]/td["+j+"]")).getText());
												}
												// add the row data to allData of the table
												allData.add(ro);
											}
											return allData;
										}
										


8. Verify presence of given data : We also should give an option to the user to check whether a particular data is present in the table or not, we can use xpath to verify whether given data is present or not by using the text() function with the xpath in selenium webdriver

There could be more than one data matching so we have used fndElements method to find how many elements present. if one or more elements present this method returns true but this methods returns false if number of elements is 0


										// verify presence of the text/data
										public boolean presenceOfData(String data){
											// verify the data by getting the size of the element matches based on the text/data passed
											int dataSize = table.findElements(By.xpath("//td[normalize-space(text())='"+data+"']")).size();
											boolean presence = false;
											if(dataSize > 0){
												presence = true;
											}
											return presence;
										}
										


9. Get data from Specific Cell : We should return the data from spcific cell when user requests, we can do it form the right xpath.

We have to exclude the Header row for that we would be adding +1 to the row requested by the user.


										// get the data from a specific cell
										public String getCellData(int rowNumber, int columnNumber) throws Exception{
											if(rowNumber == 0){
												throw new Exception("Row number starts from 1");
											}
											rowNumber = rowNumber+1;
											String cellData = table.findElement(By.xpath("//tr["+rowNumber+"]/td["+columnNumber+"]")).getText();
											return cellData;
										}
										


Complete program for Custom Webelement 'WebTable'


										package webtable;

										import java.util.ArrayList;
										import java.util.HashMap;
										import java.util.List;
										import java.util.Map;
										import org.openqa.selenium.By;
										import org.openqa.selenium.WebElement;

										public class WebTable {
											WebElement table;
											
											// accept the web element (table) as parameter to then constructor
											public WebTable(WebElement wtable) {
												this.table= wtable;
											}
											// get the number of rows present
											public int getRowCount(){
												int noOfRows = table.findElements(By.tagName("tr")).size() - 1;
												return noOfRows;
											}
											// get the number of columns present
											public int getColumnCount(){
												int noOfCols = table.findElements(By.xpath("//tr[2]/td")).size();
												return noOfCols;
											}
											// get the nuber of rows and columns and return it as Map
											public Map<String, Integer> getTableSize(){
												Map<String, Integer> tableSize = new HashMap<>();
												tableSize.put("rows", getRowCount());
												tableSize.put("columns", getColumnCount());
												return tableSize;
											}
											
												// get row data and return it as list
												public List rowData(int rowNumber) throws Exception{
													if(rowNumber == 0){
														throw new Exception("Row number starts from 1");
													}
													rowNumber = rowNumber + 1;
													List row = table.findElements(By.xpath("//tr["+rowNumber+"]/td"));
													List rData = new ArrayList<>();
													for (WebElement webElement : row) {
														rData.add(webElement.getText());
													}
													return rData;
												}
												// get the column data and return as list
												public List columnData(int columnNumber) throws Exception{
													if(columnNumber == 0){
														throw new Exception("Column number starts from 1");
													}
													List column = table.findElements(By.xpath("//tr/td["+columnNumber+"]"));
													List cData = new ArrayList<>();
													for (WebElement webElement : column) {
														cData.add(webElement.getText());
													}
													return cData;
												}
											
											// get all the data from the table
											public List getAllData(){
												// get number of rows
												int noOfRows = table.findElements(By.xpath("//tr")).size() -1;
												// get number of columns
												int noOfColumns = table.findElements(By.xpath("//tr[2]/td")).size();
												List allData = new ArrayList<>();
												// iterate over the rows, to ignore the headers we have started the i with '1'
												for (int i = 2; i < noOfRows; i++) {
													// reset the row data every time
													List<String> ro = new ArrayList<>();
													// iterate over columns
													for (int j = 1; j < noOfColumns; j++) {
														// get text from the i th row and j th column
														ro.add(table.findElement(By.xpath("//tr["+i+"]/td["+j+"]")).getText());
													}
													// add the row data to allData of the table
													allData.add(ro);
												}
												return allData;
											}
											
											// verify presence of the text/data
											public boolean presenceOfData(String data){
												// verify the data by getting the size of the element matches based on the text/data passed
												int dataSize = table.findElements(By.xpath("//td[normalize-space(text())='"+data+"']")).size();
												boolean presence = false;
												if(dataSize > 0){
													presence = true;
												}
												return presence;
											}
											
											// get the data from a specific cell
											public String getCellData(int rowNumber, int columnNumber) throws Exception{
												if(rowNumber == 0){
													throw new Exception("Row number starts from 1");
												}
												rowNumber = rowNumber+1;
												String cellData = table.findElement(By.xpath("//tr["+rowNumber+"]/td["+columnNumber+"]")).getText();
												return cellData;
											}
										}

										


Test Custom WebTable : We have to test our Selenium webdriver Custom element before we use it in framework, lets test it.

We will be using the table present in the top of this page. I hope the test code is pretty simple, please comment in the if you have troup in understanding.


										import java.util.concurrent.TimeUnit;
										import org.openqa.selenium.By;
										import org.openqa.selenium.WebDriver;
										import org.openqa.selenium.firefox.FirefoxDriver;

										public class WebTableTest {
											public static void main(String[] args) throws Exception {
												// set the geckodriver.exe property
												System.setProperty("webdriver.gecko.driver", "C:/Users/user/Pictures/geckodriver.exe");
												
												// open firefox
												WebDriver driver = new FirefoxDriver();
												driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
												
												driver.get("http://chercher.tech/java/custom-web-elements-selenium-webdriver");
												WebTable w = new WebTable(driver.findElement(By.xpath("//table")));
												
												System.out.println("No of rows : " +w.getRowCount());
												System.out.println("------------------------------------");
												System.out.println("No of cols : " +w.getColumnCount());
												System.out.println("------------------------------------");
												System.out.println("Table size : " +w.getTableSize());
												System.out.println("------------------------------------");
												System.out.println("First row data : " +w.rowData(1));
												System.out.println("------------------------------------");
												System.out.println("First column data : " +w.columnData(1));
												System.out.println("------------------------------------");
												System.out.println("All table data : " +w.getAllData());
												System.out.println("------------------------------------");
												System.out.println("presence of data : " +w.presenceOfData("Chercher.tech"));
												System.out.println("------------------------------------");
												System.out.println("Get data from Cell : " +w.getCellData(2, 2));
											}
										}

										


Output :

webtable-custom-webelement-selenium-webdriver

Capture Web Element Screenshot in selenium

Bootstrap / Custom Dropdown

We have seen already how to handle the custom dropdown which is not formed using select HTML tag, We will not be able to handle dropdown using Select Class of Selenium Webdriver if the dropdown is formed without using select HTML Tag

We have to handle this kind of the dropdown using clicks or with javascript, In this tutorial we are going to form a Dropdown Element class in selenium webdriver, which will help us to select values from the dropdown.

1. Create a Java class called CustomDropdown
2. Create CustomDropdown class constructor which accepts dropdown element
3. Create selectOption() method to select the option, this methods should accept the text as String parameter, Now find the dropdown option based on the option text by considering dropdown element as parent.


										import org.openqa.selenium.By;
										import org.openqa.selenium.WebElement;

										public class CustomDropdown {
											WebElement dropdown;
											// constructor
											public CustomDropdown(WebElement webDropdown) {
												// assign the constructor value to global wenelement
												this.dropdown = webDropdown;
											}
											// select the value from the dropdown using text
											public void selectOption(String optionValue){
												dropdown.click();
												dropdown.findElement(By.xpath("//*[text()='"+optionValue+"']")).click();
											}
										}
										


How to use the CustomDropdown : We have created the test class, I think it is very simple, you can understand without explanation. 1. the dropdown is present at http://chercher.tech/practice/custom-dropdown.html


										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;

										public class CustomDropdownTest {
											public static void main(String[] args) {
												// set the geckodriver.exe property
												System.setProperty("webdriver.gecko.driver", "C:/PATH/geckodriver.exe");
												
												// open firefox
												WebDriver driver = new FirefoxDriver();
												driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
												
												driver.get("http://chercher.tech/practice/custom-dropdown.html");
												
												WebElement element = driver.findElement(By.id("dd"));
												CustomDropdown cd = new CustomDropdown(element);
												
												cd.selectOption("Selenium-webdriver.com");
											}
										}
										

With this I am ending Custom WebElement in Selenium tutorial, these two examples are for your knowledge purpose, once you can understand the concept you can write Selenium Custom WebElements better than me.

Hidden Locators in Selenium Webdriver

About Author

Myself KarthiQ, I am the author of this blog, I know ways to write a good article but some how I donot have the skills to make it to reach people, would you like help me to reach more people By sharing this Article in the social media.

Share this Article Facebook
Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions
  • Habeeb
    Explain the framework used in your project? By coding
    Reply
    • karthiQ [admin]
      Hi Habeeb,
      
      I understand you expect more frameworks to be present in our site, we are currently working on it. But I cannot talk about my project here ot to give details about my project.
      Reply
  • Copyright © CherCher Tech