test(client): native Android E2E smoke against a live API #234

Open
opened 2026-06-23 11:52:56 +00:00 by james · 0 comments
Owner

Context

PR #232 shipped twelve fixes for issues that only surfaced when running the universal client end-to-end on Android via Expo Go — none of them would have failed any CI gate as it stands today, because CI doesn't actually boot the client against the API. Categories that escaped:

  • Bundle composition: two React copies, two react-native copies, react@19.2.3-vs-19.2.7 mismatches with Expo Go's renderer — only visible at bundle load.
  • HTTP plumbing: the URL rewriter middleware (relative URLs, body copy, headers iteration, middleware return contract) — only fires on real fetch traffic against a real API.
  • Auth wiring: /api/auth/me and 15 domain routes were session-only; bearer tokens were ignored — only fails when the client uses bearer auth (native), not when it uses cookie auth (web same-origin).
  • Visual layout: MobileHeader ignored the status-bar inset; the Sidebar outer view was missing flex: 1. Both only manifest in the drawer host.
  • i18n: single- vs double-brace interpolation mismatch. Renders literal placeholders only when actually substituting variables, which doesn't happen in static tests.

A native smoke test running the assembled artifact against a live API would have caught every one of these.

Source

Follow-up from the PR #232 debugging cycle.

Scope

Build a CI-runnable native-side smoke that boots Carol on an Android emulator (or device farm) and exercises the critical paths. Pick the lightest-weight setup that achieves the coverage:

  • Recommended: Maestro flow file(s) plus a Forgejo Actions runner with an Android emulator. Maestro is YAML-driven, doesn't compete with vitest's role, and has built-in screenshot capture for CI artifacts. Alternatives: Detox (heavier, native modules), Appium (heaviest).
  • The flow boots a fresh APK against a running apps/api container (the same image the release pipeline produces), then:
    1. Configures the server URL via the first-launch screen.
    2. Registers a user (or logs in with a fixture user spun up in API setup).
    3. Navigates to Notes, creates a note, edits it, deletes it.
    4. Navigates to Profile, edits basics, adds + removes a contact.
    5. Navigates to Skills, creates a section, creates a skill, moves it, deletes the section.
    6. Navigates to Experience, creates a job, creates a position, creates a contribution.
    7. Opens the drawer, switches theme, switches locale.
    8. Logs out, verifies the redirect to /login.
  • Captures screenshots on every step; uploads them as Forgejo release attachments per CI run for visual diff review.
  • The CI job runs on the same self-hosted runner once #227 lands the custom runner image; until then it runs on a dedicated job with setup-android installed inline.

Acceptance criteria

  • A Maestro flow file lives in apps/client/e2e/ (or e2e/ at the repo root if it ends up multi-platform).
  • A Forgejo workflow boots an Android emulator + the API container, runs the flow, uploads screenshots.
  • The flow fails if any of PR #232's twelve bug-fixes is reverted on the branch being tested.
  • CI duration stays under ~12 minutes for the native lane (acceptable cost — runs on PR and on tags).
  • Failures attach screenshots from the failed step so PR reviewers can see what diverged.

Out of scope

  • iOS — explicitly out of scope per idea.md.
  • Linux Flatpak smoke — separate ticket if Flatpak grows enough surface to warrant E2E (today the binary is a thin Tauri wrapper around the Web bundle; the web E2E covers most of it).
  • Performance benchmarking — the smoke checks functionality, not speed.
  • Visual regression beyond "screenshot exists." Pixel-diff comes with a real designer cycle.

Composes with

  • #227 — custom runner image with Android SDK preinstalled (eliminates per-run install tax).
  • #150 — Playwright tests (the web counterpart; this is its Android sibling).
  • The URL-rewriter unit tests ticket (filed alongside; covers the JS-pure surface).

Part of

#176

