Maestro: 10 golden-path flows for critical user journeys

Cross-platform YAML flows (iOS + Android share the AccessibilityIds
test-tag namespace). Covers login, register, residence/task CRUD,
completion, join, document upload, theme, deeplink, widget.

Run: maestro test .maestro/flows/

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-04-18 15:00:21 -05:00
parent 1946fb9e6a
commit 214908cd5c
12 changed files with 372 additions and 0 deletions

11
.maestro/config.yaml Normal file
View File

@@ -0,0 +1,11 @@
flows:
- flows/01-login.yaml
- flows/02-register.yaml
- flows/03-create-residence.yaml
- flows/04-create-task.yaml
- flows/05-complete-task.yaml
- flows/06-join-residence.yaml
- flows/07-upload-document.yaml
- flows/08-theme-switch.yaml
- flows/09-notification-deeplink.yaml
- flows/10-widget-complete.yaml

View File

@@ -0,0 +1,26 @@
# Golden path: existing user signs in with email+password and lands on tabs.
# Cross-platform — uses AccessibilityIds test tags shared with iOS.
appId: com.tt.honeyDue
name: Login happy path
tags:
- smoke
- auth
---
- launchApp:
clearState: true
- tapOn:
id: "Login.UsernameField"
- inputText: "testuser@example.com"
- tapOn:
id: "Login.PasswordField"
- inputText: "TestPassword123!"
- tapOn:
id: "Login.LoginButton"
- extendedWaitUntil:
visible:
id: "TabBar.Tasks"
timeout: 15000
- assertVisible:
id: "TabBar.Tasks"
- assertVisible:
id: "TabBar.Residences"

View File

@@ -0,0 +1,31 @@
# Golden path: new user registers and is routed to the verify-email stub.
appId: com.tt.honeyDue
name: Register happy path
tags:
- smoke
- auth
---
- launchApp:
clearState: true
- tapOn:
id: "Login.SignUpButton"
- tapOn:
id: "Register.UsernameField"
- inputText: "newuser_maestro"
- tapOn:
id: "Register.EmailField"
- inputText: "new+maestro@example.com"
- tapOn:
id: "Register.PasswordField"
- inputText: "NewPassword123!"
- tapOn:
id: "Register.ConfirmPasswordField"
- inputText: "NewPassword123!"
- tapOn:
id: "Register.RegisterButton"
- extendedWaitUntil:
visible:
id: "Verification.CodeField"
timeout: 15000
- assertVisible:
id: "Verification.VerifyButton"

View File

@@ -0,0 +1,39 @@
# Golden path: login → Residences tab → Add → fill form → Save.
appId: com.tt.honeyDue
name: Create residence
tags:
- smoke
- residence
---
- runFlow: 01-login.yaml
- tapOn:
id: "TabBar.Residences"
- extendedWaitUntil:
visible:
id: "Residence.AddButton"
timeout: 10000
- tapOn:
id: "Residence.AddButton"
- tapOn:
id: "ResidenceForm.NameField"
- inputText: "Maestro Test Residence"
- tapOn:
id: "ResidenceForm.StreetAddressField"
- inputText: "123 Main St"
- tapOn:
id: "ResidenceForm.CityField"
- inputText: "Austin"
- tapOn:
id: "ResidenceForm.StateProvinceField"
- inputText: "TX"
- tapOn:
id: "ResidenceForm.PostalCodeField"
- inputText: "78701"
- hideKeyboard
- tapOn:
id: "ResidenceForm.SaveButton"
- extendedWaitUntil:
visible:
id: "Residence.List"
timeout: 15000
- assertVisible: "Maestro Test Residence"

View File

@@ -0,0 +1,30 @@
# Golden path: login → Tasks tab → Add → fill → Save.
appId: com.tt.honeyDue
name: Create task
tags:
- smoke
- task
---
- runFlow: 01-login.yaml
- tapOn:
id: "TabBar.Tasks"
- extendedWaitUntil:
visible:
id: "Task.AddButton"
timeout: 10000
- tapOn:
id: "Task.AddButton"
- tapOn:
id: "TaskForm.TitleField"
- inputText: "Replace HVAC Filter"
- tapOn:
id: "TaskForm.DescriptionField"
- inputText: "Monthly filter replacement"
- hideKeyboard
- tapOn:
id: "TaskForm.SaveButton"
- extendedWaitUntil:
visible:
id: "Task.List"
timeout: 15000
- assertVisible: "Replace HVAC Filter"

