Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fe6611a
feat(appium): add native Android SDK support
fadi-george May 19, 2026
1b145f4
docs(demo): clarify build guide structure
fadi-george May 19, 2026
68f7e06
refactor(appium): pass app ID via Gradle props
fadi-george May 19, 2026
b2cf54c
refactor(appium): trim comments and skip Android fast path
fadi-george May 19, 2026
5a2a597
refactor(appium): simplify scroll helpers and remove unused fns
fadi-george May 19, 2026
f530f43
refactor(appium): derive SdkType from const array
fadi-george May 19, 2026
3e8578d
docs(demo): update test ID and input field docs
fadi-george May 19, 2026
09c06e7
refactor(appium): remove native scroll fast paths
fadi-george May 19, 2026
fc67e9c
feat(appium): add --quiet/-q flag to suppress INFO logs
fadi-george May 19, 2026
8970fbe
refactor(appium): always await webview visibility
fadi-george May 19, 2026
a856d1b
refactor(appium): auto-correct platform for android sdk
fadi-george May 19, 2026
c8191a5
refactor(appium): simplify IAM trigger tap
fadi-george May 19, 2026
6aef7a7
refactor: remove dismissKeyboard helper and its usages
fadi-george May 19, 2026
dc6e9c6
fix: move Flutter post-swipe pause outside swipe loop and remove per-…
fadi-george May 19, 2026
664cddb
fix: include bundleId in appPackageName lookup for iOS support
fadi-george May 19, 2026
71e1429
refactor: simplify isVisibleInViewport and checkInAppMessage helpers
fadi-george May 19, 2026
8b3f9fd
refactor(appium): remove Unity SDK modal workarounds
fadi-george May 20, 2026
3a221e3
refactor(appium): unify snackbar check via native context
fadi-george May 20, 2026
c9fb987
refactor(appium): apply switchToNativeContext to all SDKs
fadi-george May 20, 2026
3319f5b
refactor(appium): hardcode package ID constant
fadi-george May 20, 2026
d8ba5fe
refactor(appium): fix viewport visibility for SDK types
fadi-george May 20, 2026
3fcbcbb
refactor(appium): extract IAM context helpers
fadi-george May 20, 2026
09b5bb5
fix(appium): clear stale UiAutomator2 state on Android
fadi-george May 20, 2026
edeb383
refactor(appium): extract waitForPushId helper
fadi-george May 20, 2026
149e991
refactor(appium): remove withRetryDelay helper
fadi-george May 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions appium/scripts/run-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; }

# ── Args (forwarded as-is to run-local.sh) ────────────────────────────────────
ALL_SDKS=(cordova capacitor dotnet expo flutter react-native unity)
ALL_SDKS=(android cordova capacitor dotnet expo flutter react-native unity)

EXTRA_ARGS=()
PLATFORM_FILTER=""
SDKS_FILTER=""
BAIL=0
for arg in "$@"; do
case "$arg" in
--skip-build|--skip-device|--skip-reset|--skip)
--skip-build|--skip-device|--skip-reset|--skip|--quiet|-q)
EXTRA_ARGS+=("$arg") ;;
--spec=*)
EXTRA_ARGS+=("$arg") ;;
Expand All @@ -41,13 +41,15 @@ for arg in "$@"; do
Usage: $0 [OPTIONS]

Runs the Appium E2E suite across every SDK/platform combo by delegating
to run-local.sh. Combos: cordova, react-native, flutter, dotnet, expo,
unity on ios + android.
to run-local.sh. Combos: cordova, capacitor, react-native, flutter, dotnet,
expo, unity on ios + android, plus android (native) on android only.

Options:
--platform=ios|android Only run combos for the given platform (default: both)
--sdks=LIST Comma-separated SDKs to run (default: all)
Valid: cordova, react-native, flutter, dotnet, expo, unity
Valid: cordova, capacitor, react-native, flutter,
dotnet, expo, unity, android
Note: 'android' (native) skips --platform=ios.
--bail Stop after the first failing combo

Options forwarded to run-local.sh:
Expand All @@ -56,6 +58,7 @@ Options forwarded to run-local.sh:
--skip-reset Keep existing app data
--skip Shortcut for --skip-build --skip-device --skip-reset
--spec=GLOB Spec glob to run (default: full suite, grouped into one session)
-q, --quiet Hide run-local [INFO] log lines
-h, --help Show this help

