| Basic test | test('name', async ({ page }) => {}) | Auto-wait, web-first assertions, test isolation |
| Locator | page.getByRole() / page.locator() | Prefer role/label/text selectors over CSS |
| Assertion | expect(locator).toBeVisible() | Auto-retrying, configurable timeout |
| API testing | request fixture / apiRequestContext | Send HTTP requests, validate responses |
| Aria snapshot | expect(locator).toMatchAriaSnapshot() | Validate accessibility tree structure via YAML |
| Class assertion | expect(locator).toContainClass('active') | Match individual CSS class names (v1.52+) |
| Visible filter | locator.filter({ visible: true }) | Match only visible elements (v1.51+) |
| Test step | test.step('name', async (step) => {}) | Timeout, skip, and attachments (v1.50+) |
| Stealth mode | playwright-extra + stealth plugin | Patches 20+ detection vectors |
| Authenticated session | context.cookies() + addCookies() | Save/restore cookies and IndexedDB for persistence |
| Screenshot | page.screenshot({ fullPage: true }) | Wait for key elements to load first |
| PDF generation | page.pdf({ format: 'A4' }) | Chromium only, set printBackground: true |
| Clock API | page.clock | Freeze, fast-forward, or simulate time in tests |
| A11y assertions | toHaveAccessibleName, toHaveRole | Native assertions without axe-core dependency |
| Viewport assertion | expect(locator).toBeInViewport() | Assert element is within the visible viewport |
| Changed tests only | --only-changed=$GITHUB_BASE_REF | Run only test files changed since base branch |
| Docker | mcr.microsoft.com/playwright:v1.58.2-noble | Use --init --ipc=host flags |
| Debug methods | page.consoleMessages() / page.requests() (v1.56+) | No event listeners needed |
| Speedboard | HTML reporter (v1.57+) | Identifies slow tests and bottlenecks |
| Playwright Agents | npx playwright init-agents | Planner, generator, healer for LLM-driven testing |
| Flaky test detection | --fail-on-flaky-tests (v1.50+) | Exit code 1 on flaky tests in CI |
| Modify live responses | route.fetch() + route.fulfill() | Intercept real response, tweak JSON, return it |
| Soft assertions | expect.soft(locator) | Don't stop test on failure, report all at end |
| Retry block | expect(async () => {}).toPass() | Default timeout is 0 (forever) — always set one |
| Custom matchers | expect.extend() / mergeExpects() | Define or combine custom assertion methods |
| Actionability matrix | Per-action auto-wait checks | click: all 5 checks, fill: 3, focus/blur: none |
| Test modifiers | test.fixme() / test.fail() / test.slow() | fixme=skip+track, fail=assert failure, slow=3x |
| Parallel modes | test.describe.configure({ mode: 'serial' }) | serial, parallel, or default per-describe block |
| Teardown projects | teardown option on setup projects | Auto-cleanup after all dependents finish |