appId: cc.agentlabs.opencode name: Activation - negative path (connect-time 401 must surface a visible error) --- # Negative activation flow — regression test for the GitHub issue #76 failure # class: a connect-time 401 from the server must produce a visible, actionable # error, never a silent failure. # # Quick Connect (app/connection/add.tsx handleQuickConnect) calls # testConnection() -> client.global.health() BEFORE saving the connection. # When that call fails (any thrown error, including a 401 API error), the # screen runs probeConnection() and shows a native Alert titled # "Connection Failed" with the underlying error text — this is the CURRENT, # already-correct behavior we are locking in with this test. # # The alert body DOES contain the real error (confirmed via a temporary # logcat probe: it interpolates testConnection()'s caught error message, # `API Error: 401 - {"error":"Unauthorized",...}` — sdk.ts's # apiErrorFor(401, ...), see src/lib/api-error.test.ts for the shape), but a # native Android AlertDialog's message body isn't exposed to Maestro's # accessibility-tree text matching the way its title is — only "Connection # Failed" (the title) is ever visible to assertVisible, not any body text # ("401" and "Unauthorized" both fail here despite being on-screen). So this # asserts the title plus both action button labels (src/lib/i18n/en.json # common.ok / common.shareReport) — proving the alert rendered with its full # actionable UI (dismiss + share-report), which is what issue #76 actually # needs: a visible, actionable error, never a silent failure. # # Known gap (see report): Advanced-mode "Save Connection" (handleAdvancedSave) # does NOT call testConnection() at all — it saves the connection and # navigates back regardless of server reachability, so a 401 there is # currently silent. That gap is not covered by this flow (Quick Connect is the # only entry point that already does the right thing) — flagged in the E2E # report as follow-up work, not silently fixed here. # # The CI job starts `node tests/fixtures/mock-opencode-server.ts --port 4097 # --fail-auth` on the runner host BEFORE this flow runs, so every request the # app makes to it (including /global/health) returns HTTP 401. - launchApp: clearState: true - assertVisible: id: "telemetry-consent-card" - tapOn: id: "telemetry-decline-button" - takeScreenshot: negative-S1_consent_dismissed - assertVisible: text: "No Connection" - tapOn: id: "add-connection-button" - takeScreenshot: negative-S2_add_connection_form - tapOn: id: "connect-ip-input" - inputText: "127.0.0.1:4097" - hideKeyboard - takeScreenshot: negative-S3_401_server_url_entered - tapOn: id: "connect-submit-button" # Matches the 40s margin used for the positive flow's connection-status-dot # wait (src/lib/sdk.ts REQUEST_TIMEOUT_MS = 30_000) for consistency, even # though --fail-auth responds with 401 immediately in practice. - extendedWaitUntil: visible: text: "Connection Failed" timeout: 40000 - assertVisible: text: "Connection Failed" - assertVisible: text: "OK" - assertVisible: text: "Share report" - takeScreenshot: negative-S4_visible_error_alert # The connection must NOT have been silently saved: dismiss the alert and # confirm we are still on the add-connection screen, not a fake "connected" # screen. (handleQuickConnect's failure branch never calls router.back(), so # the app stays on this modal — the Sessions-tab "No Connection" empty state # is NOT visible here.) - tapOn: "OK" - assertVisible: id: "connect-submit-button" - takeScreenshot: negative-S5_still_on_add_connection_after_dismiss