# E2E Tests with Playwright

End-to-end testing infrastructure for the Custom PHP Framework using Playwright.

## Overview

Comprehensive browser-based E2E tests for:
- **Critical User Journeys** - Homepage, authentication, core workflows
- **LiveComponents Functionality** - Real-time updates, form validation, fragment rendering
- **Integration Scenarios** - Cross-browser compatibility, performance, security

## Test Coverage

### Critical Paths (`critical-paths/`)

#### Homepage Tests (`critical-paths/homepage.spec.ts`)
- Page load and accessibility
- Valid HTML structure and meta tags
- Navigation functionality
- JavaScript error detection
- Security headers verification
- Responsive design (mobile viewport)
- ARIA landmarks and accessibility
- CSS and asset loading

### LiveComponents Tests (`live-components/`)

#### Form Validation (`live-components/form-validation.spec.ts`)
- Real-time validation error display
- Email format validation
- Validation error clearing
- Submit prevention with errors
- Required field handling
- Max length validation
- Character counter functionality

#### Real-time Updates (`live-components/real-time-updates.spec.ts`)
- SSE (Server-Sent Events) connections
- HTMX request handling
- DOM updates without page reload
- Loading states during updates
- Form data preservation during partial updates
- WebSocket connections (if present)
- Connection error handling

### Legacy LiveComponents Tests

#### Fragment Rendering Tests (`livecomponents/fragment-rendering.spec.js`)

**Basic Functionality**:
- Single fragment patching without full re-render
- Multiple fragment updates simultaneously
- Nested fragment updates
- Fallback to full render when fragments not specified

**State Preservation**:
- Focus state preservation during fragment updates
- Scroll position preservation
- Selection range preservation in text inputs
- Event listener preservation on updated elements

**Performance**:
- Fragment rendering speed vs full HTML rendering
- Network payload size reduction (fragment vs full)
- Batch update optimization
- Rapid successive updates handling

**Edge Cases**:
- Empty fragments
- Very large fragments (1000+ items)
- Special characters in fragment content
- Whitespace and formatting changes
- Data attribute updates
- Missing fragment error handling

## Prerequisites

### System Dependencies

Playwright requires certain system libraries. Install them with:

```bash
# Option 1: Using Playwright's installer (recommended)
sudo npx playwright install-deps

# Option 2: Using apt directly
sudo apt-get install \
    libatk1.0-0 \
    libatk-bridge2.0-0 \
    libcups2 \
    libxkbcommon0 \
    libatspi2.0-0 \
    libxcomposite1 \
    libxdamage1 \
    libxfixes3 \
    libxrandr2 \
    libgbm1 \
    libcairo2 \
    libpango-1.0-0 \
    libasound2
```

### Node.js Dependencies

Install Playwright and browsers:

```bash
# Install Playwright package (already done via package.json)
npm install

# Install browser binaries
npx playwright install chromium  # Chromium only
npx playwright install           # All browsers (Chromium, Firefox, WebKit)
```

### Development Server

E2E tests require the local development server to be running:

```bash
# Start Docker containers and development server
make up

# Verify server is accessible
curl -k https://localhost
```

## Running Tests

### All E2E Tests

```bash
# Run all E2E tests headless
npm run test:e2e

# Run with UI mode (interactive)
npm run test:e2e:ui

# Run with headed browsers (see browser windows)
npm run test:e2e:headed

# Run with debug mode (step through tests)
npm run test:e2e:debug
```

### Specific Test Suites

```bash
# Critical path tests only
npm run test:e2e:critical

# LiveComponents tests only
npm run test:e2e:livecomponents

# Specific test files
npm run test:e2e:homepage
npm run test:e2e:validation
npm run test:e2e:realtime

# Legacy fragment tests
npx playwright test livecomponents/fragment-rendering.spec.js
```

### Filtering Tests

```bash
# Run specific test by title
npx playwright test --grep "should patch single fragment"

# Run tests in specific browser
npx playwright test --project=chromium
npx playwright test --project=firefox
npx playwright test --project=webkit
```

### Test Output and Reports

```bash
# Generate HTML report (automatically opens in browser)
npx playwright show-report

# View last test run results
npx playwright show-report playwright-report
```

## Configuration

### Playwright Config (`playwright.config.js`)

**Key Settings**:
- **Base URL**: `https://localhost` (local development server)
- **Ignore HTTPS Errors**: Enabled for local SSL certificates
- **User-Agent**: Set to avoid firewall blocking
- **Timeout**: 30 seconds per test
- **Retries**: 2 retries in CI, 0 locally
- **Workers**: Parallel execution (1 in CI, auto locally)

**Projects Configured**:
- Chromium (Desktop)
- Firefox (Desktop)
- WebKit/Safari (Desktop)
- Mobile Chrome (Pixel 5)
- Mobile Safari (iPhone 12)

**Reporters**:
- HTML report: `playwright-report/index.html`
- List (console output)
- JSON: `playwright-report/results.json`

### Test Environment

Tests assume the following URLs are accessible:

```
https://localhost/livecomponents/test/counter
https://localhost/livecomponents/test/shopping-cart
https://localhost/livecomponents/test/form
https://localhost/livecomponents/test/nested-fragments
https://localhost/livecomponents/test/performance
https://localhost/livecomponents/test/long-list
https://localhost/livecomponents/test/data-attributes
https://localhost/livecomponents/test/event-listeners
https://localhost/livecomponents/test/large-fragment
https://localhost/livecomponents/test/special-chars
```

**Note**: These test pages may need to be created in the application.

