e2e-generate

Generate end-to-end tests with Playwright browser automation

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "e2e-generate" with this command: npx skills add manastalukdar/claude-devstudio/manastalukdar-claude-devstudio-e2e-generate

End-to-End Test Generation

I'll generate comprehensive E2E tests using Playwright for browser automation and testing.

Capabilities:

  • Auto-detect frontend framework (React, Vue, Next.js, etc.)
  • Generate Playwright test files with best practices
  • Create page object models for maintainability
  • Set up test infrastructure if missing

Token Optimization:

  • ✅ Bash-based Playwright detection (minimal tokens)
  • ✅ Grep to find routes/pages (200 tokens vs 3,000+ reading all files)
  • ✅ Template-based test generation (no file reads for templates)
  • ✅ Caching page/route discovery - saves 80% on reruns
  • ✅ Early exit when Playwright not needed
  • ✅ Incremental test generation (one page at a time)
  • Expected tokens: 1,200-3,000 (vs. 3,000-5,000 unoptimized)
  • Optimization status: ✅ Optimized (Phase 2 Batch 2, 2026-01-26)

Caching Behavior:

  • Cache location: .claude/cache/e2e/routes.json
  • Caches: Discovered routes/pages, framework detection
  • Cache validity: Until route files change (checksum-based)
  • Shared with: /playwright-automate, /test skills

Phase 1: Prerequisites Check

# Check if Playwright is installed
if [ -f "package.json" ]; then
    if grep -q "\"@playwright/test\"" package.json; then
        echo "✓ Playwright detected"
        PLAYWRIGHT_INSTALLED=true
    else
        echo "⚠️ Playwright not installed"
        PLAYWRIGHT_INSTALLED=false
    fi
else
    echo "❌ No package.json found"
    exit 1
fi

# Offer to install Playwright if missing
if [ "$PLAYWRIGHT_INSTALLED" = false ]; then
    echo ""
    echo "Playwright is required for E2E testing"
    read -p "Install Playwright? (yes/no): " install_pw

    if [ "$install_pw" = "yes" ]; then
        echo "Installing Playwright..."
        npm install --save-dev @playwright/test
        npx playwright install
        echo "✓ Playwright installed"
    else
        echo "Skipping installation. Install manually with:"
        echo "  npm install --save-dev @playwright/test"
        echo "  npx playwright install"
        exit 1
    fi
fi

Phase 2: Framework Detection

# Token-efficient framework detection
detect_framework() {
    if grep -q "\"next\"" package.json; then
        echo "nextjs"
    elif grep -q "\"react\"" package.json; then
        if [ -d "src/pages" ] || [ -d "pages" ]; then
            echo "react-pages"
        else
            echo "react-spa"
        fi
    elif grep -q "\"vue\"" package.json; then
        echo "vue"
    elif grep -q "\"@angular/core\"" package.json; then
        echo "angular"
    elif grep -q "\"svelte\"" package.json; then
        echo "svelte"
    else
        echo "generic"
    fi
}

FRAMEWORK=$(detect_framework)
echo "✓ Framework detected: $FRAMEWORK"

Phase 3: Page/Route Discovery

# Discover pages/routes efficiently with Grep
echo ""
echo "Discovering application pages..."

case $FRAMEWORK in
    nextjs)
        # Next.js App Router
        if [ -d "app" ]; then
            PAGES=$(find app -name "page.tsx" -o -name "page.jsx" -o -name "page.js" | head -10)
        # Next.js Pages Router
        elif [ -d "pages" ]; then
            PAGES=$(find pages -name "*.tsx" -o -name "*.jsx" -o -name "*.js" | grep -v "_app\|_document\|api" | head -10)
        fi
        ;;
    react-pages)
        PAGES=$(find src/pages -name "*.tsx" -o -name "*.jsx" | head -10)
        ;;
    react-spa)
        # Look for React Router routes
        ROUTES=$(grep -r "path=" src/ --include="*.tsx" --include="*.jsx" | head -10)
        ;;
    vue)
        PAGES=$(find src -name "*.vue" | head -10)
        ;;
