Test locator / test ID
How a test finds an element: ideally by what the user sees ('the button named Save'), otherwise by a stable data-testid hook.
See it
What it is
A locator is how a test points at an element. Modern tools (Playwright, Testing Library, Cypress) give you a priority order, and it is worth following. First role and accessible name: getByRole('button', { name: 'Save changes' }), which is how a screen reader user finds the same control. Then label, placeholder, and visible text. Last, and only when nothing user-facing identifies the thing, a test ID: an attribute like data-testid='cart-total' that exists purely as a handle for tests.
The reason for the order is churn. A chain like div > div:nth-child(3) > span breaks the next time someone adds a wrapper, and a class selector breaks the next time someone touches the styles, so brittle locators are one of the top sources of flaky end-to-end suites. A test ID is immune to both, which is exactly why it is the escape hatch and not the default: it also survives you deleting the label, breaking the accessible name, and shipping a control nobody can find. Use it for things with no good name (a chart canvas, a specific table row, a container you need to scope inside).
Practical notes: scope repeated elements instead of numbering them globally, so grab the row first (getByTestId('order-row-42')) and query within it. Keep test IDs stable and semantic, never derived from copy that marketing will rewrite. Decide deliberately whether to strip them in production builds (a babel or compiler plugin can) or keep them, since your analytics and support tooling may want the same hooks. And if you find yourself adding a test ID to every element, the app probably has an accessibility problem the tests are routing around.
Ask AI for it
Refactor the locators in [TEST FILE] to be resilient. Replace every CSS class, tag chain, nth-child, and XPath selector with user-facing queries in this priority order: role plus accessible name, then label, then placeholder, then visible text. Only where no user-facing identifier exists, add a data-testid to the component and select by it, using stable kebab-case names that describe the element's purpose (not its copy or position). For repeated elements, scope the query to a parent locator instead of using an index. Use auto-retrying locator assertions rather than fixed waits or sleeps. List every data-testid you added and the component file you added it to.