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:
# 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:
# 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:
# Start Docker containers and development server
make up
# Verify server is accessible
curl -k https://localhost
Running Tests
All E2E Tests
# 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
# 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
# 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
# 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
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:
// ✅ 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:
// Always wait for LiveComponents to be ready
await page.waitForFunction(() => window.LiveComponents !== undefined);
3. Handle Async Updates:
// 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:
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:
// Use browser-agnostic APIs
const userAgent = await page.evaluate(() => navigator.userAgent);
// Avoid browser-specific features unless testing for them
Debugging Tests
Visual Debugging
# 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
// 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
# 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
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:
# Verify Docker containers are running
docker ps
# Check server is responding
curl -k https://localhost
# Check firewall/SSL settings
2. Tests timing out:
// Increase timeout for specific test
test('slow operation', async ({ page }) => {
test.setTimeout(60000); // 60 seconds
// ...
});
3. Flaky tests:
// 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:
# 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: 0in config
High memory usage:
- Close browsers between test files
- Limit workers:
--workers=2 - Use headless mode (default)
Test Maintenance
Keeping Tests Updated
- Update test pages when components change
- Update selectors when HTML structure changes
- Add new tests for new features
- Remove obsolete tests for removed features
- 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
Support
For issues or questions about E2E tests:
- Check this README
- Review existing tests for examples
- Check Playwright documentation
- Ask in team chat or create GitHub issue