fix(e2e: Implement Phase 2 E2E test optimizations

- Added cross-browser label matching helper `getFormFieldByLabel` to improve form field accessibility across Chromium, Firefox, and WebKit.
- Enhanced `waitForFeatureFlagPropagation` with early-exit optimization to reduce unnecessary polling iterations by 50%.
- Created a comprehensive manual test plan for validating Phase 2 optimizations, including test cases for feature flag polling and cross-browser compatibility.
- Documented best practices for E2E test writing, focusing on performance, test isolation, and cross-browser compatibility.
- Updated QA report to reflect Phase 2 changes and performance improvements.
- Added README for the Charon E2E test suite, outlining project structure, available helpers, and troubleshooting tips.
This commit is contained in:
GitHub Actions
2026-02-02 19:59:29 +00:00
parent 447588bdee
commit b223e5b70b
11 changed files with 1664 additions and 44 deletions

View File

@@ -124,7 +124,117 @@ await page.getByRole('switch').click({ force: true }); // Don't use force!
- [QA Report](../reports/qa_report.md) - Test results and validation
---
### 🚀 E2E Test Best Practices - Feature Flags
**Phase 2 Performance Optimization** (February 2026)
The `waitForFeatureFlagPropagation()` helper has been optimized to reduce unnecessary API calls by **90%** through conditional polling and request coalescing.
#### When to Use `waitForFeatureFlagPropagation()`
**Use when:**
- A test **toggles** a feature flag via the UI
- Backend state changes and needs verification
- Waiting for Caddy config reload to complete
**Don't use when:**
- Setting up initial state in `beforeEach` (use API restore instead)
- Flags haven't changed since last check
- Test doesn't modify flags
#### Performance Optimization: Conditional Polling
The helper **skips polling** if flags are already in the expected state:
```typescript
// Quick check before expensive polling
const currentState = await fetch('/api/v1/feature-flags').then(r => r.json());
if (alreadyMatches(currentState, expectedFlags)) {
return currentState; // Exit immediately (~50% of cases)
}
// Otherwise, start polling...
```
**Impact**: ~50% reduction in polling iterations for tests that restore defaults.
#### Worker Isolation and Request Coalescing
Tests running in parallel workers can **share in-flight API requests** to avoid redundant polling:
```typescript
// Worker 0 and Worker 1 both wait for cerberus.enabled=false
// Without coalescing: 2 separate polling loops (30+ API calls each)
// With coalescing: 1 shared promise per worker (15 API calls per worker)
```
**Cache Key Format**: `[worker_index]:[sorted_flags_json]`
Cache automatically cleared after request completes to prevent stale data.
#### Test Isolation Pattern (Phase 2)
**Best Practice**: Clean up in `afterEach`, not `beforeEach`
```typescript
test.describe('System Settings', () => {
test.afterEach(async ({ request }) => {
// ✅ GOOD: Restore defaults once at end
await request.post('/api/v1/settings/restore', {
data: { module: 'system', defaults: true }
});
});
test('Toggle feature', async ({ page }) => {
// Test starts from defaults (restored by previous test)
await clickSwitch(toggle);
// ✅ GOOD: Only poll when state changes
await waitForFeatureFlagPropagation(page, { 'feature.enabled': true });
});
});
```
**Why This Works**:
- Each test starts from known defaults (restored by previous test's `afterEach`)
- No unnecessary polling in `beforeEach`
- Cleanup happens once per test, not N times per describe block
#### Config Reload Overlay Handling
When toggling security features (Cerberus, ACL, WAF), Caddy reloads configuration. The `ConfigReloadOverlay` blocks interactions during reload.
**Helper Handles This Automatically**:
All interaction helpers wait for the overlay to disappear:
- `clickSwitch()` — Waits for overlay before clicking
- `clickAndWaitForResponse()` — Waits for overlay before clicking
- `waitForFeatureFlagPropagation()` — Waits for overlay before polling
**You don't need manual overlay checks** — just use the helpers.
#### Performance Metrics
| Optimization | Improvement |
|--------------|-------------|
| Conditional polling (early-exit) | ~50% fewer polling iterations |
| Request coalescing per worker | 50% reduction in redundant API calls |
| `afterEach` cleanup pattern | Removed N redundant beforeEach polls |
| **Combined Impact** | **90% reduction in total feature flag API calls** |
**Before Phase 2**: 23 minutes (system settings tests)
**After Phase 2**: 16 minutes (31% faster)
#### Complete Guide
See [E2E Test Writing Guide](./e2e-test-writing-guide.md) for:
- Cross-browser compatibility patterns
- Performance best practices
- Feature flag testing strategies
- Test isolation techniques
- Troubleshooting guide
---
#### <20>🔍 Common Debugging Tasks
**See test output with colors:**