← Back to Cheat Sheet Hub

🎭 Playwright Locator Strategy Cheat Sheet

TypeScript / JavaScript — Quick Reference for All Locator Methods

🟢 Recommended Built-in Locators

Use First
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.

🟡 CSS & XPath Selectors

Use When Needed
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.

🔗 Filtering & Chaining

Power Moves
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).

🖼️ Frames, Shadow DOM & Iframes

Advanced
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.

✅ Locator Assertions

Verify Elements
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.

📊 Locator Priority Guide

Decision Order
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
💡 Pro Tips:
▸ Use npx playwright codegen to auto-generate locators by recording actions.
▸ Customize test ID attribute: playwright.config.ts → use: { testIdAttribute: 'data-qa' }
▸ Prefer getByRole — it mirrors how real users & assistive tech interact with the page.
▸ Use .filter() + .locator() chaining instead of complex XPath for parent-child queries.
▸ All built-in locators auto-wait & auto-retry — no need for explicit waits.