| 1 | #!/usr/bin/env bash
|
| 2 | #
|
| 3 | # E2E harness for the nexo frontend: Maestro flows on a physical Android
|
| 4 | # device over adb (no emulator)
|
| 5 | #
|
| 6 | # The app talks to whatever API `EXPO_PUBLIC_API_BASE_URL` points at, so there is
|
| 7 | # no second API service to boot here: bring the normal stack up and point Metro
|
| 8 | # at it:
|
| 9 | #
|
| 10 | # docker compose up -d db valkey api
|
| 11 | # cd api && npm run seed # known e2e user (idempotent)
|
| 12 | # cd frontend && npx expo start # with .env.local set (see print-env)
|
| 13 | #
|
| 14 | # Usage: e2e.sh [test|print-env]
|
| 15 | # test prep the device (adb) and run the tagged Maestro flows
|
| 16 | # print-env print the EXPO_PUBLIC_* vars to set before `expo start`
|
| 17 | #
|
| 18 | # Optional env: HOST_IP (LAN IP of this machine) is auto-detected when unset
|
| 19 | set -euo pipefail
|
| 20 |
|
| 21 | ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
| 22 | FRONTEND="$ROOT/frontend"
|
| 23 |
|
| 24 | # The app under test: the dev build (`eas build --profile development`)
|
| 25 | APP_ID="${APP_ID:-com.eletrotupi.orbit}"
|
| 26 | EXPO_PORT="${EXPO_PORT:-8081}"
|
| 27 | E2E_EMAIL="${E2E_EMAIL:-e2e@example.com}"
|
| 28 | E2E_PASSWORD="${E2E_PASSWORD:-e2e-password}"
|
| 29 |
|
| 30 | die() { echo "e2e: $*" >&2; exit 1; }
|
| 31 |
|
| 32 | detect_host_ip() {
|
| 33 | if [[ -n "${HOST_IP:-}" ]]; then
|
| 34 | echo "$HOST_IP"
|
| 35 | return
|
| 36 | fi
|
| 37 |
|
| 38 | local ip=""
|
| 39 | ip="$(ip route get 1 2>/dev/null | awk '/src/{for (i=1;i<=NF;i++) if ($i=="src") {print $(i+1); exit}}')"
|
| 40 |
|
| 41 | [[ -z "$ip" ]] && ip="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
| 42 | [[ -z "$ip" ]] && die "could not detect LAN IP; export HOST_IP=<lan-ip>"
|
| 43 |
|
| 44 | echo "$ip"
|
| 45 | }
|
| 46 |
|
| 47 | adb_prepare() {
|
| 48 | command -v adb >/dev/null || die "adb not found; install android-tools"
|
| 49 | echo "e2e: waiting for an Android device (up to 15s)..."
|
| 50 |
|
| 51 | local i state=""
|
| 52 |
|
| 53 | for i in $(seq 1 15); do
|
| 54 | state="$(adb get-state 2>/dev/null)"
|
| 55 | [[ "$state" == "device" ]] && break
|
| 56 | sleep 1
|
| 57 | done
|
| 58 |
|
| 59 | if [[ "$state" != "device" ]]; then
|
| 60 | adb devices >&2 || true
|
| 61 | die "no Android device attached. Connect one over USB/wireless debugging (or set ANDROID_SERIAL when several are connected) and re-run"
|
| 62 | fi
|
| 63 |
|
| 64 | echo "e2e: adb devices:"
|
| 65 |
|
| 66 | adb devices
|
| 67 |
|
| 68 | # No `pm clear` here: each flow starts with Maestro `clearState`, which needs no
|
| 69 | # host-side help, and clearing here only re-triggered the expo-dev-client
|
| 70 | # first-run overlays. Granting the runtime permission is still worth it:
|
| 71 | # clearState resets it and the app asks for notifications right after login
|
| 72 | adb shell pm grant "$APP_ID" android.permission.POST_NOTIFICATIONS >/dev/null 2>&1 || true
|
| 73 | # Disable animations for speed and stability
|
| 74 |
|
| 75 | adb shell settings put global window_animation_scale 0 >/dev/null
|
| 76 | adb shell settings put global transition_animation_scale 0 >/dev/null
|
| 77 | adb shell settings put global animator_duration_scale 0 >/dev/null
|
| 78 | }
|
| 79 |
|
| 80 | run_maestro() {
|
| 81 | command -v maestro >/dev/null || die "maestro not found; install via https://get.maestro.mobile.dev"
|
| 82 | local host_ip
|
| 83 | host_ip="$(detect_host_ip)"
|
| 84 |
|
| 85 | (
|
| 86 | cd "$FRONTEND"
|
| 87 | maestro test e2e \
|
| 88 | --include-tags=smoke \
|
| 89 | --env HOST_IP="$host_ip" \
|
| 90 | --env PORT="$EXPO_PORT" \
|
| 91 | --env E2E_EMAIL="$E2E_EMAIL" \
|
| 92 | --env E2E_PASSWORD="$E2E_PASSWORD"
|
| 93 | )
|
| 94 | }
|
| 95 |
|
| 96 | print_env() {
|
| 97 | local host_ip
|
| 98 | host_ip="$(detect_host_ip)"
|
| 99 |
|
| 100 | cat <<EOF
|
| 101 | Put this in frontend/.env.local (gitignored) before starting Metro:
|
| 102 |
|
| 103 | EXPO_PUBLIC_API_BASE_URL=http://$host_ip:3000
|
| 104 | EXPO_PUBLIC_TOKEN_KEY=orbit-jwt
|
| 105 |
|
| 106 | npx expo start --port $EXPO_PORT
|
| 107 | EOF
|
| 108 | }
|
| 109 |
|
| 110 | case "${1:-}" in
|
| 111 | test)
|
| 112 | adb_prepare
|
| 113 | run_maestro
|
| 114 | ;;
|
| 115 | print-env)
|
| 116 | print_env
|
| 117 | ;;
|
| 118 | *)
|
| 119 | echo "usage: $0 [test|print-env]" >&2
|
| 120 | exit 1
|
| 121 | ;;
|
| 122 | esac
|