#!/usr/bin/env bash # ============================================================================= # Run Instrumentation Tests on Firebase Test Lab # ============================================================================= # This script runs the Android instrumentation tests (UI tests) on Firebase # Test Lab across the configured device matrix. # # Prerequisites: # 1. gcloud CLI installed and authenticated (gcloud auth login) # 2. Firebase project created and Blaze plan enabled # 3. Google Play Console linked to Firebase project # 4. Service account with Firebase Test Lab admin role # # Usage: # ./run_instrumentation_tests.sh [options] # # Options: # --project-id Firebase project ID (default: kordant-android) # --device-model Specific device model (runs all by default) # --api-level Specific API level (runs all by default) # --orientation Specific orientation: portrait|landscape (runs both by default) # --locale Specific locale (runs all by default) # --app-apk Path to app APK (default: auto-detected) # --test-apk Path to test APK (default: auto-detected) # --dry-run Print gcloud command without executing # --help Show this help message # ============================================================================= set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" # Default values PROJECT_ID="${FIREBASE_PROJECT_ID:-kordant-android}" APP_APK="" TEST_APK="" DRY_RUN=false # Device matrix from test_matrix_config.yaml DEVICES=( "--device model=Pixel6,version=33,locale=en_US,orientation=portrait" "--device model=Pixel6,version=33,locale=en_US,orientation=landscape" "--device model=Pixel6,version=33,locale=es_ES,orientation=portrait" "--device model=Pixel6,version=33,locale=es_ES,orientation=landscape" "--device model=Pixel4,version=30,locale=en_US,orientation=portrait" "--device model=Pixel4,version=30,locale=en_US,orientation=landscape" "--device model=Pixel4,version=30,locale=es_ES,orientation=portrait" "--device model=Pixel4,version=30,locale=es_ES,orientation=landscape" "--device model=GalaxyS21,version=31,locale=en_US,orientation=portrait" "--device model=GalaxyS21,version=31,locale=en_US,orientation=landscape" "--device model=GalaxyS21,version=31,locale=es_ES,orientation=portrait" "--device model=GalaxyS21,version=31,locale=es_ES,orientation=landscape" "--device model=RedmiNote8,version=29,locale=en_US,orientation=portrait" "--device model=RedmiNote8,version=29,locale=en_US,orientation=landscape" "--device model=RedmiNote8,version=29,locale=es_ES,orientation=portrait" "--device model=RedmiNote8,version=29,locale=es_ES,orientation=landscape" "--device model=AquestM2,version=28,locale=en_US,orientation=portrait" "--device model=AquestM2,version=28,locale=en_US,orientation=landscape" "--device model=AquestM2,version=28,locale=es_ES,orientation=portrait" "--device model=AquestM2,version=28,locale=es_ES,orientation=landscape" ) # Parse arguments while [[ $# -gt 0 ]]; do case "$1" in --project-id) PROJECT_ID="$2" shift 2 ;; --app-apk) APP_APK="$2" shift 2 ;; --test-apk) TEST_APK="$2" shift 2 ;; --dry-run) DRY_RUN=true shift ;; --help) grep "^#" "$0" | grep -v "^#!/" | sed 's/^# //' exit 0 ;; *) echo "Unknown option: $1" echo "Usage: $0 --help" exit 1 ;; esac done # Auto-detect APK paths if not provided if [ -z "$APP_APK" ]; then # Try to find release APK APP_APK=$(find "$PROJECT_DIR/android/app/build/outputs/apk" -name "*-release.apk" 2>/dev/null | head -1) if [ -z "$APP_APK" ]; then APP_APK=$(find "$PROJECT_DIR/android/app/build/outputs/apk" -name "*.apk" 2>/dev/null | head -1) fi fi if [ -z "$TEST_APK" ]; then TEST_APK=$(find "$PROJECT_DIR/android/app/build/outputs/apk" -name "*androidTest*.apk" 2>/dev/null | head -1) if [ -z "$TEST_APK" ]; then TEST_APK=$(find "$PROJECT_DIR/android/app/build/outputs" -name "*.apk" -path "*androidTest*" 2>/dev/null | head -1) fi fi if [ -z "$APP_APK" ] || [ -z "$TEST_APK" ]; then echo "Error: Could not find APK files." echo " App APK: ${APP_APK:-not found}" echo " Test APK: ${TEST_APK:-not found}" echo "" echo "Build the APKs first:" echo " ./gradlew assembleProdRelease assembleProdDebugAndroidTest" exit 1 fi echo "==========================================" echo "Firebase Test Lab - Instrumentation Tests" echo "==========================================" echo "Project ID: $PROJECT_ID" echo "App APK: $APP_APK" echo "Test APK: $TEST_APK" echo "Devices: ${#DEVICES[@]} configurations" echo "" # Build gcloud command GCLOUD_CMD="gcloud firebase test android run \ --type instrumentation \ --project \"$PROJECT_ID\" \ --app \"$APP_APK\" \ --test \"$TEST_APK\" \ --timeout 60m \ --num-flaky-test-attempts 2 \ --record-video \ --performance-metrics \ --results-history-name \"Kordant Android Instrumentation Tests\"" # Add device configurations for device in "${DEVICES[@]}"; do GCLOUD_CMD="$GCLOUD_CMD $device" done echo "Command:" echo "$GCLOUD_CMD" echo "" if [ "$DRY_RUN" = true ]; then echo "DRY RUN - Command not executed." exit 0 fi echo "Starting instrumentation tests..." echo "" eval "$GCLOUD_CMD" EXIT_CODE=$? if [ $EXIT_CODE -eq 0 ]; then echo "" echo "✅ Instrumentation tests completed successfully!" echo "View results in Firebase Console: https://console.firebase.google.com/project/$PROJECT_ID/testlab" else echo "" echo "❌ Instrumentation tests failed with exit code $EXIT_CODE" echo "View results in Firebase Console: https://console.firebase.google.com/project/$PROJECT_ID/testlab" fi exit $EXIT_CODE