esac

if [ -z "$PAGES" ]; then
    echo "⚠️ No pages found. Will generate generic test template."
    PAGE_COUNT=0
else
    PAGE_COUNT=$(echo "$PAGES" | wc -l)
    echo "✓ Found $PAGE_COUNT pages"
    echo ""
    echo "Sample pages:"
    echo "$PAGES" | head -5 | sed 's/^/  /'

    if [ $PAGE_COUNT -gt 5 ]; then
        echo "  ... and $((PAGE_COUNT - 5)) more"
    fi
fi

Phase 4: Test Generation

# Create E2E test directory
mkdir -p tests/e2e

echo ""
echo "Generating E2E tests..."

# Generate playwright config if missing
if [ ! -f "playwright.config.ts" ]; then
    cat > playwright.config.ts << 'EOF'
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',
  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
  },

  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
  ],

  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
  },
});
EOF
    echo "✓ Created playwright.config.ts"
fi

# Generate base test template
cat > tests/e2e/example.spec.ts << 'EOF'
import { test, expect } from '@playwright/test';

test.describe('Application E2E Tests', () => {
  test('should load homepage', async ({ page }) => {
    await page.goto('/');

    // Verify page loads
    await expect(page).toHaveTitle(/./);

    // Check for main content
    const mainContent = page.locator('main, #root, #app, [role="main"]');
    await expect(mainContent).toBeVisible();
  });

  test('should navigate between pages', async ({ page }) => {
    await page.goto('/');

    // Find and click a navigation link
    const navLink = page.locator('nav a, header a').first();
    await navLink.click();

    // Verify navigation occurred
    await page.waitForLoadState('networkidle');
    await expect(page.url()).not.toBe('http://localhost:3000/');
  });

  test('should be responsive', async ({ page }) => {
    // Test desktop view
    await page.setViewportSize({ width: 1920, height: 1080 });
    await page.goto('/');
    await expect(page.locator('body')).toBeVisible();

    // Test mobile view
    await page.setViewportSize({ width: 375, height: 667 });
    await expect(page.locator('body')).toBeVisible();
  });
});
EOF

echo "✓ Created tests/e2e/example.spec.ts"

# Generate page-specific tests if pages found
if [ $PAGE_COUNT -gt 0 ]; then
    # Generate test for first page as example
    FIRST_PAGE=$(echo "$PAGES" | head -1)
    PAGE_NAME=$(basename "$FIRST_PAGE" | sed 's/\.[^.]*$//')

    cat > "tests/e2e/${PAGE_NAME}.spec.ts" << EOF
import { test, expect } from '@playwright/test';

test.describe('${PAGE_NAME} Page', () => {
  test.beforeEach(async ({ page }) => {
    // Navigate to page before each test
    await page.goto('/${PAGE_NAME}');
  });

  test('should render page correctly', async ({ page }) => {
    // Verify page loads
    await page.waitForLoadState('networkidle');

    // Check for key elements
    // TODO: Update selectors based on your page structure
    const heading = page.locator('h1, h2').first();
    await expect(heading).toBeVisible();
  });

  test('should handle user interactions', async ({ page }) => {
    // TODO: Add interaction tests
    // Example: Click buttons, fill forms, etc.
  });

  test('should display correct content', async ({ page }) => {
    // TODO: Verify page content
    // Example: Check text, images, links
  });

  test('should handle errors gracefully', async ({ page }) => {
    // TODO: Test error scenarios
    // Example: Invalid input, network failures
  });
});
EOF

    echo "✓ Created tests/e2e/${PAGE_NAME}.spec.ts"
fi

Phase 5: Page Object Model (Optional but Recommended)

# Generate page object model example
mkdir -p tests/e2e/pages

cat > tests/e2e/pages/BasePage.ts << 'EOF'
import { Page } from '@playwright/test';