## Context PR [#232](https://forge.wynning.tech/james/carol/pulls/232) shipped twelve fixes for issues that only surfaced when running the universal client end-to-end on Android via Expo Go — none of them would have failed any CI gate as it stands today, because CI doesn't actually boot the client against the API. Categories that escaped: - **Bundle composition**: two React copies, two react-native copies, react@19.2.3-vs-19.2.7 mismatches with Expo Go's renderer — only visible at bundle load. - **HTTP plumbing**: the URL rewriter middleware (relative URLs, body copy, headers iteration, middleware return contract) — only fires on real fetch traffic against a real API. - **Auth wiring**: `/api/auth/me` and 15 domain routes were session-only; bearer tokens were ignored — only fails when the client uses bearer auth (native), not when it uses cookie auth (web same-origin). - **Visual layout**: `MobileHeader` ignored the status-bar inset; the `Sidebar` outer view was missing `flex: 1`. Both only manifest in the drawer host. - **i18n**: single- vs double-brace interpolation mismatch. Renders literal placeholders only when actually substituting variables, which doesn't happen in static tests. A native smoke test running the assembled artifact against a live API would have caught every one of these. ## Source Follow-up from the PR [#232](https://forge.wynning.tech/james/carol/pulls/232) debugging cycle. ## Scope Build a CI-runnable native-side smoke that boots Carol on an Android emulator (or device farm) and exercises the critical paths. Pick the lightest-weight setup that achieves the coverage: - **Recommended**: [Maestro](https://maestro.mobile.dev) flow file(s) plus a Forgejo Actions runner with an Android emulator. Maestro is YAML-driven, doesn't compete with vitest's role, and has built-in screenshot capture for CI artifacts. Alternatives: Detox (heavier, native modules), Appium (heaviest). - The flow boots a fresh APK against a running `apps/api` container (the same image the release pipeline produces), then: 1. Configures the server URL via the first-launch screen. 2. Registers a user (or logs in with a fixture user spun up in API setup). 3. Navigates to Notes, creates a note, edits it, deletes it. 4. Navigates to Profile, edits basics, adds + removes a contact. 5. Navigates to Skills, creates a section, creates a skill, moves it, deletes the section. 6. Navigates to Experience, creates a job, creates a position, creates a contribution. 7. Opens the drawer, switches theme, switches locale. 8. Logs out, verifies the redirect to /login. - Captures screenshots on every step; uploads them as Forgejo release attachments per CI run for visual diff review. - The CI job runs on the same self-hosted runner once [#227](https://forge.wynning.tech/james/carol/issues/227) lands the custom runner image; until then it runs on a dedicated job with `setup-android` installed inline. ## Acceptance criteria - [ ] A Maestro flow file lives in `apps/client/e2e/` (or `e2e/` at the repo root if it ends up multi-platform). - [ ] A Forgejo workflow boots an Android emulator + the API container, runs the flow, uploads screenshots. - [ ] The flow fails if any of PR #232's twelve bug-fixes is reverted on the branch being tested. - [ ] CI duration stays under ~12 minutes for the native lane (acceptable cost — runs on PR and on tags). - [ ] Failures attach screenshots from the failed step so PR reviewers can see what diverged. ## Out of scope - iOS — explicitly out of scope per `idea.md`. - Linux Flatpak smoke — separate ticket if Flatpak grows enough surface to warrant E2E (today the binary is a thin Tauri wrapper around the Web bundle; the web E2E covers most of it). - Performance benchmarking — the smoke checks functionality, not speed. - Visual regression beyond "screenshot exists." Pixel-diff comes with a real designer cycle. ## Composes with - [#227](https://forge.wynning.tech/james/carol/issues/227) — custom runner image with Android SDK preinstalled (eliminates per-run install tax). - [#150](https://forge.wynning.tech/james/carol/issues/150) — Playwright tests (the web counterpart; this is its Android sibling). - The URL-rewriter unit tests ticket (filed alongside; covers the JS-pure surface). ## Part of [#176](https://forge.wynning.tech/james/carol/issues/176)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
james/carol#234
No description provided.