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>
341 lines
11 KiB
YAML
341 lines
11 KiB
YAML
# screens/marketing-tour.yaml
|
|
#
|
|
# Maestro Marketing-Tour — alle 9 Screenshots in einem Lauf
|
|
#
|
|
# Dieser Flow führt nacheinander alle 9 Marketing-Screens an und macht je einen
|
|
# takeScreenshot. Maestro speichert Screenshots unter ~/.maestro/tests/<timestamp>/
|
|
# Das capture-marketing.sh Script benennt sie in 01-onboarding.png … 09-geraete.png um.
|
|
#
|
|
# REIHENFOLGE KRITISCH — entspricht der Reihenfolge auf der Preview-Seite:
|
|
# 01 Onboarding → Sign-in-Screen (neuer Nutzer, clearState)
|
|
# 02 Blocker → Blocker-Tab mit Schutz-Status
|
|
# 03 Blocked → MANUELL (VPN außerhalb App) — Proxy: Header-Dropdown
|
|
# 04 SOS/Lyra → SOS-Screen mit Lyra-Antwort + Chips
|
|
# 05 Breathing → BreathingDrawer geöffnet
|
|
# 06 Mail-Schutz → Mail-Tab
|
|
# 07 Community → Home-Feed mit Posts
|
|
# 08 Streak → Profil-StreakSection
|
|
# 09 Geräte → Devices-Screen
|
|
#
|
|
# Wichtig: Flow bricht nach dem letzten takeScreenshot ab — keine Assertions danach.
|
|
# Jeder Abschnitt setzt den App-State via launchApp + clearState zurück.
|
|
#
|
|
# HINWEIS 03-blocked:
|
|
# Der echte Block-Screen ist außerhalb der App (Safari + VPN). Dieser Flow macht
|
|
# einen Proxy-Screenshot des Header-Dropdowns. Für den echten Shot: manuell.
|
|
#
|
|
# FRAGILE STEPS (brauchen testID-Ergänzung für Robustheit):
|
|
# - Avatar-Tap (93%, 6%) in allen Flows → testID="header-avatar-btn"
|
|
# - SOS-Send-Button → testID="sos-send-btn"
|
|
# - Settings→Geräte Navigation
|
|
#
|
|
# Env-Vars: E2E_TEST_USER, E2E_TEST_PASSWORD
|
|
# Voraussetzung: iOS Simulator mit Status-Bar via xcrun simctl status_bar überschrieben
|
|
# (Details in capture-marketing.sh)
|
|
|
|
appId: org.rebreak.app
|
|
|
|
---
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# 01 — ONBOARDING / WILLKOMMEN
|
|
# Sign-in-Screen als "erster Blick" für neue Nutzer
|
|
# ══════════════════════════════════════════════════════════
|
|
- launchApp:
|
|
clearState: true
|
|
- waitForAnimationToEnd:
|
|
timeout: 6000
|
|
- assertVisible:
|
|
text: "E-Mail"
|
|
- waitForAnimationToEnd:
|
|
timeout: 2000
|
|
- takeScreenshot: screenshots/01-onboarding
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# 02 — BLOCKER AKTIV
|
|
# ══════════════════════════════════════════════════════════
|
|
- launchApp:
|
|
clearState: true
|
|
- waitForAnimationToEnd:
|
|
timeout: 5000
|
|
- assertVisible:
|
|
text: "E-Mail"
|
|
- tapOn:
|
|
text: "E-Mail"
|
|
- inputText: ${E2E_TEST_USER}@rebreak.internal
|
|
- tapOn:
|
|
text: "Passwort"
|
|
- inputText: ${E2E_TEST_PASSWORD}
|
|
- tapOn:
|
|
text: "Anmelden"
|
|
- waitForAnimationToEnd:
|
|
timeout: 10000
|
|
- assertVisible:
|
|
text: "ReBreak"
|
|
- tapOn:
|
|
text: "Blocker"
|
|
- waitForAnimationToEnd:
|
|
timeout: 4000
|
|
- assertVisible:
|
|
text: "ReBreak-Schutz"
|
|
- scrollUntilVisible:
|
|
element:
|
|
text: "URL-Filter"
|
|
direction: DOWN
|
|
timeout: 5000
|
|
- waitForAnimationToEnd:
|
|
timeout: 1000
|
|
- takeScreenshot: screenshots/02-blocker
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# 03 — BLOCKED (Proxy: Header-Dropdown als "Schutz greift")
|
|
# HINWEIS: Echter Block-Screen → manuell via Safari + VPN
|
|
# ══════════════════════════════════════════════════════════
|
|
- launchApp:
|
|
clearState: true
|
|
- waitForAnimationToEnd:
|
|
timeout: 5000
|
|
- assertVisible:
|
|
text: "E-Mail"
|
|
- tapOn:
|
|
text: "E-Mail"
|
|
- inputText: ${E2E_TEST_USER}@rebreak.internal
|
|
- tapOn:
|
|
text: "Passwort"
|
|
- inputText: ${E2E_TEST_PASSWORD}
|
|
- tapOn:
|
|
text: "Anmelden"
|
|
- waitForAnimationToEnd:
|
|
timeout: 10000
|
|
- assertVisible:
|
|
text: "ReBreak"
|
|
# Blocker-Tab zeigt den aktivsten "Schutz greift"-Screen ohne VPN
|
|
- tapOn:
|
|
text: "Blocker"
|
|
- waitForAnimationToEnd:
|
|
timeout: 4000
|
|
- assertVisible:
|
|
text: "ReBreak-Schutz"
|
|
- takeScreenshot: screenshots/03-blocked
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# 04 — SOS / LYRA
|
|
# ══════════════════════════════════════════════════════════
|
|
- launchApp:
|
|
clearState: true
|
|
- waitForAnimationToEnd:
|
|
timeout: 5000
|
|
- assertVisible:
|
|
text: "E-Mail"
|
|
- tapOn:
|
|
text: "E-Mail"
|
|
- inputText: ${E2E_TEST_USER}@rebreak.internal
|
|
- tapOn:
|
|
text: "Passwort"
|
|
- inputText: ${E2E_TEST_PASSWORD}
|
|
- tapOn:
|
|
text: "Anmelden"
|
|
- waitForAnimationToEnd:
|
|
timeout: 10000
|
|
- assertVisible:
|
|
text: "ReBreak"
|
|
# FRAGILE: Avatar-Tap Koordinaten bis testID="header-avatar-btn" gesetzt
|
|
- tapOn:
|
|
id: "header-avatar-btn"
|
|
- waitForAnimationToEnd:
|
|
timeout: 2000
|
|
- assertVisible:
|
|
text: "SOS"
|
|
- tapOn:
|
|
text: "SOS"
|
|
- waitForAnimationToEnd:
|
|
timeout: 12000
|
|
- assertVisible:
|
|
text: "Was beschäftigt dich?"
|
|
- tapOn:
|
|
text: "Was beschäftigt dich?"
|
|
- waitForAnimationToEnd:
|
|
timeout: 500
|
|
- inputText: "Ich weiß nicht mehr weiter."
|
|
- pressKey: Return
|
|
- waitForAnimationToEnd:
|
|
timeout: 20000
|
|
- assertVisible:
|
|
text: "Atemübung"
|
|
- waitForAnimationToEnd:
|
|
timeout: 1000
|
|
- takeScreenshot: screenshots/04-sos-lyra
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# 05 — ATEMÜBUNG
|
|
# BreathingDrawer bleibt nach 04-sos-lyra noch offen →
|
|
# kein launchApp nötig, direkt tippen
|
|
# ══════════════════════════════════════════════════════════
|
|
- tapOn:
|
|
text: "Atemübung"
|
|
- waitForAnimationToEnd:
|
|
timeout: 3000
|
|
- assertVisible:
|
|
text: "Atemübung"
|
|
- waitForAnimationToEnd:
|
|
timeout: 1500
|
|
- takeScreenshot: screenshots/05-breathing
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# 06 — MAIL-SCHUTZ
|
|
# ══════════════════════════════════════════════════════════
|
|
- launchApp:
|
|
clearState: true
|
|
- waitForAnimationToEnd:
|
|
timeout: 5000
|
|
- assertVisible:
|
|
text: "E-Mail"
|
|
- tapOn:
|
|
text: "E-Mail"
|
|
- inputText: ${E2E_TEST_USER}@rebreak.internal
|
|
- tapOn:
|
|
text: "Passwort"
|
|
- inputText: ${E2E_TEST_PASSWORD}
|
|
- tapOn:
|
|
text: "Anmelden"
|
|
- waitForAnimationToEnd:
|
|
timeout: 10000
|
|
- assertVisible:
|
|
text: "ReBreak"
|
|
- tapOn:
|
|
text: "Mail"
|
|
- waitForAnimationToEnd:
|
|
timeout: 4000
|
|
- assertVisible:
|
|
text: "Mail-Schutz"
|
|
- waitForAnimationToEnd:
|
|
timeout: 1000
|
|
- takeScreenshot: screenshots/06-mail-schutz
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# 07 — COMMUNITY-FEED
|
|
# ══════════════════════════════════════════════════════════
|
|
- launchApp:
|
|
clearState: true
|
|
- waitForAnimationToEnd:
|
|
timeout: 5000
|
|
- assertVisible:
|
|
text: "E-Mail"
|
|
- tapOn:
|
|
text: "E-Mail"
|
|
- inputText: ${E2E_TEST_USER}@rebreak.internal
|
|
- tapOn:
|
|
text: "Passwort"
|
|
- inputText: ${E2E_TEST_PASSWORD}
|
|
- tapOn:
|
|
text: "Anmelden"
|
|
- waitForAnimationToEnd:
|
|
timeout: 10000
|
|
- assertVisible:
|
|
text: "ReBreak"
|
|
- scrollUntilVisible:
|
|
element:
|
|
text: "Was bewegt dich gerade?"
|
|
direction: UP
|
|
timeout: 4000
|
|
- assertVisible:
|
|
text: "Was bewegt dich gerade?"
|
|
- scroll:
|
|
direction: DOWN
|
|
duration: 800
|
|
- waitForAnimationToEnd:
|
|
timeout: 1500
|
|
- takeScreenshot: screenshots/07-community
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# 08 — STREAK / PROFIL-STATS
|
|
# ══════════════════════════════════════════════════════════
|
|
- launchApp:
|
|
clearState: true
|
|
- waitForAnimationToEnd:
|
|
timeout: 5000
|
|
- assertVisible:
|
|
text: "E-Mail"
|
|
- tapOn:
|
|
text: "E-Mail"
|
|
- inputText: ${E2E_TEST_USER}@rebreak.internal
|
|
- tapOn:
|
|
text: "Passwort"
|
|
- inputText: ${E2E_TEST_PASSWORD}
|
|
- tapOn:
|
|
text: "Anmelden"
|
|
- waitForAnimationToEnd:
|
|
timeout: 10000
|
|
- assertVisible:
|
|
text: "ReBreak"
|
|
# FRAGILE: Koordinaten-Tap
|
|
- tapOn:
|
|
id: "header-avatar-btn"
|
|
- waitForAnimationToEnd:
|
|
timeout: 2000
|
|
- assertVisible:
|
|
text: "Profil"
|
|
- tapOn:
|
|
text: "Profil"
|
|
- waitForAnimationToEnd:
|
|
timeout: 4000
|
|
- assertVisible:
|
|
text: "Profil"
|
|
- scrollUntilVisible:
|
|
element:
|
|
text: "SCHUTZ-ABDECKUNG"
|
|
direction: DOWN
|
|
timeout: 6000
|
|
- assertVisible:
|
|
text: "SCHUTZ-ABDECKUNG"
|
|
- waitForAnimationToEnd:
|
|
timeout: 1000
|
|
- takeScreenshot: screenshots/08-streak
|
|
|
|
# ══════════════════════════════════════════════════════════
|
|
# 09 — GERÄTE-ÜBERSICHT
|
|
# ══════════════════════════════════════════════════════════
|
|
- launchApp:
|
|
clearState: true
|
|
- waitForAnimationToEnd:
|
|
timeout: 5000
|
|
- assertVisible:
|
|
text: "E-Mail"
|
|
- tapOn:
|
|
text: "E-Mail"
|
|
- inputText: ${E2E_TEST_USER}@rebreak.internal
|
|
- tapOn:
|
|
text: "Passwort"
|
|
- inputText: ${E2E_TEST_PASSWORD}
|
|
- tapOn:
|
|
text: "Anmelden"
|
|
- waitForAnimationToEnd:
|
|
timeout: 10000
|
|
- assertVisible:
|
|
text: "ReBreak"
|
|
# FRAGILE: Koordinaten-Tap
|
|
- tapOn:
|
|
id: "header-avatar-btn"
|
|
- waitForAnimationToEnd:
|
|
timeout: 2000
|
|
- assertVisible:
|
|
text: "Einstellungen"
|
|
- tapOn:
|
|
text: "Einstellungen"
|
|
- waitForAnimationToEnd:
|
|
timeout: 3000
|
|
- scrollUntilVisible:
|
|
element:
|
|
text: "Geräte"
|
|
direction: DOWN
|
|
timeout: 5000
|
|
- tapOn:
|
|
text: "Geräte"
|
|
- waitForAnimationToEnd:
|
|
timeout: 4000
|
|
- assertVisible:
|
|
text: "Dieses Gerät"
|
|
- waitForAnimationToEnd:
|
|
timeout: 1000
|
|
- takeScreenshot: screenshots/09-geraete
|