## Custom Elements in Webdriver

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 ?
Sometimes we may want to access few web elements 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 the operation, but in the longer run, this way doing becomes more and more challenging 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 web elements by extending the selenium class.

## Custom WebTable's test table

Website Title Field
Chercher.tech chercher Future Technologies
selenium-webdriver.com Selenium Webdriver Automation Testing

## Custom WebTable in Selenium

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

Webdriver provides helper classes to work with the which is formed using the select HTML tag. Anyways selenium does not support the tables on a 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 to implement a 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

2. 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 a parameter for the WebTable() constructor.

Constructor assigns the Webtable element into a global non-static variable table; we are assigning 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, a user may request for the 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 the 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, td HTML tags are used to form the cells. We have used xpath//tr/td to find the number of columns; If we use //tr, then we may need to use th HTML tags as trpoint 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/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 the number of rows, number of columns separately. In this case, we may need to return the Map of Key-Value pairs which contain the count of rows and columns.

Instead of creating new method implementation, we can use the getRowCount, getColumnCount to get the row count and column count. This method returns a Map of values; Map consists of 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, a user may request the WebTable class to get particular row values; we can get the row values by iterating all the td HTML elements present under that row.

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

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

``````// get row data and return it as list
public List<String> 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) {
}
return rData;
}``````

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

In this case, we will be just iterating only cell, //tr/td avoids the headers so no need perform any action regarding that, but we still have to throw an exception when the 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<WebElement> column = table.findElements(By.xpath("//tr/td["+columnNumber+"]"));
List<String> cData = new ArrayList<>();
for (WebElement webElement : column) {
}
return cData;
}``````

7. Get the total data : When we design a web table in Selenium, 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 an HTML table are formed using tr tags, and all the columns are formed using td tags. If there are 10 columns present under the 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.

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

• This method does not accept any parameters
• We have to find how many rows are present, excluding the Headers. (we are subtracting one in noOfRows).
• We have to find the number of columns present; we can use //tr/td XPath to do so.
• Based on the number of rows, we have to form an outer loop, and based on the number of columns; we have to form an inner loop.
• Create a list to accept all the values of rows; we should give the ability to the user that he/she can to extract only first if she wants so. To provide such a result, we have to use a List of Lists.
• Inside the first loop create another list variable, so whenever it crosses this line it should be created newly
• Get the text values from the inner loop and add it to the 'ro' list
• After the inner loop adds the 'ro' list into the 'allData' list.
• 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/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
}
// add the row data to allData of the table
}
return allData;
}``````

8. Verify the presence of the 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

There could be more than one data matching, so we have used the findElements method to find how many elements present. If one or more elements present this method returns true but this method returns false if the 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 a specific 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/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<String> rowData(int rowNumber) throws Exception{
if(rowNumber == 0){
throw new Exception("Row number starts from 1");
}
rowNumber = rowNumber + 1;
List<WebElement> row = table.findElements(By.xpath("//tr["+rowNumber+"]/td"));
List<String> rData = new ArrayList<>();
for (WebElement webElement : row) {
}
return rData;
}
// get the column data and return as list
public List<String> columnData(int columnNumber) throws Exception{
if(columnNumber == 0){
throw new Exception("Column number starts from 1");
}
List<WebElement> column = table.findElements(By.xpath("//tr/td["+columnNumber+"]"));
List<String> cData = new ArrayList<>();
for (WebElement webElement : column) {
}
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/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
}
// add the row data to allData of the table
}
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 Custom element before we use it in a framework, let's test it.

We will be using the table present at the top of this page. I hope the test code is pretty simple; please comment on the if you have trouble 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("https://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 : 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 Webdriver if the dropdown is formed without using select HTML Tag.

We have to handle this kind of dropdown using clicks, or with javascript, In this tutorial, we are going to form a Dropdown Element class in 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 method should accept the text as a String parameter, Now find the dropdown option based on the option text by considering a dropdown element as a 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 straightforward, you can understand without explanation. 1. the dropdown is present at https://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("https://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.

Custom Locators in Selenium

Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions
• Habeeb
`Explain the framework used in your project? By coding`
```Hi Habeeb,
{"ft_lang_label":"__label__en","ft_lang_prob":0.5777562,"math_prob":0.836264,"size":15902,"snap":"2020-34-2020-40","text_gpt3_token_len":3559,"char_repetition_ratio":0.15656057,"word_repetition_ratio":0.316762,"special_character_ratio":0.2578292,"punctuation_ratio":0.16532528,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9674374,"pos_list":[0,1,2,3,4,5,6,7,8,9,10],"im_url_duplicate_count":[null,null,null,null,null,null,null,2,null,9,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2020-09-28T19:05:55Z\",\"WARC-Record-ID\":\"<urn:uuid:e2438d40-bfcc-4a37-b413-4f5047bbeb8b>\",\"Content-Length\":\"135113\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:18950d0d-8cba-4383-adaf-041e02e3f31a>\",\"WARC-Concurrent-To\":\"<urn:uuid:a58870a1-4f00-4835-a83f-8c76ef75cf4b>\",\"WARC-IP-Address\":\"104.27.178.48\",\"WARC-Target-URI\":\"https://chercher.tech/java/custom-web-elements-selenium-webdriver\",\"WARC-Payload-Digest\":\"sha1:MWBJKS6WDWZF7TSQAZN2D4KB5VJAEGUB\",\"WARC-Block-Digest\":\"sha1:CTSDA65UP7KKRJMVWLZMDIA5CKD7QOP7\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2020/CC-MAIN-2020-40/CC-MAIN-2020-40_segments_1600401604940.65_warc_CC-MAIN-20200928171446-20200928201446-00124.warc.gz\"}"}