Skip to content

store-screenshots

store-screenshots #11

name: store-screenshots
# Genera gli screenshot App Store iOS su un runner macOS (non serve un Mac locale).
# Esecuzione manuale: Actions → store-screenshots → Run workflow.
# Gli artifact `ios-raw-screenshots` vanno scaricati in
# mobile/store/screenshots/_raw/ios/ e poi composti con:
# pwsh mobile/scripts/store-screenshots.ps1 -Mode compose-ios
#
# Prerequisiti (una tantum):
# - secret EAS_TOKEN (expo.dev → account → access tokens)
# - variabili/secret MAESTRO_EMAIL + MAESTRO_PASSWORD di un account demo
# con dati pre-popolati (cerchio "Famiglia Rossi", timeline, documenti...)
on:
workflow_dispatch:
jobs:
ios-screenshots:
runs-on: macos-15
# Monorepo npm workspaces: il lockfile e' alla ROOT (workspaces: frontend,
# mobile, packages/*). L'install va fatta dalla root; i comandi Expo/Maestro
# girano invece in mobile/ (esplicitato per-step, niente defaults globale).
env:
EXPO_TOKEN: ${{ secrets.EAS_TOKEN }}
# Il profilo store-screenshots (eas.json) usa APP_VARIANT=preview ->
# bundle id app.accanto.mobile.preview (vedi app.config.ts resolveVariant).
MAESTRO_APP_ID: app.accanto.mobile.preview
MAESTRO_EMAIL: ${{ secrets.MAESTRO_EMAIL }}
MAESTRO_PASSWORD: ${{ secrets.MAESTRO_PASSWORD }}
# Su runner CI freschi il driver XCTest di Maestro impiega piu' del
# default a installarsi/avviarsi la prima volta: alza il timeout (ms).
MAESTRO_DRIVER_STARTUP_TIMEOUT: '180000'
# Disattiva analytics anonimi di Maestro (meno rumore nei log CI).
MAESTRO_CLI_NO_ANALYTICS: '1'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
# Lockfile alla root del monorepo (mobile/package-lock.json NON esiste)
cache-dependency-path: package-lock.json
- name: Install dependencies (workspace root)
run: npm ci
# npm ci dalla root installa TUTTI gli workspace (mobile incluso) e
# linka @accanto/shared come workspace dependency. N.B.: shared e'
# consumato come SORGENTE TS (main: ./src/index.ts, niente build step
# — Metro lo transpila), quindi non serve alcuna build del workspace.
- name: Install Maestro
run: curl -Ls https://get.maestro.mobile.dev | bash
# Maestro CLI si installa in $HOME/.maestro/bin
- name: Boot iPhone 16 Pro Max simulator (6.9")
run: |
UDID=$(xcrun simctl create "store-shot" "iPhone 16 Pro Max" 2>/dev/null || true)
if [ -z "$UDID" ]; then
# fallback se il device type non e' disponibile sull'immagine
UDID=$(xcrun simctl create "store-shot" "iPhone 15 Pro Max")
fi
echo "SIM_UDID=$UDID" >> "$GITHUB_ENV"
xcrun simctl boot "$UDID"
xcrun simctl bootstatus "$UDID" -b
# Il flow Maestro naviga per testi VISIBILI in italiano ("Il tuo spazio",
# "Diario", ...). Il simulator su runner macOS parte in inglese: senza
# questo step l'app userebbe EN (se l'account demo non ha lingua salvata)
# e le asserzioni fallirebbero. Forza IT a livello di simulator.
- name: Set simulator language to Italian
run: |
xcrun simctl spawn "$SIM_UDID" defaults write "Apple Global Domain" AppleLanguages -array it
xcrun simctl spawn "$SIM_UDID" defaults write "Apple Global Domain" AppleLocale -string it_IT
# Status bar pulita (orario fisso 9:41, batteria piena, no sovrapposizioni):
# l'ora reale del simulator si sovrapponeva al layout della Welcome
# ("Passo 1 di 3" + ora) coprendo il link "Salta". status_bar override
# standard per screenshot store: rende la status bar discreta e fissa.
- name: Clean status bar for screenshots
run: |
xcrun simctl status_bar "$SIM_UDID" override \
--time "9:41" --batteryLevel 100 --batteryState charged \
--wifiMode active --cellularMode active || echo "status_bar override non supportato, continuo"
# "Scalda" il simulator: il primo launch inizializza i servizi XCUITest
# (simctl launch di un'app di sistema), riducendo il rischio che il
# driver Maestro vada in timeout alla prima connessione.
- name: Warm up simulator
run: |
xcrun simctl launch "$SIM_UDID" com.apple.mobilesafari || true
sleep 5
xcrun simctl terminate "$SIM_UDID" com.apple.mobilesafari || true
- name: Build iOS app (simulator profile) on EAS
working-directory: mobile
run: npx eas-cli build --platform ios --profile store-screenshots --non-interactive --wait --local 2>&1 | tee eas-build.log
# Profilo `store-screenshots` (eas.json): ios.simulator=true -> produce
# un .app installabile sul simulator. --local compila sul runner
# (Xcode presente su macos-15), nessuna attesa della coda EAS remota.
- name: Install app on simulator
working-directory: mobile
run: |
set -e
# eas build --local produce un <name>.tar.gz contenente il .app.
APP=$(find . -name "*.app" -maxdepth 4 | head -n1)
if [ -z "$APP" ]; then
TAR=$(find . -name "*.tar.gz" -maxdepth 3 | head -n1)
echo "Nessun .app diretto, estraggo $TAR"
mkdir -p /tmp/app # tar -C fallisce se la dir non esiste
tar -xzf "$TAR" -C /tmp/app
APP=$(find /tmp/app -name "*.app" | head -n1)
fi
if [ -z "$APP" ]; then
echo "::error::Nessun .app trovato dopo build/estrazione"; ls -la; exit 1
fi
echo "Installo $APP sul simulator $SIM_UDID"
xcrun simctl install "$SIM_UDID" "$APP"
- name: Run Maestro screenshot flow
working-directory: mobile
run: |
export PATH="$HOME/.maestro/bin:$PATH"
maestro test --device "$SIM_UDID" --output store/screenshots/_raw/ios .maestro/screenshots.yaml
- name: Flatten raw screenshots
working-directory: mobile
if: success()
run: |
# maestro salva in una sottocartella con timestamp: sposta i PNG in _raw/ios
find store/screenshots/_raw/ios -name "*.png" -exec mv {} store/screenshots/_raw/ios/ \;
ls -la store/screenshots/_raw/ios
- uses: actions/upload-artifact@v4
if: success()
with:
name: ios-raw-screenshots
path: mobile/store/screenshots/_raw/ios/*.png
retention-days: 30
# Carica SEMPRE (anche su fallimento) i debug artifact di Maestro:
# contengono gli screenshot dello schermo al momento del fallimento
# (incl. debug-after-login.png) e la UI hierarchy. Indispensabili per
# capire perche' un assertVisible fallisce.
- uses: actions/upload-artifact@v4
if: always()
with:
name: maestro-debug
path: /Users/runner/.maestro/tests/
retention-days: 14