# ts-customer-05-01 — When the customer app is backgrounded, the chat
# WebSocket must close so backend `sendMessage` falls back to FCM.
#
# Spec ref: requirement/flow_customer.mermaid.md §5 (Chat Room) +
# user-stated path:
#   1. WebSocket when app is foreground / WS connected.
#   2. FCM when app is background / WS disconnected.
#
# Fix under test: client_app/lib/main.dart `_AppState.didChangeAppLifecycleState`
# closes the chat WS on AppLifecycleState.paused / detached. Before the
# fix, Android kept the TCP socket alive after the Dart isolate paused, so
# backend's `socket.readyState === 1` check returned true and FCM never
# fired — the customer received no alert in background.
#
# Verification approach:
#   1. Drive customer through pairing → active chat (same harness as
#      ts-customer-04-04).
#   2. Assert customer-side WS is connected (backend state check).
#   3. Press HOME to background → wait briefly for the lifecycle observer
#      to fire `disconnect()` and the socket-close to round-trip.
#   4. Assert customer-side WS is now closed.
#   5. Send a message AS mitra via the real `sendMessage` code path and
#      assert it was delivered via FCM (recipient.customer WS was down at
#      dispatch time).
#
# Pre-reqs:
#   - Backend reachable; NODE_ENV != 'production'.
#   - ≥1 mitra online (the seeded mitra acts as the blast acceptor and the
#     subsequent message sender).
appId: com.halobestie.client.client_app
env:
  TEST_PHONE: "+6281234567890"
  BACKEND_INTERNAL_URL: http://localhost:3001
---
# ── Setup: pair customer with a mitra, land in active chat ──────────────
- runScript:
    file: ../scripts/reset_phone.js
    env:
      TEST_PHONE: ${TEST_PHONE}
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}
- launchApp:
    clearState: true
- runFlow: ../subflows/onboarding_returning_user.yaml

# Seed history so the SHomeReturning view renders the choice sheet (the
# seeded mitra also becomes the blast acceptor).
- runScript:
    file: ../scripts/seed_history_session.js
    env:
      TEST_PHONE: ${TEST_PHONE}
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}
- swipe:
    start: "50%, 30%"
    end: "50%, 80%"
- extendedWaitUntil:
    visible:
      text: "(?s).*curhatan sebelumnya.*"
    timeout: 10000

# "curhat sama bestie baru" → choice sheet → "bestie baru" → method-pick
- tapOn:
    text: "(?s).*curhat sama bestie baru.*"
    retryTapIfNoChange: true
- extendedWaitUntil:
    visible:
      text: "(?s).*mau curhat sama siapa.*"
    timeout: 5000
- tapOn: "(?s).*cari bestie baru yang siap dengerin.*"

# Payment chain → confirm → pairing accepted.
- extendedWaitUntil:
    visible:
      text: "(?s).*pilih cara curhat.*"
    timeout: 10000
- tapOn:
    text: "(?s).*tulis dan baca dengan tenang.*"
- extendedWaitUntil:
    visible:
      text: "(?s).*pilih durasi.*"
    timeout: 10000
- tapOn: "(?s).*5 menit.*"
- tapOn: "(?s).*bayar Rp.*"
- extendedWaitUntil:
    visible:
      text: "(?s).*cara bayar.*"
    timeout: 10000
- tapOn:
    text: "(?s).*bayar Rp.*"
    retryTapIfNoChange: true
- extendedWaitUntil:
    visible:
      text: "scan QRIS untuk bayar"
    timeout: 10000
- runScript:
    file: ../scripts/mark_latest_payment_paid.js
    env:
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}
- runFlow:
    when:
      visible:
        text: "(?s).*biar nggak ketinggalan.*"
    commands:
      - tapOn:
          text: "(?s).*nanti aja.*"
- extendedWaitUntil:
    visible:
      text: "(?s).*lagi nyari bestie.*"
    timeout: 20000
- runScript:
    file: ../scripts/mitra_accept_latest_internal.js
    env:
      MITRA_ID: ${output.MITRA_ID}
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}
- extendedWaitUntil:
    visible:
      text: "(?s).*online.*"
    timeout: 20000

# ── Assertion 1: WS is connected when chat screen is in foreground ──────
- runScript:
    file: ../scripts/assert_ws_state.js
    env:
      SESSION_ID: ${output.ACCEPTED_SESSION_ID}
      EXPECTED_CUSTOMER_CONNECTED: "true"
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}

# ── Background the app: customer's WS should close ──────────────────────
- pressKey: HOME

# Give the lifecycle observer + socket-close round-trip a moment. The
# disconnect() call posts a close frame; the backend reacts on
# `socket.on('close')`. ~1s is usually sufficient on the dev backend.
- waitForAnimationToEnd:
    timeout: 3000

# ── Assertion 2: backend now reports customer_connected=false ───────────
- runScript:
    file: ../scripts/assert_ws_state.js
    env:
      SESSION_ID: ${output.ACCEPTED_SESSION_ID}
      EXPECTED_CUSTOMER_CONNECTED: "false"
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}

# ── Assertion 3: a message sent now is delivered via FCM, not WebSocket ─
- runScript:
    file: ../scripts/assert_delivered_via.js
    env:
      SESSION_ID: ${output.ACCEPTED_SESSION_ID}
      CONTENT: "halo, balasan dari mitra sementara kamu di background"
      EXPECTED_DELIVERED_VIA: "fcm"
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}
