First off, I was.stneme facing this annoying problem where my usual CSS selectors were just breaking. Website updates, you know how it goes. Stuff moves around, classes change, and suddenly your tests are failing. Frustrating! So, I started looking into other ways to nail down elements.
The Basics - ID and Name
Okay, so I started with the basics. If an element has a unique ID, that's your golden ticket. Super reliable. Something like this:
*(*("myUniqueID"));
Easy peasy. Then there's the 'name' attribute. Useful for forms and stuff. But less reliable than IDs, in my experience.
*(*("username"));
Level Up - CSS Selectors (But Smarter)
Now, CSS selectors are powerful, but like I said, they can break. So, instead of relying on brittle class names, I started looking for more stable patterns. For example, if you've got a nested structure, you can use that to your advantage.
*(*("div#container > ul > li:nth-child(2)"));
That’s a bit more robust, but still... it can be better.
XPaths - The Heavy Hitter
Enter XPath. Now, some people hate on XPath, say it's slow and ugly. And yeah, it can be. But when you're desperate, it's a lifesaver. The trick is to use it wisely.

Absolute XPath is a no-go. Don't even think about it. Something like /html/body/div/div[2]/ul/li[5]/a
. That's just asking for trouble.
Instead, focus on relative XPath and try to anchor it to something stable. Like an ID or a unique attribute.
*(*("//div[@id='myContainer']//a[text()='Click Me']"));
See? We're starting from a known point (the div with the ID) and then navigating down to the link with the specific text.
Text-Based Locators
Sometimes, the easiest way to find something is by its text. This works especially well for buttons, links, and headings.
*(*("Forgot Password?"));
Or, if you only know part of the text:
*(*("Forgot"));
Putting It All Together - The "All Star" Approach
Okay, so here's the key. Don't rely on just one locator strategy. Mix and match! If the ID is available, use it. If not, try a CSS selector based on the element's structure. And if all else fails, bring out the XPath.
I started writing helper functions to make this easier. Something like this (pseudo-code, mind you):
- Try to find by ID
- If not found, try CSS selector
- If still not found, try XPath
- If absolutely nothing works, then throw an error
This way, you're giving your tests the best possible chance of finding the element, even if the website changes a bit.
Real-World Example
I was working on this project where the 'Submit' button kept changing its class name. Annoying, right? So, I did this:
public WebElement findSubmitButton() {
try {
return *(*("submitButton")); //First try ID
} catch (NoSuchElementException e) {
try {
return *(*("button[type='submit']")); //Then try CSS
} catch (NoSuchElementException e2) {
return *(*("//button[text()='Submit']")); //Finally, XPath
Yeah, it's a bit verbose, but it works! The test can now find the submit button, regardless of its class name or even if the ID is missing (as long as the text "Submit" is there).
The Takeaway
The bottom line is, don't be a one-trick pony. Learn different locator strategies and use them strategically. Be prepared to adapt when things change. And most importantly, write your tests in a way that's resilient to website updates. That's the "all star" approach to element location!