appId: cc.agentlabs.opencode name: Activation - positive path (consent -> connect -> send message) --- # Positive activation flow: first launch -> telemetry consent -> quick connect # to the mock opencode server (tests/fixtures/mock-opencode-server.ts, run # normally on the port below) -> connected indicator -> new session -> send a # message -> assert it sends (optimistic echo), WITHOUT waiting for the # SSE-streamed reply. See "Why no reply assertion" below. # # The CI job starts `node tests/fixtures/mock-opencode-server.ts --port 4096` # on the runner host BEFORE this flow runs. The Android emulator reaches the # runner host via the standard emulator alias 127.0.0.1. # # Why no reply assertion (issue #90 mode B — full investigation on the issue # and PR #102): the assistant reply is delivered over the app's SSE # connection (src/lib/sdk.ts global.events()), and in THIS harness # specifically (Android emulator + this Node mock server + adb-reverse port # forwarding) that connection reliably delivers exactly one chunk after # connecting and then nothing until the connection closes — confirmed across # four independently-implemented client transports (expo/fetch's # ReadableStream — the one this app ships with, a hand-rolled # XMLHttpRequest reader, react-native-sse, and react-native-fetch-api's # `reactNative: { textStreaming: true }`), and ruled out as an # adb-reverse/mock-flush problem by a raw-socket probe (a plain BSD-sockets # client with zero React Native involvement, run via `adb shell` through the # identical adb-reverse tunnel) that streamed every heartbeat incrementally # in real time. Padding every frame to ~4KB (ruling out a buffer-size # threshold) made no difference either. That isolates the stall to React # Native Android's OkHttp-backed networking layer buffering a long-lived # streaming response in this specific emulator/mock/adb-reverse combination — # not a defect in any particular client library, and not something # reproducible with a real opencode server on a real device/network (issue # #76's 65 affected users prove real SSE connections stream live agent # output in production; the bug they hit there was the 401-retry storm, not # a missing/undelivered reply). Asserting on the reply here would therefore # be asserting on a CI-harness limitation, not real app behavior — so this # flow verifies everything reliably observable (consent, connect, session # creation, message send) and stops short of the SSE round trip. If a real # fix for the underlying RN-Android streaming limitation ever lands (a native # SSE module, WebSocket transport, etc.), restore the extendedWaitUntil + # assertVisible block for "Hello from the mock opencode server" / # "chat-bubble-assistant" that used to follow chat-send-button here. - launchApp: clearState: true - takeScreenshot: positive-S1_launch_consent_modal - assertVisible: id: "telemetry-consent-card" - tapOn: id: "telemetry-decline-button" - assertVisible: text: "No Connection" - takeScreenshot: positive-S2_empty_state - tapOn: id: "add-connection-button" - assertVisible: id: "connect-ip-input" - takeScreenshot: positive-S3_add_connection_form - tapOn: id: "connect-ip-input" - inputText: "127.0.0.1:4096" - hideKeyboard - takeScreenshot: positive-S4_server_url_entered - tapOn: id: "connect-submit-button" # Quick Connect fires up to 3 sequential/parallel network calls before the # dot renders (testConnection's health(), then addConnection's parallel # project.current() + path.get()), and each individual fetch is capped by # src/lib/sdk.ts REQUEST_TIMEOUT_MS = 30_000. A 20s wait here raced that # 30s client-side timeout and flaked in CI (first real run, #82) even # though the mock server was up and reachable. 40s gives the app's own # timeout room to complete; this still asserts the real thing, just with a # wait that isn't shorter than the code path it's waiting on. - extendedWaitUntil: visible: id: "connection-status-dot" timeout: 40000 - assertVisible: id: "connection-status-dot" - takeScreenshot: positive-S5_connected - tapOn: id: "new-session-fab" - extendedWaitUntil: visible: id: "chat-message-input" timeout: 15000 - takeScreenshot: positive-S6_session_opened - tapOn: id: "chat-message-input" - inputText: "Hello from the activation e2e test" - hideKeyboard - takeScreenshot: positive-S7_message_typed - tapOn: id: "chat-send-button" # Confirms the optimistic local echo: the app shows the sent message # immediately (src/stores/sessions.ts), independent of the SSE round trip — # see the file-level comment above for why this flow stops here instead of # waiting on the streamed reply. Short wait for render, not a network call. - extendedWaitUntil: visible: id: "chat-bubble-user" timeout: 5000 - assertVisible: id: "chat-bubble-user" - assertVisible: text: "Hello from the activation e2e test" - takeScreenshot: positive-S8_message_sent