This button is formed using a button tag :
This button is built using an input tag :
This button is created using the title attribute :
Sometimes we may want to write our own custom locators to access the elements in selenium. WebDriver’s API offers eight locators currently, allowing to retrieve elements By id, name attribute, tag name, link text or partial link text, XPath, class name, and CSS selector.
However, those default locators not enough for us now because we have to access the elements through a new attribute.
Yes, we can access those elements using the attributes present in the element, either with XPath or CSS value. But I wanted my framework not to give a burden on a new team member to learn XPath and CSS; also, I want to minimize the time for writing them.
If a fresher [zero experience] on this tool comes into selenium, we have spent hours to train him on XPath and CSS, So we want to write our Custom Locators to avoid these issues. We expect something like below, * refers to any operation after finding the element.
driver.findElement(By.myLocator("locator value")).*
Or something like below
driver.findElement(ByElementText("text value")).*
This way we can find an element with a custom attribute, Before we can create a custom locator let's understand the By class architecture, We can achieve custom locators By extending the By Class.
Custom By class : In selenium webdriver methods present in the By class are used to locate the element(s), all the methods present in the By class are static methods. We can access the static methods and static variables using Class Reference.
WebDriver’s API currently provides eight locators to retrieve elements By id, name attribute, tag name, link text or partial link text, XPath, class name, and CSS Selector. These locators are low level, but we can implement our own locators for high-level purpose.
Button Text Locator : We will try to implement the custom locator to find an element based on the text present in the button We will consider the below HTML code for our experiment
<button id='button1'>Alert Me</button>
We have to use below XPath to find the experiment element, and which requires good knowledge on XPath
//button[@text()='Alert Me']
driver.findElement(By.xpath("//button[text()='Alert Me']")).*
Wouldn't it be easy if the user just can write locator like below with button text
Button text -> Alert Me
driver.findElement(buttonText("Alert Me")).*
By Class has 8 types of locators and one abstract method, which is findElements, So whoever extends the By class, they must provide implementations for the findElements method. By default, the webdriver provides the implementation for the 'findElement' method, so no need to override the 'findElement' method.
public abstract List<WebElement> findElements(SearchContext context);
1. Override By Class Constructor : Let's learn about how to implement the buttonText custom locator using By Class Constructor. 1. Create a Java class with a hint that it related with Locator ByButtonText
2. Create a method and name it as you new custom locator buttonText and set the return type as By, and this method should accept the button text as a parameter
public static By buttonText(String buttonText)
2.1. If the return type is not By class, then the WebElement interface will not consider the method as a locator.
3. Implement the By class constructor also return it
return new By(){...}
4. Override the findElements method, findElement method is not an abstract method, so no need to override the findElement method.
@Override
public List<WebElement> findElements(SearchContext arg0) {
5. Form the XPath based on the button text we received from the buttonText custom locator
String xpath = "//button[text()='" + buttonText + "']";
6. When WebElement interface processes the By class constructor, and it calls the findElements method By passing the WebDriver object as a parameter.
7. Use the call the actual findElements method from the driver object, and return the elements
List<WebElement> elements = arg0.findElements(By.xpath(xpath));
return elements;
Complete program for buttonText custom locator in webdriver
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
public class ByButtonText {
public static By buttonText(String buttonText)
{
return new By(){
@Override
public List<WebElement> findElements(SearchContext arg0) {
String xpath = "//button[text()='" + buttonText + "']";
List<WebElement> elements = arg0.findElements(By.xpath(xpath));
return elements;
}
};
}
}
Let's use the custom locator in actual use :
1. Open the browser and navigate to https://chercher.tech/java/custom-locators-selenium-webdriver
2. Get the number of buttons present with 'Alert Me' text and print it using a buttonText custom locator.
// get number of buttons using findElements with Custom Locator
int noOfButtons = driver.findElements(ByButtonText.buttonText("Alert Me")).size();
System.out.println("No. of Button : " +noOfButtons);
3. Click the Alert Me button using the text 'Alert Me' using buttonText custom locator
// click the button using findElement with Custom Locator
driver.findElement(ByButtonText.buttonText("Alert Me")).click();
Note : We have used the buttonText() method with class reference ByButtonText.buttonText, we can use just like buttonText if we static import the ByButtonText class
import static custom.ByButtonText.*;
2. Implementing Class Constructor :
We can also implement the custom constructor using Implementing Class constructor, this method is only for your informational purpose, and I do not suggest to use this method in your frameworks as it involves creating multiple objects using constructors
We can use this custom Locator to find element by attribute of the element in selenium. In this method, instead, we will learn how to find the button using button value.
For your information button can be formed using button tag and input tag, first method deal with button tag. This method deals with the button with the input tag. When developers use input tag as the attribute value's value will be the button text.
<input type='button' value='Bingo'>
xpath for the above button tag will be //input[@type='button'][@value='Bingo']
driver.findElement(By.xpath("//input[@type='button'][@value='Bingo']")).*
We want to ease the XPath to the automation script writers so that we would be expecting something like below. We can also say this as writing custom XPath with different locator name.
driver.findElement(buttonValue("Bingo")).*
ByButtonValue and the constructor should accept the button text as a String parameter.public class ByButtonValue extends By{
private String buttonValue;
public ByButtonValue(String buttonValue)
{
this.buttonValue = buttonValue;
}
@Override
public List<WebElement> findElements(SearchContext context)
{
String xpath = "//inpput[@type='button'][@value='" + buttonValue + "']";
List<WebElement> elems = context.findElements(By.xpath(xpath));
return elems;
}
}
Actual Use of custom locator :
1. Open the browser and navigate to https://chercher.tech/java/custom-locators-selenium-webdriver
2. Get the number of buttons whose value attribute is 'Bingo.'
3. Click the button By finding the button using the value attribute
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/java/custom-locators-selenium-webdriver");
// get number of buttons using findElements with Custom Locator
int noOfButtons = driver.findElements(new ByButtonValue("Bingo")).size();
System.out.println("No. of Button : " +noOfButtons);
// click the button using findElement with Custom Locator
driver.findElement(new ByButtonValue("Bingo")).click();
}
In this example, we will be using simple methods to form the custom locator, but this method is not exactly a custom method, but still, this method is in very good usage.
We will write a method which will find the element using title attribute (also known as tooltip), we have a button called 'karthiQ' (my name), which has title attribute value as 'author.'
Steps to implement Method based Custom Locator :
import org.openqa.selenium.By;
public class ByMethods {
public static By buttonTitle(String title){
String xpath = "//input[@type='button'][@title='"+title+"']";
// returned the xpath formed along with By Class
return By.xpath(xpath);
}
}
Usage :
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/java/custom-locators-selenium-webdriver");
// get number of buttons using findElements with Custom Locator
int noOfButtons = driver.findElements(ByMethods.buttonTitle("author")).size();
System.out.println("No. of Button : " +noOfButtons);
driver.findElement(ByMethods.buttonTitle("author")).click();
}
There are few more locators present in Selenium Webdriver, and we might never use them lets see one example of how to use them
The below locator may look like the same as the locator you have been using, but these are static classes present in the By class. I do not think you need any explanations for the below locators.
<a id='idp' class='classp' name='namep' >Custom Locators</a>
Please find the example for the above locators
driver.findElement(new ById("idp")).click();
driver.findElement(new ByClassName("classp")).click();
driver.findElement(new ByName("namep")).click();
driver.findElement(new ByTagName("a")).click();
driver.findElement(new ByLinkText("Custom Locators")).click();
driver.findElement(new ByPartialLinkText("Custom")).click();
driver.findElement(new ByCssSelector("a#p")).click();
driver.findElement(new ByXPath("//a")).click();
There is a locator called ByIdOrName which helps selenium user to find element either by name or by id, we have already come across such concept do you remember. While handling the frames, we can pass either id or name of the frame; internally frame uses this locator to match the frame.
ByIdOrName locator is present under org.openqa.selenium.support package, to use this locator, we have to call the constructor of the ByIdOrName class and pass the name or id.
This method tries to find the element using id first, it waits till the max wait time for the element if it is not able to find the element with id then only ByIdOrName locator tries with the name.
If the element is available with id, then there will be no wait time, and selenium will not check the element with name attribute at all.
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ByIdOrName;
public class SeleniumOtherPackages {
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/java/custom-locators-selenium-webdriver");
// pass either id or name
driver.findElement(new ByIdOrName("namep")).click();
}
}
Headless browser in Selenium webdriver
Subscribe to my youtube channel :
ByChained locator helps to find the element based on the parent element, and it accepts an unlimited number of locators, The sequence is parent, child, grandchild, great Grandchild, target.
new ByChained(By.....bys.)
The parent element comes first, and then the target element. In the below HTML code, we have two text input bars; both are formed with the same tagname. Save the HTML in your local machine.
<html>
<head></head>
<body>
Outer Textbar: <input id="outer" type="text"><br><br><br>
<div id="div">
Inner Textbar : <input id="inner" type="text"><br>
</div>
</body>
</html>
If we use the below ByChained locator, we will find the inner input bar for the above HTML code.
new ByChained(By.id("div"), By.tagName("input"))
1. First, find the element with id 'div.'
2. Finds the element with tagname 'input' which is inside the 'div' element that we found in the first step Simple program for using ByChained locator in selenium
public class ByChainedLocator {
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("file:///path/a.html");
// pass either id or name
driver.findElement(new ByChained(By.id("div"), By.tagName("input"))).sendKeys("ChereCher Tech");;
}
}
Subscribe to my youtube channel :
ByAll locator in selenium helps to find the element based on the given locators; locator could be any other types like id, name, classname, link text, XPath, CSS, partial link text.
ByAll locator tries to find the element using the first locator if the element is not present then it waits for given implicit wait time, once it reaches the maximum wait time and if there is no element, the ByAll method tries to find the element using the second locator and goes on.
Finding elements continues until it finds the element, or there are no more locators.
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("file:///C:/PATH/a.html");
// find based on given locators
driver.findElement(new ByAll(By.className("not-exist"), By.id("inner"))).sendKeys("help");
}
You may like our Selenium Locators chapter as well, so try reading : Selenium Standard Locators
Subscribe to my youtube channel :
Hi karthik, Your articles are very helpful, and are very easy to understand. I appreciate your good work.
Hi Atitkumar Shingatalur , We are glad that you like it
Hi Karthik, Very informative tutorial. You have covered topics like custom locator and other find by elements which is not shared in other selenium tutorial websites. Keep up the good work Thanks
Thanks, Suhi. for your feedback
It was a new session
Your article is very helpful. Can you please help little bit more So we make a single function and call each time by passing values only in "" For example:- driver.findElement(new ByAll(By.className("not-exist"), By.id("inner"))).sendKeys("help"); Here we make function for above code and simply pass values in "aaaa" and code find.