XPath axes (parent, following-sibling, preceding) in Selenium Java - Build an Automation Script
import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import java.time.Duration; import static org.junit.jupiter.api.Assertions.*; public class XPathAxesTest { public static void main(String[] args) { System.setProperty("webdriver.chrome.driver", "path/to/chromedriver"); WebDriver driver = new ChromeDriver(); WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10)); try { driver.get("http://example.com/tablepage"); // Wait for the table cell with text 'Row 2' in first column WebElement cellRow2 = wait.until(ExpectedConditions.presenceOfElementLocated( By.xpath("//table//td[text()='Row 2']") )); // Find parent row of this cell using parent axis WebElement parentRow = cellRow2.findElement(By.xpath("parent::tr")); assertNotNull(parentRow, "Parent row should not be null"); // Find following sibling row using following-sibling axis WebElement followingSiblingRow = parentRow.findElement(By.xpath("following-sibling::tr[1]")); String followingSiblingText = followingSiblingRow.findElement(By.xpath("td[1]")).getText(); assertEquals("Row 3", followingSiblingText, "Following sibling row first column text should be 'Row 3'"); // Find preceding row using preceding axis WebElement precedingRow = parentRow.findElement(By.xpath("preceding-sibling::tr[1]")); String precedingRowText = precedingRow.findElement(By.xpath("td[1]")).getText(); assertEquals("Row 1", precedingRowText, "Preceding row first column text should be 'Row 1'"); System.out.println("Test passed: XPath axes navigation works correctly."); } finally { driver.quit(); } } }
This test script uses Selenium WebDriver with Java to automate the manual test case.
First, it opens the target URL and waits explicitly for the table cell containing 'Row 2' to appear.
Then it uses the parent::tr XPath axis to find the row containing that cell.
Next, it finds the following sibling row using following-sibling::tr[1] and verifies the first column text is 'Row 3'.
Similarly, it finds the preceding sibling row using preceding-sibling::tr[1] and verifies the first column text is 'Row 1'.
Assertions ensure the test fails if any expected condition is not met.
Finally, the driver quits to close the browser.
Now add data-driven testing with 3 different row texts: 'Row 2', 'Row 3', and 'Row 4' to verify their parent, following sibling, and preceding sibling rows.
Practice
Solution
Step 1: Understand XPath axes purpose
XPath axes define relationships between nodes, like parent or siblings.Step 2: Identify axis for immediate parent
Theparent::axis selects the direct parent node of the current element.Final Answer:
parent:: -> Option DQuick Check:
Parent axis = parent:: [OK]
- Confusing parent:: with child:: axis
- Using following-sibling:: to select parent
- Using preceding:: which selects previous nodes, not parent
Solution
Step 1: Recall correct axis syntax for following siblings
The axis for following siblings isfollowing-sibling::and it requires a node test like*for all siblings.Step 2: Check each option syntax
//div/following-sibling::* usesfollowing-sibling::*which correctly selects all following siblings. Others are incorrect syntax or wrong axis.Final Answer:
//div/following-sibling::* -> Option CQuick Check:
Following siblings = following-sibling::* [OK]
- Omitting '::' after axis name
- Using 'following::sibling' which is invalid
- Confusing preceding-sibling with following-sibling
<ul> <li id='item1'>First</li> <li id='item2'>Second</li> <li id='item3'>Third</li> </ul>
What text will this XPath select?
//li[@id='item1']/following-sibling::li[1]/text()Solution
Step 1: Understand the XPath expression
The XPath selects the firstlielement with id 'item1', then selects its first following siblinglielement, and gets its text.Step 2: Identify the first following sibling of 'item1'
The first following siblingliafter 'item1' is theliwith id 'item2' which contains text 'Second'.Final Answer:
Second -> Option AQuick Check:
Following sibling of item1 is item2 = Second [OK]
- Selecting the current node text instead of sibling
- Confusing preceding siblings with following siblings
- Assuming index [1] means first child, not sibling
//div[@class='menu']/preceding-sibling::div[2]What is wrong?
Solution
Step 1: Understand XPath indexing with axes
When using an index with axes likepreceding-sibling::div, the index applies to the node set returned by the axis, so parentheses are needed.Step 2: Correct the XPath syntax
The correct syntax to select the second preceding sibling div is(preceding-sibling::div)[2], notpreceding-sibling::div[2].Final Answer:
The index should be inside parentheses like (preceding-sibling::div)[2] -> Option BQuick Check:
Index with axes needs parentheses [OK]
- Placing index directly after node test without parentheses
- Assuming axes do not support indexing
- Confusing predicate indexing with axis indexing
div of a span element that has a class 'highlight', but only if the parent div has a following sibling div with class 'footer'. Which XPath expression correctly achieves this?Solution
Step 1: Understand the requirement
Select the parentdivof aspanwith class 'highlight', but only if that parentdivhas a following siblingdivwith class 'footer'.Step 2: Analyze each XPath option
//span[@class='highlight']/parent::div[following-sibling::div[@class='footer']] selects the parentdivof thespanand filters it by checking if it has a following siblingdivwith class 'footer', which matches the requirement exactly.Final Answer:
//span[@class='highlight']/parent::div[following-sibling::div[@class='footer']] -> Option AQuick Check:
Parent with following sibling filter = //span[@class='highlight']/parent::div[following-sibling::div[@class='footer']] [OK]
- Selecting following sibling instead of filtering parent
- Using preceding-sibling instead of following-sibling
- Misplacing axes order causing wrong node selection
Ready to prove it?
Pass the test and this pattern moves unknown
