- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
491 lines
12 KiB
Markdown
491 lines
12 KiB
Markdown
# 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
|