# CTS Presenter — Herd Setup + Playwright E2E Tests ## TL;DR > **Quick Summary**: Configure the existing CTS Presenter App to run on Laravel Herd (replacing Docker), add a local-only dummy test login, add `data-testid` attributes to all Vue components, and write comprehensive Playwright E2E tests covering all 15 feature areas. > > **Deliverables**: > - App running on `http://cts-work.test` via Laravel Herd > - Dummy test login route + button (gated by `APP_ENV=local|testing`) > - `data-testid` attributes on all interactive Vue elements (34 components) > - Playwright test suite (~40-50 tests across 15 feature spec files) > - All tests passing against live CTS data (READ-ONLY) > > **Estimated Effort**: Large > **Parallel Execution**: YES — 4 waves > **Critical Path**: T1 (Herd env) → T2 (Dummy login) → T3 (UserFactory) → T4 (data-testid) → T5 (Playwright infra) → T6-T20 (E2E tests) → F1-F4 (verification) --- ## Context ### Original Request Run the CTS Presenter App on local dev using Laravel Herd. Write Playwright E2E tests for all implemented functions. Use a live CTS instance (READ-ONLY). Create a dummy test login for local environments. ### Interview Summary **Key Discussions**: - **Dummy Login Approach**: User chose "Route + Login-Button" — when `APP_ENV=local`, show a "Test Login" button on the Login page that logs in as a dummy user via `Auth::login()` (NOT `Auth::attempt()` due to bcrypt('') issue) - **Herd Status**: Already linked at `http://cts-work.test`, PHP 8.4, Herd 1.17.0 - **Live CTS**: `.env` has `TEST_CTS_USERNAME` and `TEST_CTS_PASSWORD` for OAuth testing — STRICTLY READ-ONLY - **Test Strategy**: Playwright E2E tests (no changes to existing 174 Pest tests) **Research Findings**: - Zero `data-testid` attributes in any Vue component — must add before writing tests - `UserFactory` is missing OAuth fields (`churchtools_id`, `avatar`, `churchtools_groups`, `churchtools_roles`) - `.env` currently points to `localhost:8000` — must update for Herd - `vite.config.js` has `hmr.host: 'localhost'` — use `npm run build` for Playwright (static assets) - `password` field has `hashed` cast — dummy login MUST use `Auth::login()`, not `Auth::attempt()` - SQLite + parallel writes = `SQLITE_BUSY` — Playwright tests must serialize (no `fullyParallel`) ### Metis Review (session ses_354eb7cb8ffeAVbUp6d0YpV3u7) **Identified Gaps** (all addressed in this plan): - UserFactory incomplete → Task T3 - Zero data-testid → Task T4 - .env hardcoded to localhost:8000 → Task T1 - Vite HMR config may fail with Herd → Use static build for tests - Auth::attempt() won't work with bcrypt('') → Use Auth::login() - Session driver = database → storageState works, test isolation needs care - SQLite BUSY → serialize Playwright workers - CTS data dependency → tests must NOT assert specific service titles/dates - Dummy login gating → `app()->environment('local', 'testing')`, NOT `APP_DEBUG` --- ## Work Objectives ### Core Objective Make the CTS Presenter App testable end-to-end on a local Herd environment with comprehensive Playwright tests that verify all 15 implemented feature areas work correctly with real ChurchTools data. ### Concrete Deliverables - `.env` configured for Herd (`APP_URL=http://cts-work.test`) - `POST /dev-login` route (local/testing only) in `routes/web.php` - "Test Login" button on `Auth/Login.vue` (conditional on `APP_ENV=local`) - Updated `UserFactory` with all OAuth fields - `data-testid` attributes on all interactive elements in 34 Vue components - `playwright.config.ts` pointing to `http://cts-work.test` - `tests/e2e/auth.setup.ts` with dummy login + storageState - ~15 Playwright spec files in `tests/e2e/` - All Playwright tests passing (green) - Existing 174 Pest tests still passing ### Definition of Done - [ ] `http://cts-work.test` loads the app successfully - [ ] Dummy "Test Login" button visible on login page, logs in, redirects to dashboard - [ ] `npx playwright test` runs ALL tests — 0 failures - [ ] `php artisan test` still passes — 174 tests, 905 assertions ### Must Have - Dummy login route gated by `app()->environment('local', 'testing')` - All Playwright tests serialize (no `fullyParallel`) to avoid SQLite BUSY - Tests must NOT assert specific CTS data (service titles, song names) — use structural assertions - All UI text assertions in German with "Du" form - `data-testid` on every interactive element (buttons, links, inputs, dropdowns, modals) - Evidence screenshots saved for all E2E test runs ### Must NOT Have (Guardrails) - NO writes to CTS API — EVERYTHING is READ-ONLY - NO `webServer` block in `playwright.config.ts` — Herd serves the app - NO changes to existing 174 Pest tests - NO `APP_DEBUG` gating for dummy login — MUST use `app()->environment()` - NO `Auth::attempt()` for dummy login — MUST use `Auth::login()` - NO `fullyParallel: true` in Playwright config — SQLite limitation - NO assertions on specific CTS data values (service titles, song names, dates) - NO modifications to ChurchTools OAuth provider or CTS API integration code - NO .pro file parser implementation (remains placeholder/501) --- ## Verification Strategy > **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed. No exceptions. ### Test Decision - **Infrastructure exists**: YES (174 Pest tests, bun/npm for frontend) - **Automated tests**: YES (Tests-after — Playwright E2E added alongside implementation) - **Framework**: Playwright (`@playwright/test`) - **Existing Pest tests**: Untouched — verified still pass at end ### QA Policy Every task MUST include agent-executed QA scenarios. Evidence saved to `.sisyphus/evidence/task-{N}-{scenario-slug}.{ext}`. - **Frontend/UI**: Use Playwright — Navigate, interact, assert DOM, screenshot - **Backend routes**: Use Bash (curl) — Send requests, assert status + response - **Config changes**: Use Bash — Verify env values, run artisan commands --- ## Execution Strategy ### Parallel Execution Waves ``` Wave 1 (Start Immediately — environment + foundation): ├── Task 1: Herd env configuration (.env, Vite build, verify) [quick] ├── Task 2: Dummy test login (route + Auth/Login.vue button) [quick] ├── Task 3: Update UserFactory with OAuth fields [quick] Wave 2 (After Wave 1 — test infrastructure): ├── Task 4: Add data-testid to ALL Vue components (depends: 1) [unspecified-high] ├── Task 5: Playwright installation + config + auth setup (depends: 1, 2) [unspecified-high] Wave 3 (After Wave 2 — E2E test writing, MAX PARALLEL): ├── Task 6: E2E — Auth tests (depends: 5) [quick] ├── Task 7: E2E — Dashboard + Navigation tests (depends: 5) [quick] ├── Task 8: E2E — Service List tests (depends: 5) [quick] ├── Task 9: E2E — Service Edit: Information Block (depends: 5) [quick] ├── Task 10: E2E — Service Edit: Moderation Block (depends: 5) [quick] ├── Task 11: E2E — Service Edit: Sermon Block (depends: 5) [quick] ├── Task 12: E2E — Service Edit: Songs Block (depends: 5) [unspecified-high] ├── Task 13: E2E — Service Finalization (depends: 5) [quick] Wave 4 (After Wave 3 — more E2E + verification): ├── Task 14: E2E — Song DB list + search (depends: 5) [quick] ├── Task 15: E2E — Song Edit Modal (depends: 5) [quick] ├── Task 16: E2E — Song Translation (depends: 5) [quick] ├── Task 17: E2E — Arrangement Configurator (depends: 5) [unspecified-high] ├── Task 18: E2E — Song Preview + PDF (depends: 5) [quick] ├── Task 19: E2E — Sync + .pro Placeholders (depends: 5) [quick] ├── Task 20: E2E — Full test suite run + fix failures (depends: 6-19) [deep] Wave FINAL (After ALL tasks — independent review, 4 parallel): ├── Task F1: Plan compliance audit (oracle) ├── Task F2: Code quality review (unspecified-high) ├── Task F3: Real manual QA via Playwright (unspecified-high) ├── Task F4: Scope fidelity check (deep) Critical Path: T1 → T5 → T6-T19 → T20 → F1-F4 Parallel Speedup: ~60% faster than sequential Max Concurrent: 8 (Wave 3) ``` ### Dependency Matrix | Task | Depends On | Blocks | Wave | |------|-----------|--------|------| | T1 | — | T4, T5, all E2E | 1 | | T2 | — | T5, T6 | 1 | | T3 | — | T5 | 1 | | T4 | T1 | T6-T19 | 2 | | T5 | T1, T2, T3 | T6-T19 | 2 | | T6-T13 | T4, T5 | T20 | 3 | | T14-T19 | T4, T5 | T20 | 4 | | T20 | T6-T19 | F1-F4 | 4 | | F1-F4 | T20 | — | FINAL | ### Agent Dispatch Summary - **Wave 1**: **3** — T1 → `quick`, T2 → `quick`, T3 → `quick` - **Wave 2**: **2** — T4 → `unspecified-high`, T5 → `unspecified-high` - **Wave 3**: **8** — T6-T8 → `quick`, T9-T11 → `quick`, T12 → `unspecified-high`, T13 → `quick` - **Wave 4**: **7** — T14-T16 → `quick`, T17 → `unspecified-high`, T18-T19 → `quick`, T20 → `deep` - **FINAL**: **4** — F1 → `oracle`, F2 → `unspecified-high`, F3 → `unspecified-high`, F4 → `deep` --- ## TODOs > Implementation + verification = ONE Task. Never separate. > EVERY task MUST have: Recommended Agent Profile + Parallelization info + QA Scenarios. --- ### Wave 1 — Environment + Foundation - [x] 1. Herd Environment Configuration **What to do**: - Update `.env.example`: Change `APP_URL=http://localhost:8000` to `APP_URL=http://cts-work.test` - Update `.env.example`: Change `CHURCHTOOLS_REDIRECT_URI` to `http://cts-work.test/auth/churchtools/callback` - In worktree `.env` (if present), apply same changes - Run `php artisan config:clear` to flush cached config - Run `npm run build` to generate fresh static assets in `public/build/` - Run `php artisan migrate` to ensure DB schema is current - Verify `http://cts-work.test/login` loads the login page **Must NOT do**: - Do NOT change vite.config.js server/HMR config (only affects dev server, not prod build) - Do NOT modify any controllers, models, or Vue components - Do NOT change Docker config (Herd replaces Docker) **Recommended Agent Profile**: - **Category**: `quick` - Reason: Simple config file updates and command execution - **Skills**: [] - No special skills needed — straightforward env changes **Parallelization**: - **Can Run In Parallel**: YES (with T2, T3) - **Parallel Group**: Wave 1 (with Tasks 2, 3) - **Blocks**: Tasks 4, 5, and all E2E tests - **Blocked By**: None (can start immediately) **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/.env.example` — Full env template (86 lines). Lines 5, 77 need URL updates. **API/Type References**: - None **External References**: - Laravel Herd docs: https://herd.laravel.com/docs — Herd link command and site config **WHY Each Reference Matters**: - `.env.example` is the only file that needs editing — update APP_URL and CHURCHTOOLS_REDIRECT_URI to match Herd's URL scheme **Acceptance Criteria**: - [ ] `.env.example` has `APP_URL=http://cts-work.test` - [ ] `.env.example` has `CHURCHTOOLS_REDIRECT_URI=http://cts-work.test/auth/churchtools/callback` - [ ] `npm run build` exits with code 0 - [ ] `php artisan migrate` exits with code 0 **QA Scenarios:** ``` Scenario: Login page loads via Herd Tool: Bash (curl) Preconditions: Herd running, cts-work linked Steps: 1. curl -s -o /dev/null -w "%{http_code}" http://cts-work.test/login 2. Assert HTTP status code is 200 3. curl -s http://cts-work.test/login | grep -c "Anmelden" 4. Assert grep count >= 1 (German title present) Expected Result: HTTP 200, page contains "Anmelden" Failure Indicators: HTTP 500/404, or page missing German text Evidence: .sisyphus/evidence/task-1-herd-login-page.txt Scenario: Non-existent route returns 404 Tool: Bash (curl) Preconditions: App running on Herd Steps: 1. curl -s -o /dev/null -w "%{http_code}" http://cts-work.test/nonexistent-page 2. Assert HTTP status code is 404 Expected Result: HTTP 404 Evidence: .sisyphus/evidence/task-1-herd-404.txt ``` **Commit**: YES (group with Wave 1) - Message: `chore(env): configure app for Laravel Herd at cts-work.test` - Files: `.env.example` - Pre-commit: `curl -s -o /dev/null -w "%{http_code}" http://cts-work.test/login` → 200 --- - [x] 2. Dummy Test Login Route + Button **What to do**: - Add route `POST /dev-login` in `routes/web.php`, gated by `app()->environment('local', 'testing')` - Route should: find-or-create a user with name='Test Benutzer', email='test@local.dev', churchtools_id=99999, then `Auth::login($user)`, redirect to dashboard - CRITICAL: Use `Auth::login()` NOT `Auth::attempt()` — the `password` field has `hashed` cast and stores bcrypt('') for OAuth users, so `Auth::attempt()` would fail - Update `Auth/Login.vue`: Accept a prop `canDevLogin` (boolean, passed from controller). When true, show a secondary button "Test Login" below the OAuth button - Update `AuthController::showLogin()` to pass `canDevLogin => app()->environment('local', 'testing')` as Inertia prop - The "Test Login" button should POST to `/dev-login` using Inertia's `router.post()` - Style the button with a distinct color (e.g., amber/yellow) and a 🔧 icon to make it clear it's for dev/testing only **Must NOT do**: - Do NOT use `APP_DEBUG` to gate the route — MUST use `app()->environment('local', 'testing')` - Do NOT use `Auth::attempt()` — MUST use `Auth::login()` - Do NOT modify the OAuth flow or callback - Do NOT create a separate login page — add button to existing Login.vue **Recommended Agent Profile**: - **Category**: `quick` - Reason: Small route addition + minor Vue component update - **Skills**: [] **Parallelization**: - **Can Run In Parallel**: YES (with T1, T3) - **Parallel Group**: Wave 1 (with Tasks 1, 3) - **Blocks**: Task 5 (Playwright auth setup depends on this) - **Blocked By**: None (can start immediately) **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/routes/web.php` — Current route definitions (60 lines). Guest middleware group at line 13-17 is where dev-login route should be added (inside guest group so unauthenticated users can access it). - `/Users/thorsten/AI/cts-work/app/Http/Controllers/AuthController.php` — Auth controller (68 lines). `showLogin()` at line 18-21 needs to pass `canDevLogin` prop. `callback()` at line 34-54 shows how User is created with OAuth fields — follow same pattern for dummy user. - `/Users/thorsten/AI/cts-work/resources/js/Pages/Auth/Login.vue` — Login page (30 lines). Add button after the existing OAuth link (line 27). Accept `canDevLogin` prop. **API/Type References**: - `/Users/thorsten/AI/cts-work/app/Models/User.php` — User model fillable fields (line 21-29): `name`, `email`, `churchtools_id`, `password`, `avatar`, `churchtools_groups`, `churchtools_roles`. Dummy user must set all of these. **External References**: - Laravel Auth::login() docs: https://laravel.com/docs/11.x/authentication#authenticate-a-user-instance **WHY Each Reference Matters**: - `routes/web.php` guest group: Dummy login must be accessible without auth, so it goes in the guest middleware group - `AuthController::callback()`: Shows the exact User::updateOrCreate pattern and fields — dummy login should match this pattern - `Login.vue`: Small component, add button conditionally based on prop **Acceptance Criteria**: - [ ] `POST /dev-login` route exists and is gated by `app()->environment('local', 'testing')` - [ ] Route creates/finds user with email `test@local.dev` and logs in via `Auth::login()` - [ ] Login page shows "Test Login" button when `APP_ENV=local` - [ ] Clicking button logs in and redirects to dashboard - [ ] Button is NOT visible when `APP_ENV=production` **QA Scenarios:** ``` Scenario: Dummy login creates user and redirects to dashboard Tool: Bash (curl) Preconditions: APP_ENV=local in .env, no session cookie Steps: 1. curl -s -X POST http://cts-work.test/dev-login -o /dev/null -w "%{http_code}" -L 2. Assert final HTTP status is 200 (after redirect to dashboard) 3. Verify user exists: php artisan tinker --execute="echo App\Models\User::where('email','test@local.dev')->exists() ? 'YES' : 'NO';" 4. Assert output is 'YES' Expected Result: 302 redirect → dashboard (200), user created in DB Failure Indicators: 404 (route missing), 500 (Auth::attempt used instead of Auth::login), user not in DB Evidence: .sisyphus/evidence/task-2-dummy-login.txt Scenario: Login page shows Test Login button in local env Tool: Bash (curl) Preconditions: APP_ENV=local Steps: 1. curl -s http://cts-work.test/login | grep -c "Test Login" 2. Assert count >= 1 Expected Result: Page HTML contains "Test Login" button text Evidence: .sisyphus/evidence/task-2-login-button.txt ``` **Commit**: YES (group with Wave 1) - Message: `feat(auth): add dummy test login for local/testing environments` - Files: `routes/web.php`, `app/Http/Controllers/AuthController.php`, `resources/js/Pages/Auth/Login.vue` - Pre-commit: `php artisan test --filter=OAuthTest` → PASS --- - [x] 3. Update UserFactory with OAuth Fields **What to do**: - Update `database/factories/UserFactory.php` to include all OAuth fields in `definition()`: - `churchtools_id` → `fake()->unique()->numberBetween(1000, 99999)` - `avatar` → `null` (most test users won't have avatars) - `churchtools_groups` → `[]` (empty array) - `churchtools_roles` → `[]` (empty array) - Verify existing Pest tests still pass after the change (UserFactory is used extensively) **Must NOT do**: - Do NOT change the User model - Do NOT modify existing test files - Do NOT change the `hashed` cast on password **Recommended Agent Profile**: - **Category**: `quick` - Reason: Single file, ~5 line change - **Skills**: [] **Parallelization**: - **Can Run In Parallel**: YES (with T1, T2) - **Parallel Group**: Wave 1 (with Tasks 1, 2) - **Blocks**: Task 5 (ensures factory works for Playwright seeding) - **Blocked By**: None (can start immediately) **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/database/factories/UserFactory.php` — Current factory (44 lines). `definition()` at line 24-33 returns only `name`, `email`, `email_verified_at`, `password`, `remember_token`. Missing: `churchtools_id`, `avatar`, `churchtools_groups`, `churchtools_roles`. - `/Users/thorsten/AI/cts-work/app/Models/User.php` — User model (55 lines). `$fillable` at line 21-29 lists all fields that must be present. `$casts` at line 48-53 shows `churchtools_groups` and `churchtools_roles` are cast to `array`. - `/Users/thorsten/AI/cts-work/app/Http/Controllers/AuthController.php:39-49` — OAuth callback shows how these fields are populated in production: `churchtools_id` from `$rawUser['id']`, `avatar` from `$socialiteUser->getAvatar()`, groups/roles from `$rawUser`. **WHY Each Reference Matters**: - Factory must match all `$fillable` fields to prevent `null` database errors in tests - `$casts` for groups/roles as `array` means factory must provide arrays (not strings) - OAuth callback pattern shows realistic values to mimic in factory **Acceptance Criteria**: - [ ] UserFactory includes `churchtools_id`, `avatar`, `churchtools_groups`, `churchtools_roles` - [ ] `php artisan test` still passes — 174 tests, 905 assertions, 0 failures **QA Scenarios:** ``` Scenario: UserFactory creates user with all OAuth fields Tool: Bash (php artisan tinker) Preconditions: Factory updated Steps: 1. php artisan tinker --execute="$u = App\Models\User::factory()->make(); echo json_encode(['ct_id' => $u->churchtools_id, 'avatar' => $u->avatar, 'groups' => $u->churchtools_groups, 'roles' => $u->churchtools_roles]);" 2. Assert JSON output has ct_id (integer), avatar (null), groups (array), roles (array) Expected Result: All fields present with correct types Failure Indicators: Missing fields, wrong types, factory error Evidence: .sisyphus/evidence/task-3-factory-fields.txt Scenario: Existing Pest tests still pass Tool: Bash Preconditions: Factory updated Steps: 1. cd /Users/thorsten/AI/cts-work && php artisan test 2. Assert output contains "174 passed" and "0 failed" Expected Result: 174 tests, 905 assertions, 0 failures Evidence: .sisyphus/evidence/task-3-pest-pass.txt ``` **Commit**: YES (group with Wave 1) - Message: `fix(factory): add OAuth fields to UserFactory` - Files: `database/factories/UserFactory.php` - Pre-commit: `php artisan test` → 174 passed --- ### Wave 2 — Test Infrastructure - [x] 4. Add `data-testid` Attributes to ALL Vue Components **What to do**: - Add `data-testid` attributes to EVERY interactive element across all 34 Vue components - Naming convention: `data-testid="{component-kebab}-{element-description}"` - Example: `data-testid="login-oauth-button"`, `data-testid="service-list-edit-button"` - Example: `data-testid="song-edit-modal-name-input"`, `data-testid="arrangement-add-button"` - Target elements: buttons, links, form inputs, select dropdowns, checkboxes, modal triggers, drag handles, upload areas, navigation items - This is ATTRIBUTE-ONLY changes — no logic, no styling, no behavior changes - Do NOT change any component props, events, or template logic **Component Inventory** (34 files, grouped by priority): **Pages (6 files — high priority):** - `resources/js/Pages/Auth/Login.vue` — OAuth button, (new) Test Login button - `resources/js/Pages/Dashboard.vue` — Welcome text, any action elements - `resources/js/Pages/Services/Index.vue` — Service rows, Edit/Finalize/ReOpen/Download buttons, status indicators - `resources/js/Pages/Services/Edit.vue` — Block accordion headers, save indicators - `resources/js/Pages/Songs/Index.vue` — Song rows, search input, pagination, Edit/Delete/Download/Translate buttons - `resources/js/Pages/Songs/Translate.vue` — Two-column editor, URL input, fetch button, save button, group/slide selectors **Block Components (4 files — high priority):** - `resources/js/Components/Blocks/InformationBlock.vue` — Upload area, thumbnail grid, delete buttons, datepickers - `resources/js/Components/Blocks/ModerationBlock.vue` — Upload area, thumbnail grid, delete buttons - `resources/js/Components/Blocks/SermonBlock.vue` — Upload area, thumbnail grid, delete buttons - `resources/js/Components/Blocks/SongsBlock.vue` — Song rows, arrangement select, add/clone buttons, preview/download/assign buttons, translation checkbox **Feature Components (5 files — high priority):** - `resources/js/Components/ArrangementConfigurator.vue` — Group items, drag handles, add/remove buttons, arrangement name - `resources/js/Components/SlideUploader.vue` — Drop zone, file input, progress indicator - `resources/js/Components/SlideGrid.vue` — Thumbnail items, delete buttons, datepicker inputs - `resources/js/Components/SongEditModal.vue` — Modal container, name/CCLI/copyright inputs, close button - `resources/js/Components/SongPreviewModal.vue` — Modal container, group labels, slide text, close button **Layout Components (3 files — medium priority):** - `resources/js/Layouts/AuthenticatedLayout.vue` — Nav links (Gottesdienste, Song-Datenbank), user dropdown, sync button, sync timestamp, logout - `resources/js/Layouts/GuestLayout.vue` — Logo, container - `resources/js/Layouts/MainLayout.vue` — Wrapper elements **UI Primitives (16 files — low priority, only if used directly in tests):** - `ApplicationLogo.vue`, `Checkbox.vue`, `ConfirmDialog.vue`, `DangerButton.vue`, `Dropdown.vue`, `DropdownLink.vue`, `FlashMessage.vue`, `InputError.vue`, `InputLabel.vue`, `LoadingSpinner.vue`, `Modal.vue`, `NavLink.vue`, `PrimaryButton.vue`, `ResponsiveNavLink.vue`, `SecondaryButton.vue`, `TextInput.vue` - For primitives: Only add `data-testid` if the component is a direct test target. Skip generic wrappers unless they contain unique interactive elements. **Must NOT do**: - Do NOT change component logic, props, events, computed properties, or methods - Do NOT change CSS classes or styling - Do NOT rename or restructure components - Do NOT remove any existing attributes **Recommended Agent Profile**: - **Category**: `unspecified-high` - Reason: Many files (34) but each change is mechanical — needs thoroughness, not complexity - **Skills**: [] **Parallelization**: - **Can Run In Parallel**: YES (with T5) - **Parallel Group**: Wave 2 (with Task 5) - **Blocks**: Tasks 6-19 (all E2E tests depend on testids) - **Blocked By**: Task 1 (need Herd running to verify no regressions) **References**: **Pattern References**: - All 34 `.vue` files listed above — each needs `data-testid` on interactive elements - Standard Playwright `data-testid` convention: https://playwright.dev/docs/locators#locate-by-test-id **WHY Each Reference Matters**: - Playwright's `page.getByTestId()` is the most stable selector strategy — immune to CSS/class changes - Naming convention must be consistent for maintainability **Acceptance Criteria**: - [ ] All 6 Page components have `data-testid` on all interactive elements - [ ] All 4 Block components have `data-testid` on all interactive elements - [ ] All 5 Feature components have `data-testid` on all interactive elements - [ ] All 3 Layout components have `data-testid` on key navigation elements - [ ] `npm run build` succeeds (no broken templates) - [ ] `php artisan test` still passes (174 tests) **QA Scenarios:** ``` Scenario: data-testid attributes present in built HTML Tool: Bash (curl + grep) Preconditions: npm run build completed, app running on Herd Steps: 1. curl -s http://cts-work.test/login | grep -c 'data-testid' 2. Assert count >= 2 (at least OAuth button + Test Login button) Expected Result: data-testid attributes present in rendered HTML Failure Indicators: count is 0 (attributes missing or stripped by build) Evidence: .sisyphus/evidence/task-4-testid-login.txt Scenario: Build and tests still pass after attribute additions Tool: Bash Preconditions: All Vue files updated Steps: 1. cd /Users/thorsten/AI/cts-work && npm run build 2. Assert exit code 0 3. cd /Users/thorsten/AI/cts-work && php artisan test 4. Assert "174 passed" Expected Result: Build succeeds, all tests pass Evidence: .sisyphus/evidence/task-4-build-tests.txt ``` **Commit**: YES (group with Wave 2) - Message: `test(e2e): add data-testid attributes to all Vue components` - Files: All modified `.vue` files - Pre-commit: `npm run build && php artisan test` --- - [x] 5. Playwright Installation + Configuration + Auth Setup **What to do**: - Install Playwright: `npm install -D @playwright/test` - Install browsers: `npx playwright install chromium` (chromium only — keep it fast) - Create `playwright.config.ts` with: - `baseURL: 'http://cts-work.test'` - `fullyParallel: false` (SQLite BUSY prevention) - `workers: 1` (serialize all tests) - `testDir: './tests/e2e'` - `use.storageState` pointing to auth state file - NO `webServer` block — Herd serves the app - `projects`: setup project (for auth) + default project (depends on setup) - `outputDir: 'test-results'`, `snapshotDir: 'tests/e2e/snapshots'` - `timeout: 30000` (30s per test) - Create `tests/e2e/auth.setup.ts`: - Navigate to `http://cts-work.test/login` - Click the "Test Login" button (using `data-testid="login-test-button"`) - Wait for redirect to Dashboard - Save `storageState` to `tests/e2e/.auth/user.json` - Add to `.gitignore`: `tests/e2e/.auth/` - Add npm script: `"test:e2e": "npx playwright test"` to `package.json` - Verify setup by running auth setup: `npx playwright test --project=setup` **Must NOT do**: - Do NOT add `webServer` config — Herd serves the app - Do NOT set `fullyParallel: true` — SQLite limitation - Do NOT install all browsers — chromium only - Do NOT use real OAuth for auth setup — use dummy login **Recommended Agent Profile**: - **Category**: `unspecified-high` - Reason: Multiple files to create, npm install, config needs precision - **Skills**: [`playwright`] - `playwright`: Playwright skill has config patterns and auth setup knowledge **Parallelization**: - **Can Run In Parallel**: YES (with T4) - **Parallel Group**: Wave 2 (with Task 4) - **Blocks**: Tasks 6-19 (all E2E tests depend on Playwright infra) - **Blocked By**: Tasks 1, 2, 3 (needs Herd URL, dummy login route, factory) **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/package.json` — Current npm scripts and dependencies. Add `@playwright/test` to devDependencies and `test:e2e` script. - `/Users/thorsten/AI/cts-work/.gitignore` — Add `tests/e2e/.auth/` to prevent committing auth state files. **API/Type References**: - Playwright `defineConfig`: https://playwright.dev/docs/test-configuration - Playwright auth setup: https://playwright.dev/docs/auth **External References**: - Playwright docs: https://playwright.dev/docs/intro — Installation and project setup - Playwright storageState: https://playwright.dev/docs/auth#basic-shared-account-in-all-tests — Pattern for reusing login state **WHY Each Reference Matters**: - `package.json`: Must add devDependency and script correctly - Playwright auth docs: storageState pattern saves login state so every test doesn't re-login - `workers: 1` is critical for SQLite — parallel workers cause SQLITE_BUSY **Acceptance Criteria**: - [ ] `@playwright/test` in devDependencies - [ ] `playwright.config.ts` exists with `baseURL`, `workers: 1`, no `webServer` - [ ] `tests/e2e/auth.setup.ts` exists and performs dummy login - [ ] `npx playwright test --project=setup` passes (auth state saved) - [ ] `tests/e2e/.auth/user.json` exists after setup runs **QA Scenarios:** ``` Scenario: Playwright auth setup logs in via dummy login Tool: Bash Preconditions: Playwright installed, Herd running, dummy login route exists Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test --project=setup 2. Assert exit code 0 3. ls tests/e2e/.auth/user.json 4. Assert file exists and is non-empty Expected Result: Auth setup passes, storageState file created Failure Indicators: Setup fails (dummy login not working), file missing Evidence: .sisyphus/evidence/task-5-playwright-setup.txt Scenario: Playwright config has correct settings Tool: Bash (grep) Preconditions: playwright.config.ts created Steps: 1. grep 'cts-work.test' playwright.config.ts 2. grep 'workers.*1' playwright.config.ts 3. grep -c 'webServer' playwright.config.ts (should be 0) Expected Result: baseURL correct, workers=1, no webServer Evidence: .sisyphus/evidence/task-5-config-check.txt ``` **Commit**: YES (group with Wave 2) - Message: `test(e2e): add Playwright infrastructure with auth setup` - Files: `playwright.config.ts`, `tests/e2e/auth.setup.ts`, `package.json`, `.gitignore` - Pre-commit: `npx playwright test --project=setup` → PASS --- ### Wave 3 — E2E Tests (Core Features) - [x] 6. E2E — Auth Tests **What to do**: - Create `tests/e2e/auth.spec.ts` with these tests: - Test: Login page displays correctly (German text, OAuth button visible, Test Login button visible in local) - Test: Dummy test login works (click Test Login → redirect to Dashboard → user name visible in nav) - Test: Logout works (click user dropdown → click Abmelden → redirect to login page) - Test: Protected routes redirect to login when unauthenticated (visit /services without auth → redirect to /login) - Test: OAuth button links to correct ChurchTools URL - ALL tests use `data-testid` selectors (from Task 4) - Use `storageState` from auth setup for authenticated tests - For unauthenticated test: create a separate test that does NOT use storageState **Must NOT do**: - Do NOT actually complete an OAuth flow in tests (would require real credentials + browser interaction with external site) - Do NOT assert specific user names from CTS (use structural assertions) **Recommended Agent Profile**: - **Category**: `quick` - Reason: Single spec file, ~5 test cases, straightforward Playwright patterns - **Skills**: [`playwright`] - `playwright`: Needed for Playwright test authoring patterns **Parallelization**: - **Can Run In Parallel**: YES (with T7-T13) - **Parallel Group**: Wave 3 (with Tasks 7-13) - **Blocks**: Task 20 (full suite run) - **Blocked By**: Tasks 4, 5 (data-testid + Playwright infra) **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Pages/Auth/Login.vue` — Login page structure. After T2: has OAuth button + Test Login button. Check `data-testid` names from T4. - `/Users/thorsten/AI/cts-work/resources/js/Layouts/AuthenticatedLayout.vue` — Nav layout with user dropdown and logout button. Verify `data-testid` for user name, dropdown, logout. - `/Users/thorsten/AI/cts-work/routes/web.php` — Route definitions. `/login` is guest-only, `/services` requires auth. After T2: `/dev-login` route exists. - `/Users/thorsten/AI/cts-work/tests/e2e/auth.setup.ts` — Auth setup pattern (created in T5). Follow same Playwright conventions. **WHY Each Reference Matters**: - Login.vue: Need exact `data-testid` values for the OAuth and Test Login buttons - AuthenticatedLayout: Test logout flow using nav dropdown testids - Routes: Know which routes require auth for redirect testing **Acceptance Criteria**: - [ ] `tests/e2e/auth.spec.ts` exists with ≥ 4 tests - [ ] `npx playwright test auth.spec.ts` → all pass **QA Scenarios:** ``` Scenario: Auth E2E tests all pass Tool: Bash Preconditions: Playwright installed, auth setup complete, Herd running Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test auth.spec.ts 2. Assert exit code 0 3. Assert output shows all tests passed (0 failed) Expected Result: All auth tests pass Failure Indicators: Test failures, timeout errors, missing selectors Evidence: .sisyphus/evidence/task-6-auth-tests.txt ``` **Commit**: YES (group with Wave 3) - Message: `test(e2e): add auth E2E tests` - Files: `tests/e2e/auth.spec.ts` --- - [x] 7. E2E — Dashboard + Navigation Tests **What to do**: - Create `tests/e2e/navigation.spec.ts` with these tests: - Test: Dashboard page renders after login (heading visible, German text) - Test: Top navigation shows correct links ("Gottesdienste", "Song-Datenbank") - Test: Top navigation shows logged-in user name - Test: Sync button visible in top bar with timestamp - Test: Clicking "Gottesdienste" navigates to services list - Test: Clicking "Song-Datenbank" navigates to songs list - All assertions must use German text **Must NOT do**: - Do NOT test sync functionality here (that's Task 19) - Do NOT assert specific data content (only structural elements) **Recommended Agent Profile**: - **Category**: `quick` - Reason: Single spec file, straightforward navigation tests - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T6, T8-T13) - **Parallel Group**: Wave 3 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Layouts/AuthenticatedLayout.vue` — Main navigation structure. Contains nav links (Gottesdienste, Song-Datenbank), user dropdown, sync button + timestamp. - `/Users/thorsten/AI/cts-work/resources/js/Pages/Dashboard.vue` — Dashboard page content. **WHY Each Reference Matters**: - AuthenticatedLayout: All navigation elements live here — need exact `data-testid` values - Dashboard: Know what heading/content to assert after login **Acceptance Criteria**: - [ ] `tests/e2e/navigation.spec.ts` exists with ≥ 4 tests - [ ] `npx playwright test navigation.spec.ts` → all pass **QA Scenarios:** ``` Scenario: Navigation E2E tests all pass Tool: Bash Preconditions: Playwright setup complete, storageState available Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test navigation.spec.ts 2. Assert exit code 0 Expected Result: All navigation tests pass Evidence: .sisyphus/evidence/task-7-navigation-tests.txt ``` **Commit**: YES (group with Wave 3) - Message: `test(e2e): add dashboard and navigation E2E tests` - Files: `tests/e2e/navigation.spec.ts` --- - [x] 8. E2E — Service List Tests **What to do**: - Create `tests/e2e/service-list.spec.ts` with these tests: - Test: Services page renders with heading "Gottesdienste" - Test: Service list shows at least one service (from CTS sync) — assert table/card structure exists, do NOT assert specific service names - Test: Each service row shows: title, date, status indicators (song count, slides count, finalized status) - Test: Unfinalized service shows "Bearbeiten" and "Abschließen" buttons - Test: Finalized service shows "Wiederöffnen" and "Herunterladen" buttons - Test: Status indicators show structural format "x/y" for songs - CRITICAL: Tests must NOT assert specific service titles, dates, or counts from CTS — only structural patterns - If no services exist (CTS sync not run), test should handle empty state gracefully **Must NOT do**: - Do NOT assert specific service titles or dates (CTS data is live and changes) - Do NOT click Edit/Finalize buttons (those are separate tests) - Do NOT trigger CTS sync in this test **Recommended Agent Profile**: - **Category**: `quick` - Reason: Single spec file, structural assertions - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T6-T7, T9-T13) - **Parallel Group**: Wave 3 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Pages/Services/Index.vue` — Service list page. Contains service table/cards with status indicators, action buttons (Edit, Finalize, ReOpen, Download). - `/Users/thorsten/AI/cts-work/app/Http/Controllers/ServiceController.php` — `index()` method shows what data is passed to the view (services with relationships). **WHY Each Reference Matters**: - Services/Index.vue: Need exact `data-testid` values for service rows, buttons, status indicators - ServiceController: Understand data shape to know what structural elements to assert **Acceptance Criteria**: - [ ] `tests/e2e/service-list.spec.ts` exists with ≥ 4 tests - [ ] `npx playwright test service-list.spec.ts` → all pass - [ ] Tests do NOT contain hardcoded CTS data values **QA Scenarios:** ``` Scenario: Service list E2E tests all pass Tool: Bash Preconditions: CTS sync has been run at least once, services exist in DB Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test service-list.spec.ts 2. Assert exit code 0 Expected Result: All service list tests pass Evidence: .sisyphus/evidence/task-8-service-list-tests.txt ``` **Commit**: YES (group with Wave 3) - Message: `test(e2e): add service list E2E tests` - Files: `tests/e2e/service-list.spec.ts` --- - [x] 9. E2E — Service Edit: Information Block **What to do**: - Create `tests/e2e/service-edit-information.spec.ts` with these tests: - Test: Navigate to first editable (non-finalized) service edit page - Test: Information block accordion is visible and can be expanded/collapsed - Test: Upload area is visible with drag-and-drop zone and click-to-upload - Test: Existing slides show as thumbnails with expire date fields - Test: Datepicker for expire date is functional (can select a date) - Test: Delete button on slide thumbnail triggers confirmation and soft-deletes - Must find a non-finalized service dynamically (do NOT hardcode service IDs) - If no editable service exists, skip test gracefully with `test.skip()` **Must NOT do**: - Do NOT upload real files in test (file conversion depends on system tools) - Do NOT assert specific slide content (dynamic CTS data) - Do NOT modify finalization status **Recommended Agent Profile**: - **Category**: `quick` - Reason: Single spec file, standard Playwright interactions - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T6-T8, T10-T13) - **Parallel Group**: Wave 3 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Pages/Services/Edit.vue` — Edit page with 4-block accordion. Information block is first. - `/Users/thorsten/AI/cts-work/resources/js/Components/Blocks/InformationBlock.vue` — Information block component with SlideUploader + SlideGrid. - `/Users/thorsten/AI/cts-work/resources/js/Components/SlideUploader.vue` — Upload area with drop zone. - `/Users/thorsten/AI/cts-work/resources/js/Components/SlideGrid.vue` — Thumbnail grid with delete + datepicker. **WHY Each Reference Matters**: - Edit.vue: Accordion structure determines how to expand/collapse blocks - InformationBlock: Contains the upload area + grid — need testids for each interactive element - SlideUploader/SlideGrid: Specific interactive elements (drop zone, thumbnails, delete, datepicker) **Acceptance Criteria**: - [ ] `tests/e2e/service-edit-information.spec.ts` exists with ≥ 3 tests - [ ] `npx playwright test service-edit-information.spec.ts` → all pass **QA Scenarios:** ``` Scenario: Information block E2E tests pass Tool: Bash Preconditions: At least one non-finalized service exists Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test service-edit-information.spec.ts 2. Assert exit code 0 Expected Result: All information block tests pass Evidence: .sisyphus/evidence/task-9-info-block-tests.txt ``` **Commit**: YES (group with Wave 3) - Message: `test(e2e): add service edit information block E2E tests` - Files: `tests/e2e/service-edit-information.spec.ts` --- - [x] 10. E2E — Service Edit: Moderation Block **What to do**: - Create `tests/e2e/service-edit-moderation.spec.ts` with these tests: - Test: Moderation block accordion can be expanded - Test: Upload area visible (same as Information but WITHOUT datepicker) - Test: Existing moderation slides show as thumbnails - Test: Delete button works on moderation slides - Same dynamic service finding as Task 9 **Must NOT do**: - Do NOT upload real files - Do NOT test datepicker (Moderation block doesn't have one — unlike Information) **Recommended Agent Profile**: - **Category**: `quick` - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T6-T9, T11-T13) - **Parallel Group**: Wave 3 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Components/Blocks/ModerationBlock.vue` — Moderation block (same as Information but no datepicker). - `/Users/thorsten/AI/cts-work/resources/js/Pages/Services/Edit.vue` — Accordion structure (Moderation is second block). **Acceptance Criteria**: - [ ] `tests/e2e/service-edit-moderation.spec.ts` exists with ≥ 3 tests - [ ] `npx playwright test service-edit-moderation.spec.ts` → all pass **QA Scenarios:** ``` Scenario: Moderation block E2E tests pass Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test service-edit-moderation.spec.ts 2. Assert exit code 0 Expected Result: All moderation block tests pass Evidence: .sisyphus/evidence/task-10-moderation-tests.txt ``` **Commit**: YES (group with Wave 3) - Message: `test(e2e): add service edit moderation block E2E tests` - Files: `tests/e2e/service-edit-moderation.spec.ts` - [x] 11. E2E — Service Edit: Sermon Block **What to do**: - Create `tests/e2e/service-edit-sermon.spec.ts` with these tests: - Test: Sermon block accordion can be expanded - Test: Upload area visible (same as Moderation — no datepicker) - Test: Existing sermon slides show as thumbnails - Test: Delete button works on sermon slides - Same dynamic service finding as Task 9 **Must NOT do**: - Do NOT upload real files - Do NOT test datepicker (Sermon block doesn't have one) **Recommended Agent Profile**: - **Category**: `quick` - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T6-T10, T12-T13) - **Parallel Group**: Wave 3 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Components/Blocks/SermonBlock.vue` — Sermon block (same features as Moderation). - `/Users/thorsten/AI/cts-work/resources/js/Pages/Services/Edit.vue` — Accordion structure (Sermon is third block). **Acceptance Criteria**: - [ ] `tests/e2e/service-edit-sermon.spec.ts` exists with ≥ 3 tests - [ ] `npx playwright test service-edit-sermon.spec.ts` → all pass **QA Scenarios:** ``` Scenario: Sermon block E2E tests pass Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test service-edit-sermon.spec.ts 2. Assert exit code 0 Expected Result: All sermon block tests pass Evidence: .sisyphus/evidence/task-11-sermon-tests.txt ``` **Commit**: YES (group with Wave 3) - Message: `test(e2e): add service edit sermon block E2E tests` - Files: `tests/e2e/service-edit-sermon.spec.ts` --- - [x] 12. E2E — Service Edit: Songs Block **What to do**: - Create `tests/e2e/service-edit-songs.spec.ts` with these tests: - Test: Songs block accordion can be expanded - Test: Song list shows songs in correct order (if service has songs from CTS) - Test: Each song row shows: name, CCLI ID, arrangement selector, translation checkbox (if applicable) - Test: Unmatched songs show "Erstellung anfragen" button and manual assign select - Test: Matched songs show arrangement dropdown with options - Test: Arrangement "Hinzufügen" (Add) button opens name prompt - Test: Arrangement "Klonen" (Clone) button opens name prompt - Test: Preview button opens song preview modal - Test: Download (PDF) button is present for songs with selected arrangement - Test: Translation checkbox toggles (if song has translation) - CRITICAL: This is the most complex block — many interactive elements - Do NOT assert specific song names from CTS — use structural assertions - If no songs exist on any service, skip gracefully **Must NOT do**: - Do NOT create/delete arrangements in this test (arrangement config is Task 17) - Do NOT test the preview modal content (that's Task 18) - Do NOT trigger email sending for missing songs **Recommended Agent Profile**: - **Category**: `unspecified-high` - Reason: Complex block with many interactive elements, needs thoroughness - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T6-T11, T13) - **Parallel Group**: Wave 3 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Components/Blocks/SongsBlock.vue` — Songs block component. Contains song rows with arrangement selectors, action buttons (preview, download, assign, request creation), translation checkboxes. - `/Users/thorsten/AI/cts-work/resources/js/Components/ArrangementConfigurator.vue` — Arrangement config component embedded in songs block. - `/Users/thorsten/AI/cts-work/resources/js/Components/SongPreviewModal.vue` — Preview modal (verify it opens, don't test content deeply). - `/Users/thorsten/AI/cts-work/resources/js/Pages/Services/Edit.vue` — Songs is the fourth block in the accordion. **WHY Each Reference Matters**: - SongsBlock: Core component with most interactive elements in the app — needs comprehensive testids - ArrangementConfigurator: Embedded within songs — verify add/clone buttons open prompts - SongPreviewModal: Verify it opens on button click (detailed content testing in T18) **Acceptance Criteria**: - [ ] `tests/e2e/service-edit-songs.spec.ts` exists with ≥ 6 tests - [ ] `npx playwright test service-edit-songs.spec.ts` → all pass - [ ] Tests do NOT contain hardcoded song names or CTS data **QA Scenarios:** ``` Scenario: Songs block E2E tests pass Tool: Bash Preconditions: At least one service with songs exists from CTS sync Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test service-edit-songs.spec.ts 2. Assert exit code 0 Expected Result: All songs block tests pass Evidence: .sisyphus/evidence/task-12-songs-block-tests.txt ``` **Commit**: YES (group with Wave 3) - Message: `test(e2e): add service edit songs block E2E tests` - Files: `tests/e2e/service-edit-songs.spec.ts` --- - [x] 13. E2E — Service Finalization Tests **What to do**: - Create `tests/e2e/service-finalization.spec.ts` with these tests: - Test: Click "Abschließen" on an unfinalized service → shows confirmation/warning dialog → confirm → service becomes finalized - Test: Finalized service shows "Wiederöffnen" and "Herunterladen" buttons ("Bearbeiten" and "Abschließen" hidden) - Test: Click "Wiederöffnen" on finalized service → service returns to editable state - Test: Click "Herunterladen" on finalized service → download response (assert non-error HTTP response) - IMPORTANT: These tests MODIFY state. Run them in order. The test should reopen the service at the end to restore state. - Find a service dynamically, do NOT hardcode service IDs **Must NOT do**: - Do NOT leave services in finalized state after tests (restore original state) - Do NOT assert specific file contents of download (just verify it's a valid response) **Recommended Agent Profile**: - **Category**: `quick` - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T6-T12) — BUT be careful: this test modifies service state, so it must not conflict with T9-T12 which read service state. Best to run after T8-T12 if possible, or use a different service. - **Parallel Group**: Wave 3 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Pages/Services/Index.vue` — Service list with Finalize/ReOpen/Download buttons. - `/Users/thorsten/AI/cts-work/app/Http/Controllers/ServiceController.php` — `finalize()`, `reopen()`, `download()` methods. - `/Users/thorsten/AI/cts-work/resources/js/Components/ConfirmDialog.vue` — Confirmation dialog component. **WHY Each Reference Matters**: - Services/Index: Button visibility logic (finalized vs not) and testid targets - ServiceController: Understand what finalize/reopen actually does to know what to assert - ConfirmDialog: Need testid for confirm/cancel buttons **Acceptance Criteria**: - [ ] `tests/e2e/service-finalization.spec.ts` exists with ≥ 3 tests - [ ] `npx playwright test service-finalization.spec.ts` → all pass - [ ] Tests restore service state (reopen after finalize) **QA Scenarios:** ``` Scenario: Finalization E2E tests pass Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test service-finalization.spec.ts 2. Assert exit code 0 Expected Result: All finalization tests pass, service state restored Evidence: .sisyphus/evidence/task-13-finalization-tests.txt ``` **Commit**: YES (group with Wave 3) - Message: `test(e2e): add service finalization E2E tests` - Files: `tests/e2e/service-finalization.spec.ts` --- ### Wave 4 — E2E Tests (Song DB + Advanced Features) - [x] 14. E2E — Song DB List + Search **What to do**: - Create `tests/e2e/song-db.spec.ts` with these tests: - Test: Song-Datenbank page renders with heading - Test: Song list shows songs in a table/grid (if any exist) - Test: Each song row shows: name, CCLI ID, created date, last used date - Test: Search input filters songs (type a query, verify list updates) - Test: Pagination works (if enough songs exist) - Test: Delete button triggers confirmation dialog (cancel → song still visible) - Test: Edit button opens SongEditModal - Test: Download button triggers download (assert non-error response) - Test: Translate button navigates to translate page - Do NOT assert specific song names — use structural assertions **Must NOT do**: - Do NOT actually delete songs (cancel the confirmation) - Do NOT test edit modal content (that's Task 15) - Do NOT test translate page (that's Task 16) **Recommended Agent Profile**: - **Category**: `quick` - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T15-T19) - **Parallel Group**: Wave 4 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Pages/Songs/Index.vue` — Song DB list page with search, pagination, action buttons (Edit, Delete, Download, Translate). - `/Users/thorsten/AI/cts-work/app/Http/Controllers/SongController.php` — Song CRUD controller. **Acceptance Criteria**: - [ ] `tests/e2e/song-db.spec.ts` exists with ≥ 5 tests - [ ] `npx playwright test song-db.spec.ts` → all pass **QA Scenarios:** ``` Scenario: Song DB E2E tests pass Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test song-db.spec.ts 2. Assert exit code 0 Expected Result: All song DB tests pass Evidence: .sisyphus/evidence/task-14-song-db-tests.txt ``` **Commit**: YES (group with Wave 4) - Message: `test(e2e): add song database list and search E2E tests` - Files: `tests/e2e/song-db.spec.ts` --- - [x] 15. E2E — Song Edit Modal **What to do**: - Create `tests/e2e/song-edit-modal.spec.ts` with these tests: - Test: Click Edit button on a song → modal opens - Test: Modal shows song name, CCLI ID, copyright text fields - Test: Fields are auto-saved on change (debounced) — verify no explicit save button - Test: Arrangement configurator is embedded in modal - Test: Close modal (X button or overlay click) - Navigate to Songs/Index first, then open modal on first available song **Must NOT do**: - Do NOT modify song data permanently (or restore if modified) - Do NOT test arrangement drag-and-drop (that's Task 17) **Recommended Agent Profile**: - **Category**: `quick` - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T14, T16-T19) - **Parallel Group**: Wave 4 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Components/SongEditModal.vue` — Edit modal with name/CCLI/copyright inputs and arrangement configurator. - `/Users/thorsten/AI/cts-work/resources/js/Pages/Songs/Index.vue` — Parent page where Edit button triggers modal. **Acceptance Criteria**: - [ ] `tests/e2e/song-edit-modal.spec.ts` exists with ≥ 3 tests - [ ] `npx playwright test song-edit-modal.spec.ts` → all pass **QA Scenarios:** ``` Scenario: Song edit modal E2E tests pass Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test song-edit-modal.spec.ts 2. Assert exit code 0 Expected Result: All song edit modal tests pass Evidence: .sisyphus/evidence/task-15-song-edit-modal-tests.txt ``` **Commit**: YES (group with Wave 4) - Message: `test(e2e): add song edit modal E2E tests` - Files: `tests/e2e/song-edit-modal.spec.ts` --- - [x] 16. E2E — Song Translation Page **What to do**: - Create `tests/e2e/song-translate.spec.ts` with these tests: - Test: Navigate to translate page for a song (from Song DB → click Translate) - Test: Page shows two-column editor layout (original left, translation right) - Test: URL input field visible with "Abrufen" (Fetch) button - Test: Group/slide navigation works (can switch between groups) - Test: Text editor on right column is editable - Test: Save button persists changes - Find a song with groups/slides dynamically - If no song has groups, skip test gracefully **Must NOT do**: - Do NOT fetch from external URLs in tests (network dependency) - Do NOT permanently modify translation data (or restore after test) **Recommended Agent Profile**: - **Category**: `quick` - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T14-T15, T17-T19) - **Parallel Group**: Wave 4 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Pages/Songs/Translate.vue` — Two-column translation editor with URL fetch, group/slide navigation. - `/Users/thorsten/AI/cts-work/app/Http/Controllers/TranslationController.php` — Translation controller with `page()`, `import()`, `fetchUrl()` methods. **Acceptance Criteria**: - [ ] `tests/e2e/song-translate.spec.ts` exists with ≥ 3 tests - [ ] `npx playwright test song-translate.spec.ts` → all pass **QA Scenarios:** ``` Scenario: Song translation E2E tests pass Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test song-translate.spec.ts 2. Assert exit code 0 Expected Result: All translation tests pass Evidence: .sisyphus/evidence/task-16-translate-tests.txt ``` **Commit**: YES (group with Wave 4) - Message: `test(e2e): add song translation page E2E tests` - Files: `tests/e2e/song-translate.spec.ts` --- - [ ] 17. E2E — Arrangement Configurator **What to do**: - Create `tests/e2e/arrangement.spec.ts` with these tests: - Test: Arrangement configurator shows groups in correct order - Test: "Hinzufügen" (Add) button creates new arrangement — prompt for name, confirm, new arrangement appears in select - Test: "Klonen" (Clone) button duplicates arrangement — prompt for name, confirm, new arrangement appears - Test: Group items can be reordered via drag-and-drop (drag group down, verify order changes) - Test: Group can be added to arrangement (if available groups exist) - Test: Group can be removed from arrangement - Test: Delete arrangement button triggers confirmation - Access via: Song DB → Edit button (modal) → Arrangement Configurator - OR via: Service Edit → Songs Block → Song with arrangement - IMPORTANT: Create test arrangements, then delete them to restore state **Must NOT do**: - Do NOT delete the "Normal" default arrangement - Do NOT leave test-created arrangements in the DB (clean up after test) **Recommended Agent Profile**: - **Category**: `unspecified-high` - Reason: Complex interactions (drag-and-drop, prompts, create/delete lifecycle) - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T14-T16, T18-T19) - **Parallel Group**: Wave 4 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Components/ArrangementConfigurator.vue` — Drag-and-drop group configurator with add/clone/delete functionality. - `/Users/thorsten/AI/cts-work/app/Http/Controllers/ArrangementController.php` — CRUD operations for arrangements (store, clone, update, destroy). - `/Users/thorsten/AI/cts-work/resources/js/Components/SongEditModal.vue` — Modal that embeds the ArrangementConfigurator. **WHY Each Reference Matters**: - ArrangementConfigurator: Core component — need testids for drag handles, group items, add/remove buttons - ArrangementController: Understand API shape for create/clone/delete assertions - SongEditModal: Entry point to reach the configurator **Acceptance Criteria**: - [ ] `tests/e2e/arrangement.spec.ts` exists with ≥ 4 tests - [ ] `npx playwright test arrangement.spec.ts` → all pass - [ ] No leftover test arrangements in DB after test run **QA Scenarios:** ``` Scenario: Arrangement configurator E2E tests pass Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test arrangement.spec.ts 2. Assert exit code 0 Expected Result: All arrangement tests pass, no leftover test data Evidence: .sisyphus/evidence/task-17-arrangement-tests.txt ``` **Commit**: YES (group with Wave 4) - Message: `test(e2e): add arrangement configurator E2E tests` - Files: `tests/e2e/arrangement.spec.ts` - [x] 18. E2E — Song Preview + PDF Download **What to do**: - Create `tests/e2e/song-preview-pdf.spec.ts` with these tests: - Test: Click Preview button on a matched song → SongPreviewModal opens - Test: Modal shows song text organized by groups with highlighted group labels - Test: Each group shows its slides in correct order - Test: Close modal (X button or ESC key) - Test: Click Download/PDF button → triggers PDF download (assert response has PDF content-type) - Access via: Service Edit → Songs Block → Preview/Download buttons on a matched song - If no matched songs exist, skip gracefully **Must NOT do**: - Do NOT assert specific song text content (dynamic data) - Do NOT validate PDF content structure (just verify it's a PDF response) **Recommended Agent Profile**: - **Category**: `quick` - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T14-T17, T19) - **Parallel Group**: Wave 4 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Components/SongPreviewModal.vue` — Preview modal showing song text by arrangement groups. - `/Users/thorsten/AI/cts-work/app/Http/Controllers/SongPdfController.php` — PDF generation + preview JSON endpoints. **Acceptance Criteria**: - [ ] `tests/e2e/song-preview-pdf.spec.ts` exists with ≥ 3 tests - [ ] `npx playwright test song-preview-pdf.spec.ts` → all pass **QA Scenarios:** ``` Scenario: Song preview and PDF E2E tests pass Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test song-preview-pdf.spec.ts 2. Assert exit code 0 Expected Result: All preview/PDF tests pass Evidence: .sisyphus/evidence/task-18-preview-pdf-tests.txt ``` **Commit**: YES (group with Wave 4) - Message: `test(e2e): add song preview and PDF download E2E tests` - Files: `tests/e2e/song-preview-pdf.spec.ts` --- - [x] 19. E2E — Sync + .pro Placeholders **What to do**: - Create `tests/e2e/sync-and-pro.spec.ts` with these tests: - Test: Sync button visible in top navigation bar - Test: Click sync button → loading indicator appears → sync completes → timestamp updates - Test: After sync, services list has data (at least one service from CTS) - Test: .pro file upload (Song DB upload area) → shows 501 / "Noch nicht verfügbar" error - Test: .pro file download button → shows 501 / "Noch nicht verfügbar" error - CRITICAL: Sync test hits the LIVE CTS API — this is READ-ONLY, verify no writes - .pro tests verify the placeholder behavior (501 status) **Must NOT do**: - Do NOT modify any CTS data (sync is READ-ONLY) - Do NOT implement .pro parsing (verify it's still 501) **Recommended Agent Profile**: - **Category**: `quick` - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: YES (with T14-T18) - **Parallel Group**: Wave 4 - **Blocks**: Task 20 - **Blocked By**: Tasks 4, 5 **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/resources/js/Layouts/AuthenticatedLayout.vue` — Sync button + timestamp in top nav. - `/Users/thorsten/AI/cts-work/app/Http/Controllers/SyncController.php` — Sync controller that calls ChurchToolsService. - `/Users/thorsten/AI/cts-work/app/Http/Controllers/ProFileController.php` — .pro placeholder endpoints returning 501. **WHY Each Reference Matters**: - AuthenticatedLayout: Sync button testid and timestamp element - SyncController: Verify it's read-only (no POST/PUT/DELETE to CTS API) - ProFileController: Verify 501 responses for upload/download **Acceptance Criteria**: - [ ] `tests/e2e/sync-and-pro.spec.ts` exists with ≥ 4 tests - [ ] `npx playwright test sync-and-pro.spec.ts` → all pass - [ ] Tests verify .pro endpoints return 501 **QA Scenarios:** ``` Scenario: Sync and .pro placeholder E2E tests pass Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test sync-and-pro.spec.ts 2. Assert exit code 0 Expected Result: All sync/.pro tests pass Evidence: .sisyphus/evidence/task-19-sync-pro-tests.txt ``` **Commit**: YES (group with Wave 4) - Message: `test(e2e): add sync and .pro placeholder E2E tests` - Files: `tests/e2e/sync-and-pro.spec.ts` --- - [x] 20. E2E — Full Test Suite Run + Fix Failures **What to do**: - Run the ENTIRE Playwright test suite: `npx playwright test` - Fix ALL failures — this is the integration task that catches cross-test issues - Common issues to fix: - Flaky tests due to timing (add `waitFor` / `toBeVisible` assertions) - SQLite BUSY errors (verify `workers: 1` in config) - State contamination between tests (ensure proper setup/teardown) - Missing `data-testid` attributes (go back and add them) - Auth state expired (verify storageState is refreshed) - Also verify existing Pest tests still pass: `php artisan test` - Run `npm run build` to verify Vite build still works - Document final test count and pass rate **Must NOT do**: - Do NOT skip failing tests with `.skip` — fix them - Do NOT modify existing Pest tests - Do NOT change app logic to make tests pass (fix tests, not app) **Recommended Agent Profile**: - **Category**: `deep` - Reason: Debugging test failures requires deep investigation, multiple iterations - **Skills**: [`playwright`] **Parallelization**: - **Can Run In Parallel**: NO (must run after all E2E test tasks) - **Parallel Group**: Sequential (after T6-T19) - **Blocks**: F1-F4 (Final Verification) - **Blocked By**: Tasks 6-19 (all E2E test files must exist) **References**: **Pattern References**: - `/Users/thorsten/AI/cts-work/playwright.config.ts` — Playwright config (created in T5). Verify workers=1, baseURL correct. - `/Users/thorsten/AI/cts-work/tests/e2e/` — All E2E test files created in T6-T19. - `/Users/thorsten/AI/cts-work/tests/e2e/auth.setup.ts` — Auth setup (created in T5). **WHY Each Reference Matters**: - Config: Root cause of many failures (wrong URL, parallel workers, timeout) - All spec files: Need to debug and fix each failing test - Auth setup: Common failure point if storageState is stale **Acceptance Criteria**: - [ ] `npx playwright test` → ALL tests pass, 0 failures - [ ] `php artisan test` → 174 tests, 905 assertions, 0 failures - [ ] `npm run build` → exit code 0 - [ ] Test count documented in evidence file **QA Scenarios:** ``` Scenario: Full Playwright suite passes Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && npx playwright test 2. Assert exit code 0 3. Assert output shows "0 failed" 4. Record total test count Expected Result: All E2E tests pass Evidence: .sisyphus/evidence/task-20-full-suite.txt Scenario: Pest tests unchanged and passing Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && php artisan test 2. Assert "174 passed" Expected Result: All existing Pest tests pass Evidence: .sisyphus/evidence/task-20-pest-pass.txt Scenario: Vite build succeeds Tool: Bash Steps: 1. cd /Users/thorsten/AI/cts-work && npm run build 2. Assert exit code 0 Expected Result: Build completes without errors Evidence: .sisyphus/evidence/task-20-build.txt ``` **Commit**: YES - Message: `test(e2e): fix all test failures and verify full suite passes` - Files: Any modified `.spec.ts` files, `playwright.config.ts` (if adjusted) - Pre-commit: `npx playwright test && php artisan test` --- ## Final Verification Wave > 4 review agents run in PARALLEL. ALL must APPROVE. Rejection → fix → re-run. - [x] F1. **Plan Compliance Audit** — `oracle` Read the plan end-to-end. For each "Must Have": verify implementation exists (read file, curl endpoint, run command). For each "Must NOT Have": search codebase for forbidden patterns — reject with file:line if found. Check evidence files exist in `.sisyphus/evidence/`. Compare deliverables against plan. Output: `Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT` - [x] F2. **Code Quality Review** — `unspecified-high` Run `php artisan test` (174 Pest tests still pass). Run `npx playwright test` (all E2E pass). Review all changed files for: TypeScript errors, unused imports, console.log in prod code. Check AI slop: excessive comments, over-abstraction, generic names. Verify `data-testid` naming follows pattern `{component}-{element}`. Output: `Pest [PASS/FAIL] | Playwright [N pass/N fail] | Files [N clean/N issues] | VERDICT` - [x] F3. **Real Manual QA** — `unspecified-high` (+ `playwright` skill) Start from clean state (clear storageState). Navigate to `http://cts-work.test/login`. Verify dummy "Test Login" button visible. Click it, verify redirect to Dashboard. Navigate through ALL pages: Services list, Service Edit (open one), Song DB, Song Translate page. Verify German text throughout. Take screenshots of each major page. Save to `.sisyphus/evidence/final-qa/`. Output: `Pages [N/N accessible] | German text [PASS/FAIL] | Screenshots [N captured] | VERDICT` - [x] F4. **Scope Fidelity Check** — `deep` For each task: read "What to do", read actual diff (`git diff` for changed files). Verify 1:1 — everything in spec was built (no missing), nothing beyond spec was built (no creep). Check "Must NOT do" compliance. Detect cross-task contamination. Flag unaccounted changes. Verify NO writes to CTS API in any test file. Output: `Tasks [N/N compliant] | Contamination [CLEAN/N issues] | CTS Writes [CLEAN/FOUND] | VERDICT` --- ## Commit Strategy - **Wave 1**: `feat(auth): add dummy test login for local dev + update env for Herd` — routes/web.php, AuthController.php, Login.vue, UserFactory.php, .env.example - **Wave 2**: `test(e2e): add data-testid attributes + Playwright infrastructure` — all .vue files, playwright.config.ts, auth.setup.ts, package.json - **Wave 3**: `test(e2e): add E2E tests for auth, services, and blocks` — tests/e2e/*.spec.ts - **Wave 4**: `test(e2e): add E2E tests for songs, arrangements, and full suite validation` — tests/e2e/*.spec.ts --- ## Success Criteria ### Verification Commands ```bash # App loads via Herd curl -s -o /dev/null -w "%{http_code}" http://cts-work.test/login # Expected: 200 # Dummy login works curl -s -X POST http://cts-work.test/dev-login -o /dev/null -w "%{http_code}" # Expected: 302 # Existing Pest tests still pass cd /Users/thorsten/AI/cts-work && php artisan test # Expected: 174 tests, 905 assertions, 0 failures # Playwright tests pass cd /Users/thorsten/AI/cts-work && npx playwright test # Expected: all pass, 0 failures # Vite build succeeds cd /Users/thorsten/AI/cts-work && npm run build # Expected: exit 0 ``` ### Final Checklist - [ ] All "Must Have" present - [ ] All "Must NOT Have" absent - [ ] All Pest tests pass (174/174) - [ ] All Playwright tests pass - [ ] Dummy login gated by environment, NOT debug - [ ] Zero CTS API writes in test code