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

72 KiB

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 (individual spec files verified)
  • 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

  • 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:

    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

  • 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:

    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

  • 3. Update UserFactory with OAuth Fields

    What to do:

    • Update database/factories/UserFactory.php to include all OAuth fields in definition():
      • churchtools_idfake()->unique()->numberBetween(1000, 99999)
      • avatarnull (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

  • 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:

    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

  • 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:

    External References:

    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)

  • 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

  • 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

  • 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.phpindex() 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

  • 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

  • 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
  • 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

  • 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

  • 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.phpfinalize(), 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)

  • 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

  • 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

  • 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
  • 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

  • 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

  • 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.

  • F1. Plan Compliance Auditoracle 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

  • F2. Code Quality Reviewunspecified-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

  • F3. Real Manual QAunspecified-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

  • F4. Scope Fidelity Checkdeep 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

# 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