FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

GitHub Viewer

#!/usr/bin/env bash # Build the e2e-suite example app and run the comprehensive Maestro suite. # # This script is the supported way for AI agents and humans to run the # full E2E pass locally. It mirrors what CI does in .github/workflows/e2e.yml. # # Usage: # ./scripts/run-e2e.sh android [suite ...] # ./scripts/run-e2e.sh ios [suite ...] # # Examples: # ./scripts/run-e2e.sh android # full suite # ./scripts/run-e2e.sh android components # only the components suite # ./scripts/run-e2e.sh ios hooks # only the hooks suite on iOS # ./scripts/run-e2e.sh android hooks navigation # two categories, one session # # Available suites: full, components, hooks, navigation, layout, styling, # animations, gestures, misc. # # Multiple category suites can be passed at once; they run sequentially in # a single Maestro session (and against a single emulator/simulator boot). # CI uses this to shard the Android run into a few balanced groups so no # single emulator session has to survive the entire 60-flow marathon; # GitHub-hosted Android emulators grow unstable under ~15 minutes of # sustained Maestro driving and start reporting "device offline". See # .github/workflows/e2e.yml and tests/e2e/AGENTS.md. # # Prerequisites: # - `pn` CLI available (e.g. via `uv sync`, then run through `uv run`). # - `maestro` CLI on PATH (https://maestro.dev/). # - For Android: an emulator running. # - For iOS: a simulator running. # # The script: # 1. Builds + installs the e2e-suite app via `pn run --no-logs`. # 2. Resolves each requested suite to its Maestro YAML target. # 3. Runs `maestro test` (over all targets) up to ``MAESTRO_MAX_ATTEMPTS`` # times (default 2) and exits with the last attempt's exit code. # # A successful run prints "All E2E suites passed." at the end and exits 0. # Any failed flow is reported by Maestro in its standard format; see # tests/e2e/AGENTS.md for guidance on interpreting failures. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" cd "$ROOT_DIR" PLATFORM="${1:-android}" shift || true # Remaining args are suite names; default to the full aggregate suite. SUITES=("$@") if [[ ${#SUITES[@]} -eq 0 ]]; then SUITES=("full") fi case "$PLATFORM" in android|ios) ;; *) echo "Error: platform must be 'android' or 'ios' (got: $PLATFORM)" >&2 exit 2 ;; esac if ! command -v pn > /dev/null; then echo "Error: 'pn' CLI not found on PATH. Run 'uv sync', then invoke this" >&2 echo "script through 'uv run ./scripts/run-e2e.sh ...'." >&2 exit 2 fi if ! command -v maestro > /dev/null; then echo "Error: 'maestro' CLI not found on PATH." >&2 echo "Install: curl -Ls 'https://get.maestro.mobile.dev' | bash" >&2 exit 2 fi # Resolve the app/bundle id straight from the example's pythonnative.toml so # this stays correct no matter what id the config declares. APP_ID="$(cd examples/e2e-suite && pn app-id "$PLATFORM")" if [[ -z "$APP_ID" ]]; then echo "Error: could not resolve APP_ID via 'pn app-id $PLATFORM'." >&2 exit 2 fi # Resolve each requested suite to a Maestro YAML target. ``full`` expands # to the platform's master aggregate; the category names map to the # per-category suite files under tests/e2e/suites/. MAESTRO_TARGETS=() for suite in "${SUITES[@]}"; do case "$suite" in full) if [[ "$PLATFORM" == "android" ]]; then MAESTRO_TARGETS+=("tests/e2e/android.yaml") else MAESTRO_TARGETS+=("tests/e2e/ios.yaml") fi ;; components|components-a|components-b|hooks|navigation|layout|styling|animations|gestures|misc) MAESTRO_TARGETS+=("tests/e2e/suites/${suite}.yaml") ;; *) echo "Error: unknown suite '$suite'" >&2 echo "Available suites: full, components, components-a, components-b, hooks, navigation, layout, styling, animations, gestures, misc" >&2 exit 2 ;; esac done printf "\n==> Building e2e-suite app for %s\n" "$PLATFORM" pushd examples/e2e-suite > /dev/null pn run "$PLATFORM" --no-logs popd > /dev/null run_maestro() { if [[ "$PLATFORM" == "ios" ]]; then maestro --platform ios test -e "APP_ID=$APP_ID" "${MAESTRO_TARGETS[@]}" else maestro test -e "APP_ID=$APP_ID" "${MAESTRO_TARGETS[@]}" fi } printf "\n==> Running Maestro suite(s): %s\n" "${MAESTRO_TARGETS[*]}" # Maestro's iOS XCUITest driver occasionally loses its connection to the # app during long suites and surfaces transient "Application is not # running" / "Request for viewHierarchy failed" errors that have nothing # to do with the test under test. Allow one automatic retry of the whole # suite (overridable via ``MAESTRO_MAX_ATTEMPTS``) so CI doesn't fail on # driver flakes. A retry can also mask a genuine race in the suite, so # treat the "retrying..." line as a signal to investigate, not just to # trust the second pass. # Kill the app so the next Maestro attempt starts from a cold launch # (open_demo relaunches a dead app). A failed attempt can leave the app # mid-demo with dirty in-process state (e.g. module-level counters some # demos display), which would make a same-process retry fail assertions # that hold on a first visit. terminate_app() { if [[ "$PLATFORM" == "ios" ]]; then xcrun simctl terminate booted "$APP_ID" 2> /dev/null || true else adb shell am force-stop "$APP_ID" 2> /dev/null || true fi } MAX_ATTEMPTS="${MAESTRO_MAX_ATTEMPTS:-2}" attempt=1 while (( attempt &2 exit 1 fi printf "\n==> Maestro suite failed (attempt %d/%d); restarting app and retrying...\n" \ "$attempt" "$MAX_ATTEMPTS" >&2 terminate_app attempt=$(( attempt + 1 )) done printf "\nAll E2E suites passed.\n"

Back | FazBrowse Home | New Git URL