World’s largest virtual agentic engineering & quality conference
An XPath and Selenium cheat sheet: absolute vs relative XPath, axes, functions and predicates, WebDriver commands, exception handling, and AI self-healing.

Devansh Bhardwaj
Author

Shubham Soni
Reviewer
Published on: May 24, 2022
Last Updated on: July 17, 2026
OVERVIEW
Locators are where most Selenium tests succeed or break, and XPath is the most flexible locator strategy available: it can traverse the DOM in any direction and match elements by text, which CSS selectors cannot. This cheat sheet is a fast reference for the XPath and Selenium syntax you reach for daily, from absolute-versus-relative paths to axes, functions, WebDriver commands, and the AI-driven self-healing that keeps locators alive as the UI changes.
For an exhaustive locator reference, keep the XPath locators cheat sheet open alongside this page; here the focus is the syntax you memorize and the commands that run it.
Before the syntax tables, the one decision every locator starts with: CSS selector or XPath. Default to CSS for speed and readability; switch to XPath when you need to match by text or walk up the DOM.
| Capability | CSS Selector | XPath |
|---|---|---|
| Select by id | #username | //*[@id='username'] |
| Select by class | .btn-primary | //*[contains(@class,'btn-primary')] |
| Select by attribute | input[name='email'] | //input[@name='email'] |
| Direct child | ul > li | //ul/li |
| Any descendant | div p | //div//p |
| Match by visible text | Not possible | //button[text()='Submit'] |
| Traverse to parent | Not possible | //span/parent::div |
| Speed | Faster (native engine) | Slightly slower |
For the CSS side in depth, see the CSS selectors guide. The rest of this cheat sheet focuses on XPath and Selenium.
An absolute XPath starts at the document root with a single slash and names every node down to the target. A relative XPath starts anywhere with a double slash. Absolute paths break the moment the layout shifts, so relative XPath is the default for real automation.
# Absolute XPath - brittle, breaks on any layout change
/html/body/div[2]/form/input[1]
# Relative XPath - resilient, starts with //
//form/input[@id='user-message']The core relative-XPath syntax, using the Selenium Playground as the target site:
| Goal | Syntax |
|---|---|
| Any element by tag | //input |
| By id attribute | //input[@id='user-message'] |
| By any attribute | //input[@name='email'] |
| By class | //button[contains(@class,'btn-primary')] |
| Nth match by index | (//input)[2] |
| Two attributes combined | //input[@type='text' and @name='email'] |
| Direct child | //form/input |
| Any descendant | //form//input |
Note that XPath indexes start at 1, not 0, so (//input)[1] is the first match. For the wider set of locator strategies, the Selenium locators guide covers id, name, CSS, and link-text alongside XPath.
Note: Test your XPath locators live across 3,000+ browser and OS combinations. Try TestMu AI free!
Axes are how XPath moves through the DOM tree relative to a node you can already find. They are the tool for reaching an element that has no useful attributes of its own but sits next to one that does, for example a value cell beside a labeled header.
| Axis | Selects | Example |
|---|---|---|
| child | Direct children only | //ul/child::li |
| parent | The immediate parent | //input/parent::div |
| ancestor | All ancestors up the tree | //input/ancestor::form |
| following-sibling | Siblings after the node | //label/following-sibling::input |
| preceding-sibling | Siblings before the node | //input/preceding-sibling::label |
| descendant | All descendants below | //form/descendant::input |
| descendant-or-self | The node plus all descendants | //div/descendant-or-self::a |
The most common real-world pattern is following-sibling: find a stable label, then hop to the input or value next to it, for example //label[text()='Email']/following-sibling::input. This survives redesigns that a positional absolute path never would.
Modern apps generate IDs like input_a8f3c that change on every page load, so exact-match locators break constantly. XPath functions solve this by matching on the stable part of an attribute or on visible text.
| Function / operator | Purpose | Example |
|---|---|---|
| contains() | Match a partial attribute or text value | //input[contains(@id,'user')] |
| starts-with() | Match a known prefix | //input[starts-with(@id,'email_')] |
| text() | Match exact visible text | //button[text()='Show Message'] |
| and | Require two conditions | //input[@type='text' and @required] |
| or | Match either condition | //button[@id='save' or @id='submit'] |
| not() | Exclude a condition | //input[not(@disabled)] |
| last() | Select the final match | (//tr)[last()] |
| normalize-space() | Match text ignoring extra whitespace | //p[normalize-space()='Success'] |
A robust locator for a dynamic field usually combines a function with a partial value: //input[starts-with(@id,'email_') and @type='email']. For dozens more worked examples, the complete guide to using XPath in Selenium walks through each function on real pages.
XPath finds the element; Selenium WebDriver acts on it. The commands below cover initialization, locating with By.xpath, interaction, and window or frame handling in both Java and Python.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
WebDriver driver = new ChromeDriver();
driver.get("https://www.testmuai.com/selenium-playground/simple-form-demo/");
// Locate with XPath and interact
WebElement input = driver.findElement(By.xpath("//input[@id='user-message']"));
input.sendKeys("Hello TestMu AI");
driver.findElement(By.xpath("//button[@id='showInput']")).click();
// Read text back
String output = driver.findElement(By.xpath("//p[@id='message']")).getText();
driver.quit();from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.testmuai.com/selenium-playground/simple-form-demo/")
driver.find_element(By.XPATH, "//input[@id='user-message']").send_keys("Hello TestMu AI")
driver.find_element(By.XPATH, "//button[@id='showInput']").click()
output = driver.find_element(By.XPATH, "//p[@id='message']").text
driver.quit()Frequently used WebDriver commands:
| Task | Java | Python |
|---|---|---|
| Find element | driver.findElement(By.xpath(...)) | driver.find_element(By.XPATH, ...) |
| Find all matches | driver.findElements(...) | driver.find_elements(...) |
| Click / type | el.click() / el.sendKeys(...) | el.click() / el.send_keys(...) |
| Switch to frame | driver.switchTo().frame(...) | driver.switch_to.frame(...) |
| Switch window | driver.switchTo().window(handle) | driver.switch_to.window(handle) |
| Explicit wait | new WebDriverWait(driver, ...) | WebDriverWait(driver, ...) |
These commands run under any Selenium test runner, most commonly TestNG or JUnit in Java and pytest in Python, which handle grouping, assertions, and reporting around the WebDriver calls. To run the suite across real browsers instead of one local machine, point the driver at the TestMu AI cloud grid with a capabilities block; the full flag list is in the Selenium automation capabilities docs, and the language-specific reference lives in the Selenium Python cheat sheet.
Most Selenium failures are a handful of exceptions with predictable causes. Knowing the fix turns a red build into a two-line change.
| Exception | Cause | Fix |
|---|---|---|
| NoSuchElementException | Locator matched nothing | Verify the XPath in DevTools; wait for the element to render |
| TimeoutException | Element did not appear within the wait window | Increase the explicit wait or fix the condition being waited on |
| StaleElementReferenceException | The DOM re-rendered after the element was found | Re-locate the element instead of reusing the old reference |
| ElementNotInteractableException | Element exists but is hidden or covered | Wait for visibility, scroll into view, or dismiss the overlay |
| ElementClickInterceptedException | Another element received the click | Wait for the intercepting element to clear, then click |
The single highest-value fix is replacing fixed sleeps with explicit waits, so tests proceed the moment an element is ready rather than failing on a slow render or waiting longer than needed.
Even a well-written XPath breaks when developers rename an id or restructure the DOM, and locator maintenance is the largest hidden cost in a mature Selenium suite. AI is changing that in three ways:
TestMu AI's Automation Cloud applies self-healing directly: with the auto-healing capability enabled, it detects DOM changes, records the paths of located elements, and reformulates locators when one goes missing, reducing the maintenance the exceptions above create. One honest caveat: healing is heuristic, so for strict regression lanes where any UI change must fail the test, keep stable explicit selectors and leave it off.
For natural-language authoring, KaneAI turns plain-English prompts into executable web, mobile, and API tests and exports them to major frameworks, so the XPath and Selenium syntax in this cheat sheet becomes the layer you review rather than the layer you hand-write.
Keep this cheat sheet within reach: default to relative XPath, reach for axes when an element has no attributes of its own, use contains() and starts-with() for dynamic IDs, and replace fixed sleeps with explicit waits to kill most exceptions. Then let AI carry the maintenance, with self-healing locators keeping the suite green as the UI evolves. Start by running your locators across real browsers on the TestMu AI cloud grid, and use the linked XPath and Selenium deep-dive guides whenever you need more than a quick reference.
Author
Devansh Bhardwaj is a Community Evangelist at TestMu AI with 4+ years of experience in the tech industry. He has authored 30+ technical blogs on web development and automation testing and holds certifications in Automation Testing, KaneAI, Selenium, Appium, Playwright, and Cypress. Devansh has contributed to end-to-end testing of a major banking application, spanning UI, API, mobile, visual, and cross-browser testing, demonstrating hands-on expertise across modern testing workflows.
Reviewer
Shubham Soni is a Senior Member of Technical Staff at TestMu AI (formerly LambdaTest), building the Real Device Cloud and real-time testing infrastructure. He optimized the WebRTC services that power live testing to sub-100ms latency with adaptive bitrate streaming, led a frontend migration from Angular to React that cut page load time from 5-6 seconds to 1-1.5 seconds, and contributes to the official Device SDK. He led a team of four to build an accessibility testing product covering manual and automated testing and mentored a team of six on a real-time testing product. He brings over eight years of experience and earlier scaled a cloud code platform to 200K+ monthly users. Shubham holds a B.Tech in Computer Science.
Did you find this page helpful?
More Related Blogs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance