# Maestro E2E — apps/user-ui (Android only) Maestro flows that drive the **user-ui** app through placing an order: home → product → add to cart (choose delivery slot) → cart → checkout (address if needed, Cash on Delivery) → **Place Order** → confirmation. Everything here targets **Android only** (`appId: in.freshyo.app`), and `run.sh` always passes `--platform android` — it will never use an iOS simulator. ## Prerequisites - Maestro CLI installed (`maestro --version`; installed here at `~/.maestro/bin/maestro`). - A running **Android emulator/device** with the user-ui dev build installed: ```bash cd apps/user-ui npx expo run:android ``` - A **test account with a password set**. OTP login can't be automated (the OTP is server-issued, no dev bypass). The flow reaches the login screen by tapping **Checkout** as a guest — checkout is behind `useAuthenticatedRoute`, so the app bounces there — then signs in via `other ways to login` → `Username` + `Password` and returns to the cart. Alternatively, sign in once by hand and the subflow becomes a no-op; `launchApp` uses `clearState: false` so the session and the first-run onboarding survive. - A catalog with at least one **in-stock product that has a future delivery slot**. Note: in a dev build the "Open debugger to view warnings" toast overlays the bottom of the screen and swallows taps on the bottom tab bar — the flows avoid the tab bar and use `centerElement: true` where a control can land under it. ## Running **Recommended — one command, values from a gitignored file.** Create `e2e/.env` (see `.env.example`) and then, from the repo root: ```bash bun run e2e # or: bash e2e/run.sh ``` `e2e/run.sh` sources `e2e/.env`, runs `maestro test e2e --platform android`, and falls back to `~/.maestro/bin/maestro` when `maestro` isn't on `PATH`. Extra flags pass through, and flow paths are relative to `e2e/`: ```bash bash e2e/run.sh flows/place-order.yaml # one flow bash e2e/run.sh --format junit # junit report bash e2e/run.sh --device emulator-5554 # pick an emulator (needed if several are connected) ``` To see which emulators are available: `adb devices -l`. ### How values are supplied Maestro resolves `${VAR}` from three places: 1. **`config.yaml` → `env:`** — committed, non-secret defaults shared by all flows (`ADDRESS_NAME`, `ADDRESS_PHONE`, `ADDRESS_LINE1` live here). 2. **`e2e/.env`** (gitignored) — loaded by `run.sh`; put `TEST_IDENTIFIER` / `TEST_PASSWORD` here so secrets stay out of git and off the command line. 3. **Shell / CLI** — `MAESTRO_`-prefixed env vars or `-e KEY=VALUE`, good for CI: ```bash MAESTRO_TEST_IDENTIFIER=... MAESTRO_TEST_PASSWORD=... bash e2e/run.sh # or maestro test e2e -e TEST_IDENTIFIER=... -e TEST_PASSWORD=... ``` Need more than one setup (e.g. CI vs local)? Maestro supports alternate configs: `maestro test --config e2e/ci-config.yaml e2e`. Useful flags: `--include-tags`, `--format junit`, `--test-output-dir`. Reports/screenshots land in `e2e/.maestro-output/`. ## Layout ``` e2e/ config.yaml # workspace config (flows, execution order, env defaults) subflows/login.yaml # reusable login (runs only if the login screen is visible) flows/smoke.yaml # app launches, home renders flows/place-order.yaml # the order flow ``` ## What place-order covers 1. Home → add a product from the card's cart icon → pick a delivery slot in the "Select Delivery Slot" dialog → add to cart. (The icon sits inside the card's touchable, so the tap can fall through to the card; the flow then adds from the product detail page instead.) 2. Cart → checkout. A guest is bounced to login (checkout is behind `useAuthenticatedRoute`), signs in, and the flow re-enters the cart. 3. Address (only when the account has none) → Cash on Delivery → **Place Order**. 4. **Home glimpse**: `Continue Shopping` returns home; the flow scrolls to the `NextOrderGlimpse` card and captures it with `takeScreenshot`, so each run leaves a picture of the upcoming-order card. Maestro writes it under `~/.maestro/tests//place-order/takeScreenshot/home-upcoming-order-glimpse.png`. 5. **Cancel**: taps the glimpse card (which routes to `/(drawer)/(tabs)/me/my-orders/{id}`), scrolls to **Cancel Order**, fills the reason, confirms, dismisses the success alert, and asserts the **Cancellation Reason** panel renders. ## Notes - **These flows place real orders** on whatever backend the app points at, and then cancel the one they placed. Point the app at a non-production backend / use a throwaway account. - The product is chosen as **the first card** (`id: product-card`, `index: 0`). If that item is out of stock or has no future slot, change the index or seed a known product. - The address step is conditional: it only runs when `No addresses found` is visible, so an account with a saved address skips it. - Payment defaults to **Cash on Delivery**, so the flow just asserts it's visible. - Controls below the fold need `scrollUntilVisible`; the home glimpse sits below **Our Stores**, and **Cancel Order** below the bill summary. - `launchApp` uses `clearState: false`, so the session and (on the first run) the onboarding survive. The trade-off is that the app resumes wherever the previous run left it — the flow taps the **Home** tab (`optional: true`) to get back. - Maestro taps can be eaten by a dismissing keyboard or the dev-warning toast, so the flow waits for animations and retries the confirm tap once. - Stable `testID` anchors used by the flows live in user-ui: `product-card`, `add-to-cart-icon`, `slot-option`, `add-to-cart-confirm`, `go-to-cart`, `checkout-button`, `address-name`, `address-phone`, `address-line1`, `address-submit`, `place-order-button`, `cancel-reason`.