# 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)