export class BasePage {
  constructor(protected page: Page) {}

  async goto(path: string) {
    await this.page.goto(path);
    await this.page.waitForLoadState('networkidle');
  }

  async waitForElement(selector: string) {
    await this.page.waitForSelector(selector);
  }

  async clickElement(selector: string) {
    await this.page.click(selector);
  }

  async typeIntoField(selector: string, text: string) {
    await this.page.fill(selector, text);
  }
}
EOF

echo "✓ Created tests/e2e/pages/BasePage.ts (Page Object Model base)"

cat > tests/e2e/pages/HomePage.ts << 'EOF'
import { Page } from '@playwright/test';
import { BasePage } from './BasePage';

export class HomePage extends BasePage {
  constructor(page: Page) {
    super(page);
  }

  async navigate() {
    await this.goto('/');
  }

  async getPageTitle() {
    return await this.page.title();
  }

  async clickNavLink(linkText: string) {
    await this.page.click(`nav a:has-text("${linkText}")`);
  }

  // Add more page-specific methods
}
EOF

echo "✓ Created tests/e2e/pages/HomePage.ts"

Phase 6: Test Scripts

# Update package.json with E2E test scripts
if [ -f "package.json" ]; then
    # Check if test:e2e script exists
    if ! grep -q "\"test:e2e\"" package.json; then
        echo ""
        echo "Add these scripts to package.json:"
        echo ""
        cat << 'EOF'
  "scripts": {
    "test:e2e": "playwright test",
    "test:e2e:headed": "playwright test --headed",
    "test:e2e:debug": "playwright test --debug",
    "test:e2e:ui": "playwright test --ui"
  }
EOF
    fi
fi

Running Your E2E Tests

echo ""
echo "=== E2E Test Setup Complete! ==="
echo ""
echo "📁 Test files created:"
echo "  - tests/e2e/example.spec.ts"
if [ $PAGE_COUNT -gt 0 ]; then
    echo "  - tests/e2e/${PAGE_NAME}.spec.ts"
fi
echo "  - tests/e2e/pages/BasePage.ts"
echo "  - tests/e2e/pages/HomePage.ts"
echo "  - playwright.config.ts"
echo ""
echo "🚀 Run tests:"
echo "  npm run test:e2e              # Run all tests"
echo "  npm run test:e2e:headed       # Run with browser visible"
echo "  npm run test:e2e:debug        # Run in debug mode"
echo "  npm run test:e2e:ui           # Run with Playwright UI"
echo ""
echo "📝 Next steps:"
echo "  1. Customize test selectors for your app"
echo "  2. Add more page-specific tests"
echo "  3. Implement page object models for complex pages"
echo "  4. Add to CI/CD pipeline with /ci-setup"

Best Practices

E2E Testing Tips:

  • ✅ Use data-testid attributes for reliable selectors
  • ✅ Test user workflows, not implementation details
  • ✅ Keep tests independent (no shared state)
  • ✅ Use page object models for maintainability
  • ✅ Run tests in CI/CD pipeline

Anti-Patterns:

  • ❌ Testing every possible scenario (focus on critical paths)
  • ❌ Fragile selectors (CSS classes that change often)
  • ❌ Long test chains (break into smaller tests)
  • ❌ No waiting for async operations

Integration Points

  • /ci-setup - Add E2E tests to CI pipeline
  • /test - Run E2E tests alongside unit tests
  • /deploy-validate - Run E2E tests before deployment

Credits: Playwright integration patterns based on community best practices and MCP Playwright server capabilities.

Token Optimization

This skill implements aggressive token optimization achieving 60% token reduction compared to naive implementation:

Token Budget:

  • Current (Optimized): 1,200-3,000 tokens per invocation
  • Previous (Unoptimized): 3,000-5,000 tokens per invocation
  • Reduction: 60% (average)

Optimization Strategies Applied

1. Early Exit for Playwright Detection (saves 95%)

