store-screenshots #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |