getByRole is great, but sometimes you need simpler alternatives. Need to find a paragraph by its text? Use getByText. A form input by its label? getByLabel. An input by its placeholder? getByPlaceholder. Three locators, each with a clear purpose.
Finds any element that contains the given text. This is different from getByRole because it does not care about the element's role. A div, span, p, td -- anything with matching text content.
import { test, expect } from '@playwright/test';
test('getByText examples', async ({ page }) => {
await page.goto('/shopping');
// Find element containing exact text
await expect(page.getByText('Your cart is empty')).toBeVisible();
// Substring match -- finds "Total: $49.99" or "Grand Total: $49.99"
await expect(page.getByText('Total:')).toBeVisible();
// Regex match -- case insensitive
await expect(page.getByText(/welcome back/i)).toBeVisible();
// Regex with dynamic values
await expect(page.getByText(/\d+ items in cart/)).toBeVisible();
// Exact match -- must be full text, not substring
await expect(page.getByText('Add to Cart', { exact: true })).toBeVisible();
});getByText by default does substring matching. "Cart" will match "Add to Cart", "Shopping Cart", and "Cart is empty." If you want an exact full-text match, pass { exact: true }. Or use a regex with ^ and $ anchors.
This is the go-to locator for form fields. It finds the input element that is associated with a <label> tag. The association can be through the for attribute or by nesting the input inside the label.
import { test, expect } from '@playwright/test';
test('getByLabel examples', async ({ page }) => {
await page.goto('/banking');
// Works with <label for="email">Email</label>
// <input id="email" type="email">
await page.getByLabel('Email').fill('john@test.com');
// Works with nested labels too:
// <label>Password <input type="password"></label>
await page.getByLabel('Password').fill('secret123');
// Regex for flexible matching
await page.getByLabel(/phone/i).fill('9876543210');
// For textarea elements
await page.getByLabel('Comments').fill('This is great');
// For select dropdowns (with associated label)
await page.getByLabel('Country').selectOption('India');
});getByLabel only works when the HTML has proper <label> elements. If a developer skipped labels and used placeholder text instead, use getByPlaceholder. But tell the developer to fix their HTML -- missing labels is an accessibility violation.
Finds input elements by their placeholder attribute. Use this when the form has no labels -- only placeholder text inside inputs. This is common in modern UIs with floating labels.
import { test, expect } from '@playwright/test';
test('getByPlaceholder examples', async ({ page }) => {
await page.goto('/shopping');
// Find search bar
await page.getByPlaceholder('Search products...').fill('laptop');
// Find email field with placeholder
await page.getByPlaceholder('Enter your email').fill('john@test.com');
// Regex matching
await page.getByPlaceholder(/enter.*name/i).fill('John Doe');
});| Locator | Best For | Example |
|---|---|---|
| getByText | Static text, messages, headings, paragraphs | getByText('Welcome back') |
| getByLabel | Form inputs with proper <label> tags | getByLabel('Email') |
| getByPlaceholder | Inputs with placeholder text but no label | getByPlaceholder('Search...') |
Key Point: Prefer getByLabel over getByPlaceholder for form inputs. Labels are always visible. Placeholders disappear as soon as the user types. Tests should target what the user can always see.
Q: What is the difference between getByText and getByLabel?
A: getByText finds ANY element (div, span, p, button -- anything) that contains the given text content. getByLabel specifically finds form input elements that are associated with a <label> element. If you have <label for="email">Email</label><input id="email">, getByLabel('Email') returns the input, not the label. getByText('Email') would find the label element itself. For filling form fields, always use getByLabel because it directly targets the input you want to type into.
Key Point: getByText for visible text, getByLabel for labeled inputs, getByPlaceholder for placeholder-based inputs. Prefer getByLabel for forms.