Skip to content

Commit 1ceee09

Browse files
committed
ci: extract local runners into reusable actions
1 parent 26a9642 commit 1ceee09

3 files changed

Lines changed: 224 additions & 81 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
name: '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.'
3+
4+
inputs:
5+
app-path:
6+
description: 'Absolute path to the .apk to install on the emulator'
7+
required: true
8+
sdk-type:
9+
description: 'SDK type passed to the tests (flutter, react-native, capacitor, unity, cordova, dotnet, android, etc.)'
10+
required: true
11+
api-level:
12+
description: 'Android API level for the AVD'
13+
required: false
14+
default: '36'
15+
arch:
16+
description: 'AVD architecture'
17+
required: false
18+
default: 'x86_64'
19+
profile:
20+
description: 'AVD device profile (as listed by `avdmanager list device`)'
21+
required: false
22+
default: 'medium_phone'
23+
onesignal-app-id:
24+
description: 'OneSignal App ID for the test app'
25+
required: true
26+
onesignal-api-key:
27+
description: 'OneSignal REST API key for the test app'
28+
required: true
29+
appium-port:
30+
description: 'Port Appium listens on'
31+
required: false
32+
default: '4723'
33+
34+
runs:
35+
using: composite
36+
steps:
37+
- name: Setup Bun
38+
uses: oven-sh/setup-bun@v2
39+
40+
- name: Enable KVM
41+
shell: bash
42+
run: |
43+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
44+
sudo udevadm control --reload-rules
45+
sudo udevadm trigger --name-match=kvm
46+
47+
- name: Install test dependencies
48+
shell: bash
49+
working-directory: ${{ github.action_path }}/../../../appium
50+
run: bun install --frozen-lockfile
51+
52+
- name: Run Appium tests on emulator
53+
uses: reactivecircus/android-emulator-runner@v2
54+
env:
55+
SDK_TYPE: ${{ inputs.sdk-type }}
56+
PLATFORM: android
57+
APP_PATH: ${{ inputs.app-path }}
58+
ONESIGNAL_APP_ID: ${{ inputs.onesignal-app-id }}
59+
ONESIGNAL_API_KEY: ${{ inputs.onesignal-api-key }}
60+
APPIUM_PORT: ${{ inputs.appium-port }}
61+
with:
62+
api-level: ${{ inputs.api-level }}
63+
arch: ${{ inputs.arch }}
64+
profile: ${{ inputs.profile }}
65+
force-avd-creation: false
66+
emulator-options: -no-window -no-boot-anim -gpu swiftshader_indirect
67+
working-directory: ${{ github.action_path }}/../../../appium
68+
script: |
69+
bun add -g appium@3
70+
appium driver install uiautomator2
71+
appium --port "$APPIUM_PORT" --log-level error > appium.log 2>&1 &
72+
for i in {1..30}; do
73+
if curl -sf "http://localhost:$APPIUM_PORT/status" >/dev/null; then
74+
break
75+
fi
76+
sleep 1
77+
done
78+
if ! curl -sf "http://localhost:$APPIUM_PORT/status" >/dev/null; then
79+
echo "::error::Appium did not become ready on port $APPIUM_PORT"
80+
cat appium.log || true
81+
exit 1
82+
fi
83+
bunx wdio run wdio.android.conf.ts
84+
85+
- name: Upload Appium + test results
86+
if: always()
87+
uses: actions/upload-artifact@v4
88+
with:
89+
name: appium-local-android-${{ inputs.sdk-type }}
90+
path: |
91+
${{ github.action_path }}/../../../appium/results/
92+
${{ github.action_path }}/../../../appium/appium.log
93+
if-no-files-found: ignore
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
name: 'Appium E2E - Local iOS'
2+
description: 'Boot an iPhone simulator, start Appium, and run the shared OneSignal Appium E2E tests against a local .app bundle.'
3+
4+
inputs:
5+
app-path:
6+
description: 'Absolute path to the simulator .app bundle or a .app.zip containing it'
7+
required: true
8+
sdk-type:
9+
description: 'SDK type passed to the tests (flutter, react-native, capacitor, unity, cordova, dotnet, ios, etc.)'
10+
required: true
11+
device:
12+
description: 'Simulator device name'
13+
required: false
14+
default: 'iPhone 17'
15+
os-version:
16+
description: 'Simulator iOS major version (matched against iOS-<version> in simctl runtimes)'
17+
required: false
18+
default: '26'
19+
onesignal-app-id:
20+
description: 'OneSignal App ID for the test app'
21+
required: true
22+
onesignal-api-key:
23+
description: 'OneSignal REST API key for the test app'
24+
required: true
25+
appium-port:
26+
description: 'Port Appium listens on'
27+
required: false
28+
default: '4723'
29+
30+
runs:
31+
using: composite
32+
steps:
33+
- name: Setup Bun
34+
uses: oven-sh/setup-bun@v2
35+
36+
- name: Unpack .app bundle if zipped
37+
shell: bash
38+
env:
39+
APP_PATH_IN: ${{ inputs.app-path }}
40+
run: |
41+
if [[ "$APP_PATH_IN" == *.zip ]]; then
42+
DEST_DIR=$(dirname "$APP_PATH_IN")
43+
unzip -o -q "$APP_PATH_IN" -d "$DEST_DIR"
44+
RESOLVED="${APP_PATH_IN%.zip}"
45+
else
46+
RESOLVED="$APP_PATH_IN"
47+
fi
48+
if [ ! -d "$RESOLVED" ]; then
49+
echo "::error::Expected .app bundle directory at $RESOLVED"
50+
exit 1
51+
fi
52+
echo "APP_PATH=$RESOLVED" >> "$GITHUB_ENV"
53+
54+
- name: Boot iOS simulator
55+
shell: bash
56+
env:
57+
DEVICE: ${{ inputs.device }}
58+
OS_MAJOR: ${{ inputs.os-version }}
59+
run: |
60+
UDID=$(xcrun simctl list devices available -j | jq -r --arg dev "$DEVICE" --arg os "iOS-$OS_MAJOR" '
61+
.devices | to_entries[]
62+
| select(.key | contains($os))
63+
| .value[] | select(.name == $dev) | .udid' | head -1)
64+
if [ -z "$UDID" ]; then
65+
echo "::error::Simulator '$DEVICE' (iOS $OS_MAJOR) not found on this runner"
66+
xcrun simctl list devices available
67+
exit 1
68+
fi
69+
xcrun simctl boot "$UDID" 2>/dev/null || true
70+
xcrun simctl bootstatus "$UDID" -b
71+
72+
- name: Install Appium and driver
73+
shell: bash
74+
run: |
75+
bun add -g appium@3
76+
appium driver install xcuitest
77+
78+
- name: Start Appium
79+
shell: bash
80+
env:
81+
APPIUM_PORT: ${{ inputs.appium-port }}
82+
run: |
83+
appium --port "$APPIUM_PORT" --log-level error > appium.log 2>&1 &
84+
echo "APPIUM_PID=$!" >> "$GITHUB_ENV"
85+
for i in {1..30}; do
86+
if curl -sf "http://localhost:$APPIUM_PORT/status" >/dev/null; then
87+
echo "Appium ready"
88+
exit 0
89+
fi
90+
sleep 1
91+
done
92+
echo "::error::Appium did not become ready on port $APPIUM_PORT"
93+
cat appium.log || true
94+
exit 1
95+
96+
- name: Install test dependencies
97+
shell: bash
98+
working-directory: ${{ github.action_path }}/../../../appium
99+
run: bun install --frozen-lockfile
100+
101+
- name: Run Appium tests
102+
shell: bash
103+
working-directory: ${{ github.action_path }}/../../../appium
104+
env:
105+
SDK_TYPE: ${{ inputs.sdk-type }}
106+
PLATFORM: ios
107+
DEVICE: ${{ inputs.device }}
108+
OS_VERSION: ${{ inputs.os-version }}
109+
ONESIGNAL_APP_ID: ${{ inputs.onesignal-app-id }}
110+
ONESIGNAL_API_KEY: ${{ inputs.onesignal-api-key }}
111+
run: bunx wdio run wdio.ios.conf.ts
112+
113+
- name: Stop Appium
114+
if: always()
115+
shell: bash
116+
run: |
117+
if [ -n "${APPIUM_PID:-}" ]; then
118+
kill "$APPIUM_PID" 2>/dev/null || true
119+
fi
120+
121+
- name: Upload Appium + test results
122+
if: always()
123+
uses: actions/upload-artifact@v4
124+
with:
125+
name: appium-local-ios-${{ inputs.sdk-type }}
126+
path: |
127+
${{ github.action_path }}/../../../appium/results/
128+
appium.log
129+
if-no-files-found: ignore

.github/workflows/appium-e2e.yml

Lines changed: 2 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@ on:
1919
description: 'SDK type: react-native, flutter, capacitor, unity, cordova, dotnet, ios, or android'
2020
required: true
2121
type: string
22-
runner:
23-
description: 'Where to run: browserstack or local'
24-
required: false
25-
default: 'browserstack'
26-
type: string
2722
device:
2823
description: 'BrowserStack device name'
2924
required: false
@@ -39,9 +34,7 @@ on:
3934

4035
jobs:
4136
e2e:
42-
runs-on: >-
43-
${{ (inputs.runner == 'local' && inputs.platform == 'ios') && 'macos-26'
44-
|| 'ubuntu-latest' }}
37+
runs-on: ubuntu-latest
4538
steps:
4639
- name: Download app artifact
4740
uses: actions/download-artifact@v4
@@ -58,7 +51,6 @@ jobs:
5851
uses: oven-sh/setup-bun@v2
5952

6053
- name: Upload app to BrowserStack
61-
if: inputs.runner == 'browserstack'
6254
id: bs-upload
6355
env:
6456
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
@@ -80,8 +72,7 @@ jobs:
8072
working-directory: _sdk-shared/appium
8173
run: bun install --frozen-lockfile
8274

83-
- name: Run Appium tests (BrowserStack)
84-
if: inputs.runner == 'browserstack'
75+
- name: Run Appium tests
8576
working-directory: _sdk-shared/appium
8677
env:
8778
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
@@ -96,76 +87,6 @@ jobs:
9687
ONESIGNAL_API_KEY: ${{ secrets.APPIUM_ONESIGNAL_API_KEY }}
9788
run: bunx wdio run "wdio.${PLATFORM}.conf.ts"
9889

99-
- name: Enable KVM
100-
if: inputs.runner == 'local' && inputs.platform == 'android'
101-
run: |
102-
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
103-
sudo udevadm control --reload-rules
104-
sudo udevadm trigger --name-match=kvm
105-
106-
- name: Run Appium tests (local Android)
107-
if: inputs.runner == 'local' && inputs.platform == 'android'
108-
uses: reactivecircus/android-emulator-runner@v2
109-
env:
110-
SDK_TYPE: ${{ inputs.sdk-type }}
111-
PLATFORM: android
112-
APP_PATH: ${{ github.workspace }}/${{ inputs.app-filename }}
113-
ONESIGNAL_APP_ID: ${{ vars.APPIUM_ONESIGNAL_APP_ID }}
114-
ONESIGNAL_API_KEY: ${{ secrets.APPIUM_ONESIGNAL_API_KEY }}
115-
with:
116-
api-level: 36
117-
arch: x86_64
118-
profile: medium_phone
119-
force-avd-creation: false
120-
emulator-options: -no-window -no-boot-anim -gpu swiftshader_indirect
121-
working-directory: _sdk-shared/appium
122-
script: |
123-
bun add -g appium@3
124-
appium driver install uiautomator2
125-
appium --port 4723 --log-level error &
126-
for i in {1..30}; do
127-
curl -sf http://localhost:4723/status && break
128-
sleep 1
129-
done
130-
bunx wdio run wdio.android.conf.ts
131-
132-
- name: Boot iPhone 17 simulator
133-
if: inputs.runner == 'local' && inputs.platform == 'ios'
134-
run: |
135-
UDID=$(xcrun simctl list devices available -j | jq -r '
136-
.devices | to_entries[]
137-
| select(.key | contains("iOS-26"))
138-
| .value[] | select(.name == "iPhone 17") | .udid' | head -1)
139-
if [ -z "$UDID" ]; then
140-
echo "::error::iPhone 17 (iOS 26) simulator not found on this runner"
141-
xcrun simctl list devices available
142-
exit 1
143-
fi
144-
xcrun simctl boot "$UDID"
145-
xcrun simctl bootstatus "$UDID" -b
146-
147-
- name: Start Appium (local iOS)
148-
if: inputs.runner == 'local' && inputs.platform == 'ios'
149-
run: |
150-
bun add -g appium@3
151-
appium driver install xcuitest
152-
appium --port 4723 --log-level error &
153-
for i in {1..30}; do
154-
curl -sf http://localhost:4723/status && break
155-
sleep 1
156-
done
157-
158-
- name: Run Appium tests (local iOS)
159-
if: inputs.runner == 'local' && inputs.platform == 'ios'
160-
working-directory: _sdk-shared/appium
161-
env:
162-
SDK_TYPE: ${{ inputs.sdk-type }}
163-
PLATFORM: ios
164-
APP_PATH: ${{ github.workspace }}/${{ inputs.app-filename }}
165-
ONESIGNAL_APP_ID: ${{ vars.APPIUM_ONESIGNAL_APP_ID }}
166-
ONESIGNAL_API_KEY: ${{ secrets.APPIUM_ONESIGNAL_API_KEY }}
167-
run: bunx wdio run wdio.ios.conf.ts
168-
16990
- name: Upload test results
17091
if: always()
17192
uses: actions/upload-artifact@v4

0 commit comments

Comments
 (0)