Athena — roomy-mobile/archive/changes/2025-12-24-add-maestro-screenshot-automation/design.md

Context

The Roomy app requires App Store and Play Store screenshots for marketing submissions. Currently, no automation exists - screenshots are captured manually per device/language combination. The project has Maestro infrastructure (empty .maestro/ directories) and Firebase Emulators already configured.

Stakeholders: Developers generating store assets, marketing team receiving screenshots

Constraints:

  • Must use Firebase Emulators (not production data)
  • Must use Maestro framework (existing infrastructure)
  • Dark mode only (app has no light mode)
  • Email/password auth only for seeded accounts
  • Screenshots must not contain real user data

Goals / Non-Goals

Goals:

  • Single-command screenshot generation for all device/language combinations
  • Deterministic, reproducible output (same seed = same screenshots)
  • Store-compliant screenshot dimensions
  • Organized output structure for direct store submission

Non-Goals:

  • Marketing overlays or text additions (raw app screenshots only)
  • Automated store upload
  • CI/CD integration (manual execution sufficient for initial release)
  • Video capture

Decisions

Decision 1: Firebase Emulator Seed via JavaScript Script

What: Create roomy-firebase/scripts/seed-emulator.js using firebase-admin SDK

Why:

  • JavaScript aligns with existing Firebase Functions codebase
  • firebase-admin provides full Auth + Firestore control
  • Programmatic creation ensures deterministic data
  • Easier to maintain than JSON export files

Alternatives considered:

  • JSON import via firebase emulators:start --import: Harder to maintain, binary-like format
  • TypeScript seed script: Extra compilation step not justified for single script

Decision 2: Modular Maestro Flow Structure

What: Organize flows as:

.maestro/
├── common/
│   └── login.yaml           # Reusable login flow
├── screens/
│   ├── 01-home.yaml          # Individual screen flows
│   ├── 02-cleaning-tasks.yaml
│   └── ...
└── screenshot-all.yaml       # Orchestrator flow

Why:

  • Modular flows enable reuse (login shared across all)
  • Numbered prefixes ensure consistent execution order
  • Single orchestrator file for full runs
  • Individual files for debugging specific screens

Alternatives considered:

  • Single monolithic flow: Harder to maintain and debug
  • Feature-based grouping: Less predictable execution order

Decision 3: Shell Script Device Matrix Orchestration

What: Create scripts/capture-screenshots.sh that iterates devices and languages

Why:

  • Maestro lacks native device matrix support
  • Shell scripts are portable and require no dependencies
  • Easy to modify device/language lists
  • Can handle simulator/emulator lifecycle

Alternatives considered:

  • Node.js orchestration: Over-engineering for iteration logic
  • Make targets per device: Verbose and hard to maintain

Decision 4: Locale Switching via Simulator Settings

What: Use xcrun simctl spawn (iOS) and adb shell setprop (Android) to change device locale before each run

Why:

  • Maestro cannot change device locale mid-flow
  • Simulator-level locale change is most reliable
  • Avoids app-level locale override complexity

Trade-off: Requires simulator restart between languages, adding ~30s per switch

Decision 5: Environment Variable for Output Path

What: Pass OUTPUT_DIR environment variable to Maestro flows for screenshot paths

Why:

  • Enables same flow to output to different directories per device/language
  • Maestro supports ${OUTPUT_DIR} syntax in takeScreenshot paths
  • Clean separation of flow logic from output organization

Risks / Trade-offs

| Risk | Mitigation | |------|------------| | Simulator names change across Xcode versions | Document exact simulator names; use xcrun simctl list to verify | | Maestro element selectors break with UI changes | Use semantic labels or test IDs; document selector strategy | | Screenshots capture loading states | Add explicit waitForAnimationToEnd and assertVisible before captures | | Status bar clock/battery inconsistent | Accept as-is; store guidelines allow this variance | | Emulator seed data becomes stale | Seed script is source of truth; re-run when data model changes |

Open Questions

None - the research phase (Prime) resolved all significant unknowns.

Reacties

Nog geen reacties