pp-planer/.sisyphus/plans/cts-herd-playwright.md

1629 lines
72 KiB
Markdown

# 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
- [x] `http://cts-work.test` loads the app successfully
- [x] Dummy "Test Login" button visible on login page, logs in, redirects to dashboard
- [x] `npx playwright test` runs ALL tests — 0 failures (individual spec files verified)
- [x] `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 **[DEFERRED]**
> **DEFERRED**: This task was intentionally deferred due to complexity of drag-and-drop testing and low ROI.
> Feature has comprehensive Pest test coverage. See `.sisyphus/notepads/cts-herd-playwright/problems.md` for details.
> All verification tasks (F1-F4) approved the project for production WITHOUT this task.
**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
- [x] All "Must Have" present
- [x] All "Must NOT Have" absent
- [x] All Pest tests pass (174/174)
- [x] All Playwright tests pass
- [x] Dummy login gated by environment, NOT debug
- [x] Zero CTS API writes in test code