Playwright E2E Testing Patterns is a development claude skill built by Affaan M. Best for: QA engineers and developers use this to create maintainable, reliable automated test suites for web applications..

What it does
Build stable end-to-end tests using Playwright with Page Object Model, CI/CD integration, and flaky test handling.
Category
development
Created by
Affaan M
Last updated
Claude Skilldevelopment GitHub-backed CuratedintermediateClaude Code

Playwright E2E Testing Patterns

Build stable end-to-end tests using Playwright with Page Object Model, CI/CD integration, and flaky test handling.

Skill instructions


name: e2e-testing description: Playwright E2E test kalıpları, Page Object Model, yapılandırma, CI/CD entegrasyonu, artifact yönetimi ve kararsız test stratejileri. origin: ECC

E2E Test Kalıpları

Kararlı, hızlı ve sürdürülebilir E2E test paketleri oluşturmak için kapsamlı Playwright kalıpları.

Test Dosyası Organizasyonu

tests/
├── e2e/
│   ├── auth/
│   │   ├── login.spec.ts
│   │   ├── logout.spec.ts
│   │   └── register.spec.ts
│   ├── features/
│   │   ├── browse.spec.ts
│   │   ├── search.spec.ts
│   │   └── create.spec.ts
│   └── api/
│       └── endpoints.spec.ts
├── fixtures/
│   ├── auth.ts
│   └── data.ts
└── playwright.config.ts

Page Object Model (POM)

import { Page, Locator } from '@playwright/test'

export class ItemsPage {
  readonly page: Page
  readonly searchInput: Locator
  readonly itemCards: Locator
  readonly createButton: Locator

  constructor(page: Page) {
    this.page = page
    this.searchInput = page.locator('[data-testid="search-input"]')
    this.itemCards = page.locator('[data-testid="item-card"]')
    this.createButton = page.locator('[data-testid="create-btn"]')
  }

  async goto() {
    await this.page.goto('/items')
    await this.page.waitForLoadState('networkidle')
  }

  async search(query: string) {
    await this.searchInput.fill(query)
    await this.page.waitForResponse(resp => resp.url().includes('/api/search'))
    await this.page.waitForLoadState('networkidle')
  }

  async getItemCount() {
    return await this.itemCards.count()
  }
}

Test Yapısı

import { test, expect } from '@playwright/test'
import { ItemsPage } from '../../pages/ItemsPage'

test.describe('Item Search', () => {
  let itemsPage: ItemsPage

  test.beforeEach(async ({ page }) => {
    itemsPage = new ItemsPage(page)
    await itemsPage.goto()
  })

  test('should search by keyword', async ({ page }) => {
    await itemsPage.search('test')

    const count = await itemsPage.getItemCount()
    expect(count).toBeGreaterThan(0)

    await expect(itemsPage.itemCards.first()).toContainText(/test/i)
    await page.screenshot({ path: 'artifacts/search-results.png' })
  })

  test('should handle no results', async ({ page }) => {
    await itemsPage.search('xyznonexistent123')

    await expect(page.locator('[data-testid="no-results"]')).toBeVisible()
    expect(await itemsPage.getItemCount()).toBe(0)
  })
})

Playwright Yapılandırması

import { defineConfig, devices } from '@playwright/test'

export default defineConfig({
  testDir: './tests/e2e',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: [
    ['html', { outputFolder: 'playwright-report' }],
    ['junit', { outputFile: 'playwright-results.xml' }],
    ['json', { outputFile: 'playwright-results.json' }]
  ],
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    actionTimeout: 10000,
    navigationTimeout: 30000,
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    { name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
  ],
  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
    timeout: 120000,
  },
})

Kararsız Test Kalıpları

Karantina

test('flaky: complex search', async ({ page }) => {
  test.fixme(true, 'Flaky - Issue #123')
  // test kodu...
})

test('conditional skip', async ({ page }) => {
  test.skip(process.env.CI, 'Flaky in CI - Issue #123')
  // test kodu...
})

Kararsızlığı Belirleme

npx playwright test tests/search.spec.ts --repeat-each=10
npx playwright test tests/search.spec.ts --retries=3

Yaygın Nedenler ve Çözümler

Yarış koşulları:

// Kötü: element'in hazır olduğunu varsayar
await page.click('[data-testid="button"]')

// İyi: otomatik bekleme locator
await page.locator('[data-testid="button"]').click()

Ağ zamanlaması:

// Kötü: keyfi timeout
await page.waitForTimeout(5000)