# Check if Playwright is installed before any other operations
if ! grep -q "\"@playwright/test\"" package.json 2>/dev/null; then
    echo "⚠️ Playwright not installed"
    echo "Install with: npm install --save-dev @playwright/test"
    exit 0  # Exit immediately, saves ~4,500 tokens
fi

# If Playwright is installed but user wants to skip
if [ "$SKIP_E2E" = "true" ]; then
    echo "✓ Skipping E2E test generation"
    exit 0  # Saves ~4,500 tokens
fi

Exit scenarios:

  • Playwright not installed and user declines installation
  • E2E tests not needed for current change
  • Tests already exist and no changes to pages/components
  • Skip flag explicitly set

2. Framework Detection Caching (saves 70% on cache hits)

CACHE_FILE=".claude/cache/e2e/framework-config.json"

if [ -f "$CACHE_FILE" ] && [ $(find "$CACHE_FILE" -mtime -7 | wc -l) -gt 0 ]; then
    # Use cached configuration (50 tokens)
    FRAMEWORK=$(jq -r '.framework' "$CACHE_FILE")
    TEST_DIR=$(jq -r '.test_dir' "$CACHE_FILE")
    BASE_URL=$(jq -r '.base_url' "$CACHE_FILE")
    PAGE_PATTERNS=$(jq -r '.page_patterns[]' "$CACHE_FILE")
else
    # Detect framework from scratch (300 tokens)
    # Check package.json for next/react/vue/angular/svelte
    # Cache results for 7 days
    detect_framework
    cache_framework_config
fi

Cache Contents:

  • Frontend framework (Next.js, React, Vue, Angular, Svelte)
  • Page/route patterns for discovery
  • Base URL and dev server configuration
  • Test directory structure
  • Playwright configuration

Cache Invalidation:

  • Time-based: 7 days
  • Triggers: package.json changes, playwright.config.ts changes
  • Manual: --no-cache flag

3. Template-Based Test Generation (saves 70%)

# Instead of reading existing tests and analyzing patterns,
# use pre-defined templates (200 tokens)

generate_test_from_template() {
    local page_name="$1"
    local page_path="$2"

    # Use inline template - no file reads needed
    cat > "tests/e2e/${page_name}.spec.ts" <<EOF
import { test, expect } from '@playwright/test';

test.describe('${page_name} Page', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('${page_path}');
  });

  test('should render correctly', async ({ page }) => {
    await page.waitForLoadState('networkidle');
    const heading = page.locator('h1, h2').first();
    await expect(heading).toBeVisible();
  });
});
EOF
}

# vs. Reading 5+ existing test files to infer patterns (1,500+ tokens)

Templates:

  • Basic page test
  • Form interaction test
  • Navigation test
  • Responsive test
  • Error handling test
  • Authentication flow test

4. Grep-Based Route Discovery (saves 80%)

# Instead of reading all page files, use Grep patterns
case $FRAMEWORK in
    nextjs)
        # Fast file discovery with find (100 tokens)
        PAGES=$(find app -name "page.tsx" -o -name "page.jsx" | head -10)
        ;;
    react-spa)
        # Grep for route definitions (150 tokens)
        ROUTES=$(grep -r "path=" src/ --include="*.tsx" --include="*.jsx" | head -10)
        ;;
esac

# vs. Reading and parsing all route files with AST analysis (2,000+ tokens)

Discovery optimization:

  • Use find for file-based routing (Next.js, Nuxt)
  • Use Grep for code-based routing (React Router, Vue Router)
  • Limit results with head -10 (only generate tests for key pages)
  • Cache discovered routes for 24 hours

5. Git Diff for Changed Pages (saves 85% during development)

# Only generate tests for changed pages/components
CHANGED_FILES=$(git diff --name-only HEAD)
CHANGED_PAGES=$(echo "$CHANGED_FILES" | grep -E 'pages/|routes/|app/.*page\.')

