getByText
getByText finds elements containing given text. It complements getByRole for static content, status messages, and non-interactive copy.
Text-Based Location
Playwright normalizes whitespace and performs substring matching by default. Pass { exact: true } when 'Pass' should not match 'Password'.
Prefer getByRole with name for interactive controls; use getByText for paragraphs, spans, and validation messages without distinct roles.
await expect(page.getByText('Order confirmed')).toBeVisible();
await page.getByText('Delete account', { exact: true }).click();
await page.getByText(/welcome back/i).isVisible();
Regex patterns work for case-insensitive or dynamic text.
getByText Options
page.getByText('substring')
page.getByText('Exact', { exact: true })
page.getByText(/pattern/)
locator.getByText('nested') // scoped search
- Substring match is default — tighten with
exact: true when needed. - Regex helps dynamic timestamps or IDs in messages.
- Scope with parent locators to avoid matching hidden duplicate text.
- Combine with
filter({ hasText }) on containers for tables.
getByText Patterns
When and how to use text locators.
| Scenario | Example |
| Success message | getByText('Saved successfully') |
| Exact match | getByText('OK', { exact: true }) |
| Case insensitive | getByText(/error/i) |
| Partial in table cell | row.getByText('Pending') |
| Avoid brittle copy | Prefer role+name or test id for buttons |
| Hidden text | Use toBeVisible() — hidden matches may still exist |
getByText vs getByRole name
| Use | Locator |
| Clickable button labeled Save | getByRole('button', { name: 'Save' }) |
| Paragraph of terms text | getByText('Terms and conditions') |
| Inline validation error | getByText('Email is required') |
| Link with visible text | getByRole('link', { name: 'Learn more' }) |
Exact Strings vs Regular Expressions
getByText('Welcome') matches substring by default. Pass { exact: true } for full-string match, or a RegExp for dynamic content like order numbers.
Common Mistakes
- Matching marketing copy that changes every sprint.
- Substring 'Log' matching 'Login' and 'Logout' simultaneously.
- Not scoping text search in lists with repeated labels.
- Using getByText for buttons when getByRole is available.
Key Takeaways
- getByText excels for static and status copy.
- Use exact mode or regex to control matching precision.
- Scope text locators within rows or dialogs.
- Prefer roles for interactive elements.
Pro Tip
For i18n apps, avoid hard-coded locale strings in tests — read expected copy from fixtures or use test ids for language-agnostic checks.