# Locators (Humand E2E) Use accessibility-first locators by default. Treat `data-testid` as fallback, not first choice. ## Priority order 1. `getByRole` 2. `getByLabel` 3. `getByText` 4. `getByPlaceholder` / `getByTitle` / `getByAltText` 5. `getByTestId` (fallback) 6. CSS/XPath only when nothing else is viable ## Humand rules - UI language is English (`locale: 'en'` in `playwright.config.ts`, `i18nextLng` set to `en` in auth setup). - Prefer resilient regex for text that may vary slightly: - `page.getByRole('button', { name: /create competency/i })` - Avoid class-based selectors for MUI-generated markup. - Keep raw locator details inside page objects, not in test files. - Verify the actual accessibility tree before assuming `getByRole` works for tabs or custom controls. - Scope drawer and slide-in inputs under `[role="presentation"]` when the page contains duplicate fields. - If the UI renders raw i18n keys, prefer a regex that matches both the key and the translated label. ## Good examples ```ts page.getByRole('button', { name: /create competency/i }); page.getByRole('button', { name: /save/i }); page.getByPlaceholder('Name'); page.getByText('Competencies', { exact: true }).first(); ``` ## `data-testid` fallback Use when: - the element has no stable accessible role/name - translated labels vary too much - custom controls are hard to target semantically Naming convention: `{module}-{component}-{element}` Examples: - `goals-cycle-new-button` - `auth-login-submit-button` ## Anti-patterns - `page.locator('.MuiButton-root.some-random-class')` - brittle nth-child selectors in tests - hardcoded selector duplication across tests and page objects - guessing selectors for collapsed or icon-only regions without MCP inspection