Exits non-zero if any combo fails. Prints a summary at the end.
Expand Down Expand Up @@ -91,9 +94,19 @@ fi
declare -a RESULTS
FAILED=0
BAILED=0
SKIPPED=0

for platform in "${PLATFORMS[@]}"; do
for sdk in "${SDKS[@]}"; do
# Native Android demo only exists for Android.
if [[ "$sdk" == "android" && "$platform" == "ios" ]]; then
if [[ -n "$PLATFORM_FILTER" ]]; then
warn "--sdk=android only runs on --platform=android; skipping --platform=ios"
RESULTS+=("SKIP ${sdk} / ${platform}")
SKIPPED=$((SKIPPED + 1))
fi
continue
fi
label="${sdk} / ${platform}"
echo ""
echo -e "${BOLD}━━━ Running: ${label} ━━━${NC}"
Expand All @@ -118,6 +131,8 @@ echo -e "${BOLD}━━━ Summary ━━━${NC}"
for line in "${RESULTS[@]}"; do
if [[ "$line" == PASS* ]]; then
echo -e " ${GREEN}${line}${NC}"
elif [[ "$line" == SKIP* ]]; then
echo -e " ${YELLOW}${line}${NC}"
else
echo -e " ${RED}${line}${NC}"
fi
Expand All @@ -134,4 +149,8 @@ if (( FAILED > 0 )); then
fi

echo ""
info "All combos passed"
if (( SKIPPED > 0 )); then
info "No combos failed"
else
info "All combos passed"
fi
102 changes: 97 additions & 5 deletions appium/scripts/run-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

info() { echo -e "${GREEN}[INFO]${NC} $*"; }
info() { [[ "${QUIET:-false}" == true ]] || echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; }

Expand All @@ -30,6 +30,7 @@ SKIP_BUILD=false
SKIP_DEVICE=false
SKIP_RESET=false
SPEC=""
QUIET=false
ANDROID_CHANNEL_ID=7ec2ece9-c538-4656-9516-1316f48a005c
IOS_REAL_DEVICE=false
UDID="${UDID:-}"
Expand All @@ -50,6 +51,7 @@ for arg in "$@"; do
--skip-device) SKIP_DEVICE=true ;;
--skip-reset) SKIP_RESET=true ;;
--spec=*) SPEC="${arg#--spec=}" ;;
--quiet|-q) QUIET=true ;;
--help|-h)
cat <<USAGE
Usage: $0 [OPTIONS]
Expand All @@ -62,7 +64,9 @@ via flags or env vars.

Options:
--platform=P ios | android
--sdk=S flutter | react-native | cordova | capacitor | dotnet | expo | unity
--sdk=S flutter | react-native | cordova | capacitor | dotnet | expo | unity | android
android = native Android (OneSignal-Android-SDK/examples/demo);
skips with exit 0 when --platform=ios.
--device=NAME Device/simulator/AVD name (default: iPhone 17 / Samsung Galaxy S26)
--appium-port=N Appium server port (default: 4723). Use unique values when
running multiple sessions in parallel on the same host.
Expand All @@ -79,6 +83,7 @@ Options:
--udid=ID Physical device UDID (xcrun devicectl list devices).
Required by --device-real; also accepted via UDID env.
--spec=GLOB Spec glob (default: all specs grouped into one session)
-q, --quiet Hide [INFO] log lines
-h, --help Show this help

Env vars (set in .env or export):
Expand All @@ -98,6 +103,9 @@ Env vars (set in .env or export):
UNITY_PATH Path to Unity Editor binary
(default: /Applications/Unity/Hub/Editor/6000.4.6f1/Unity.app/Contents/MacOS/Unity)
UNITY_IOS_SIM_ARCH Unity iOS simulator arch (default: host arch)
ANDROID_DIR Native Android SDK repo root (default: ../../OneSignal-Android-SDK)
ANDROID_FLAVOR Native Android product flavor (default: gms; also: huawei)
ANDROID_BUILD_TYPE Native Android build type (default: debug; also: release)
OS_VERSION Platform version (default: 26.2 / 16)
IOS_SIMULATOR iOS simulator name (default: iPhone 17)
IOS_RUNTIME simctl runtime id (default: iOS-26-2)
Expand Down Expand Up @@ -152,19 +160,31 @@ prompt_choice() {
done
}

