# Stage 3 acceptance: drive a payment session into the expired state and # verify the expired screen renders. # # Self-contained: clearState=true + verified-onboarding-to-home prelude + # payment shell exercise. # # Pre-req: # 1. At least one mitra is ONLINE (so the home CTA is enabled). # 2. anonymity_enabled=true on the dev backend (verif sheet + verified # branch). # 3. NODE_ENV != 'production' (so /internal/_test/* routes register). # # Run: # maestro test client_app/.maestro/flows/04_payment_expired.yaml appId: com.mybestie env: TEST_PHONE: "+628155557704" 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 # --- Onboarding prelude (verified path → /home) --- - extendedWaitUntil: visible: text: "Mulai" timeout: 15000 - tapOn: text: "Mulai" - waitForAnimationToEnd: timeout: 5000 # Onboarding finish path is async (writes SharedPreferences then go) — # give it a small grace then retry the tap if still on carousel. - runFlow: when: visible: text: "Mulai" commands: - tapOn: text: "Mulai" - extendedWaitUntil: visible: text: "Lanjut sebagai Tamu" timeout: 15000 - 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 - extendedWaitUntil: visible: text: "verifikasi nomor HP" timeout: 10000 - tapOn: text: "verifikasi nomor HP" retryTapIfNoChange: true - extendedWaitUntil: visible: text: "Lagi mikirin apa?" timeout: 10000 - tapOn: text: "lewati" - extendedWaitUntil: visible: text: "Sebelum mulai" timeout: 10000 - tapOn: text: "aku ngerti, lanjut" retryTapIfNoChange: true - extendedWaitUntil: visible: text: "Nomor HP" timeout: 10000 - tapOn: text: "Nomor HP" - inputText: ${TEST_PHONE} - hideKeyboard - tapOn: text: "kirim OTP" retryTapIfNoChange: true - 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} - extendedWaitUntil: notVisible: text: "Masukkan OTP" timeout: 15000 # Post-OTP: anon→verified upgrade routes to /auth/set-name (display name # entry). The page has the same "Nama panggilan" placeholder as # /auth/display-name. Wait for it, type, submit. - extendedWaitUntil: visible: text: "Nama panggilan" timeout: 15000 - tapOn: text: "Nama panggilan" - inputText: "Maestro" - hideKeyboard - tapOn: text: "Lanjut" retryTapIfNoChange: true # --- Now on /home — exercise the payment shell. --- - extendedWaitUntil: visible: text: "Mulai Curhat" timeout: 15000 # Tap CTA → /payment/entry routes to discount paywall (eligible) since # this is a fresh first-session-discount-eligible verified user. - tapOn: text: "Mulai Curhat" retryTapIfNoChange: true - extendedWaitUntil: visible: text: "SESI PERTAMA" timeout: 10000 # CTA copy on discount paywall is "mulai · Rp 2.000". Maestro text: is # anchored full-regex match — use .* wildcards. - tapOn: text: "mulai.*Rp.*" # On the cara-bayar screen, QRIS preselected. CTA copy: "bayar Rp 2.000". - extendedWaitUntil: visible: text: "cara bayar" timeout: 10000 - tapOn: text: "bayar Rp.*" retryTapIfNoChange: true # QR/waiting screen. Force-expire via dev endpoint. - extendedWaitUntil: visible: text: "scan QRIS untuk bayar" timeout: 10000 - runScript: file: ../scripts/force_expire_latest_payment.js env: BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL} # Poller picks up `expired` within ~3s and routes to the expired screen. - extendedWaitUntil: visible: text: "pembayaran kedaluwarsa" timeout: 10000 - assertVisible: "coba lagi.*" - assertVisible: "kembali ke home"