capture-screenshots.sh (5959B)
1 #!/usr/bin/env bash 2 3 set -euo pipefail 4 5 SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 6 REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" 7 8 # Defaults 9 BASE_DIR="$REPO_ROOT/TalerPOS/build/screenshots" 10 ONLY_SCENARIOS="" 11 12 # Parse flags 13 while [[ $# -gt 0 ]]; do 14 case "$1" in 15 -s|--scenario) 16 ONLY_SCENARIOS="$2" 17 shift 2 18 ;; 19 -o|--output) 20 BASE_DIR="$2" 21 shift 2 22 ;; 23 -h|--help) 24 echo "Usage: $(basename "$0") [options]" 25 echo "" 26 echo "Options:" 27 echo " -s, --scenario <name> Run only the specified scenario(s), comma-separated" 28 echo " e.g. -s history or -s login,mfa-select,mfa-code" 29 echo " -o, --output <dir> Output directory (default: TalerPOS/build/screenshots)" 30 echo " -h, --help Show this help" 31 echo "" 32 echo "Scenarios: login, mfa-select, mfa-code, amount-entry, order, order-custom," 33 echo " order-custom-added, payment, payment-success, history, refund," 34 echo " refund-qr, navigation" 35 exit 0 36 ;; 37 *) 38 echo "Unknown option: $1 (use -h for help)" >&2 39 exit 1 40 ;; 41 esac 42 done 43 44 # Auto-detect simulators 45 echo "Auto-detecting available simulators..." 46 SIMULATORS=() 47 IPHONE=$(xcodebuild -project "$REPO_ROOT/TalerPOS.xcodeproj" -scheme TalerPOS -showdestinations 2>/dev/null \ 48 | grep 'platform:iOS Simulator' | grep 'name:iPhone' \ 49 | sed 's/.*name:\([^,}]*\).*/\1/' | sed 's/ *$//' | sort -u | tail -1) 50 IPAD=$(xcodebuild -project "$REPO_ROOT/TalerPOS.xcodeproj" -scheme TalerPOS -showdestinations 2>/dev/null \ 51 | grep 'platform:iOS Simulator' | grep 'name:iPad' | grep '11-inch' \ 52 | sed 's/.*name:\([^,}]*\).*/\1/' | sed 's/ *$//' | sort -u | tail -1) 53 [[ -n "$IPHONE" ]] && SIMULATORS+=("$IPHONE") 54 [[ -n "$IPAD" ]] && SIMULATORS+=("$IPAD") 55 56 if [[ ${#SIMULATORS[@]} -eq 0 ]]; then 57 echo "No simulators found." >&2 58 exit 1 59 fi 60 echo " Found: ${SIMULATORS[*]}" 61 echo "" 62 63 LOCALES=("en" "de" "fr") 64 65 # Read version from the Xcode project 66 VERSION=$(grep 'MARKETING_VERSION' "$REPO_ROOT/TalerPOS.xcodeproj/project.pbxproj" \ 67 | head -1 | sed 's/.*= *"\{0,1\}\([^";]*\)"\{0,1\}.*/\1/' | tr -d ' ') 68 VERSION="${VERSION:-unknown}" 69 70 # Ensure scheme includes TalerPOSUITests (Xcode sometimes strips it) 71 SCHEME_FILE="$REPO_ROOT/TalerPOS.xcodeproj/xcshareddata/xcschemes/TalerPOS.xcscheme" 72 if ! grep -q 'BlueprintName = "TalerPOSUITests"' "$SCHEME_FILE" 2>/dev/null; then 73 echo "Injecting TalerPOSUITests into scheme..." 74 UI_TEST_REF=' <TestableReference\ 75 skipped = "NO">\ 76 <BuildableReference\ 77 BuildableIdentifier = "primary"\ 78 BlueprintIdentifier = "E5000001"\ 79 BuildableName = "TalerPOSUITests.xctest"\ 80 BlueprintName = "TalerPOSUITests"\ 81 ReferencedContainer = "container:TalerPOS.xcodeproj">\ 82 <\/BuildableReference>\ 83 <\/TestableReference>' 84 sed -i '' "/<\/Testables>/i\\ 85 $UI_TEST_REF 86 " "$SCHEME_FILE" 87 fi 88 89 # Build test target to pick the right test method 90 if [[ -n "$ONLY_SCENARIOS" ]]; then 91 TEST_TARGET="-only-testing:TalerPOSUITests/ScreenshotTests/testSelectedScenarios" 92 echo "=== Capturing scenario(s): $ONLY_SCENARIOS ===" 93 else 94 TEST_TARGET="-only-testing:TalerPOSUITests/ScreenshotTests/testAllScreenshots" 95 echo "=== Capturing all screenshots for version $VERSION ===" 96 fi 97 echo "" 98 99 for SIMULATOR in "${SIMULATORS[@]}"; do 100 echo "--- Device: $SIMULATOR ---" 101 102 # Sanitize device name for folder (spaces -> underscores, lowercase) 103 DEVICE_FOLDER=$(echo "$SIMULATOR" | tr ' ' '_' | tr '[:upper:]' '[:lower:]') 104 105 # Boot simulator and override status bar to 9:41 106 SIM_UDID=$(xcrun simctl list devices available | grep "$SIMULATOR" | head -1 | sed 's/.*(\([A-F0-9-]*\)).*/\1/') 107 if [[ -n "$SIM_UDID" ]]; then 108 xcrun simctl boot "$SIM_UDID" 2>/dev/null || true 109 sleep 3 110 xcrun simctl status_bar "$SIM_UDID" override \ 111 --time "9:41" \ 112 --batteryState charged \ 113 --batteryLevel 100 \ 114 --cellularBars 4 \ 115 --wifiBars 3 116 echo " Status bar set to 9:41 on $SIM_UDID" 117 fi 118 119 for LOCALE in "${LOCALES[@]}"; do 120 echo " === Locale: $LOCALE ===" 121 122 DEVICE_DIR="$BASE_DIR/$VERSION/$DEVICE_FOLDER/$LOCALE" 123 mkdir -p "$DEVICE_DIR" 124 125 RESULT_BUNDLE="$DEVICE_DIR/ScreenshotTests.xcresult" 126 rm -rf "$RESULT_BUNDLE" 127 128 TMPDIR_EXPORT=$(mktemp -d) 129 130 SCREENSHOT_LOCALE="$LOCALE" SCREENSHOT_SCENARIOS="$ONLY_SCENARIOS" xcodebuild test \ 131 -project "$REPO_ROOT/TalerPOS.xcodeproj" \ 132 -scheme TalerPOS \ 133 -destination "platform=iOS Simulator,name=$SIMULATOR" \ 134 $TEST_TARGET \ 135 -resultBundlePath "$RESULT_BUNDLE" \ 136 | grep -E '(Test Case|Test Suite|error:|BUILD|Failing)' || true 137 138 echo "" 139 140 # Export attachments + manifest 141 xcrun xcresulttool export attachments \ 142 --path "$RESULT_BUNDLE" \ 143 --output-path "$TMPDIR_EXPORT" 144 145 # Use manifest.json to rename files by scenario name 146 if [[ -f "$TMPDIR_EXPORT/manifest.json" ]]; then 147 python3 -c " 148 import json, shutil, os 149 manifest = json.load(open('$TMPDIR_EXPORT/manifest.json')) 150 for entry in manifest: 151 for att in entry.get('attachments', []): 152 exported = att.get('exportedFileName', '') 153 suggested = att.get('suggestedHumanReadableName', '') 154 scenario = suggested.split('_0_')[0] if '_0_' in suggested else suggested.rsplit('.', 1)[0] 155 src = os.path.join('$TMPDIR_EXPORT', exported) 156 dst = os.path.join('$DEVICE_DIR', scenario + '.png') 157 if os.path.exists(src): 158 shutil.move(src, dst) 159 print(f' {scenario}.png') 160 " 161 fi 162 163 rm -rf "$TMPDIR_EXPORT" 164 rm -rf "$RESULT_BUNDLE" 165 166 echo "" 167 done 168 169 # Clear status bar override 170 if [[ -n "$SIM_UDID" ]]; then 171 xcrun simctl status_bar "$SIM_UDID" clear 172 fi 173 done 174 175 echo "=== Done ===" 176 echo "Screenshots at: $BASE_DIR/$VERSION/" 177 find "$BASE_DIR/$VERSION" -name "*.png" | sort