Source profileQuality 67/100Review permissions

affaan-m/ECC/skills/e2e-testing/SKILL.md

e2e-testing

Playwright E2E testing patterns, Page Object Model, configuration, CI/CD integration, artifact management, and flaky test strategies.

Source repository stars
234,327
Declared platforms
0
Static risk flags
2
Last source update
2026-07-27
Source checked
2026-07-28

Decision brief

What it does—and where it fits

Comprehensive Playwright patterns for building stable, fast, and maintainable E2E test suites.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/affaan-m/ECC --skill "skills/e2e-testing"
    Safe inspection promptEditorial

    Inspect the Agent Skill "e2e-testing" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/skills/e2e-testing/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Test File Organization

      Review the “Test File Organization” section in the pinned source before continuing.

      Review and apply the “Test File Organization” source section.
    2. 02

      Page Object Model (POM)

      Review the “Page Object Model (POM)” section in the pinned source before continuing.

      Review and apply the “Page Object Model (POM)” source section.
    3. 03

      Test Structure

      Review the “Test Structure” section in the pinned source before continuing.

      Review and apply the “Test Structure” source section.
    4. 04

      Playwright Configuration

      Review the “Playwright Configuration” section in the pinned source before continuing.

      Review and apply the “Playwright Configuration” source section.
    5. 05

      Flaky Test Patterns

      Review the “Flaky Test Patterns” section in the pinned source before continuing.

      Review and apply the “Flaky Test Patterns” source section.

    Permission review

    Static risk signals and limitations

    Network access

    medium · line 111

    The documentation includes network, browsing, or remote request actions.

    baseURL: process.env.BASE_URL || 'http://localhost:3000',

    Network access

    medium · line 126

    The documentation includes network, browsing, or remote request actions.

    url: 'http://localhost:3000',

    Runs scripts

    medium · line 152

    The documentation asks the agent to run terminal commands or scripts.

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

    Runs scripts

    medium · line 153

    The documentation asks the agent to run terminal commands or scripts.

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

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score67/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars234,327SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    affaan-m/ECC
    Skill path
    skills/e2e-testing/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original SKILL.md

    E2E Testing Patterns

    Comprehensive Playwright patterns for building stable, fast, and maintainable E2E test suites.

    Test File Organization

    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 Structure

    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 Configuration

    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,
      },
    })
    

    Flaky Test Patterns

    Quarantine

    test('flaky: complex search', async ({ page }) => {
      test.fixme(true, 'Flaky - Issue #123')
      // test code...
    })
    
    test('conditional skip', async ({ page }) => {
      test.skip(process.env.CI, 'Flaky in CI - Issue #123')
      // test code...
    })
    

    Identify Flakiness

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

    Common Causes & Fixes

    Race conditions:

    // Bad: assumes element is ready
    await page.click('[data-testid="button"]')
    
    // Good: auto-wait locator
    await page.locator('[data-testid="button"]').click()
    

    Network timing:

    // Bad: arbitrary timeout
    await page.waitForTimeout(5000)
    
    // Good: wait for specific condition
    await page.waitForResponse(resp => resp.url().includes('/api/data'))
    

    Animation timing:

    // Bad: click during animation
    await page.click('[data-testid="menu-item"]')
    
    // Good: wait for stability
    await page.locator('[data-testid="menu-item"]').waitFor({ state: 'visible' })
    await page.waitForLoadState('networkidle')
    await page.locator('[data-testid="menu-item"]').click()
    

    Artifact Management

    Screenshots

    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' })
    

    Traces

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

    Video

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

    CI/CD Integration

    # .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 Report Template

    # E2E Test Report
    
    **Date:** YYYY-MM-DD HH:MM
    **Duration:** Xm Ys
    **Status:** PASSING / FAILING
    
    ## Summary
    - Total: X | Passed: Y (Z%) | Failed: A | Flaky: B | Skipped: C
    
    ## Failed Tests
    
    ### test-name
    **File:** `tests/e2e/feature.spec.ts:45`
    **Error:** Expected element to be visible
    **Screenshot:** artifacts/failed.png
    **Recommended Fix:** [description]
    
    ## Artifacts
    - HTML Report: playwright-report/index.html
    - Screenshots: artifacts/*.png
    - Videos: artifacts/videos/*.webm
    - Traces: artifacts/*.zip
    

    Wallet / Web3 Testing

    test('wallet connection', async ({ page, context }) => {
      // Mock wallet provider
      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')
    })
    

    Financial / Critical Flow Testing

    test('trade execution', async ({ page }) => {
      // Skip on production — real money
      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')
    
      // Verify preview
      const preview = page.locator('[data-testid="trade-preview"]')
      await expect(preview).toContainText('1.0')
    
      // Confirm and wait for blockchain
      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()
    })
    

    Alternatives

    Compare before choosing