Files
halobestie-clone/control_center/tests/e2e/README.md
ramadhan sjamsani d09e50af55 Phase 3.7: paid pairing flow + returning chat + extension flip
- Backend: payment_sessions + pairing_failures tables; payment.service.js
  and pairing-failure.service.js (new); rewritten pairing.service.js
  (payment-gated blast + targeted "Curhat lagi" + cancel + fallback);
  rewritten extension.service.js (data-driven auto-approve with offline
  safeguard, charge-at-approval); pricing.service.js (extension tiers
  without free trial); mitra-status.service.js (countAvailableMitras
  cached path); 60s sweeper for stale payment sessions
- Backend routes: client.payment.routes, client.mitra-availability.routes,
  internal/failed-pairings.routes; client.chat.routes rewritten for
  payment-gated start + /returning + /cancel + /fallback-to-blast;
  internal/config.routes adds 4 new keys with Valkey invalidate publish
- client_app: mitra-availability poll, payment screen + notifier, pairing
  notifier rewrite (PairingTargetedWaiting + PairingFailed states),
  targeted-waiting overlay + bestie-unavailable dialog, "Curhat lagi"
  CTA, failed-pairing terminal, extension via payment-session
- mitra_app: PairingRequestType enum, returning-chat 20s countdown
  auto-dismiss, extension card "otomatis disetujui" copy
- control_center: 4 new config rows in Settings, Failed Pairings page
  (filter + paginate + action menu), sidebar + route registered
- Test infrastructure: Vitest backend (7/7 pass), Playwright CC (4/4
  pass), Maestro mobile scaffold (CLI install pending)
- Bugs found via Playwright + fixed: LoginPage labels not associated
  with inputs (a11y); backend internal CORS missing PATCH/PUT/DELETE
  in allow-methods (silent settings breakage in browsers since Stage 4)
- Docs: phase3.7.md PRD, phase3.7-plan.md, phase3.7-questions.md (Q&A),
  phase3.7-testing.md (E2E checklist), phase3.7-test-run-2026-05-03.md
  (today's run results)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:02:49 +08:00

4.3 KiB

Control Center — Playwright E2E Tests

End-to-end tests for the Halo Bestie control center. Tests run a real browser against a running CC dev server, which talks to a running internal backend.

Install

From control_center/:

npm install
npx playwright install chromium

To add Firefox or WebKit later:

npx playwright install firefox webkit

…then add a project entry in playwright.config.js.

Configure

Copy the example env file and fill in your local values:

cp .env.example .env

Required env vars (all have sensible defaults for localhost):

Var Default Purpose
CC_BASE_URL http://localhost:5173 Where the CC SPA is reachable
BACKEND_INTERNAL_URL http://localhost:3001 Where the internal Fastify listener is
CC_TEST_EMAIL placeholder Operator account used by the suite
CC_TEST_PASSWORD placeholder Operator account password

The seeded admin (admin@halobestie.com / ChangeMe123! from backend/src/db/seed.js) works as the test operator for local dev. For shared/CI environments, provision a dedicated test user.

playwright.config.js automatically loads .env via dotenv.config(). CLI env vars still take precedence — useful when running one-off:

CC_BASE_URL=http://192.168.1.10:5173 npm run test:e2e

Run on the same machine

  1. Start the backend (public + internal listeners):

    cd backend && npm run dev
    
  2. Start the CC dev server (separate shell):

    cd control_center && npm run dev
    
  3. Run the suite (separate shell):

    cd control_center && npm run test:e2e
    

Run on a different machine

The Playwright config does NOT auto-start the CC dev server — that's deliberate so the same suite can target a remote dev server. Point the env vars at it:

CC_BASE_URL=http://192.168.88.247:5173 \
BACKEND_INTERNAL_URL=http://192.168.88.247:3001 \
CC_TEST_EMAIL=test-operator@example.com \
CC_TEST_PASSWORD=changeme \
npm run test:e2e

The CC dev server must be reachable on the network — by default Vite binds to localhost. To make it listen on all interfaces, start it with:

npm run dev -- --host

…or set server.host: true in vite.config.js.

Run a single test

# One file
npm run test:e2e -- tests/e2e/settings.spec.js

# Tests matching a pattern (across all files)
npm run test:e2e -- --grep "payment session timeout"

Debug

Three options, in order of how heavy they are:

# 1. UI mode — watches files, lets you re-run individual tests, inspect DOM,
#    and see the timeline. Best for iterating on a flaky test.
npm run test:e2e:ui

# 2. Headed mode — same suite, but with a visible browser window.
npm run test:e2e:headed

# 3. Inspector — pauses execution, opens devtools, lets you step through.
npm run test:e2e:debug

To record video for every test:

RECORD=1 npm run test:e2e

Failure artifacts (screenshots, traces, videos) land in test-results/. Open the HTML report with:

npx playwright show-report

Adding a new test

  1. Create tests/e2e/<feature>.spec.js.

  2. Import the helpers:

    import { test, expect } from '@playwright/test'
    import { loginAsOperator } from './helpers/auth.js'
    import { backendRequest } from './helpers/backend-api.js'
    
  3. Use loginAsOperator(page) in beforeEach for any test that hits a protected route.

  4. Use backendRequest('/internal/...') for fixture setup/teardown so the test body stays focused on the UI behavior.

  5. Look at settings.spec.js and failed-pairings.spec.js for the patterns already in use (snapshot → mutate → reload → restore).

Files

tests/e2e/
├── README.md                       (you are here)
├── helpers/
│   ├── auth.js                     loginAsOperator() — UI login flow
│   └── backend-api.js              fetch wrapper + fixture helpers
├── settings.spec.js                Phase 3.7 config rows (2 cases)
└── failed-pairings.spec.js         Failed Pairings page (2 cases)