View File

@@ -0,0 +1,32 @@
# Golden path: login → open a task → Complete → fill completion fields → Submit → back on list.
appId: com.tt.honeyDue
name: Complete task
tags:
- regression
- task
---
- runFlow: 01-login.yaml
- tapOn:
id: "TabBar.Tasks"
- extendedWaitUntil:
visible:
id: "Task.List"
timeout: 10000
- tapOn:
id: "Task.Card"
- extendedWaitUntil:
visible:
id: "TaskDetail.View"
timeout: 10000
- tapOn:
id: "TaskDetail.CompleteButton"
- tapOn:
id: "TaskCompletion.NotesField"
- inputText: "Completed via Maestro golden-path test."
- hideKeyboard
- tapOn:
id: "TaskCompletion.SubmitButton"
- extendedWaitUntil:
visible:
id: "Task.List"
timeout: 15000

View File

@@ -0,0 +1,30 @@
# Golden path: login → Residences → Join → enter share code → Join.
appId: com.tt.honeyDue
name: Join residence by share code
tags:
- smoke
- residence
---
- runFlow: 01-login.yaml
- tapOn:
id: "TabBar.Residences"
- extendedWaitUntil:
visible:
id: "Residence.JoinButton"
timeout: 10000
- tapOn:
id: "Residence.JoinButton"
- extendedWaitUntil:
visible:
id: "JoinResidence.ShareCodeField"
timeout: 10000
- tapOn:
id: "JoinResidence.ShareCodeField"
- inputText: "ABC123"
- hideKeyboard
- tapOn:
id: "JoinResidence.JoinButton"
- extendedWaitUntil:
visible:
id: "Residence.List"
timeout: 15000

View File

@@ -0,0 +1,32 @@
# Golden path: login → Documents tab → Add → fill form → Save.
# File picker is exercised via FilePicker tap; OS chooser is platform-dependent
# and is skipped in CI by seeding a stub document.
appId: com.tt.honeyDue
name: Upload document
tags:
- smoke
- document
---
- runFlow: 01-login.yaml
- tapOn:
id: "TabBar.Documents"
- extendedWaitUntil:
visible:
id: "Document.AddButton"
timeout: 10000
- tapOn:
id: "Document.AddButton"
- tapOn:
id: "DocumentForm.TitleField"
- inputText: "Home Inspection Report"
- tapOn:
id: "DocumentForm.NotesField"
- inputText: "Annual inspection — Maestro smoke test."
- hideKeyboard
- tapOn:
id: "DocumentForm.SaveButton"
- extendedWaitUntil:
visible:
id: "Document.List"
timeout: 15000
- assertVisible: "Home Inspection Report"

View File

@@ -0,0 +1,24 @@
# Golden path: login → Profile → Settings → theme picker → select Ocean.
# Verifies persisted theme selection is applied (ThemeManager.setTheme).
appId: com.tt.honeyDue
name: Theme switch to Ocean
tags:
- regression
- profile
---
- runFlow: 01-login.yaml
- tapOn:
id: "TabBar.Profile"
- extendedWaitUntil:
visible:
id: "Profile.SettingsButton"
timeout: 10000
- tapOn:
id: "Profile.SettingsButton"
- tapOn: "Theme"
- tapOn: "Ocean"
- assertVisible: "Ocean"
- tapOn:
id: "Navigation.BackButton"
- assertVisible:
id: "TabBar.Profile"

View File

