Playwright Best Practices

Essential best practices for using Playwright effectively in testing.

From playwright.dev/docs/best-practices.

CategoryRule
LocatorsPrefer getByRole, getByLabel, getByText over CSS/XPath
LocatorsChain + filter: getByRole('listitem').filter({ hasText: 'X' }).getByRole('button')
AssertionsWeb-first only — toBeVisible(), toHaveText() auto-retry until condition met
AssertionsNever expect(await el.isVisible()).toBe(true) — resolves once, no retry
IsolationEach test: own storage, session, cookies — no shared state
IsolationMock external APIs — never call real third-party services in tests
Anti-patternsNo XPath — brittle, no auto-wait semantics
Anti-patternsNo CSS class chains tied to styling — breaks on redesign
Anti-patternsNo waitUntil: 'networkidle' — unreliable on SPAs with long-polling/WebSockets
Anti-patternsNo page.click(selector) — deprecated; use page.locator(selector).click()
Anti-patternsNo expect() or action without await — silently skips verification
CItsc --noEmit before every commit
CI--trace on-first-retry for CI debugging — not --trace on (too expensive)