diff --git a/.sisyphus/CONTINUATION_GUIDE.md b/.sisyphus/CONTINUATION_GUIDE.md new file mode 100644 index 0000000..b4adfc8 --- /dev/null +++ b/.sisyphus/CONTINUATION_GUIDE.md @@ -0,0 +1,405 @@ +# CTS Herd + Playwright E2E Testing - Continuation Guide + +**Status**: 7/24 implementation tasks complete (29.2%) +**Worktree**: `/Users/thorsten/AI/cts-work` (branch: `cts-presenter-app`) +**Plan**: `.sisyphus/plans/cts-herd-playwright.md` + +--- + +## QUICK START + +```bash +# Verify environment +cd /Users/thorsten/AI/cts-work +curl -s -o /dev/null -w "%{http_code}" http://cts-work.test/login # Should return 200 +npx playwright test --list # Should show auth.spec.ts and navigation.spec.ts + +# Run existing tests +npx playwright test # Should pass 12 tests +php artisan test # Should pass 174 tests +npm run build # Should succeed +``` + +--- + +## COMPLETED WORK + +### Wave 1 — Environment + Foundation ✅ +- **T1**: Herd Environment Configuration + - `.env.example` updated for http://cts-work.test + - App running on Herd (PHP 8.4) + +- **T2**: Dummy Test Login Route + Button + - `POST /dev-login` route (gated by `app()->environment('local', 'testing')`) + - "Test-Anmeldung" button in Login.vue (amber styling) + - Uses `Auth::login()` (NOT `Auth::attempt()`) + +- **T3**: Update UserFactory with OAuth Fields + - Added `churchtools_id`, `avatar`, `churchtools_groups`, `churchtools_roles` + +### Wave 2 — Test Infrastructure ✅ +- **T4**: Add data-testid Attributes + - 98 attributes across 18 Vue components + - Naming: `{component-kebab}-{element-description}` + - Examples: `login-oauth-button`, `service-list-edit-button`, `auth-layout-nav-services` + +- **T5**: Playwright Installation + Configuration + - `playwright.config.ts` (baseURL, workers:1, no webServer) + - `tests/e2e/auth.setup.ts` (POST /dev-login with XSRF token) + - `tests/e2e/.auth/user.json` (storageState with session cookies) + +### Wave 3 — E2E Tests (Partial) ✅ +- **T6**: Auth Tests (`auth.spec.ts`) — 5 tests passing +- **T7**: Navigation Tests (`navigation.spec.ts`) — 9 tests passing + +--- + +## REMAINING TASKS + +### Wave 3 — E2E Tests (6 tasks) + +**Pattern**: Each task creates ONE spec file with ~5-8 tests. All use: +- Category: `quick` +- Skills: `["playwright"]` +- Auth: storageState (authenticated by default) +- German UI: All assertions use German text + +#### T8: Service List Tests (`service-list.spec.ts`) +**data-testid references**: +- `service-list-table` — Main table +- `service-list-row-{id}` — Each service row +- `service-list-edit-button` — Edit button +- `service-list-finalize-button` — Finalize button +- `service-list-reopen-button` — Reopen button +- `service-list-download-button` — Download button +- `service-list-empty` — Empty state message + +**Tests**: +1. Service list page renders with table +2. Service rows display with correct data structure +3. Edit button navigates to edit page +4. Finalize button shows confirmation dialog +5. Finalized services show reopen/download buttons +6. Empty state displays when no services + +**German text**: "Gottesdienste", "Bearbeiten", "Finalisieren", "Wieder öffnen", "Herunterladen" + +#### T9: Service Edit — Information Block (`service-edit-information.spec.ts`) +**data-testid references**: +- `information-block-upload-area` — Upload drop zone +- `information-block-thumbnail-{id}` — Thumbnail items +- `information-block-delete-{id}` — Delete buttons +- `information-block-datepicker-{id}` — Expire date pickers + +**Tests**: +1. Information block renders with upload area +2. Existing slides display as thumbnails +3. Delete button removes slide +4. Datepicker updates expire date +5. Upload area accepts file selection + +**German text**: "Informationen", "Ablaufdatum", "Löschen" + +#### T10: Service Edit — Moderation Block (`service-edit-moderation.spec.ts`) +Same pattern as T9 but for moderation block (no datepicker). + +#### T11: Service Edit — Sermon Block (`service-edit-sermon.spec.ts`) +Same pattern as T9 but for sermon block (no datepicker). + +#### T12: Service Edit — Songs Block (`service-edit-songs.spec.ts`) +**data-testid references**: +- `songs-block-song-row-{id}` — Song rows +- `songs-block-arrangement-select-{id}` — Arrangement dropdown +- `songs-block-add-arrangement-{id}` — Add arrangement button +- `songs-block-clone-arrangement-{id}` — Clone arrangement button +- `songs-block-preview-{id}` — Preview button +- `songs-block-download-{id}` — Download button +- `songs-block-assign-{id}` — Assign song button +- `songs-block-translation-checkbox-{id}` — Translation checkbox + +**Tests**: +1. Songs block displays all service songs +2. Matched songs show arrangement selector +3. Unmatched songs show assign button +4. Translation checkbox toggles translation +5. Preview button opens preview modal +6. Download button triggers PDF download + +**German text**: "Lieder", "Arrangement", "Vorschau", "Herunterladen", "Zuweisen", "Mit Übersetzung" + +#### T13: Service Finalization (`service-finalization.spec.ts`) +**data-testid references**: +- `service-list-finalize-button` — Finalize button +- `service-list-confirm-submit-button` — Confirm button +- `service-list-confirm-cancel-button` — Cancel button +- `service-list-reopen-button` — Reopen button + +**Tests**: +1. Finalize button shows confirmation dialog +2. Confirm button finalizes service +3. Cancel button closes dialog without finalizing +4. Finalized service shows reopen button +5. Reopen button reopens service + +**German text**: "Finalisieren", "Bestätigen", "Abbrechen", "Wieder öffnen" + +--- + +### Wave 4 — E2E Tests (7 tasks) + +#### T14-T19: Song DB Tests +Similar pattern to Wave 3. Each creates one spec file. + +#### T20: Full Test Suite Run + Fix Failures +Integration task — run all tests, fix any failures, ensure full suite passes. + +--- + +### Final Verification (4 tasks) + +#### F1: Plan Compliance Audit +- Agent: `oracle` +- Verify all plan requirements met +- Check all checkboxes marked correctly + +#### F2: Code Quality Review +- Agent: `unspecified-high` +- Review all test code for quality +- Check for anti-patterns, hardcoded values + +#### F3: Real Manual QA via Playwright +- Agent: `unspecified-high` + skill `playwright` +- Manually test the app via browser +- Verify all flows work end-to-end + +#### F4: Scope Fidelity Check +- Agent: `deep` +- Verify scope matches original requirements +- Check no scope creep occurred + +--- + +## EXECUTION PATTERN + +### For Each Task (T8-T19) + +1. **Delegate**: + ```typescript + task( + category="quick", + load_skills=["playwright"], + run_in_background=false, + description="Create {filename}.spec.ts with E2E tests", + prompt=`[6-section prompt with exact requirements]` + ) + ``` + +2. **Verify**: + ```bash + # Check file created + ls -la tests/e2e/{filename}.spec.ts + + # Run tests + npx playwright test {filename}.spec.ts + + # Verify all pass + # Expected: X passed, 0 failed + ``` + +3. **Mark Complete**: + ```typescript + Edit(".sisyphus/plans/cts-herd-playwright.md", [ + {op: "replace", pos: "{line}#{hash}", lines: "- [x] {task-number}. {task-name}"} + ]) + ``` + +4. **Commit**: + ```bash + git add tests/e2e/{filename}.spec.ts + git commit -m "test(e2e): add {description} + + - X tests: {test-list} + - German UI text assertions + - All tests passing" + ``` + +### Parallel Execution + +Wave 3 tasks (T8-T13) can run in parallel: +```typescript +// Dispatch all 6 simultaneously +task(category="quick", load_skills=["playwright"], ...) // T8 +task(category="quick", load_skills=["playwright"], ...) // T9 +task(category="quick", load_skills=["playwright"], ...) // T10 +task(category="quick", load_skills=["playwright"], ...) // T11 +task(category="quick", load_skills=["playwright"], ...) // T12 +task(category="quick", load_skills=["playwright"], ...) // T13 +``` + +--- + +## CRITICAL PATTERNS + +### 6-Section Prompt Template + +```markdown +## 1. TASK +Create `tests/e2e/{filename}.spec.ts` with E2E tests for {feature}. + +**Exact Task from Plan (Line {line})**: - [ ] {task-number}. {task-name} + +## 2. EXPECTED OUTCOME +- [ ] File created: `tests/e2e/{filename}.spec.ts` with ≥ {count} tests +- [ ] Tests cover: {list-of-scenarios} +- [ ] All tests use `data-testid` selectors from Task 4 +- [ ] All tests use `storageState` (authenticated) +- [ ] All assertions use German text +- [ ] Verification: `npx playwright test {filename}.spec.ts` → all pass + +## 3. REQUIRED TOOLS +- **Read**: Read {component-files} for context +- **Write**: Create `tests/e2e/{filename}.spec.ts` +- **Bash**: Run `npx playwright test {filename}.spec.ts` for verification + +## 4. MUST DO +- **Test 1**: {description} + ```typescript + test('{name}', async ({ page }) => { + await page.goto('{url}'); + await page.waitForLoadState('networkidle'); + await expect(page.getByTestId('{testid}')).toBeVisible(); + }); + ``` +- [Repeat for each test] +- **Use German Text**: {list-of-german-terms} +- **Save Evidence**: `.sisyphus/evidence/task-{number}-{name}.txt` +- **Append to Notepad**: `.sisyphus/notepads/cts-herd-playwright/learnings.md` + +## 5. MUST NOT DO +- **Do NOT** {anti-pattern-1} +- **Do NOT** {anti-pattern-2} + +## 6. CONTEXT +### Worktree +- **Path**: `/Users/thorsten/AI/cts-work` +- **App URL**: `http://cts-work.test` + +### Inherited Wisdom +- **Test Strategy**: No CTS data assertions, structural patterns only +- **German UI**: All assertions use German with "Du" form +- **data-testid naming**: `{component-kebab}-{element-description}` +- **Auth Setup**: storageState pattern from `tests/e2e/auth.setup.ts` +- **Page Load**: Use `page.waitForLoadState('networkidle')` for reliability + +### Dependencies +- ✅ T4: data-testid attributes in {component-list} +- ✅ T5: Playwright infrastructure +- ✅ T6-T7: Test patterns established + +### data-testid Reference +- `{testid-1}` — {description} +- `{testid-2}` — {description} + +### Verification Command +```bash +cd /Users/thorsten/AI/cts-work +npx playwright test {filename}.spec.ts +``` +``` + +### Test Structure Pattern + +```typescript +import { test, expect } from '@playwright/test'; + +// Test 1: {description} +test('{name}', async ({ page }) => { + await page.goto('{url}'); + await page.waitForLoadState('networkidle'); + + // Verify URL + await expect(page).toHaveURL(/{pattern}/); + + // Verify elements visible + await expect(page.getByTestId('{testid}')).toBeVisible(); + + // Verify German text + await expect(page.getByText('{german-text}')).toBeVisible(); +}); + +// Test 2: {description} +test('{name}', async ({ page }) => { + await page.goto('{url}'); + await page.waitForLoadState('networkidle'); + + // Interact with element + await page.getByTestId('{testid}').click(); + + // Verify result + await expect(page).toHaveURL(/{pattern}/); +}); +``` + +--- + +## TROUBLESHOOTING + +### Session Timeouts +If task times out after 10 minutes: +1. Check if file was created: `ls -la tests/e2e/{filename}.spec.ts` +2. If created, verify tests: `npx playwright test {filename}.spec.ts` +3. If tests pass, mark complete and commit +4. If tests fail, resume session: `task(session_id="{id}", prompt="fix: {error}")` + +### Test Failures +Common issues: +- **Element not found**: Check data-testid spelling in Vue component +- **Timeout**: Increase timeout or add `page.waitForLoadState('networkidle')` +- **Redirect to login**: storageState expired, re-run auth setup: `npx playwright test --project=setup` + +### SQLite BUSY Errors +If tests fail with SQLITE_BUSY: +- Verify `workers: 1` in playwright.config.ts +- Verify `fullyParallel: false` in playwright.config.ts +- Stop any running `php artisan serve` processes + +--- + +## VERIFICATION CHECKLIST + +Before marking task complete: +- [ ] File created in correct location +- [ ] All tests pass (`npx playwright test {filename}.spec.ts`) +- [ ] German text used in all assertions +- [ ] data-testid selectors used (no CSS selectors) +- [ ] Evidence file saved +- [ ] Notepad updated (if learnings discovered) +- [ ] Plan checkbox marked complete +- [ ] Changes committed with clear message + +--- + +## FINAL DELIVERABLES + +When all tasks complete: +- 15 E2E test spec files (~40-50 tests total) +- All tests passing +- All plan checkboxes marked complete +- All changes committed +- Final verification by 4 review agents +- Handoff document for production deployment + +--- + +## CONTACT POINTS + +**Plan File**: `.sisyphus/plans/cts-herd-playwright.md` (READ-ONLY for subagents) +**Notepad**: `.sisyphus/notepads/cts-herd-playwright/` (APPEND-ONLY) +**Evidence**: `.sisyphus/evidence/` (CREATE new files) +**Worktree**: `/Users/thorsten/AI/cts-work` (branch: `cts-presenter-app`) + +--- + +**Last Updated**: 2026-03-01 23:10 UTC +**Progress**: 7/24 tasks complete (29.2%) +**Next**: Complete Wave 3 tasks T8-T13 (6 tasks in parallel) diff --git a/.sisyphus/notepads/cts-herd-playwright/learnings.md b/.sisyphus/notepads/cts-herd-playwright/learnings.md new file mode 100644 index 0000000..2be343c --- /dev/null +++ b/.sisyphus/notepads/cts-herd-playwright/learnings.md @@ -0,0 +1,141 @@ +# 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