#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" WORKSPACE_ROOT="$(cd "${PROJECT_ROOT}/.." && pwd)" PROJECT_PATH="${PROJECT_ROOT}/TheNoiseClock.xcodeproj" SCHEME="${SCHEME:-TheNoiseClock}" TEST_IDENTIFIER="${TEST_IDENTIFIER:-TheNoiseClockUITests/TheNoiseClockUITests/testAppStoreScreenshots_iPhone69}" RUNTIME_ID="${RUNTIME_ID:-com.apple.CoreSimulator.SimRuntime.iOS-26-2}" OUTPUT_ROOT="${OUTPUT_ROOT:-${WORKSPACE_ROOT}/Screenshots}" EXPECTED_COUNT=5 expected_files=( "01-clock-view-portrait.png" "02-clock-view-landscape.png" "03-alarms-view-portrait.png" "04-noise-view-portrait.png" "05-clock-settings-portrait.png" ) locales=( "fr-CA|fr|CA" "es-MX|es|MX" ) devices=( "iPhone-6.3|AppStore iPhone 17 Pro 26.2|com.apple.CoreSimulator.SimDeviceType.iPhone-17-Pro" "iPhone-6.5|AppStore iPhone 11 Pro Max 26.2|com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro-Max" "iPhone-6.9|AppStore iPhone 17 Pro Max 26.2|com.apple.CoreSimulator.SimDeviceType.iPhone-17-Pro-Max" "iPad-13|AppStore iPad Pro 13-inch (M5) 26.2|com.apple.CoreSimulator.SimDeviceType.iPad-Pro-13-inch-M5-12GB" ) simctl_json() { xcrun simctl list devices available -j } find_sim_udid() { local runtime_id="$1" local name="$2" simctl_json | jq -r --arg runtime_id "$runtime_id" --arg name "$name" ' .devices[$runtime_id][]? | select(.isAvailable == true and .name == $name) | .udid ' | head -n1 } ensure_simulator() { local name="$1" local device_type="$2" local runtime_id="$3" local udid udid="$(find_sim_udid "$runtime_id" "$name")" if [[ -n "$udid" ]]; then echo "$udid" return 0 fi udid="$(xcrun simctl create "$name" "$device_type" "$runtime_id")" echo "$udid" } validate_output_folder() { local folder="$1" local png_count png_count="$(find "$folder" -maxdepth 1 -name '*.png' | wc -l | tr -d ' ')" if [[ "$png_count" -ne "$EXPECTED_COUNT" ]]; then echo "Expected ${EXPECTED_COUNT} screenshots in ${folder}, found ${png_count}." >&2 return 1 fi local missing=0 for file_name in "${expected_files[@]}"; do if [[ ! -f "${folder}/${file_name}" ]]; then echo "Missing ${folder}/${file_name}" >&2 missing=1 fi done if [[ "$missing" -ne 0 ]]; then return 1 fi } export_attachments_to_output_folder() { local result_bundle="$1" local folder="$2" local attachments_tmp attachments_tmp="$(mktemp -d "/tmp/noiseclock-attachments.XXXXXX")" xcrun xcresulttool export attachments \ --path "$result_bundle" \ --output-path "$attachments_tmp" >/dev/null local manifest_path="${attachments_tmp}/manifest.json" if [[ ! -f "$manifest_path" ]]; then echo "Missing attachment manifest at ${manifest_path}" >&2 rm -rf "$attachments_tmp" return 1 fi local missing=0 for file_name in "${expected_files[@]}"; do local base_name="${file_name%.png}" local exported_name exported_name="$(jq -r --arg base_name "$base_name" ' [.[].attachments[]? | select((.suggestedHumanReadableName // "") | startswith($base_name + "_")) | .exportedFileName][0] // empty ' "$manifest_path")" if [[ -z "$exported_name" || ! -f "${attachments_tmp}/${exported_name}" ]]; then echo "Missing exported attachment for ${file_name} in ${result_bundle}" >&2 missing=1 continue fi cp "${attachments_tmp}/${exported_name}" "${folder}/${file_name}" done if [[ "$missing" -ne 0 ]]; then rm -rf "$attachments_tmp" return 1 fi rm -rf "$attachments_tmp" } echo "Using project: ${PROJECT_PATH}" echo "Using scheme: ${SCHEME}" echo "Output root: ${OUTPUT_ROOT}" echo "Runtime: ${RUNTIME_ID}" mkdir -p "$OUTPUT_ROOT" for locale_entry in "${locales[@]}"; do IFS='|' read -r locale_folder language_code region_code <<< "$locale_entry" echo "" echo "=== Locale ${locale_folder} (${language_code}-${region_code}) ===" for device_entry in "${devices[@]}"; do IFS='|' read -r device_folder sim_name device_type <<< "$device_entry" echo "--- Device ${device_folder} (${sim_name}) ---" udid="$(ensure_simulator "$sim_name" "$device_type" "$RUNTIME_ID")" output_dir="${OUTPUT_ROOT}/${locale_folder}/${device_folder}" result_bundle="/tmp/TheNoiseClock-${locale_folder}-${device_folder}.xcresult" rm -rf "$result_bundle" mkdir -p "$output_dir" rm -f "${output_dir}"/*.png xcrun simctl shutdown "$udid" >/dev/null 2>&1 || true xcrun simctl erase "$udid" >/dev/null 2>&1 || true SCREENSHOT_OUTPUT_DIR="$output_dir" xcodebuild \ -project "$PROJECT_PATH" \ -scheme "$SCHEME" \ -destination "platform=iOS Simulator,id=${udid}" \ -testLanguage "$language_code" \ -testRegion "$region_code" \ -only-testing:"${TEST_IDENTIFIER}" \ -parallel-testing-enabled NO \ -resultBundlePath "$result_bundle" \ test export_attachments_to_output_folder "$result_bundle" "$output_dir" validate_output_folder "$output_dir" echo "Saved ${EXPECTED_COUNT} screenshots to ${output_dir}" done done echo "" echo "Screenshot matrix completed successfully."