I'd replace CSS selectors and most test ids with role and label queries. A test id is still fine when nothing the user can see identifies the element.
The problem: CSS selectors and test ids tie the test to markup details the user never sees.
- Renaming a class or restructuring the markup breaks the test.
- The test says nothing about accessibility.
What I'd use instead:
getByRolewith an accessible name, such asgetByRole('button', { name: /save/i }).getByLabelTextfor form fields.
If you can't find an element by role or label, that often reveals an accessibility bug. Examples: a clickable div, or an input with no label. That bug is worth fixing in the component.
A data-testid is fine when there's no meaningful role or text. Examples:
- A chart canvas.
- A layout wrapper you need to scope with
within. - Dynamic content where the text isn't stable.
Treat a test id as the last resort.
- CSS selectors and test ids tie tests to markup the user never sees.
- Prefer
getByRolewith a name, andgetByLabelTextfor form fields. - If an element is hard to find by role, it often has an accessibility bug.
- Test ids are OK when nothing the user can see identifies the element.
Read more
- About queries (https://testing-library.com/docs/queries/about)testing-library.com
- ByRole (https://testing-library.com/docs/queries/byrole)testing-library.com