Locators are the instructions an automation tool uses to find an element on a page. A good locator points to the intended element clearly and keeps working when the interface changes in harmless ways.
Types of locators
Finds an element as a user or assistive technology perceives it, such as a button named “Save”.
Useful for form fields and visible content. Prefer stable, user-facing wording.
A dedicated contract such as data-testid="checkout". Very stable when semantic locators are not suitable.
Targets IDs, classes, attributes, relationships and element states using browser-native syntax.
Traverses the DOM by structure, attributes or text. Powerful, but long structural paths are brittle.
Classic WebDriver strategies. Simple and effective when the selected value is unique and stable.
CSS selector syntax
| Target | Syntax | Example |
|---|---|---|
| ID | #id | #email |
| Class | .class | .primary-button |
| Attribute | [attribute="value"] | [data-testid="save"] |
| Attribute contains | [attribute*="part"] | [href*="checkout"] |
| Descendant | parent child | form input |
| Direct child | parent > child | nav > a |
| Multiple conditions | tag.class[attribute] | button.primary[type="submit"] |
| Position | :nth-child(n) | tbody tr:nth-child(2) |
document.querySelector('selector') for the first match or document.querySelectorAll('selector') for every match.XPath syntax
| Target | Example |
|---|---|
| Any element by tag | //button |
| Exact attribute | //input[@name='email'] |
| Exact visible text | //button[normalize-space()='Save'] |
| Partial text | //a[contains(normalize-space(), 'Account')] |
| Partial attribute | //div[contains(@class, 'alert')] |
| Child relationship | //form[@id='login']//input |
| Following sibling | //label[.='Email']/following-sibling::input |
| Parent relationship | //span[.='Total']/parent::div |
$x("//button") in the Console to inspect XPath matches. Avoid absolute paths such as /html/body/div[2]/...; small DOM changes will break them.Framework examples
Playwright · TypeScript
await page.getByRole('button', { name: 'Save' }).click();
await page.getByLabel('Email').fill('qa@example.com');
await page.getByTestId('checkout').click();
await page.locator('[data-status="ready"]').click();
Cypress
cy.get('[data-cy="save"]').click();
cy.contains('button', 'Save').click();
cy.get('input[name="email"]').type('qa@example.com');
Selenium · Python
from selenium.webdriver.common.by import By
driver.find_element(By.ID, 'email')
driver.find_element(By.CSS_SELECTOR, '[data-testid="save"]')
driver.find_element(By.XPATH, "//button[normalize-space()='Save']")
Robot Framework
Click Element css:[data-testid="save"]
Input Text id:email qa@example.com
Click Element xpath://button[normalize-space()='Save']
Best practices
- Prefer how users identify the element. Accessible role, name, label and visible text usually produce readable tests.
- Use a dedicated test attribute when needed. Agree on
data-testid,data-cyor one project-wide equivalent. - Make the locator unique. Confirm that it matches exactly the intended element.
- Avoid styling classes and deep DOM paths. They often change without any functional change.
- Scope before indexing. Locate a stable container, then the element inside it. Use
nth()only when position is genuinely meaningful. - Let the framework wait. Prefer Playwright auto-waiting, Cypress retrying or explicit WebDriver waits over fixed sleeps.
- Keep locators readable. A teammate should understand the target without opening the page source.
Tools and links
- Playwright locator guide ↗ — semantic locators, filtering and chaining.
- Playwright Codegen ↗ — record actions and generate resilient locators.
- Selenium locator strategies ↗ — the standard WebDriver locator types.
- Cypress selector best practices ↗ — guidance on stable
data-*attributes. - MDN querySelector reference ↗ — test CSS selectors in the browser.
- MDN XPath guide ↗ — evaluate XPath expressions in JavaScript.
- Built into Chrome: Elements panel → right-click an element → Copy → Copy selector or Copy XPath. Treat generated selectors as a starting point, then simplify them.