Playwright is a modern end-to-end testing framework developed by Microsoft for testing web applications across Chromium, Firefox, and WebKit browsers. Built on a multi-browser, multi-platform architecture, Playwright enables reliable automation through features like auto-waiting, web-first assertions, and browser context isolation. Unlike older tools that rely on polling and explicit waits, Playwright's actionability checks and parallel execution capabilities make it a top choice for creating fast, stable, and maintainable test suites that scale with modern CI/CD pipelines. As of v1.59, Playwright extends into AI-assisted workflows with Test Agents, MCP server integration, and agentic video receipts for automated test authoring and repair.
What This Cheat Sheet Covers
This topic spans 24 focused tables and 254 indexed concepts, 143 flashcards. Below is a complete table-by-table outline of this topic, spanning foundational concepts through advanced details.
A jump-to index of every table row in this cheat sheet.
An interactive map of every table and concept in this topic.
Table 1: Core Locator Strategies
Locators are how Playwright finds elements, and the order they appear here is a recommendation β reach for getByRole, getByText, and getByLabel first because they mirror how real users and assistive tech perceive the page, and drop down to CSS or XPath only when nothing user-facing fits. The filtering and chaining methods at the bottom let you narrow a broad match down to exactly one element without writing brittle selectors.
| Method | Example | Description | |
|---|---|---|---|
page.getByRole('button', { name: 'Submit' }) | β’ Finds elements by ARIA role β most accessibility-friendly and recommended strategy β’ supports name, checked, pressed, expanded options. | ||
page.getByText('Welcome back') | β’ Matches elements by visible text content β’ supports exact match, substring, or regex. | ||
page.getByLabel('Email address') | β’ Finds form inputs by their associated label text β’ works with <label>, aria-label, and aria-labelledby. | ||
page.getByPlaceholder('Search...') | Locates inputs by their placeholder attribute β convenient for search fields without labels. | ||
page.getByTestId('user-profile') | β’ Finds elements by data-testid attribute (configurable) β’ provides stable, framework-agnostic selectors. | ||
page.getByAltText('Company logo') | Finds <img> or <area> elements by their alt attribute β essential for image and accessibility testing. | ||
page.getByTitle('Close dialog') | Matches elements by their title attribute β typically used for tooltips or icon buttons. | ||
page.getByRole('button').filter({ hasText: 'Save' }) | Narrows locator results by filtering on text content for precise targeting. | ||
page.getByRole('article').filter({ has: page.locator('.new-badge') }) | Filters elements that contain a specific child or descendant β powerful for nested structures. | ||
page.getByRole('listitem').filter({ hasNotText: 'Out of stock' }) | Filters elements that do not contain specified text β useful for inventory checks. | ||
page.locator('button').filter({ visible: true }) | Returns only visible elements from a locator match β avoids strict mode violations with hidden duplicates. | ||
page.getByRole('button').and(page.getByTitle('Subscribe')) | Narrows a locator by requiring it to also match a second locator simultaneously. | ||
newEmail.or(dialog).first() | Matches either of two locators β useful when two different elements may appear. | ||
page.locator('.sidebar').getByRole('link') | Combines locators to narrow scope β finds links within the sidebar only. | ||
page.getByRole('listitem').nth(2) | Selects the nth element (zero-indexed) from multiple matches. | ||
page.getByRole('button').first() | Selects the first or last element from multiple matches β more readable than nth(0). | ||
const better = await page.locator('#id').normalize() | β’ Converts a locator to best-practice form (prefers test IDs and ARIA roles) β’ added in v1.59. | ||
page.locator('.submit-btn') | β’ Uses CSS selector syntax β powerful but less readable β’ prefer stable classes or IDs. | ||
page.locator('xpath=//button[@id="submit"]') | Uses XPath expressions β useful for complex DOM traversal but generally harder to maintain. |