# --sdk=android implies --platform=android (the native demo only targets
# Android), so resolve PLATFORM first to skip the platform prompt when the
# user only passed --sdk=android.
if [[ "${SDK_TYPE:-}" == "android" && -z "${PLATFORM:-}" ]]; then
PLATFORM="android"
fi

prompt_choice PLATFORM "Select platform:" ios android
prompt_choice SDK_TYPE "Select SDK type:" flutter react-native cordova capacitor dotnet expo unity
prompt_choice SDK_TYPE "Select SDK type:" flutter react-native cordova capacitor dotnet expo unity android

case "$PLATFORM" in
ios|android) ;;
*) error "PLATFORM must be 'ios' or 'android', got '$PLATFORM'" ;;
esac

case "$SDK_TYPE" in
flutter|react-native|cordova|capacitor|dotnet|expo|unity) ;;
*) error "SDK_TYPE must be 'flutter', 'react-native', 'cordova', 'capacitor', 'dotnet', 'expo', or 'unity', got '$SDK_TYPE'" ;;
flutter|react-native|cordova|capacitor|dotnet|expo|unity|android) ;;
*) error "SDK_TYPE must be 'flutter', 'react-native', 'cordova', 'capacitor', 'dotnet', 'expo', 'unity', or 'android', got '$SDK_TYPE'" ;;
esac

if [[ "$SDK_TYPE" == "android" && "$PLATFORM" != "android" ]]; then
warn "--sdk=android only runs on --platform=android; skipping --platform=$PLATFORM"
exit 0
fi

# ── Real-device validation + signing setup ────────────────────────────────────
# When --device-real is set, we need a physical-device build and codesigning
# inputs. Centralised here so the rest of the script stays simulator-shaped
Expand All @@ -174,6 +194,7 @@ if [[ "$IOS_REAL_DEVICE" == true ]]; then
[[ "$PLATFORM" == "ios" ]] || error "--device-real only supports --platform=ios"
case "$SDK_TYPE" in
cordova|capacitor|react-native|expo) ;;
android) error "--device-real not applicable to --sdk=android (native Android)" ;;
flutter|dotnet) error "--device-real not yet supported for $SDK_TYPE — patch run-local.sh's build_${SDK_TYPE//-/_}_ios to invoke the device build" ;;
esac
[[ -n "$UDID" ]] || error "--device-real requires --udid=<id> (or UDID env). Find via: xcrun devicectl list devices"
Expand Down Expand Up @@ -293,6 +314,22 @@ elif [[ "$SDK_TYPE" == "unity" ]]; then
else
APP_PATH="${APP_PATH:-$DEMO_DIR/Build/Android/onesignal-demo.apk}"
fi
elif [[ "$SDK_TYPE" == "android" ]]; then
ANDROID_DIR="${ANDROID_DIR:-$SDK_ROOT/OneSignal-Android-SDK}"
[[ -d "$ANDROID_DIR" ]] || error "Native Android SDK not found at $ANDROID_DIR — set ANDROID_DIR in .env"
DEMO_DIR="$ANDROID_DIR/examples/demo"
ANDROID_FLAVOR="${ANDROID_FLAVOR:-gms}"
ANDROID_BUILD_TYPE="${ANDROID_BUILD_TYPE:-debug}"
case "$ANDROID_FLAVOR" in
gms|huawei) ;;
*) error "ANDROID_FLAVOR must be 'gms' or 'huawei', got '$ANDROID_FLAVOR'" ;;
esac
case "$ANDROID_BUILD_TYPE" in
debug|release) ;;
*) error "ANDROID_BUILD_TYPE must be 'debug' or 'release', got '$ANDROID_BUILD_TYPE'" ;;
esac
# Gradle emits per-flavor/type APKs under app/build/outputs/apk/<flavor>/<buildType>/.
APP_PATH="${APP_PATH:-$DEMO_DIR/app/build/outputs/apk/${ANDROID_FLAVOR}/${ANDROID_BUILD_TYPE}/app-${ANDROID_FLAVOR}-${ANDROID_BUILD_TYPE}.apk}"
fi

# ── Platform defaults ────────────────────────────────────────────────────────
Expand Down Expand Up @@ -1373,6 +1410,48 @@ build_unity_android() {
info "App built: $APP_PATH"
}