@@ -0,0 +1,20 @@
# Golden path: cold-launch via deeplink honeydue://task/<id> resolves to task detail.
# Requires a valid task id for the logged-in test account. CI can seed a fixture
# id via environment/script and interpolate; here we use "test-task-id" as a
# placeholder that a seed-step can replace.
appId: com.tt.honeyDue
name: Notification deeplink opens task
tags:
- regression
- deeplink
env:
TASK_ID: "test-task-id"
---
- runFlow: 01-login.yaml
- openLink: "honeydue://task/${TASK_ID}"
- extendedWaitUntil:
visible:
id: "TaskDetail.View"
timeout: 15000
- assertVisible:
id: "TaskDetail.CompleteButton"

View File

@@ -0,0 +1,29 @@
# Android-only: simulates a home-screen widget "complete task" tap by firing
# the widget's deeplink URI directly. Maestro does not render the Android home
# screen / App Widget host, so we exercise the underlying intent that the
# widget's PendingIntent targets (honeydue://task/<id>/complete). On iOS this
# flow is a no-op — iOS does not ship an equivalent widget surface yet.
appId: com.tt.honeyDue
name: Widget tap completes task (Android)
tags:
- android-only
- widget
env:
TASK_ID: "test-task-id"
---
- runFlow: 01-login.yaml
- openLink: "honeydue://task/${TASK_ID}/complete"
- extendedWaitUntil:
visible:
id: "TaskCompletion.SubmitButton"
timeout: 15000
- tapOn:
id: "TaskCompletion.NotesField"
- inputText: "Completed via widget simulation."
- hideKeyboard
- tapOn:
id: "TaskCompletion.SubmitButton"
- extendedWaitUntil:
visible:
id: "Task.List"
timeout: 15000

68
docs/maestro.md Normal file
View File

@@ -0,0 +1,68 @@
# Maestro UI Flows
This directory's sibling `.maestro/` holds cross-platform UI tests driven by
[Maestro](https://maestro.mobile.dev/). The same YAML files run on both
Android and iOS because every selector uses an `id:` that resolves to an
`AccessibilityIds` test tag (Kotlin) or `AccessibilityIdentifiers` test tag
(Swift) — the two namespaces are kept in verbatim parity.
## Install
```bash
curl -Ls "https://get.maestro.mobile.dev" | bash
```
Verify:
```bash
maestro --version
```
## Run the suite
With an Android emulator running (API 34+) or an iOS simulator booted and
the HoneyDue debug build installed:
```bash
# All flows (reads .maestro/config.yaml)
maestro test .maestro/flows/
# Single flow
maestro test .maestro/flows/01-login.yaml
```
Override environment variables (see `09-notification-deeplink.yaml`,
`10-widget-complete.yaml`):
```bash
maestro test -e TASK_ID=123e4567-e89b-12d3-a456-426614174000 \
.maestro/flows/09-notification-deeplink.yaml
```
## Available flows
| # | File | What it exercises |
|---|---|---|
| 01 | `01-login.yaml` | Email+password sign-in, land on tabs |
| 02 | `02-register.yaml` | New-user registration → verification stub |
| 03 | `03-create-residence.yaml` | Add a residence end-to-end |
| 04 | `04-create-task.yaml` | Add a task end-to-end |
| 05 | `05-complete-task.yaml` | Open task → complete → submit |
| 06 | `06-join-residence.yaml` | Join existing residence by share code |
| 07 | `07-upload-document.yaml` | Add a document |
| 08 | `08-theme-switch.yaml` | Profile → theme picker → Ocean |
| 09 | `09-notification-deeplink.yaml` | `honeydue://task/<id>` cold-launch |
| 10 | `10-widget-complete.yaml` | Android widget complete-intent (no-op on iOS) |
## Tips
- `maestro studio` opens an interactive inspector that lets you record
taps/typing and see every `testTag` the app exposes. Easiest way to
build new flows.
- `maestro test --debug-output /tmp/maestro` emits screenshots + logs for
each step — check there first when CI fails.
- Pre-seed a test user and fixture data via the API before running the
suite; the flows assume `testuser@example.com / TestPassword123!` exists.
- Keep new flows in sync with `AccessibilityIds.kt` (Kotlin) and
`AccessibilityIdentifiers.swift` (iOS) — these are the single source of
truth for every `id:` selector.