## Writing New E2E Tests

### Test Structure

```javascript
import { test, expect } from '@playwright/test';

test.describe('Feature Name', () => {
    test.beforeEach(async ({ page }) => {
        // Navigate to test page
        await page.goto('https://localhost/path/to/test-page');

        // Wait for LiveComponents to initialize
        await page.waitForFunction(() => window.LiveComponents !== undefined);
    });

    test('should do something', async ({ page }) => {
        // Arrange: Set up test state
        const component = page.locator('[data-component-id="component:id"]');

        // Act: Perform actions
        await page.click('[data-action="someAction"]');
        await page.waitForTimeout(100); // Wait for fragment update

        // Assert: Verify results
        const result = await page.textContent('[data-lc-fragment="result"]');
        expect(result).toContain('Expected Value');
    });
});
```

### Best Practices

**1. Use Data Attributes for Selectors**:
```javascript
// ✅ Good: Stable selectors
await page.click('[data-action="increment"]');
await page.locator('[data-lc-fragment="counter"]');

// ❌ Bad: Brittle selectors
await page.click('button.btn-primary');
await page.locator('.counter-display');
```

**2. Wait for LiveComponents Initialization**:
```javascript
// Always wait for LiveComponents to be ready
await page.waitForFunction(() => window.LiveComponents !== undefined);
```

**3. Handle Async Updates**:
```javascript
// Wait for network request to complete
await page.waitForResponse(response =>
    response.url().includes('/live-component/') && response.status() === 200
);

// Or use small timeout for fragment updates
await page.waitForTimeout(100);
```

**4. Use Page Object Pattern for Complex Pages**:
```javascript
class ShoppingCartPage {
    constructor(page) {
        this.page = page;
        this.addItemButton = page.locator('[data-action="addItem"]');
        this.cartItems = page.locator('[data-lc-fragment="cart-items"] .cart-item');
        this.cartTotal = page.locator('[data-lc-fragment="cart-total"]');
    }

    async addItem(item) {
        await this.addItemButton.click();
        await this.page.waitForTimeout(100);
    }

    async getItemCount() {
        return await this.cartItems.count();
    }
}
```

**5. Test Cross-Browser Compatibility**:
```javascript
// Use browser-agnostic APIs
const userAgent = await page.evaluate(() => navigator.userAgent);

// Avoid browser-specific features unless testing for them
```

## Debugging Tests

### Visual Debugging

```bash
# Run with UI mode (recommended)
npm run test:e2e:ui

# Run with headed browsers
npm run test:e2e:headed

# Debug specific test
npm run test:e2e:debug -- --grep "test name"
```

### Screenshots and Videos

Playwright automatically captures:
- **Screenshots**: On test failure
- **Videos**: Retained on failure
- **Traces**: On first retry

View artifacts in `test-results/` directory.

### Console Logs

```javascript
// Listen to console messages
page.on('console', msg => console.log('Browser log:', msg.text()));

// Listen to page errors
page.on('pageerror', err => console.error('Page error:', err));
```

### Playwright Inspector

```bash
# Step through test with debugger
npx playwright test --debug

# Pause test at specific point
await page.pause(); // Add this in test code
```

## CI/CD Integration

### GitHub Actions Example

```yaml
name: E2E Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright browsers
        run: npx playwright install --with-deps chromium

      - name: Start development server
        run: make up

      - name: Run E2E tests
        run: npm run test:e2e

      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: playwright-report
          path: playwright-report/
```

## Troubleshooting

### Common Issues

**1. Server not accessible**:
```bash
# Verify Docker containers are running
docker ps

# Check server is responding
curl -k https://localhost

# Check firewall/SSL settings
```

**2. Tests timing out**:
```javascript
// Increase timeout for specific test
test('slow operation', async ({ page }) => {
    test.setTimeout(60000); // 60 seconds
    // ...
});
```

**3. Flaky tests**:
```javascript
// Use waitForSelector with state
await page.waitForSelector('[data-lc-fragment="result"]', {
    state: 'visible',
    timeout: 5000
});

// Or wait for network to be idle
await page.waitForLoadState('networkidle');
```

**4. Browser launch errors**:
```bash
# Install missing dependencies
sudo npx playwright install-deps

# Use specific browser
npx playwright test --project=chromium
```

### Performance Issues

**Slow tests**:
- Run fewer browsers: `npx playwright test --project=chromium`
- Disable parallel execution: `npx playwright test --workers=1`
- Reduce retries: Set `retries: 0` in config

**High memory usage**:
- Close browsers between test files
- Limit workers: `--workers=2`
- Use headless mode (default)

## Test Maintenance

### Keeping Tests Updated

1. **Update test pages** when components change
2. **Update selectors** when HTML structure changes
3. **Add new tests** for new features
4. **Remove obsolete tests** for removed features
5. **Review flaky tests** regularly

### Test Quality Metrics

Track these metrics for test health:
- **Pass rate**: Should be >95%
- **Flakiness**: Retry rate should be <5%
- **Duration**: Average test duration <30s
- **Coverage**: All critical user flows tested

## Resources

- [Playwright Documentation](https://playwright.dev)
- [Playwright Test API](https://playwright.dev/docs/api/class-test)
- [Best Practices](https://playwright.dev/docs/best-practices)
- [Debugging Guide](https://playwright.dev/docs/debug)

## Support

For issues or questions about E2E tests:
1. Check this README
2. Review existing tests for examples
3. Check Playwright documentation
4. Ask in team chat or create GitHub issue