build_android_native() {
# Building from OneSignalSDK/ (not examples/demo/) so the demo's :app
# transitively pulls in local SDK source via settings.gradle dependency
# substitution. This is the whole point of --sdk=android for SDK dev:
# changes under OneSignal-Android-SDK/OneSignalSDK/onesignal/ get exercised.
# See OneSignalSDK/settings.gradle for the substitution rules.
local sdk_dir="$ANDROID_DIR/OneSignalSDK"
[[ -x "$sdk_dir/gradlew" ]] || error "gradlew not found or not executable at $sdk_dir/gradlew"

# SDK_VERSION is required by settings.gradle; pull it from gradle.properties
# (defaults to whatever the local repo is on, e.g. 5.9.2) so callers don't
# have to keep it in sync.
local sdk_version
sdk_version=$(grep -E "^SDK_VERSION=" "$sdk_dir/gradle.properties" 2>/dev/null | head -1 | cut -d= -f2 | tr -d '[:space:]')
[[ -n "$sdk_version" ]] || error "Could not read SDK_VERSION from $sdk_dir/gradle.properties"

# Capitalize flavor + buildType to assemble the Gradle task name
# (assemble<Flavor><BuildType>, e.g. assembleGmsDebug).
local flavor_cap="$(tr '[:lower:]' '[:upper:]' <<< "${ANDROID_FLAVOR:0:1}")${ANDROID_FLAVOR:1}"
local type_cap="$(tr '[:lower:]' '[:upper:]' <<< "${ANDROID_BUILD_TYPE:0:1}")${ANDROID_BUILD_TYPE:1}"
local task="assemble${flavor_cap}${type_cap}"

# Demo reads ONESIGNAL_APP_ID / ONESIGNAL_ANDROID_CHANNEL_ID / E2E_MODE from
# `BuildConfig.*` (see examples/demo/app/build.gradle.kts:demoOverride). Pass
# them as Gradle -P props so the CLI value wins over examples/demo/local.properties.
local -a gradle_args=("-PSDK_VERSION=$sdk_version" "-PE2E_MODE=true")
if [[ -n "${ONESIGNAL_APP_ID:-}" ]]; then
gradle_args+=("-PONESIGNAL_APP_ID=$ONESIGNAL_APP_ID")
else
warn "ONESIGNAL_APP_ID not set — demo will fall back to its built-in default"
fi
if [[ -n "${ANDROID_CHANNEL_ID:-}" ]]; then
gradle_args+=("-PONESIGNAL_ANDROID_CHANNEL_ID=$ANDROID_CHANNEL_ID")
fi

info "Building :app:$task with local SDK source (SDK_VERSION=$sdk_version)..."
(cd "$sdk_dir" && ./gradlew ":app:$task" "${gradle_args[@]}")

[[ -f "$APP_PATH" ]] || error ".apk not found after build at $APP_PATH"
info "App built: $APP_PATH"
}

build_app() {
if [[ "$SKIP_BUILD" == true ]]; then
if [[ "$PLATFORM" == "ios" && ! -d "$APP_PATH" ]] || [[ "$PLATFORM" == "android" && ! -f "$APP_PATH" ]]; then
Expand Down Expand Up @@ -1424,6 +1503,8 @@ build_app() {
else
build_unity_android
fi
elif [[ "$SDK_TYPE" == "android" ]]; then
build_android_native
fi
}

Expand Down Expand Up @@ -1583,6 +1664,16 @@ start_appium() {
info "Appium ready (pid $pid)"
}

# Clear stale UiAutomator2 state between Android combos without rebooting the emulator.
cleanup_android_automation() {
[[ "$PLATFORM" == "android" ]] || return 0
adb shell cmd statusbar collapse >/dev/null 2>&1 || true
adb shell input keyevent KEYCODE_BACK >/dev/null 2>&1 || true
adb shell input keyevent KEYCODE_HOME >/dev/null 2>&1 || true
adb shell am force-stop io.appium.uiautomator2.server >/dev/null 2>&1 || true
adb shell am force-stop io.appium.uiautomator2.server.test >/dev/null 2>&1 || true
}

# ── 3. Reset app ─────────────────────────────────────────────────────────────
reset_app() {
if [[ "$SKIP_RESET" == true ]]; then
Expand Down Expand Up @@ -1674,6 +1765,7 @@ main() {
build_app
start_device
start_appium
cleanup_android_automation
reset_app
run_tests

Expand Down
Loading