TypeScript / JavaScript — Quick Reference for All Locator Methods
| Priority | Locator | Code Example | HTML Target | When to Use |
|---|---|---|---|---|
| 1 | getByRole |
page.getByRole('button', { name: 'Submit' }) page.getByRole('heading', { level: 1 }) page.getByRole('checkbox', { checked: true }) | <button>Submit</button> |
Best for accessibility. Works with ARIA roles. First choice always. |
| 2 | getByTestId |
page.getByTestId('login-btn') page.getByTestId('user-card') | <button data-testid="login-btn"> |
Most stable. Add custom test IDs for reliable automation. |
| 3 | getByText |
page.getByText('Welcome back') page.getByText('Login', { exact: true }) page.getByText(/welcome/i) | <span>Welcome back</span> |
Match visible text content. Supports regex. |
| 4 | getByLabel |
page.getByLabel('Email') page.getByLabel('Password') | <label>Email <input/></label> |
Form inputs with associated labels. |
| 5 | getByPlaceholder |
page.getByPlaceholder('Enter email') page.getByPlaceholder(/search/i) | <input placeholder="Enter email"> |
Inputs with placeholder text, no label available. |
| 6 | getByAltText |
page.getByAltText('Company Logo') page.getByAltText(/profile/i) | <img alt="Company Logo"> |
Images with alt text. |
| 7 | getByTitle |
page.getByTitle('Close dialog') page.getByTitle(/settings/i) | <button title="Close dialog"> |
Elements with title attribute. |
| Type | Syntax | Code Example | Notes |
|---|---|---|---|
CSS |
Direct string | page.locator('#submit') page.locator('.btn.primary') page.locator('div.card > h2') page.locator('[data-type="user"]') page.locator('input[name="email"]') | Widely known. Good for attribute selectors. Can't traverse up to parent. |
XPath |
// or xpath= |
page.locator('//button[@id="submit"]') page.locator('//div[@class="card"]//a') page.locator('//span[contains(text(),"Hello")]') page.locator('//input/parent::div') page.locator('xpath=//table/tbody/tr[2]/td[1]') | Can go to parent. Good for complex DOM. Brittle — use as last resort. |
| Method | Code Example | Description |
|---|---|---|
.filter() |
page.getByRole('listitem') .filter({ hasText: 'Buy milk' }) | Narrow results by text content. |
.filter({ has }) |
page.locator('.card') .filter({ has: page.getByRole('button') }) | Filter by child element presence. |
.filter({ hasNot }) |
page.locator('.card') .filter({ hasNot: page.locator('.disabled') }) | Exclude elements with specific children. |
.locator() |
page.locator('.card') .locator('h2') | Chain to find child within parent. |
.nth() |
page.locator('.item').nth(0) page.locator('.item').first() page.locator('.item').last() | Select by index (0-based). |
.and() |
page.getByRole('button') .and(page.getByText('Submit')) | Match both conditions (AND logic). |
.or() |
page.getByRole('button') .or(page.getByRole('link')) | Match either condition (OR logic). |
| Scenario | Code Example | Notes |
|---|---|---|
iframe |
const frame = page.frameLocator('#my-iframe'); frame.getByRole('button', { name: 'OK' }).click(); | Use frameLocator for iframes. |
Shadow DOM |
// Playwright pierces shadow DOM by default! page.locator('my-component >> button').click(); | CSS/text locators auto-pierce shadow DOM. XPath does NOT. |
Nested iframe |
page.frameLocator('#outer') .frameLocator('#inner') .getByText('Hello'); | Chain frameLocator for nested iframes. |
| Assertion | Code Example | Description |
|---|---|---|
| Visible | await expect(locator).toBeVisible() |
Element is visible on page. |
| Hidden | await expect(locator).toBeHidden() |
Element is not visible. |
| Enabled | await expect(locator).toBeEnabled() |
Element is not disabled. |
| Text | await expect(locator).toHaveText('Hello') |
Exact or regex text match. |
| Contain Text | await expect(locator).toContainText('Hi') |
Partial text match. |
| Attribute | await expect(locator).toHaveAttribute('href', '/home') |
Check any attribute value. |
| Count | await expect(locator).toHaveCount(5) |
Number of matched elements. |
| CSS Class | await expect(locator).toHaveClass(/active/) |
Check CSS class presence. |
| Value | await expect(locator).toHaveValue('[email protected]') |
Input field value. |
| Checked | await expect(locator).toBeChecked() |
Checkbox / radio is checked. |
| Priority | Locator | Resilience | Readability | Shadow DOM |
|---|---|---|---|---|
| 1 | getByRole |
⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ✅ Yes |
| 2 | getByTestId |
⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ✅ Yes |
| 3 | getByText |
⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ✅ Yes |
| 4 | getByLabel |
⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ✅ Yes |
| 5 | CSS Selector |
⭐⭐⭐ | ⭐⭐⭐ | ✅ Yes |
| 6 | XPath |
⭐⭐ | ⭐⭐ | ❌ No |
npx playwright codegen to auto-generate locators by recording actions.playwright.config.ts → use: { testIdAttribute: 'data-qa' }getByRole — it mirrors how real users & assistive tech interact with the page..filter() + .locator() chaining instead of complex XPath for parent-child queries.