agentsclimarketplace

Playwright best practices

Skill danielcg-net/claude_status_dashboard/.claude/skills/playwright-best-practices

Playwright best practices including selectors, wait strategies, accessibility testing, responsive design, and flaky-test prevention. Use when writing or improving Playwright E2E tests.From its SKILL.md

Install
npx -y skills add danielcg-net/claude_status_dashboard --skill playwright-best-practices

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

3.5 KB, as published. Nobody here has run it

Playwright Best Practices

Expert guidance for writing reliable, maintainable Playwright tests.

Quick Reference

ConcernBest PracticeAvoid
SelectorsgetByRole, getByTestId, getByLabelCSS classes, DOM structure
WaitsAuto-waiting, explicit assertionswaitForTimeout, hardcoded delays
AccessibilitygetByRole, a11y checksVisual-only testing
Flaky testsProper waits, stable selectorsTiming-dependent assertions
IsolationCleanup after each testTests depending on each other
ParallelIndependent testsShared state

Essential Principles

Use semantic selectors: getByRole, getByLabel, getByTestId are stable. CSS classes and DOM structure change frequently.

Never waitForTimeout: Hardcoded delays make tests slow and flaky. Use auto-waiting and explicit assertions.

Test accessibility: getByRole ensures accessible markup. Keyboard tests verify a11y.

Isolate tests: Each test should work independently. Clean up test data after each test.

Responsive testing: Test mobile, tablet, desktop viewports.

Selector Best Practices

// ❌ Bad: Fragile selectors
page.click('div > div > button')
page.click('.btn-primary')
page.click('#submit-btn-123')

// ✅ Good: Stable, semantic selectors
page.getByRole('button', { name: 'Submit' })
page.getByTestId('submit-button')
page.getByLabel('Email address')

Wait Strategies

// ❌ Bad: Hardcoded waits
page.waitForTimeout(5000)  // Flaky, slow

// ✅ Good: Explicit waits
await page.waitForURL('/dashboard')
await page.waitForSelector('[data-testid="success-message"]')
await expect(page.getByTestId('loading')).toBeHidden()
await page.waitForResponse(resp => resp.url().includes('/api/users') && resp.status() === 200)

Accessibility Testing

// Good: Semantic selectors enforce a11y
await page.getByRole('button', { name: 'Submit' }).click()

// Good: Keyboard navigation test
test('is keyboard navigable', async ({ page }) => {
  await page.goto('/form')
  await page.keyboard.press('Tab')
  await expect(page.getByTestId('name-input')).toBeFocused()
})

// Good: A11y assertions (with axe-core)
await expect(page).toHaveAccessibleTree()

Responsive Testing

test.describe('Mobile', () => {
  test.use({ viewport: { width: 375, height: 667 } })

  test('shows mobile menu', async ({ page }) => {
    await page.goto('/')
    await expect(page.getByTestId('hamburger-menu')).toBeVisible()
  })
})

Common Anti-Patterns

Anti-PatternSeverityFix
waitForTimeoutCriticalUse explicit waits/assertions
CSS class selectorsHighUse getByRole/getByTestId
Tests depending on each otherHighMake tests independent
No cleanupMediumUse fixtures with proper cleanup
Only desktop testingLowTest multiple viewports
Hardcoded test dataMediumUse data factories

Success Criteria

Tests are reliable when:

  • No waitForTimeout in tests
  • Selectors are semantic (getByRole, getByTestId)
  • Tests run in isolation (independent)
  • Test data cleaned up after each test
  • Multiple viewports tested
  • Accessibility assertions present
  • Tests are deterministic (no randomness)

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.