11name : ' Appium E2E - Local Android'
2- description : ' Boot an Android emulator (via reactivecircus/android-emulator-runner) , start Appium, and run the shared OneSignal Appium E2E tests against a local .apk.'
2+ description : ' Boot an Android emulator, start Appium, and run the shared OneSignal Appium E2E tests against a local .apk. Uses raw sdkmanager/avdmanager/emulator commands so each phase is a separate, cacheable, debuggable step .'
33
44inputs :
55 app-path :
@@ -16,6 +16,10 @@ inputs:
1616 description : ' AVD architecture'
1717 required : false
1818 default : ' x86_64'
19+ target :
20+ description : ' System-image target (e.g. google_apis, default, google_apis_playstore)'
21+ required : false
22+ default : ' google_apis'
1923 profile :
2024 description : ' AVD device profile (as listed by `avdmanager list device`)'
2125 required : false
@@ -30,75 +34,163 @@ inputs:
3034 description : ' Port Appium listens on'
3135 required : false
3236 default : ' 4723'
37+ boot-timeout-seconds :
38+ description : ' Max seconds to wait for emulator boot completion'
39+ required : false
40+ default : ' 900'
3341
3442runs :
3543 using : composite
3644 steps :
3745 - name : Setup Bun
3846 uses : oven-sh/setup-bun@v2
3947
48+ - name : Resolve appium dir
49+ shell : bash
50+ run : |
51+ APPIUM_DIR=$(cd "${{ github.action_path }}/../../../appium" && pwd -P)
52+ echo "APPIUM_DIR=$APPIUM_DIR" >> "$GITHUB_ENV"
53+
4054 - name : Enable KVM
4155 shell : bash
4256 run : |
4357 echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
4458 sudo udevadm control --reload-rules
4559 sudo udevadm trigger --name-match=kvm
4660
47- - name : Install test dependencies
61+ - name : Cache Android system image
62+ uses : actions/cache@v4
63+ with :
64+ path : ${{ env.ANDROID_HOME }}/system-images/android-${{ inputs.api-level }}/${{ inputs.target }}/${{ inputs.arch }}
65+ key : android-sysimg-${{ inputs.api-level }}-${{ inputs.target }}-${{ inputs.arch }}
66+
67+ - name : Install SDK packages
4868 shell : bash
49- working-directory : ${{ github.action_path }}/../../../appium
50- run : bun install --frozen-lockfile
69+ env :
70+ API_LEVEL : ${{ inputs.api-level }}
71+ TARGET : ${{ inputs.target }}
72+ ARCH : ${{ inputs.arch }}
73+ run : |
74+ yes | sdkmanager --licenses >/dev/null 2>&1 || true
75+ sdkmanager --install \
76+ "platforms;android-$API_LEVEL" \
77+ "system-images;android-$API_LEVEL;$TARGET;$ARCH" \
78+ "emulator" \
79+ "platform-tools" > /tmp/sdkmanager.log 2>&1 || {
80+ echo "::error::sdkmanager install failed"
81+ tail -40 /tmp/sdkmanager.log
82+ exit 1
83+ }
5184
52- - name : Resolve appium dir
85+ - name : Create AVD
5386 shell : bash
87+ env :
88+ API_LEVEL : ${{ inputs.api-level }}
89+ TARGET : ${{ inputs.target }}
90+ ARCH : ${{ inputs.arch }}
91+ PROFILE : ${{ inputs.profile }}
5492 run : |
55- APPIUM_DIR=$(cd "${{ github.action_path }}/../../../appium" && pwd -P)
56- echo "APPIUM_DIR=$APPIUM_DIR" >> "$GITHUB_ENV"
93+ echo "no" | avdmanager create avd \
94+ -n test \
95+ -k "system-images;android-$API_LEVEL;$TARGET;$ARCH" \
96+ -d "$PROFILE" \
97+ --force
98+
99+ - name : Boot emulator
100+ shell : bash
101+ env :
102+ BOOT_TIMEOUT : ${{ inputs.boot-timeout-seconds }}
103+ run : |
104+ nohup "$ANDROID_HOME/emulator/emulator" \
105+ -avd test \
106+ -no-window -no-audio -no-boot-anim \
107+ -gpu swiftshader_indirect \
108+ -no-snapshot-save \
109+ -memory 4096 \
110+ > emulator.log 2>&1 &
111+ echo "EMULATOR_PID=$!" >> "$GITHUB_ENV"
112+
113+ adb wait-for-device
114+
115+ echo "Waiting for boot completion (timeout ${BOOT_TIMEOUT}s)..."
116+ deadline=$(( $(date +%s) + BOOT_TIMEOUT ))
117+ while :; do
118+ boot=$(adb shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)
119+ if [ "$boot" = "1" ]; then
120+ break
121+ fi
122+ if [ "$(date +%s)" -ge "$deadline" ]; then
123+ echo "::error::Emulator boot timed out"
124+ echo "--- emulator.log (last 100 lines) ---"
125+ tail -100 emulator.log || true
126+ exit 1
127+ fi
128+ sleep 2
129+ done
130+ adb shell input keyevent 82 >/dev/null 2>&1 || true
131+ echo "Emulator booted"
57132
58- - name : Run Appium tests on emulator
59- uses : reactivecircus/android-emulator-runner@v2
133+ - name : Install Appium and driver
134+ shell : bash
135+ run : |
136+ bun add -g appium@3
137+ appium driver install uiautomator2
138+
139+ - name : Start Appium
140+ shell : bash
141+ env :
142+ APPIUM_PORT : ${{ inputs.appium-port }}
143+ run : |
144+ appium --port "$APPIUM_PORT" --log-level error > appium.log 2>&1 &
145+ echo "APPIUM_PID=$!" >> "$GITHUB_ENV"
146+ i=0
147+ while [ "$i" -lt 30 ]; do
148+ if curl -sf "http://localhost:$APPIUM_PORT/status" >/dev/null; then
149+ echo "Appium ready"
150+ exit 0
151+ fi
152+ sleep 1
153+ i=$((i + 1))
154+ done
155+ echo "::error::Appium did not become ready on port $APPIUM_PORT"
156+ cat appium.log || true
157+ exit 1
158+
159+ - name : Install test dependencies
160+ shell : bash
161+ working-directory : ${{ env.APPIUM_DIR }}
162+ run : bun install --frozen-lockfile
163+
164+ - name : Run Appium tests
165+ shell : bash
166+ working-directory : ${{ env.APPIUM_DIR }}
60167 env :
61168 SDK_TYPE : ${{ inputs.sdk-type }}
62169 PLATFORM : android
63170 APP_PATH : ${{ inputs.app-path }}
64171 ONESIGNAL_APP_ID : ${{ inputs.onesignal-app-id }}
65172 ONESIGNAL_API_KEY : ${{ inputs.onesignal-api-key }}
66- APPIUM_PORT : ${{ inputs.appium-port }}
67- with :
68- api-level : ${{ inputs.api-level }}
69- target : google_apis
70- arch : ${{ inputs.arch }}
71- profile : ${{ inputs.profile }}
72- force-avd-creation : false
73- disable-animations : true
74- ram-size : 4096M
75- heap-size : 1024M
76- emulator-boot-timeout : 900
77- emulator-options : -no-window -no-boot-anim -gpu swiftshader_indirect
78- working-directory : ${{ env.APPIUM_DIR }}
79- script : |
80- bun add -g appium@3
81- appium driver install uiautomator2
82- appium --port "$APPIUM_PORT" --log-level error > appium.log 2>&1 &
83- for i in {1..30}; do
84- if curl -sf "http://localhost:$APPIUM_PORT/status" >/dev/null; then
85- break
86- fi
87- sleep 1
88- done
89- if ! curl -sf "http://localhost:$APPIUM_PORT/status" >/dev/null; then
90- echo "::error::Appium did not become ready on port $APPIUM_PORT"
91- cat appium.log || true
92- exit 1
93- fi
94- bunx wdio run wdio.android.conf.ts
173+ run : bunx wdio run wdio.android.conf.ts
174+
175+ - name : Shut down emulator and Appium
176+ if : always()
177+ shell : bash
178+ run : |
179+ adb emu kill 2>/dev/null || true
180+ if [ -n "${APPIUM_PID:-}" ]; then
181+ kill "$APPIUM_PID" 2>/dev/null || true
182+ fi
183+ if [ -n "${EMULATOR_PID:-}" ]; then
184+ kill "$EMULATOR_PID" 2>/dev/null || true
185+ fi
95186
96- - name : Upload Appium + test results
187+ - name : Upload Appium + emulator logs
97188 if : always()
98189 uses : actions/upload-artifact@v5
99190 with :
100191 name : appium-local-android-${{ inputs.sdk-type }}
101192 path : |
102193 ${{ env.APPIUM_DIR }}/results/
103- ${{ env.APPIUM_DIR }}/appium.log
194+ emulator.log
195+ appium.log
104196 if-no-files-found : ignore
0 commit comments