# ts-mitra-3-04 — §3 Session-expired chat chrome renders # Spec ref: requirement/flow_mitra.mermaid.md §3 + figma BestieChatV5 ended state (v5.jsx:294) # # Walks: # 1. Seed + sign in # 2. Fire blast → accept → /chat/session/:id (active chat opens) # 3. force-session-expires-at (seconds_from_now: -1) → backend marks # expires_at in the past, fires session_expired WS event # 4. Assert ended-state chrome: # - red "Durasi sesi habis. Tunggu klien perpanjang atau tutup obrolan." # banner under the AppBar # - input bar replaced with "Sesi sudah berakhir 💛" notice # - "SELESAI" label in the timer pill (and value "00:00") # 5. Screenshot for design review # # Note: the subtitle in the AppBar also flips to "sesi berakhir" via the # `sessionExpired` flag on `MitraChatConnectedData`; we assert on that too # because it's the most stable marker that the WS frame landed. appId: com.mybestie.mitra env: TEST_PHONE: "+628200000904" MITRA_DISPLAY_NAME: "Maestro Ended" BACKEND_INTERNAL_URL: http://localhost:3001 --- - runScript: file: ../scripts/seed_mitra.js env: TEST_PHONE: ${TEST_PHONE} MITRA_DISPLAY_NAME: ${MITRA_DISPLAY_NAME} IS_ACTIVE: "true" BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL} - runScript: file: ../scripts/reset_phone.js env: TEST_PHONE: ${TEST_PHONE} BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL} - launchApp: clearState: true - extendedWaitUntil: visible: text: "(?s).*Halo Mitra Bestie.*" timeout: 10000 - tapOn: point: "50%, 53%" - inputText: "8200000904" - tapOn: "(?s).*kirim kode.*" - extendedWaitUntil: visible: text: "(?s).*masukin 6 digit kode.*" timeout: 10000 - runScript: file: ../scripts/peek_otp.js env: TEST_PHONE: ${TEST_PHONE} BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL} - inputText: ${output.OTP} - extendedWaitUntil: visible: text: "(?s).*Kamu lagi (ONLINE|OFFLINE).*" timeout: 15000 # Conditional online toggle. Fresh mitra defaults to OFFLINE (per DB schema # default for mitra_online_status.is_online). If a prior test run force-onlined # this row already, skip the CTA. Otherwise tap "Nyalain Status (Online)" so # downstream flow has the tile grid + is blast-eligible. - runFlow: when: visible: text: "(?s).*Kamu lagi OFFLINE.*" commands: - tapOn: "(?s).*Nyalain Status.*" - extendedWaitUntil: visible: text: "(?s).*Kamu lagi ONLINE.*" timeout: 10000 - waitForAnimationToEnd: timeout: 3000 - runScript: ../scripts/customer_blast_now.js - extendedWaitUntil: visible: text: "(?s).*Curhat Baru!.*" timeout: 10000 - tapOn: "(?s).*Terima.*" # Confirm we landed in the active chat first. - extendedWaitUntil: visible: text: "(?s).*sesi aktif · Chat.*" timeout: 15000 # Force-expire the active session. seconds_from_now defaults to -1 (already # in the past) so the backend fires session_expired immediately. The chat # screen's WS listener flips `sessionExpired = true` → ended chrome renders. - runScript: file: ../scripts/force_session_expires_at.js env: BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL} # Ended chrome. - extendedWaitUntil: visible: text: "(?s).*Durasi sesi habis.*" timeout: 15000 - assertVisible: text: "(?s).*Tunggu klien perpanjang atau tutup obrolan.*" - assertVisible: text: "(?s).*Sesi sudah berakhir.*" - assertVisible: text: "(?s).*SELESAI.*" - assertVisible: text: "(?s).*00:00.*" - assertVisible: text: "(?s).*sesi berakhir.*" - takeScreenshot: ts-mitra-3-04-chat-ended