Files
halobestie-clone/client_app/.maestro/flows/02_onboarding_verified.yaml
ramadhan sjamsani 770f61074c Phase 4 Stage 9: real-device sweep, 4 flows green + 2 shipping bugs fixed
Stage 9 sweep on Client_Phone AVD + physical mitra phone:
- 01_smoke 
- 02_onboarding_verified 
- 03_onboarding_anon 
- 04_payment_expired 
- 05_searching_timeout: in progress when wrap-up began
- 06–08: not yet attempted

## Real shipping bugs fixed (would have hit prod)

1. **Router carve-out too narrow** (router.dart). The AuthAnonymousData
   carve-out only protected /auth/display-name. On refreshListenable
   notify after loginAnonymous resolves, GoRouter re-evaluates the
   *bottom* of the navigation stack (/welcome — also an auth route),
   and the AuthAnonymousData fallback redirected to /home, tearing down
   the verif sheet before it could open. Loosened to allow any auth
   route under AuthAnonymousData.

2. **Phase 4 multi-screen payment never called startSearch**
   (searching_screen.dart). The legacy single-screen /payment did
   `pairing.startSearch()` on confirm. The Phase 4 flow is
   waiting → notif-gate → /chat/searching with no intermediate that
   owned the call — customers would land on the searching screen with
   no pairing in flight and never get matched. Added the kickoff to
   searching_screen::initState when state is PairingInitialData and
   paymentDraft.paymentId is set.

## Test infrastructure

- Self-contained Maestro flows 04 + 05 with inline verified-onboarding
  prelude, distinct test phones per flow, robust waits.
- 02 + 03 fixed: malformed `extendedWaitUntil` (visible: + notVisible:
  true → Maestro parsed as compound predicate); now use proper
  notVisible: block.
- New dev-only POST /internal/_test/force-confirm-payment so flows can
  advance past the waiting-payment screen without going through Xendit.
- /internal/_test/reset-phone now cascades through chat_messages →
  chat_sessions → payment_sessions → auth_sessions before deleting the
  customer row (FK 23503 was blocking re-runs).
- /internal/_test/force-pairing-timeout now accepts both
  `searching` and `pending_acceptance` states (mitra-online dev means
  the chat_session transitions through searching very quickly).
- mark_latest_payment_paid.js helper script for Stage 5+ flows.

## Maestro YAML quirks documented in flows

- text: matches anchored regex against the FULL content-desc — need .*
  wildcards for substring, e.g. "mulai.*Rp.*" not "mulai".
- The middot `·` and other special unicode break naive matching;
  always use .* anchors when the source string contains them.
- runFlow `when:` evaluates immediately; pair with waitForAnimationToEnd
  or a preceding extendedWaitUntil before branching.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:11:05 +08:00

117 lines
3.1 KiB
YAML

# Phase 4 Stage 2 — verified onboarding path:
# Splash → onboarding carousel → Welcome → Display Name → Verif Choice Sheet
# (verifikasi nomor HP) → ESP (pick a chip) → USP → Register → OTP (6-digit)
# → S6 paywall (when first-session-discount eligible) or duration picker.
#
# Run:
# maestro test client_app/.maestro/flows/02_onboarding_verified.yaml
#
# Pre-reqs: client_app debug APK installed, backend reachable at
# BACKEND_URL/BACKEND_INTERNAL_URL, NODE_ENV != 'production' (so the
# /internal/_test/peek-otp + /reset-phone routes register), and
# `anonymity_enabled = true` in the dev DB so the verif choice sheet shows.
#
# NOTE: numeric prefix conflicts with the existing
# 02_cta_disabled_when_no_mitra.yaml — Stage 9 will reorganize the flow
# directory once the full Phase 4 suite lands.
appId: com.halobestie.client.client_app
env:
TEST_PHONE: "+628155557701"
BACKEND_INTERNAL_URL: http://localhost:3001
---
- runScript:
file: ../scripts/reset_phone.js
env:
TEST_PHONE: ${TEST_PHONE}
BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}
- launchApp:
clearState: true
- extendedWaitUntil:
visible:
text: "Mulai"
timeout: 15000
- tapOn:
text: "Mulai"
retryTapIfNoChange: true
- extendedWaitUntil:
visible:
text: "Lanjut sebagai Tamu"
timeout: 10000
- tapOn:
text: "Lanjut sebagai Tamu"
retryTapIfNoChange: true
- extendedWaitUntil:
visible:
text: "Nama panggilan"
timeout: 10000
- tapOn:
text: "Nama panggilan"
- inputText: "Maestro"
- hideKeyboard
- tapOn:
text: "lanjut"
retryTapIfNoChange: true
# Verif Choice Sheet
- extendedWaitUntil:
visible:
text: "verifikasi nomor HP"
timeout: 10000
- tapOn:
text: "verifikasi nomor HP"
retryTapIfNoChange: true
# ESP screen — pick at least one chip then tap "lanjut"
- extendedWaitUntil:
visible:
text: "Lagi mikirin apa?"
timeout: 10000
- tapOn:
text: "Hubungan"
- tapOn:
text: "lanjut"
retryTapIfNoChange: true
# USP screen
- extendedWaitUntil:
visible:
text: "Sebelum mulai"
timeout: 10000
- tapOn:
text: "aku ngerti, lanjut"
retryTapIfNoChange: true
# Register (S3a) — phone entry
- extendedWaitUntil:
visible:
text: "Nomor HP"
timeout: 10000
- tapOn:
text: "Nomor HP"
- inputText: ${TEST_PHONE}
- hideKeyboard
- tapOn:
text: "kirim OTP"
retryTapIfNoChange: true
# OTP screen (S3b)
- extendedWaitUntil:
visible:
text: "Masukkan OTP"
timeout: 15000
- runScript:
file: ../scripts/peek_otp.js
env:
TEST_PHONE: ${TEST_PHONE}
BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}
- inputText: ${output.OTP}
# Verified path: first-session-discount eligible customers land on the S6
# paywall; non-eligibles land on the duration picker. Either is acceptable
# arrival for this flow.
- extendedWaitUntil:
notVisible:
text: "Masukkan OTP"
timeout: 15000
# Verified path: first-session-discount eligible customers land on the S6
# paywall; non-eligibles land on the duration picker. Accept either.
- extendedWaitUntil:
visible:
text: "harga sesi pertama"
timeout: 5000
optional: true