-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun-e2e.sh
More file actions
executable file
·144 lines (131 loc) · 4.98 KB
/
run-e2e.sh
File metadata and controls
executable file
·144 lines (131 loc) · 4.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/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, 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 `pip install -e .`).
# - `maestro` CLI on PATH (https://maestro.dev/).
# - For Android: an emulator running.
# - For iOS: a simulator running (and `idb-companion` installed).
#
# The script:
# 1. Builds + installs the e2e-suite app via `pn run <platform> --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. Install via 'pip install -e .'" >&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
case "$PLATFORM" in
android) APP_ID="com.pythonnative.android_template" ;;
ios) APP_ID="com.pythonnative.ios-template" ;;
esac
# 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|hooks|navigation|layout|styling|animations|misc)
MAESTRO_TARGETS+=("tests/e2e/suites/${suite}.yaml")
;;
*)
echo "Error: unknown suite '$suite'" >&2
echo "Available suites: full, components, hooks, navigation, layout, styling, animations, 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.
MAX_ATTEMPTS="${MAESTRO_MAX_ATTEMPTS:-2}"
attempt=1
while (( attempt <= MAX_ATTEMPTS )); do
if run_maestro; then
break
fi
if (( attempt == MAX_ATTEMPTS )); then
printf "\nMaestro suite failed after %d attempt(s).\n" "$attempt" >&2
exit 1
fi
printf "\n==> Maestro suite failed (attempt %d/%d); retrying...\n" \
"$attempt" "$MAX_ATTEMPTS" >&2
attempt=$(( attempt + 1 ))
done
printf "\nAll E2E suites passed.\n"