XPath & Locator Functions
The tricky bits of locator writing: whitespace and text nodes, pseudo-elements, comments in the DOM, multi-language text, XPath axes and not() — plus a quiz and a live XPath/CSS tester.
1. Text, dot and normalize-space()
Each element below has awkward text. Compare text(), . (string value) and normalize-space().
Welcome back, Amir!
↑ text() only returns “Welcome ”, “, ” and “!”. Use //p[.='Welcome back, Amir!'] or //p[normalize-space()='Welcome back, Amir!'].
Total Amount: ₹1,299
↑ Contains non-breaking spaces ( ) — contains(., 'Total Amount') fails; try translate() or match on “Amount”.
//button[text()='Save'] fails.2. Pseudo-elements (::before / ::after)
Text drawn by CSS isn't in the DOM — XPath and getText() can't see it. Read it with getComputedStyle(el, '::before').content.
Price: 999
Full name
3. Comment in the DOM
Inspect the element below — the secret code is in an HTML comment right after it. Locate it with XPath comment() and type it in.
XPath: //span[@data-testid='comment-target']/following-sibling::comment() — then read its text in JavaScript.
4. Multi-language text
Locate by non-English text — watch encoding in your source files and right-to-left scripts.
5. Axes and not()
No test ids on the buttons — add the cheapest in-stock product using XPath axes (ancestor, following-sibling, preceding) and not().
Wireless Mouse
₹799
In stockMechanical Keyboard
₹3,499
Out of stockUSB-C Hub
₹1,299
In stockWebcam HD
₹2,199
Out of stockLaptop Stand
₹999
In stockExample: //h4[.='USB-C Hub']/following-sibling::button · //div[@class='product-card'][not(.//span[contains(@class,'out')])]
6. Which XPaths are invalid — and why?
Pick an answer for each expression, then check your score.
//input[@data-testid='comment-code']//label[normalize-space()='Delivery Address']/following::input[1]//button[normalise-space()='Checkout']//div[@class='product-card']h4//ol[@data-testid='xpath-quiz']/li///h4[ends-with(.,'Hub')]//svg[@data-icon='star']//div[@class='product-card'][.//span[contains(@class,'in')]][not(.//button[@disabled])](//div[@class='product-card']//button)[last()]//span[@class='price' and]//p[@data-testid='split-text']/text()[2]
Score: 0 / 11
7. Live XPath / CSS tester
Try any locator against this page — matches are counted and outlined.