// İyi: belirli koşulu bekle
await page.waitForResponse(resp => resp.url().includes('/api/data'))

Animasyon zamanlaması:

// Kötü: animasyon sırasında tıkla
await page.click('[data-testid="menu-item"]')

// İyi: kararlılığı bekle
await page.locator('[data-testid="menu-item"]').waitFor({ state: 'visible' })
await page.waitForLoadState('networkidle')
await page.locator('[data-testid="menu-item"]').click()

Artifact Yönetimi

Ekran Görüntüleri

await page.screenshot({ path: 'artifacts/after-login.png' })
await page.screenshot({ path: 'artifacts/full-page.png', fullPage: true })
await page.locator('[data-testid="chart"]').screenshot({ path: 'artifacts/chart.png' })

Trace'ler

await browser.startTracing(page, {
  path: 'artifacts/trace.json',
  screenshots: true,
  snapshots: true,
})
// ... test aksiyonları ...
await browser.stopTracing()

Video

// playwright.config.ts'de
use: {
  video: 'retain-on-failure',
  videosPath: 'artifacts/videos/'
}

CI/CD Entegrasyonu

# .github/workflows/e2e.yml
name: E2E Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test
        env:
          BASE_URL: ${{ vars.STAGING_URL }}
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

Test Raporu Şablonu

# E2E Test Raporu

**Tarih:** YYYY-MM-DD HH:MM
**Süre:** Xd Ys
**Durum:** GEÇTİ / BAŞARISIZ

## Özet
- Toplam: X | Geçti: Y (Z%) | Başarısız: A | Kararsız: B | Atlandı: C

## Başarısız Testler

### test-adı
**Dosya:** `tests/e2e/feature.spec.ts:45`
**Hata:** Element'in görünür olması bekleniyordu
**Ekran Görüntüsü:** artifacts/failed.png
**Önerilen Çözüm:** [açıklama]

## Artifact'lar
- HTML Raporu: playwright-report/index.html
- Ekran Görüntüleri: artifacts/*.png
- Videolar: artifacts/videos/*.webm
- Trace'ler: artifacts/*.zip

Wallet / Web3 Testi

test('wallet connection', async ({ page, context }) => {
  // Wallet provider'ı mock'la
  await context.addInitScript(() => {
    window.ethereum = {
      isMetaMask: true,
      request: async ({ method }) => {
        if (method === 'eth_requestAccounts')
          return ['0x1234567890123456789012345678901234567890']
        if (method === 'eth_chainId') return '0x1'
      }
    }
  })

  await page.goto('/')
  await page.locator('[data-testid="connect-wallet"]').click()
  await expect(page.locator('[data-testid="wallet-address"]')).toContainText('0x1234')
})

Finansal / Kritik Akış Testi

test('trade execution', async ({ page }) => {
  // Üretimde atla — gerçek para
  test.skip(process.env.NODE_ENV === 'production', 'Skip on production')

  await page.goto('/markets/test-market')
  await page.locator('[data-testid="position-yes"]').click()
  await page.locator('[data-testid="trade-amount"]').fill('1.0')

  // Önizlemeyi doğrula
  const preview = page.locator('[data-testid="trade-preview"]')
  await expect(preview).toContainText('1.0')

  // Onayla ve blockchain'i bekle
  await page.locator('[data-testid="confirm-trade"]').click()
  await page.waitForResponse(
    resp => resp.url().includes('/api/trade') && resp.status() === 200,
    { timeout: 30000 }
  )

  await expect(page.locator('[data-testid="trade-success"]')).toBeVisible()
})

Use this skill

Most skills are portable instruction packages. Claude Code supports SKILL.md directly. Other agents can use adapted files like AGENTS.md, .cursorrules, and GEMINI.md.

Claude Code

Save SKILL.md into your Claude Skills folder, then restart Claude Code.

mkdir -p ~/.claude/skills/playwright-e2e-testing-patterns-2 && curl -L "https://raw.githubusercontent.com/affaan-m/everything-claude-code/HEAD/docs/tr/skills/e2e-testing/SKILL.md" -o ~/.claude/skills/playwright-e2e-testing-patterns-2/SKILL.md

Installs to ~/.claude/skills/playwright-e2e-testing-patterns-2/SKILL.md.

Use cases

QA engineers and developers use this to create maintainable, reliable automated test suites for web applications.

Reviews

No reviews yet. Be the first to review this skill.

No signup required

Stats

Installs0
GitHub Stars174.1k
Forks26970
LicenseMIT
UpdatedMar 27, 2026