You now know six ways to find an element: getByRole, getByText, getByLabel, getByPlaceholder, getByTestId, and page.locator(). Which one do you pick? Playwright has a clear priority order. Follow it and your tests will be resilient. Ignore it and your tests will break with every UI change.
Is it a button, link, heading, checkbox, radio, or textbox? Use getByRole with name option.
Is it a form input with a visible <label>? Use getByLabel.
Is it a form input with only placeholder text? Use getByPlaceholder.
Is it a non-interactive element with unique visible text? Use getByText.
Does it have a data-testid attribute? Use getByTestId.
Nothing above works? Use page.locator() with a short, stable CSS selector.
CSS is not enough (need parent traversal, complex conditions)? Use XPath as last resort.
| Element | Best Locator | Code |
|---|---|---|
| Login button | getByRole | getByRole('button', { name: 'Login' }) |
| Email input with label | getByLabel | getByLabel('Email') |
| Search box (placeholder only) | getByPlaceholder | getByPlaceholder('Search...') |
| Error message text | getByText | getByText('Invalid credentials') |
| Loading spinner | getByTestId | getByTestId('loading-spinner') |
| Nav link "Home" | getByRole | getByRole('link', { name: 'Home' }) |
| Page heading | getByRole | getByRole('heading', { name: 'Dashboard' }) |
| Checkbox "Remember me" | getByRole | getByRole('checkbox', { name: 'Remember me' }) |
| Table row by cell content | locator + filter | getByRole('row').filter({ hasText: 'John' }) |
| Third-party widget | getByTestId or CSS | getByTestId('chart-widget') or locator('.chart') |
When in doubt, open the Playwright Inspector (npx playwright codegen) and hover over the element. It always suggests the highest-priority locator first. Trust its suggestion unless you have a specific reason to deviate.
Key Point: getByRole first. Always. Then getByLabel for form fields. Then getByText for static content. getByTestId and CSS/XPath are fallbacks, not defaults.
Key Point: Follow the priority: getByRole > getByLabel > getByPlaceholder > getByText > getByTestId > CSS > XPath. The higher up the list, the more resilient your test.