if [ -n "$CHANGED_PAGES" ]; then
    # Generate tests only for changed pages (200 tokens)
    echo "Generating tests for modified pages:"
    echo "$CHANGED_PAGES"
    for page in $CHANGED_PAGES; do
        generate_test_for_page "$page"
    done
else
    # No page changes, check if this is initial setup
    if [ ! -d "tests/e2e" ]; then
        echo "Initial E2E setup - generating base tests"
    else
        echo "✓ No page changes - E2E tests up to date"
        exit 0  # Early exit, saves ~2,800 tokens
    fi
fi

6. Incremental Test Generation (saves 90% for existing setups)

# Check if E2E infrastructure already exists
if [ -f "playwright.config.ts" ] && [ -d "tests/e2e" ]; then
    # Skip infrastructure setup (saves 1,500 tokens)
    echo "✓ Playwright already configured"
    SKIP_SETUP=true
else
    # Full setup needed
    SKIP_SETUP=false
fi

# Check for existing tests
EXISTING_TESTS=$(find tests/e2e -name "*.spec.ts" -o -name "*.spec.js" 2>/dev/null | wc -l)

if [ "$EXISTING_TESTS" -gt 0 ] && [ -z "$CHANGED_PAGES" ]; then
    echo "✓ E2E tests exist and pages unchanged"
    exit 0  # Early exit, saves ~2,800 tokens
fi

7. Page Object Model Optional Generation (saves 60%)

# Only generate POM if user explicitly requests or project is complex
PAGE_COUNT=$(find app pages src -name "*.tsx" -o -name "*.jsx" 2>/dev/null | wc -l)

if [ "$PAGE_COUNT" -lt 5 ] && [ "$GENERATE_POM" != "true" ]; then
    echo "✓ Skipping Page Object Models (simple app)"
    SKIP_POM=true  # Saves 800 tokens
else
    echo "Generating Page Object Models for maintainability"
    SKIP_POM=false
fi

Optimization Impact by Operation

OperationBeforeAfterSavingsMethod
Playwright detection5002096%Early exit with grep package.json
Framework detection1,0005095%Caching framework config
Route/page discovery2,00015093%Grep patterns vs file reads
Test template generation1,50020087%Inline templates vs analysis
POM generation80010088%Conditional generation
Config file creation20015025%Template-based
Total6,00067089%Combined optimizations

Realistic Scenarios:

  • Initial setup: 1,200-2,000 tokens (full setup with templates)
  • Subsequent runs (cache hit): 300-800 tokens (use cached config)
  • Single page change: 400-1,000 tokens (generate one test)
  • No changes: 50-200 tokens (early exit)

Performance Characteristics

First Run (No Cache):

  • Token usage: 1,200-2,000 tokens
  • Detects framework and caches configuration
  • Discovers all pages/routes
  • Generates base test infrastructure
  • Creates example tests

Subsequent Runs (Cache Hit):

  • Token usage: 300-800 tokens
  • Uses cached framework detection
  • Only processes changed pages
  • 60-75% faster than first run

No Changes (Early Exit):

  • Token usage: 50-200 tokens
  • Exits if no pages changed
  • 95% savings

Single Page Change:

  • Token usage: 400-1,000 tokens
  • Generates test only for modified page
  • Uses templates for fast generation

Cache Structure

.claude/cache/e2e/
├── framework-config.json        # Framework detection (7d TTL)
│   ├── framework                # nextjs, react-spa, vue, etc.
│   ├── test_dir                 # tests/e2e
│   ├── base_url                 # http://localhost:3000
│   ├── page_patterns            # [app/**/page.tsx, pages/*.tsx]
│   ├── dev_command              # npm run dev
│   └── timestamp                # Cache creation time
├── routes.json                  # Discovered routes (1d TTL)
│   ├── pages                    # [{path: "/", file: "app/page.tsx"}]
│   ├── total_pages              # 15
│   └── last_scan                # 2026-01-27T10:00:00Z
├── test-coverage.json           # Generated tests tracking (1d TTL)
│   ├── covered_pages            # ["/", "/about", "/contact"]
│   ├── missing_tests            # ["/admin", "/dashboard"]
│   └── last_update              # 2026-01-27T10:00:00Z
└── playwright-config.json       # Cached playwright setup (7d TTL)
    ├── browsers                 # [chromium, firefox, webkit]
    ├── parallel_workers         # 4
    └── retry_count              # 2

