These are the mistakes I've seen junior engineers make over and over. Learn from their pain so you don't repeat it.
// BAD — breaks if ANY element in the path changes
driver.findElement(By.xpath(
"/html/body/div/div[2]/div/form/div[1]/div/input"));
// GOOD
driver.findElement(By.cssSelector("#userId"));// BAD — auto-generated, changes every page load
driver.findElement(By.id("react-select-3-option-2"));
driver.findElement(By.className("css-1s2u09g-control"));
// GOOD — use stable attributes
driver.findElement(By.cssSelector("[data-testid='accountType']"));
driver.findElement(By.cssSelector("[id*='account-type']"));// BAD — too many levels, any wrapper change breaks it
driver.findElement(By.cssSelector(
"div.main > div.content > div.form-wrapper > form > div > input"));
// GOOD — go directly to the target
driver.findElement(By.cssSelector("#userId"));// BAD — searches entire page, might match wrong element
WebElement name = driver.findElement(
By.cssSelector(".product-name"));
// GOOD — scope within a specific product card
WebElement card = driver.findElement(
By.cssSelector("[data-testid='product-item']:nth-child(1)"));
WebElement name = card.findElement(
By.cssSelector(".product-name"));// 1. Use data-testid (best)
driver.findElement(By.cssSelector("[data-testid='userId']"));
// 2. Partial attribute match (starts-with / contains)
driver.findElement(By.cssSelector("[id^='input-userId']"));
// 3. Use other stable attributes (name, placeholder, type)
driver.findElement(By.cssSelector(
"input[placeholder='User ID / Email']"));
// 4. Parent-child relationship
driver.findElement(By.cssSelector(".login-form input[type='text']"));
// 5. Text-based XPath
driver.findElement(By.xpath(
"//label[text()='Email']/following-sibling::div//input"));
// 6. aria-label attribute
driver.findElement(By.cssSelector("[aria-label='Search products']"));When reviewing locators in a code review, ask: "Would this still work if a dev changed the CSS classes but not the functionality?" If the answer is no, the locator is too fragile. Push back and use data-testid or a stable attribute.
Q: How do you handle dynamic IDs in Selenium?
A: Six strategies: (1) Use data-testid if available. (2) Use starts-with or contains for partial matching: By.cssSelector("[id^='product-']"). (3) Use other stable attributes like name, placeholder, or type. (4) Use parent-child relationships. (5) Use text-based XPath: //label[text()="Email"]/following-sibling::input. (6) Ask the developer to add a data-testid attribute.
Q: How do you find an element with no ID, name, or class?
A: Multiple approaches: (1) Check for data-testid. (2) Use other attributes like placeholder, type, or aria-label. (3) Use visible text with XPath: //button[text()="Submit"]. (4) Navigate from a nearby identifiable element: //label[text()="Email"]/following-sibling::input. (5) Use parent-child CSS: .form-section > input:nth-child(2). (6) Ask the developer to add a data-testid — this is a legitimate best practice.
Key Point: Avoid absolute XPath, dynamic IDs, and over-specific selectors. Scope within parent elements. When in doubt, use data-testid.