RebreakVpnService.onStartCommand crashed with SecurityException because Android 16's validateForegroundServiceType rejects the implicit 2-arg startForeground(). Now passes FOREGROUND_SERVICE_TYPE_SPECIAL_USE explicitly (Google's documented best practice) and guards the call so a failed foreground promotion stops the service cleanly instead of crashing the app. Verified vs reported Galaxy A54 / Android 16 signature (97% of crash events, 1-user crash loop). Bundles pending working-tree work across native/marketing/locales/mac + graphify-out rebuild. gitignore: google-services.json + /screenshots/. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
10 KiB
Maestro E2E — Local Setup (Phase A)
Phase A: lokales CLI, 0 Cost, kein Cloud-Account. Phase B (post-TestFlight): Maestro Cloud fuer CI-Reports + Multi-Device-Parallel — Entscheidung steht aus.
1. Maestro CLI installieren
curl -Ls "https://get.maestro.mobile.dev" | bash
Danach Shell neu starten oder:
export PATH="$PATH:$HOME/.maestro/bin"
Verify:
maestro --version
# Erwarteter Output: Maestro CLI 1.x.x
2. App auf Device / Simulator bauen
Maestro benoetigt eine laufende App-Installation. Expo Dev-Client oder Production-Build.
iOS Simulator
# Im rebreak-native Verzeichnis:
cd apps/rebreak-native
# Dev-Build auf Standard-Simulator (erster verfuegbarer):
pnpm exec expo run:ios
# Spezifischer Simulator (Name aus "xcrun simctl list devices"):
pnpm exec expo run:ios --device "iPhone 15"
Alternativ via konsolidiertem Dev-Script:
# Vollbuild auf iPhone via USB:
bash apps/rebreak-native/dev.sh ios
# WiFi-Modus (kein Kabel, Metro über LAN):
bash apps/rebreak-native/dev.sh ios --wifi
# Schneller JS-Reload ohne Native-Rebuild:
bash apps/rebreak-native/dev.sh ios --no-build
Android Emulator
Emulator muss vorher gestartet sein (Android Studio -> Device Manager).
bash apps/rebreak-native/install-android.sh
Oder direkt:
pnpm exec expo run:android
Bundle-ID
org.rebreak.app (iOS + Android identisch) — steht so in app.config.ts und in den
Flow-Headern als appId: org.rebreak.app.
3. Env-Vars setzen
Flows benoetigen Test-User-Credentials. Nie hardcoden — immer als Env-Vars uebergeben.
Option A: direktes --env Flag
maestro test \
--env=E2E_TEST_USER=admin \
--env=E2E_TEST_PASSWORD=<Passwort aus Infisical> \
apps/rebreak-native/.maestro/auth/email-signin.yaml
Option B: Infisical Wrapper
infisical run -- maestro test apps/rebreak-native/.maestro/auth/email-signin.yaml
Voraussetzung: Infisical-Projekt hat E2E_TEST_USER und E2E_TEST_PASSWORD als Secrets.
Variablen die Flows erwarten:
| Var | Beschreibung |
|---|---|
E2E_TEST_USER |
Username-Teil der E-Mail (ohne @rebreak.internal) |
E2E_TEST_PASSWORD |
Passwort des Test-Users auf Staging |
Wichtig: Der Backend-Server haengt @rebreak.internal automatisch an den Username.
In den Flows steht deshalb ${E2E_TEST_USER}@rebreak.internal als E-Mail-Input.
Test-Account (aktueller Stand)
admin@rebreak.org— email-basierter Account, Passwort in Infisical alsE2E_TEST_PASSWORDDann:E2E_TEST_USER=admincharioanouar@gmail.com— Google OAuth only, kein Passwort → kann NICHT fuer Maestro-Email-Login genutzt werdenclaude-android-test@rebreak.internal— dedizierter CI-Test-Account (Erstellung via Service-Role noetig wenn nicht vorhanden)
Empfehlung: admin-Account fuer lokale Flow-Tests nutzen.
4. Flows ausfuehren
Einen einzelnen Flow
maestro test apps/rebreak-native/.maestro/auth/signin.yaml \
--env=E2E_TEST_USER=claude-android-test \
--env=E2E_TEST_PASSWORD=<passwort>
Alle Flows (sequenziell)
maestro test apps/rebreak-native/.maestro/
Mit ENV-Datei-Uebergabe:
maestro test \
--env=E2E_TEST_USER=claude-android-test \
--env=E2E_TEST_PASSWORD=<passwort> \
apps/rebreak-native/.maestro/
Spezifische Subdirectory
maestro test apps/rebreak-native/.maestro/auth/
5. Flow-Entwicklung: Maestro Studio
Visual Flow-Builder im Browser — zeigt Screen-Snapshot + verfuegbare Elemente.
# App muss laufen auf Device/Simulator:
maestro studio
Browser oeffnet auf http://localhost:9999. Elemente anklicken, YAML auto-generieren,
dann in .maestro/<area>/<scenario>.yaml speichern.
6. Tipps fuer stabile Flows
Warte auf Animationen:
- waitForAnimationToEnd:
timeout: 4000
Splash-Screen, Screen-Transitions und API-Calls brauchen Zeit.
Faustregel: nach launchApp min. 5000ms, nach Navigation 2000-4000ms.
Flaky Tests debuggen:
# Output-Logs waehrend Run:
maestro test --format junit --output report.xml apps/rebreak-native/.maestro/auth/signin.yaml
# Screenshot bei Fehler: Maestro macht automatisch einen Screenshot im Fehlerfall.
# Findet sich unter ~/.maestro/tests/<timestamp>/
Selektoren — Prioritaet:
id: "<testID>"— stabielste Option. RN-Prop:testID="mein-btn".text: "..."— nur fuer statische, locale-unabhaengige Strings.point: "x%, y%"— letzter Ausweg, bricht bei Screen-Size-Aenderungen.- Niemals
text:fuer i18n-Strings (t('...')-Output) wenn Locale-Wechsel moeglich.
Device angeben (Multi-Device):
maestro test --device=<DEVICE_ID> apps/rebreak-native/.maestro/
# Device-IDs: `adb devices` (Android) / `xcrun simctl list` (iOS)
7. App-State vor Test-Lauf
clearState: true in jedem Flow-Header stellt sicher dass:
- Auth-Session geleert ist
- Kein persistierter State (MMKV / AsyncStorage) den Flow stoert
- Jeder Flow von einem definierten Ausgangspunkt startet (Login-Screen)
Test-User muss vorab auf dem Staging-Backend existieren:
- Username:
claude-android-test - E-Mail:
claude-android-test@rebreak.internal - Account: email-confirmed, kein Admin-Flag
- Erstellung: nur per Service-Role-Key +
auth.admin.createUser({ email_confirm: true })(nicht im Flow selbst — Test-User ist persistent)
8. Flow-Uebersicht
Bestehende Flows (Phase A)
| Flow | Was wird geprueft | Stabil? |
|---|---|---|
auth/signin.yaml |
App startet, Login via Email+Pw, Home-Feed sichtbar | Ja (text-selektoren) |
auth/email-signin.yaml |
Identisch — aktuelle Version mit besseren Kommentaren | Ja |
urge/start-session.yaml |
SOS im Dropdown erreichbar, Lyra-Screen laedt | Koordinaten-Fallback |
urge/sos-flow.yaml |
SOS → Lyra-Chat → "Atemübung" Chip → BreathingDrawer | LLM-abhaengig |
community/post.yaml |
ComposeCard, Text-Input, Submit | Ja |
community/create-post.yaml |
Identisch — aktuelle Version | Ja |
profile/view-profile.yaml |
Profil-Navigation, ProfileHeader, StatsBar | Koordinaten-Fallback |
profile/view-and-edit.yaml |
Profil → Edit → Nickname aendern → Speichern | Koordinaten-Fallback |
profile/demographics.yaml |
DemographicsAccordion toggle, WheelPicker oeffnet | Text-selektoren |
settings/dark-theme.yaml |
Settings → Theme → Dunkel | Native-Menu-Limitation |
Neue Flows (Phase A+, kritische Coverage)
| Flow | Prioritaet | Was wird geprueft | Stabil? | Blocker |
|---|---|---|---|---|
onboarding/new-user-streak-guard.yaml |
HOCH | Streak-Counter nach Login nicht 0 — Regressions-Guard fuer current_days-Bug | Ja | Kein frischer-Account-Test ohne reset-Mechanismus |
sos/crisis-flow.yaml |
HOECHSTE | SOS-Navigation + Lyra antwortet + Atemübung erreichbar | LLM-abhaengig | Avatar-Tap Koordinaten-Fallback |
blocker/activation-smoke.yaml |
HOCH | Blocker-Tab erreichbar, Protection Card + URL-Filter-Layer sichtbar | Ja | Activation-Step selbst nicht testbar (System-Dialog) |
calls/incoming-call-screen.yaml |
MITTEL | Chat-Tab laedt, DM-Liste zeigt keine Phantom-Call-Artefakte | Teilweise | Echter Incoming-Call braucht 2 Devices (Phase B) |
dm/send-message.yaml |
HOCH | DM oeffnen, Nachricht senden, Bubble erscheint | Abhaengig von E2E_TEST_PEER_NICKNAME | Peer-Nickname-Env-Var noetig |
dm/realtime-receive.yaml |
MITTEL | Realtime-Empfang — Nachricht erscheint ohne Reload | SCAFFOLD ONLY | Braucht externen Trigger oder 2-Device-Setup |
stress/dm-scroll-performance.yaml |
MITTEL | DM-Scroll auf A50, kein ANR/Crash nach 8 Swipes | Geraete-abhaengig | Braucht 50+ Messages in Test-DM |
stress/rapid-post-submit.yaml |
MITTEL | 3 Posts hintereinander, ComposeCard resettet jedes Mal | Ja | Posts landen in Staging-DB — manuelles Cleanup |
Koordinaten-Fallback = Flow nutzt point: "x%, y%" fuer Avatar-Button, weil kein testID vorhanden.
Bricht wenn Header-Layout geaendert wird. Betroffene testIDs: TODO_TESTIDS.md.
Native-Menu-Limitation = @react-native-menu/menu (UIMenu auf iOS) kann Maestro moeglicherweise
nicht interagieren — Flow koennte an diesem Step haengen. Wenn settings/dark-theme.yaml immer
an "Systemstandard" haengt: bekanntes Problem, kein Maestro-Bug, sondern iOS-Restriktion.
SCAFFOLD ONLY = Flow ist dokumentiertes Intent, laeuft aber nicht im CI durch ohne externe Infrastruktur (2. Device, API-Trigger). Nicht in den default Run aufnehmen bis Phase B.
9. Neue Env-Vars fuer Phase-A+-Flows
Bestehende Vars (E2E_TEST_USER, E2E_TEST_PASSWORD) werden weiterhin genutzt.
Zusaetzlich noetig fuer neue Flows:
| Var | Flow | Beschreibung |
|---|---|---|
E2E_TEST_PEER_NICKNAME |
dm/send-message.yaml, dm/realtime-receive.yaml, stress/dm-scroll-performance.yaml |
Nickname des DM-Peers im Staging-Account des Test-Users (z.B. ein zweites CI-Test-Konto) |
Empfehlung: claude-android-test als Test-User + ein zweites Konto claude-android-test-peer
anlegen via Service-Role. Beide als DM-Kontakt seeden (ein manueller DM loest das).
10. Run-Befehle Phase A+
Nur stabile Flows (alles ausser SCAFFOLD ONLY):
maestro test \
--env=E2E_TEST_USER=claude-android-test \
--env=E2E_TEST_PASSWORD=<passwort> \
--env=E2E_TEST_PEER_NICKNAME=<peer-nickname> \
apps/rebreak-native/.maestro/onboarding/ \
apps/rebreak-native/.maestro/sos/ \
apps/rebreak-native/.maestro/blocker/ \
apps/rebreak-native/.maestro/calls/ \
apps/rebreak-native/.maestro/dm/send-message.yaml \
apps/rebreak-native/.maestro/stress/rapid-post-submit.yaml
Stress-Tests separat (laenger, geraete-abhaengig):
maestro test \
--env=E2E_TEST_USER=claude-android-test \
--env=E2E_TEST_PASSWORD=<passwort> \
--env=E2E_TEST_PEER_NICKNAME=<peer-nickname> \
apps/rebreak-native/.maestro/stress/
11. Phase B — Maestro Cloud (Zukunft, post-TestFlight)
Was bei Cloud-Wechsel geaendert werden muss:
- Maestro-Cloud-Account anlegen:
maestro cloud login - CI-Run-Befehl aendern:
maestro cloud apps/rebreak-native/.maestro/ - ENV-Vars in CI-Secret-Store hinterlegen (GitHub Actions Secrets / Infisical CI-Integration)
- Multi-Device-Matrix:
--device ios/--device androidseparat schedulen - Report-URL aus Cloud-Output in PR-Kommentare posten (GitHub Actions Step)
Bis dahin: lokaler CLI reicht fuer Pre-Release-Smoke-Tests.