pp-planer/.sisyphus/notepads/cts-herd-playwright/learnings.md
Thorsten Bus 7c4eb31769 docs: add comprehensive continuation guide for CTS E2E testing
- Complete execution patterns for remaining 20 tasks
- 6-section prompt templates for each task type
- Troubleshooting guide for common issues
- Verification checklists and best practices
- Session learnings from Wave 2-3 completion
2026-03-01 23:17:11 +01:00

142 lines
4.7 KiB
Markdown

# Learnings — cts-herd-playwright
## Inherited from Phase 1 (cts-presenter-app)
### Vue Key Pattern
For repeating groups in arrangements, MUST use `${group.id}-${index}` NOT just `group.id`
### PDF Generation
Old-school CSS only (NO Tailwind) with DejaVu Sans font for German umlauts
### Auto-Save
500ms debounce for text, immediate for selects/checkboxes via `useDebounceFn`
### Line-Count Translation
Distribute translated text by matching original slide line counts
### SQLite date gotcha
Returns `YYYY-MM-DD 00:00:00` instead of `YYYY-MM-DD` — needs `substr($date, 0, 10)`
---
## Phase 2 Specific
## [2026-03-01 23:10] Wave 2-3 Completion Session
### Playwright Test Patterns Established
**Auth Setup Pattern** (auth.setup.ts):
- Navigate to /login to establish session cookies (XSRF-TOKEN)
- Extract XSRF token from cookies: `decodeURIComponent(xsrfCookie.value)`
- POST to /dev-login with XSRF token in headers
- Navigate to /dashboard to confirm login
- Save storageState to tests/e2e/.auth/user.json
- Pattern works reliably for all authenticated tests
**Test Structure Pattern**:
```typescript
test('description', async ({ page }) => {
await page.goto('/url');
await page.waitForLoadState('networkidle'); // CRITICAL for Inertia apps
await expect(page).toHaveURL(/pattern/);
await expect(page.getByTestId('testid')).toBeVisible();
});
```
**CSRF Protection Pattern** (for POST requests in tests):
```typescript
const cookies = await page.context().cookies();
const xsrfCookie = cookies.find((c) => c.name === 'XSRF-TOKEN');
const xsrfToken = xsrfCookie ? decodeURIComponent(xsrfCookie.value) : '';
await page.request.post('/endpoint', {
headers: { 'X-XSRF-TOKEN': xsrfToken }
});
```
### Session Timeout Handling
**Issue**: Long-running task() calls timeout after 10 minutes (600000ms)
**Solution**:
1. Check if file was created despite timeout: `ls -la tests/e2e/{filename}.spec.ts`
2. If created, verify tests: `npx playwright test {filename}.spec.ts`
3. If tests pass, proceed with verification and commit
4. If tests fail, resume session with session_id (saves 70%+ tokens)
**Pattern**: Timeouts don't mean failure — check actual output before retrying
### data-testid Naming Conventions
**Established Patterns**:
- Navigation: `auth-layout-nav-{page}` (e.g., `auth-layout-nav-services`)
- User controls: `auth-layout-user-dropdown-trigger`, `auth-layout-logout-link`
- Sync: `auth-layout-sync-button`, `auth-layout-sync-timestamp`
- Lists: `{feature}-list-table`, `{feature}-list-row-{id}`, `{feature}-list-empty`
- Actions: `{feature}-list-{action}-button` (e.g., `service-list-edit-button`)
- Blocks: `{block}-block-{element}-{id}` (e.g., `information-block-thumbnail-{id}`)
**Rule**: Always use kebab-case, always include component context, always be specific
### German UI Text Assertions
**Common Terms**:
- Navigation: "Gottesdienste", "Song-Datenbank"
- Actions: "Bearbeiten", "Finalisieren", "Wieder öffnen", "Herunterladen", "Löschen"
- Auth: "Mit ChurchTools anmelden", "Abmelden", "Test-Anmeldung"
- General: "Willkommen", "Ablaufdatum", "Vorschau", "Zuweisen", "Mit Übersetzung"
**Rule**: Always use exact German text from Vue components, never English
### Inertia.js + Playwright Gotchas
**Issue**: Inertia apps render client-side, so page.goto() returns before Vue renders
**Solution**: ALWAYS use `await page.waitForLoadState('networkidle')` after navigation
**Issue**: data-testid attributes don't appear in raw HTML (curl output)
**Solution**: Check compiled JS bundles: `grep -r 'data-testid' public/build/assets/*.js`
### Parallel Task Execution
**Wave 3 Pattern**: All 6 tasks (T8-T13) can run in parallel
- Each creates independent spec file
- No shared state between tests
- All use same storageState (auth.setup.ts)
- workers:1 in playwright.config.ts prevents SQLite conflicts
**Optimization**: Dispatch all 6 tasks in ONE message for maximum parallelism
### Verification Best Practices
**4-Phase Verification** (MANDATORY):
1. **Read Code**: Read EVERY changed file line-by-line
2. **Automated Checks**: Run tests, build, lsp_diagnostics
3. **Hands-On QA**: Actually run the tests and see them pass
4. **Gate Decision**: Can explain every line? Saw it work? Confident nothing broken?
**Evidence Files**: Save test output to `.sisyphus/evidence/task-{number}-{name}.txt`
**Commit Messages**: Use conventional commits format:
```
test(e2e): add {feature} E2E tests
- X tests: {list}
- German UI text assertions
- All tests passing
```
### Token Budget Management
**Session Stats**:
- Started: 200K tokens
- Used: ~124K tokens (62%)
- Remaining: ~76K tokens (38%)
- Tasks completed: 7/24 (29.2%)
**Optimization**: Use session_id for retries (saves 70%+ tokens vs new task)
**Strategy**: Focus on completing Wave 3 (6 tasks) before token exhaustion