#!/usr/bin/env bash # Author: cirakg & claude ai # Summary: Run the scripted UI flow on each device in the headless simulator and compare every screen with its golden image. # # Usage: screenshots.sh DEVICE [DEVICE ...] (APPROVE=1 saves new goldens) # Output: build/screenshots//.png (the watch screen only), # plus -diff.png where a screen differs from # test/golden//.png. # # Uses the UI-test build (uitest.jungle): fake entries, PIN 1234 and a # frozen clock, so every screenshot is reproducible. tools/ui_flow.py # drives the app and checks the screens. Then the app is launched again and # its glance, which now shows the favourite's code (the first run sealed it), # is checked as glance_code.png. Then the second UI-test build # (uitest-extra.jungle: legacy PIN, queued "Require PIN", more symbologies) # runs the extra scenario (ui_flow.py --scenario extra), and its glance, # without a code, is checked as glance.png. set -euo pipefail # shellcheck source=ciq-env.sh source "$(dirname "${BASH_SOURCE[0]}")/ciq-env.sh" (($# > 0)) || die "usage: screenshots.sh DEVICE [DEVICE ...]" ciq_require_sdk ciq_require_key for device in "$@"; do build-app.sh uitest "${device}" build-app.sh uitest-extra "${device}" done ciq_start_display ciq_start_simulator out="${BUILD_DIR}/screenshots" # A new launch of MODE's build starts in the glance; screenshot it as SCREEN # (its "DIAG shown" name) before anything opens the app. shoot_glance() { local device="$1" mode="$2" screen="$3" glance_log="${out}/$1/${3}.log" : >"${glance_log}" monkeydo "${BUILD_DIR}/${mode}/${device}.prg" "${device}" >>"${glance_log}" 2>&1 & CIQ_MONKEYDO_PID=$! local shown=0 for _ in $(seq 1 600); do if grep -Eq "DIAG shown ${screen}[[:space:]]*$" "${glance_log}"; then shown=1 break fi sleep 0.05 done if ((shown == 0)); then ciq_stop_app log "${device}: the glance (${screen}) didn't appear; see ${glance_log}" return 1 fi sleep 1 local status=0 python3 /work/tools/ui_flow.py --shot "${screen}" --device-dir "${CIQ_HOME}/Devices/${device}" \ --window "$(ciq_simulator_window)" --out "${out}/${device}" --golden "/work/test/golden/${device}" \ "${approve[@]}" || status=1 ciq_stop_app return "${status}" } mkdir -p "${out}" approve=() [[ "${APPROVE:-0}" == 1 ]] && approve=(--approve) failed=0 for device in "$@"; do mkdir -p "${out}/${device}" log_file="${out}/${device}/app.log" if ! ciq_launch_app "${device}" "${log_file}" uitest; then ciq_stop_app log "no first frame on ${device}; see ${log_file}" failed=1 continue fi python3 /work/tools/ui_flow.py --device-dir "${CIQ_HOME}/Devices/${device}" --log "${log_file}" \ --window "$(ciq_simulator_window)" --out "${out}/${device}" --golden "/work/test/golden/${device}" \ "${approve[@]}" || failed=1 ciq_stop_app shoot_glance "${device}" uitest glance_code || failed=1 # The extra scenario: its own build and launch (README 17.4). extra_log="${out}/${device}/app-extra.log" if ! ciq_launch_app "${device}" "${extra_log}" uitest-extra; then ciq_stop_app log "no first frame of the extra scenario on ${device}; see ${extra_log}" failed=1 continue fi python3 /work/tools/ui_flow.py --scenario extra --device-dir "${CIQ_HOME}/Devices/${device}" --log "${extra_log}" \ --window "$(ciq_simulator_window)" --out "${out}/${device}" --golden "/work/test/golden/${device}" \ "${approve[@]}" || failed=1 ciq_stop_app shoot_glance "${device}" uitest-extra glance || failed=1 done ((failed == 0)) || die "screenshot checks failed; see build/screenshots/" log "screenshots checked on: $*"