Phase 4 Stage 10 Maestro: 09_chat_tab.yaml + seed-pending-payment endpoint

Closes the Stage 10 acceptance criterion §10.11 #13 (Maestro coverage).

- New dev-only `POST /internal/_test/seed-pending-payment` — inserts a
  payment_sessions row in `pending` status with expires_at 20m out, so
  the Pembayaran sub-tab has a deterministic row to render. Body
  accepts { phone, isExtension?, amount?, durationMinutes?, mode? }.
  Gated on NODE_ENV != 'production' like the other test routes.

- New Maestro helper script `seed_pending_payment.js` mirrors the
  existing seed_history_session pattern.

- New flow `09_chat_tab.yaml`:
    cold-start onboarding → home (returning view) →
    seed completed session + seed pending payment →
    tap "💬 chat" bottom-nav → lands on /chat/aktif via redirect →
    assert "aktif" / "pembayaran" / "selesai" pills + empty-state copy →
    tap pembayaran → assert "menunggu pembayaran sesi" + "bayar Rp..." →
    tap selesai → assert "X menit" duration row → tap row → assert
    "Transkrip Chat" appbar → back → still on /chat/selesai.

  Maestro parsed the YAML cleanly and started executing against the
  device; full run requires backend + online mitra in dev DB (same
  pre-reqs as flows 03/05/06/08).

- TECH_DEBT entry: Stage 10 retired the standalone bestie-history list
  screen, which means (a) the "curhat lagi" targeted-payment entry
  point has no UI affordance anywhere in the app — its plumbing in
  payment_notifier / payment_screen is now orphaned, and (b) the
  Stage 8 flow `08_returning_targeted.yaml` will fail at
  `assertVisible: "Riwayat Chat"` because it expects the deleted
  screen. Three fix paths listed in the entry for product to pick.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-12 20:24:50 +08:00
parent e3ea1d793e
commit 1908e98012
4 changed files with 328 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
// Seed a `pending` payment_sessions row for TEST_PHONE so the Pembayaran
// sub-tab has a row to render without walking the multi-screen S6 paywall →
// method-pick → duration-pick → method flow.
//
// Hits the dev-only /internal/_test/seed-pending-payment endpoint.
const phone = TEST_PHONE
const url = BACKEND_INTERNAL_URL || 'http://localhost:3001'
const body = {
phone,
isExtension: PENDING_KIND === 'extension',
amount: PENDING_AMOUNT ? Number(PENDING_AMOUNT) : 5000,
}
const resp = http.post(`${url}/internal/_test/seed-pending-payment`, {
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
})
if (resp.status !== 200) {
throw new Error(`seed-pending-payment failed (${resp.status}): ${resp.body}`)
}
const data = json(resp.body)
output.PAYMENT_ID = data.payment_id