Top 20 Ways to Write Ultimate XPATH for ANY Type of Web Element (XPATH will never be invalid):
A web application is made up of different types of web elements such as web element for a button to click on, input web element to type text, drop-down, radio buttons, etc.
Recommended IPTV Service Providers
- IPTVGREAT – Rating 4.8/5 ( 600+ Reviews )
- IPTVRESALE – Rating 5/5 ( 200+ Reviews )
- IPTVGANG – Rating 4.7/5 ( 1200+ Reviews )
- IPTVUNLOCK – Rating 5/5 ( 65 Reviews )
- IPTVFOLLOW -Rating 5/5 ( 48 Reviews )
- IPTVTOPS – Rating 5/5 ( 43 Reviews )
These web elements are also called tags or nodes.
When it comes to automating web applications, it starts with writing an automation script that will find the web element, perform an action on it such as, click on a button, enter text into input box, select a checkbox, select a radio button, scroll up or down and finally verify the expected behavior in turn of the action.
What You Will Learn:
- What is XPath and How It Look Like?
- Top 20 Ways to Write XPath for Any Web Element
- #1) Reverse Lookup
- #2) Using Variables and Custom Values
- #3) Using “XML” tags, “AND” etc
- #4) Using Attributes and Table XPATH
- #5) Using Attributes, Tables, and Text
- #6) Generating XPATH Using Nested Attributes
- #7) XPath Generation by Combining Attributes, Divs, and Button
- #8) XPATH Generating using CONTAINS, REVERSE LOOKUP, etc.
- #9) XPath Generation using Relative, CONTAINS, REVERSE, FOLLOWING SIBLING, etc.
- #10) XPath Generation using Attributes, Contains, Reverse, Preceding-Sibling, Divs, and Span
- #11) Using Attributes, XML Tags etc.
- #12) XPath Generation by not Looking into the Entire Page but Looking into all the Links instead and Contains
- #13) Using Contains and Attributes
- #14) Using Attributes, Following Siblings and Descendant
- #15) Using Attributes, Following Siblings, Descendant, and Text
- #16) Using Header and Text
- #17) Using Header Text, Following Siblings, Path, etc.
- #18) Using Attributes, Contains and Preceding Siblings
- #19) Looking for drop-down by using Id Attribute, some Specific Text, and Reverse Lookup
- #20) Combining “id” Attribute and looking for a link with Specific Text
- Conclusion
What is XPath and How It Look Like?
Finding an element is like finding someone’s house on the map. The only way we can find a friend’s home without any external help is that we should have a map and know what to find (house).
In order to put this analogy in our case, the map will be used as DOM (HTML tags, JavaScript, etc.) where all the web elements exist, along with the specific web element that we want to find.
Once the unique address or path of an element is found, automation script will then perform some actions on it based on the test scenario. For Example, you want to verify the URL of the page which opens up after clicking on a button.
However, it is not straight forward to find a unique address/path of a web element as there might be similar tags, same attributes values, identical paths making by it hard to create exact unique address to a web element called “XPATH”.
Here, we’ll deep dive into some great and effective techniques to generate valid and unique XPATH for any type of web element.
Recommended Read => Identify Web Elements Using XPath in Selenium
Sometimes you can easily create XPaths using browser extensions but in my automation testing career, I have faced countless situations where traditional browser extensions don’t work and you must come up with your own customized XPaths using your own creativity. I’m sure that you have or will face similar situations.
In this tutorial, we will take a look at the 20 best ways on how to create ultimate XPath for a web element in such as way that even when your code is changed, your XPath will stay valid all the time (unless developer rewrites the entire feature/module).
By knowing all these techniques, you will become a master of writing your own XPath and would be able to write killer XPaths with very few chances of becoming invalid.
First, let’s start with understanding XPath syntax and define each of its parts.
The below image will show how XPath will look along with a description of each part:
- // : Select current node such as input, div etc.
- Tagname: Tagname of the web element/node
- @: Select attribute
- Attribute: Attribute name of the node/particular web element
- Value: Value of the attribute
Just want to share a couple of tips here that 80% of time my automation test script failed because of XPath. This caused by either there are multiple web elements for the provided XPath or XPath is not valid or the page has not been loaded yet.
So, whenever your test case fails:
- Copy your XPath.
- Search it in the Browser (F12 or developer tool window) in the DOM to verify if it is valid or not (See the below image).
Pro Tip 1: Make sure it is unique and no other web element appears when you search twice in the DOM.
Pro Tip 2: Sometimes there is a timing issue, which means that your web element/page is not yet loaded while the script was looking for it, hence add some wait time and retest.
Pro Tip 3: Try to print the entire DOM before searching for the web element. This way you can tell by looking into Console if your web element exists in the DOM or not.
Before we dive deep into XPath look up, one important thing that I want to share is that if you have direct access to the development team or if your team is located where you are, then ask your development team to provide you with unique IDs in each web element or at least the ones that you want to use for Automation and this will save a lot of your time.
If this is not the possibility, then you might need to use your creativity and come up with your own customized XPaths and which is what we are going to learn now.
Top 20 Ways to Write XPath for Any Web Element
Let’s deep dive into creating the top 20 ways to a killer XPath.
#1) Reverse Lookup
Let’s say that you want to click on a button and there is a similar button. Both buttons have id attributes, but they are dynamic and none of the attributes are unique in both the button elements.
In the below scenario we want to click on the “Setting” button of the “Test Interactive”.
Code
If you look at the “Setting” buttons, both the codes are similar. By using traditional ways such as id, name, value, contains, etc., none of them will work for example.
//*[contains(text(), ‘Setting’)], This will result in two web elements. Hence it is not unique.
So here is the final strategy,
>> First, Find the closest tag that is unique and in this case, it is <widget id=’rcTest’………>
XPATH: “//*[@id='rcTEST']
>> Second, Find the closest web element to the intended web element which in this case contains(text(), ‘TEST Interactive’). Now we are in the same <DIV> where the ‘Setting’ button exists but to click on it, we first need to go to the main <DIV> by using double dots as shown below.
XPATH: “//*[@id='rcTEST']//*[contains(text(), 'TEST Interactive')]/..
>> As you can see, we are in the <DIV> level which has the second web element as the ‘Setting’ button. This <DIV> has two buttons in it and we want to go to the second button which is the ‘Setting’ button. By adding ‘/button[2]’ at the end we can get our unique XPATH for the ‘Setting’ button as shown below.
Final XPATH:
“//*[@id='rcTEST']//*[contains(text(), 'TEST Interactive')]/../button[2]”
Here is another way to generate if you think they might change the web element type from “button” to something else.
“//*[@id='rcTEST']//*[contains(text(), 'TEST Interactive')]/..//*[contains(text(), 'Setting')]”
or using “following-sibling”
“//*[@id='rcTEST']//*[contains(text(), 'TEST Interactive')]/following-sibling::button”
#2) Using Variables and Custom Values
Let’s say that there is a web application that has FTP (“File Transfer Protocol”) feature to upload/download files and you have a test case to download a specific file by clicking on the download link.
First, we can define the file name that we are looking for as a variable.
String expectedfileName = “Test1”;
Now using the XPATH we can find the actual file name.
“String actualFileName = WebDriverAccess.getDriver().findElement (By.xpath("//*"+fileName +"/tr/td[1]")).getAttribute("title");”
In the above XPath, …‘/tr/td[1].getAttribute(“title”)’ will go to the specific row and first column and get the value of the title attribute. We can store the actual file name into another variable.
Once we have both the expected and actual file names, we can compare both and if both match we can simply click on its download link.
(if acutalFileName == expectedFileName) { WebDriverAccess.getDriver().findElement(By.xpath("//*"+fileName +"/tr/td[4]")).click(); }
We can also create a loop through each row and keep verifying the file name until you find it.
Loop(int count < 30) { String actualFileName = WebDriverAccess.getDriver().findElement (By.xpath("//*"+acutalFileName +"/tr[" + count + "]/td[1]")).getAttribute("title"); (if acutalFileName == expectedFileName) { WebDriverAccess.getDriver().findElement(By.xpath("//*"+fileName +"/tr/td[4]")).click(); } Count++; }
We can generate unique XPATH using customized tags plus add other conditions.
For Example, let’s say our intended web element exists in the main <address> tag, and there are multiple address tags, but you want to find only a specific one. All address tags have a class attribute, thus we can start with.
// address[@class='ng-scope ng-isolate-scope']
We noticed that our intended web element is in a <DIV> tag which has some text called ‘Testing’.
// address[@class='ng-scope ng-isolate-scope']//div[contains(.,'Testing')
We figured out that there are multiple web elements found as a result. Hence to make it more unique, we can add the other conditions such as “id” which will finally point us to the web element that we are looking for.
// address[@class='ng-scope ng-isolate-scope']//div[contains(.,Testing') and @id='msgTitle']
#4) Using Attributes and Table XPATH
Let’s assume that we want to type into a web element that is placed inside a table and the table is placed inside a form element.
We can find all the forms inside DOM with the name ‘myForm’.
“//*[@name='myForm']”
Now in all the forms find the table with id ‘tbl_testdm’.
"//*[@name='myForm']//table[@id='tbl_ testdm’]”
Within the table go to a specific row and column.
"//*[@name='myForm']//table[@id='tbl_ testdm’]/tbody/tr/td[6]/”
Within the cell, if there are multiple inputs, then find an input where value = ‘Open RFS’, and this will give us the final XPath of the field.
//*[@name='myForm']//table[@id='tbl_ testdm’]/tbody/tr/td[6]/ input[@value='Open RFS']"
#5) Using Attributes, Tables, and Text
Assume that your intended web element lies in the Panel Table and has some common text.
First start with a panel having a unique attribute which in this case is ‘TITLE’.
//*[@title=’Songs Lis Applet']
Now navigate through all the table tags.
//*[@title=’Songs Lis Applet']//table
Within all the tables find the column which has text ‘Author’.
Final XPath would be like:
//*[@title=’Songs List Applet']//table//td[contains(text(),'Author')]
#6) Generating XPATH Using Nested Attributes
Target web element’s XPath can also be generated using the nested attributes. For Example, in this case, it’ll look for a specific attribute across DOM and then look for another attribute within it.
//*[@id='parameters']//*[@id='testUpdateTime']")
#7) XPath Generation by Combining Attributes, Divs, and Button
For Example, in the below XPath, I was able to find the target web element by using an id (relative XPath), some div tags and a button.
“//*[@id='MODEL/PLAN']/div[1]/div[2]/div[1]/div[1]/widget/section/div[1]/div/div[1]/div/div/button[1]"
#8) XPATH Generating using CONTAINS, REVERSE LOOKUP, etc.
Once I had a drop-down with no direct identification. I had to use CONTAINS, REVERSE, DIVs, attributes to come up with the final XPATH as shown below.
//*[contains(text(),'Watch Dial)]/../div/select[@data-ng-model='context.questions [subqts.subHandleSubId]']"),
#9) XPath Generation using Relative, CONTAINS, REVERSE, FOLLOWING SIBLING, etc.
I had a situation where the application displays a graph, and each graph value had to be validated. But, unfortunately, each value didn’t have any unique identification, so I have come up with the final XPATH as shown below for one graph value which combines relative, contains, reverse, following-sibling and div tags.
//*[@id='RESEARCH/PLAN']//*[contains(@id, 'A4')]/../../following-sibling::div[1]/div[1]/span[1]/span[1]
#10) XPath Generation using Attributes, Contains, Reverse, Preceding-Sibling, Divs, and Span
Once I had to validate different Alarm data and each alarm value has been displayed based on a specific calculation or timings. In order to capture each value, I had to come up with the below XPATH that uses attributes, contains, reverse, preceding-sibling, divs, and span tags.
//*[@id='ALARMDATA']//*[contains(@id, 'AFC2')]/../../preceding-sibling::div[1]/div[1]/span[1]/span[1]
#11) Using Attributes, XML Tags etc.
In the below XPATH, attributes and XML tags, a sequence is used to come up with the final unique address of a web element.
//*[@id='RESEARCH/REVIEW'] //widget/section/div[1]/div/div[2]/div[1]/div[3]/div[1]//span[@class='details']
#12) XPath Generation by not Looking into the Entire Page but Looking into all the Links instead and Contains
The below XPath would look for only links in an entire page which contain the text as “Parameter Data Manual Entry”.
//a[contains(.,'Parameter Data Manual Entry')]
#13) Using Contains and Attributes
//*[contains(@style,'display: block; top:')]//input[@name='daterangepicker_end']
#14) Using Attributes, Following Siblings and Descendant
//*[@id='dropdown-filter-serviceTools']/following-sibling::ul/descendant::a[text()='Notepad']
#15) Using Attributes, Following Siblings, Descendant, and Text
//*[@id='dropdown-filter-service tools'] /following-sibling::ul/descendant::a[text()='Trigger Dashboard']
#16) Using Header and Text
If the web element is a header with some specific text, then the XPath could be as shown below:
//h3[text()='Internal Debrief']
#17) Using Header Text, Following Siblings, Path, etc.
//h3[contains(text(),'Helium Level')]/following-sibling::div/label/input
#18) Using Attributes, Contains and Preceding Siblings
Once I had a span that didn’t have any unique attribute, I had created XPATH by combining absolute, Contains, preceding siblings and another absolute path.
//div[div[p[contains(text(),'Status')]]]/preceding-sibling::div/div/span[3]/span
#19) Looking for drop-down by using Id Attribute, some Specific Text, and Reverse Lookup
//*[@id='COUPLING']//*[contains(text(),'COUPLE Trend')]/../div/select
#20) Combining “id” Attribute and looking for a link with Specific Text
//*[@id='ffaHeaderDropdown']//a[contains(text(),'Start Workflow')]
Conclusion
When it comes to writing a killer XPATH, it really depends on how well you understand and analyze the code. The more you understand the code the more will be the number of ways that you’ll find in writing effective XPATHs.
The first step in writing XPath is to find the closest unique web element to your target web element and keep getting closer using different techniques discussed above such as attributes, DIVs, following, contains, etc.
In the end, we would say this again that it’ll really make your life easier if you request your development team to add unique ids in all web elements that you are interested in.
Whenever a sprint cycle or work on new requirement starts and the team is shared with new mockups, I always go through all the mocks ups and think about potential automation test cases in my mind, prepare a list of all potential web elements that will be used in automation tests and prepare my own ids.
Once a list of all the web elements along with my suggested ids is completed, I would share it to developer beforehand to be used in the development code. This way, I would always get unique IDs by making my XPATH writing battle easy.
Below is a combined list of different ways to write XPATHs:
- “//*[@id=’rcTEST’]//*[contains(text(), ‘TEST Interactive’)]/../button[2]”
- “//*[@id=’rcTEST’]//*[contains(text(), ‘TEST Interactive’)]/..//*[contains(text(), ‘Setting’)]”
- “//*[@id=’rcTEST’]//*[contains(text(), ‘TEST Interactive’)]/following-sibling::button”
- “String actualFileName = WebDriverAccess.getDriver().findElement(By.xpath(“//*”+fileName +”/tr/td[1]”)).getAttribute(“title”);”
- WebDriverAccess.getDriver().findElement(By.xpath(“//*”+fileName +”/tr/td[4]”)).click();
- “// address[@class=’ng-scope ng-isolate-scope’]//div[contains(.,Testing’) and @id=’msgTitle’]”
- “//*[@name=’myForm’]//table[@id=’tbl_ testdm’]/tbody/tr/td[6]/
- input[@value=’Open RFS’]”
- “//*[@title=’Songs List Applet’]//table//td[contains(text(),’Author’)]”
- “//*[@id=’parameters’]//*[@id=’testUpdateTime’]”)”
- “//*[@id=’MODEL/PLAN’]/div[1]/div[2]/div[1]/div[1]/widget/section/div[1]/div/div[1]/div/div/button[1]”
- “//*[contains(text(),’Watch Dial)]/../div/select[@data-ng-model=’context.questions[subqts.subHandleSubId]’]”),”
- “//*[@id=’RESEARCH/PLAN’]//*[contains(@id, ‘A4’)]/../../following-sibling::div[1]/div[1]/span[1]/span[1]”
- “//*[@id=’ALARMDATA’]//*[contains(@id, ‘AFC2’)]/../../preceding-sibling::div[1]/div[1]/span[1]/span[1]”
- “//*[@id=’RESEARCH/REVIEW’]//widget/section/div[1]/div/div[2]/div[1]/div[3]/div[1]//span[@class=’details’]”
- “//a[contains(.,’Parameter Data Manual Entry’)]”
- “//*[contains(@style,’display: block; top:’)]//input[@name=’daterangepicker_end’]”
- “//*[@id=’dropdown-filter-serviceTools’]/following-sibling::ul/descendant::a[text()=’Notepad’]”
- “//*[@id=’dropdown-filter-serviceTools’]/following-sibling::ul/descendant::a[text()=’Trigger Dashboard’]”
- “//h3[text()=’Internal Debrief’]”
- “//h3[contains(text(),’Helium Level’)]/following-sibling::div/label/input”
- “//div[div[p[contains(text(),’Status’)]]]/preceding-sibling::div/div/span[3]/span”
- “//*[@id=’COUPLING’]//*[contains(text(),’COUPLE Trend’)]/../div/select”
- “//*[@id=’ffaHeaderDropdown’]//a[contains(text(),’Start Workflow’)]”
Hope this informative article would have enriched your knowledge on writing XPaths.
Author Bio: This article is written by Adnan Arif an IT professional having diverse experience and skills in his career spanning over 9 years.