Usage Patterns

Efficient patterns:

# Initial E2E setup
/e2e-generate

# Generate tests for specific page
/e2e-generate --page=dashboard

# Regenerate with fresh framework detection
/e2e-generate --no-cache

# Generate with Page Object Models
/e2e-generate --pom

# Only update changed pages
/e2e-generate --incremental

Flags:

  • --no-cache: Bypass framework detection cache
  • --page=<name>: Generate test for specific page
  • --pom: Force Page Object Model generation
  • --incremental: Only generate for changed pages
  • --all: Regenerate all tests

Context-Aware Test Generation

Session integration:

# After scaffolding new pages
# Context: /scaffold user-dashboard
# I'll detect: New dashboard routes
# I'll generate: E2E tests for dashboard flows only (saves 80%)

# During feature development
# Context: /session-current shows "user authentication feature"
# I'll prioritize: Auth flow E2E tests
# I'll skip: Unrelated page tests

# After deployment changes
# Context: git diff shows modified routes
# I'll regenerate: Only tests for changed routes (saves 90%)

Integration with other skills:

  • After /scaffold/e2e-generate for new features
  • Before /deploy-validate → Ensure E2E tests exist
  • With /ci-setup → Add E2E tests to pipeline
  • After /test failures → Generate E2E regression tests
  • With /playwright-automate → Share cached route discovery

Important optimization notes:

  • Never read entire codebase for route discovery
  • Use git diff to identify changed pages first
  • Cache framework detection for 7 days
  • Template-based generation avoids pattern analysis
  • Early exit when Playwright not needed
  • Incremental generation during development
  • Share cache with /playwright-automate and /test skills

Pre-Generation Quality Checks

Optimization for quality checks:

# Only check what's necessary (avoid wasted operations)
if [ -f "playwright.config.ts" ]; then
    echo "✓ Playwright config exists"
    NEEDS_CONFIG=false  # Skip config generation (saves 150 tokens)
else
    NEEDS_CONFIG=true
fi

# Check for test directory
if [ -d "tests/e2e" ] && [ $(ls tests/e2e/*.spec.* 2>/dev/null | wc -l) -gt 0 ]; then
    echo "✓ E2E tests exist"
    HAS_TESTS=true  # Use incremental mode (saves 1,500 tokens)
else
    HAS_TESTS=false
fi

# Cache check results (.claude/cache/e2e/setup-status.json)
# Saves 200 tokens on subsequent runs

Integration with Development Workflow

E2E generation workflow:

# 1. Feature development
/scaffold user-profile           # Create feature
/e2e-generate --page=profile     # Generate E2E tests (400 tokens)

# 2. Test and iterate
/test --e2e                      # Run E2E tests
# [tests fail]
# Fix implementation
/test --e2e                      # Re-run tests

# 3. CI/CD integration
/ci-setup                        # Add E2E tests to pipeline
/deploy-validate                 # Include E2E in pre-deploy checks

# 4. Session tracking
/session-update "Added E2E tests for user profile"
/session-end                     # Include E2E test summary

Shared cache optimization:

  • Cache route discovery shared with /playwright-automate
  • Framework detection shared with /test and /ci-setup
  • Test results shared with /deploy-validate
  • Total shared savings: 40-60% across related skills

This optimization approach ensures E2E test generation is fast, cost-effective, and seamlessly integrated into the development workflow while maintaining comprehensive test coverage.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

sessions-init

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

cache-strategy

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

postman-convert

No summary provided by upstream source.

Repository SourceNeeds Review