lecture 6 of 200 completed

Finding elements

A locator based on position breaks the next time someone edits the page. Find elements by what they are instead.

Let me show you the bug that made me stop trusting position-based locators.

We had a test that added the first product to the cart:

await driver.findElement(By.css('.product-card:nth-child(1) button')).click();

It worked for months. Then the marketing team added a "Featured" product to the top of the page. Our test still passed. It was adding the wrong product to the cart, and the test could not tell the difference.

That is the worst thing a test can do. Not fail. Pass while being wrong.

nth-child(1) means "the first one in the list". It describes where the element sits. Positions change whenever someone edits the page.

Selenium gives you several ways to find elements, called locator strategies. Here they are, best first:

By.id('add-to-cart')                          // fastest and most stable
By.css('[data-testid="add-to-cart"]')         // an attribute added for testing
By.name('email')                              // common on form fields
By.css('.product-card:nth-child(1) button')   // avoid: based on position
By.xpath('/html/body/div[2]/div/button[1]')   // worst: the whole page structure

By.id is the best choice when the app provides one. An id is meant to be unique, and it rarely changes.

That last example is worth understanding, because you will see it a lot. When you right-click an element in your browser and choose "Copy XPath", you usually get something like that. It works today and breaks as soon as anyone adds a <div> anywhere above it. Please do not copy XPaths from the browser.

XPath itself is not bad. It is the only way to find an element by its text:

By.xpath("//button[text()='Add to cart']")

Keep XPath short and based on meaning, not on the page structure.

Remember this: if your locator would break when someone reorders the page, it is the wrong locator.

Reference: Locator strategies.

now prove it

Reading is the setup. Solve these problems in the editor. We break the app on purpose to check your test would catch it.