Skip to content

Commit 75fff3a

Browse files
Merge branch 'main' into jonathanseehagen/feature/411-cross-granularity-playback
Resolve DraftTakeRow conflict: optional onDelete for stitched rows (#411) with Maestro delete testIDs from main (#491).
2 parents 8728abb + edbfb40 commit 75fff3a

48 files changed

Lines changed: 1148 additions & 18 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cursor/mcp.maestro.example.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"mcpServers": {
3+
"maestro": {
4+
"command": "${workspaceFolder}/scripts/maestro-mcp.sh",
5+
"args": []
6+
}
7+
}
8+
}

.env.maestro.example

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copy to `.env.maestro` (gitignored via `.env.*`). Never commit real credentials.
2+
#
3+
# Dedicated Maestro translator on the Fluent API (see epic #488 / #491).
4+
# Account must have ≥1 chapter assignment for nav/record/sync smokes.
5+
# `scripts/maestro-test.sh` loads this file literally (no Bash expansion) when present.
6+
# Or: `maestro test -e MAESTRO_EMAIL=... -e MAESTRO_PASSWORD=... .maestro/...`
7+
8+
MAESTRO_EMAIL=
9+
MAESTRO_PASSWORD=
10+
# Second pair reserved for multi-account isolation (#495):
11+
# MAESTRO_EMAIL_2=
12+
# MAESTRO_PASSWORD_2=
13+
14+
# API the Debug APK / Metro session should hit (must match your .env / Metro env).
15+
EXPO_PUBLIC_API_BASE_URL=https://dev.api.fluent.bible
16+
17+
# Local Debug + Metro only — suppresses Expo Dev Menu so it does not steal taps.
18+
# Do NOT set on production / preview / nightly EAS profiles.
19+
# EXPO_PUBLIC_E2E_MODE=1

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ pnpm-lock.yaml
4141
.env
4242
.env.*
4343
!.env.example
44+
!.env.maestro.example
45+
46+
# Maestro E2E (local artifacts; flows under .maestro/ are committed)
47+
.maestro/test_output/
48+
.maestro/**/screenshots/
49+
.maestro/**/*.png
50+
.maestro/**/*.mp4
4451

4552
# Expo CNG — native projects are generated locally and in CI
4653
.expo/

.maestro/config.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Android-only Maestro workspace (fluent-mobile). See docs/guides/maestro.md.
2+
appId: com.eten.fluent
3+
flows:
4+
- 'flows/**'
5+
- '!helpers/**'
6+
- '!flows/**/subflows/**'
7+
# Relative to this workspace (.maestro/) — outputs land in .maestro/test_output/
8+
testOutputDir: test_output
9+
# disableAnimations applies on Maestro Cloud only; local emulators ignore it.
10+
platform:
11+
android:
12+
disableAnimations: true
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Launch → login → Home; session restore; logout.
2+
appId: com.eten.fluent
3+
tags:
4+
- smoke
5+
- auth
6+
---
7+
- runFlow: subflows/boot-to-login.yaml
8+
- runFlow: subflows/login.yaml
9+
- runFlow: subflows/wait-for-home.yaml
10+
11+
# Session restore without clearState
12+
- stopApp
13+
- launchApp
14+
- runFlow: ../../helpers/dismiss-expo-dev-menu.yaml
15+
- runFlow: subflows/wait-for-home.yaml
16+
17+
# Logout via Settings
18+
- tapOn:
19+
id: 'home-settings-button'
20+
- tapOn:
21+
id: 'settings-menu-more-settings'
22+
- scrollUntilVisible:
23+
element:
24+
id: 'settings-log-out'
25+
direction: DOWN
26+
timeout: 15000
27+
- tapOn:
28+
id: 'settings-log-out'
29+
# Confirm only when the unsynced-work alert is shown
30+
- runFlow:
31+
when:
32+
visible: 'Unsynced work on device'
33+
commands:
34+
- tapOn: 'Log out'
35+
- extendedWaitUntil:
36+
visible:
37+
id: 'login-email-input'
38+
timeout: 60000
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Edges: forgot-password, Privacy/Terms, mic/notification deny (no crash).
2+
# Reauth forced-session is residual — see docs/guides/maestro.md (no backend hook).
3+
appId: com.eten.fluent
4+
tags:
5+
- smoke
6+
- edges
7+
---
8+
# --- Forgot password happy path ---
9+
- runFlow: subflows/boot-to-login.yaml
10+
- tapOn:
11+
id: 'login-forgot-password-link'
12+
- extendedWaitUntil:
13+
visible:
14+
id: 'forgot-password-email-input'
15+
timeout: 15000
16+
- tapOn:
17+
id: 'forgot-password-email-input'
18+
- eraseText
19+
- inputText: ${MAESTRO_EMAIL}
20+
- hideKeyboard
21+
- tapOn:
22+
id: 'forgot-password-submit-button'
23+
- extendedWaitUntil:
24+
visible:
25+
id: 'forgot-password-sent-view'
26+
timeout: 60000
27+
- tapOn:
28+
id: 'forgot-password-sent-back-link'
29+
- extendedWaitUntil:
30+
visible:
31+
id: 'login-email-input'
32+
timeout: 15000
33+
34+
# --- Legal by id (auth login footer) ---
35+
- tapOn:
36+
id: 'login-privacy-link'
37+
- extendedWaitUntil:
38+
visible:
39+
id: 'privacy-policy-scroll'
40+
timeout: 15000
41+
- back
42+
- extendedWaitUntil:
43+
visible:
44+
id: 'login-email-input'
45+
timeout: 15000
46+
- tapOn:
47+
id: 'login-terms-link'
48+
- extendedWaitUntil:
49+
visible:
50+
id: 'terms-of-use-scroll'
51+
timeout: 15000
52+
- back
53+
- extendedWaitUntil:
54+
visible:
55+
id: 'login-email-input'
56+
timeout: 15000
57+
58+
# --- Mic + notification deny: reach Record without crash ---
59+
- launchApp:
60+
clearState: true
61+
permissions:
62+
microphone: deny
63+
notifications: deny
64+
- runFlow: ../../helpers/dismiss-expo-dev-menu.yaml
65+
- extendedWaitUntil:
66+
visible:
67+
id: 'login-email-input'
68+
timeout: 60000
69+
- runFlow: subflows/login.yaml
70+
- runFlow: subflows/wait-for-home.yaml
71+
- runFlow: subflows/open-first-my-work-chapter.yaml
72+
- tapOn:
73+
id: 'drafting-tab-record'
74+
- assertVisible:
75+
id: 'record-tab'
76+
# Attempt start; system may no-op when denied — assert we did not crash
77+
- tapOn:
78+
id: 'record-start-button'
79+
optional: true
80+
- assertVisible:
81+
id: 'record-tab'
82+
# Forced reauth without a backend/session hook is residual — see docs/guides/maestro.md
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Home → My Work / Projects → chapter → Bible / Resources / Record tabs.
2+
# Requires Maestro translator with ≥1 My Work assignment (and project chapters).
3+
appId: com.eten.fluent
4+
tags:
5+
- smoke
6+
- nav
7+
---
8+
- runFlow: subflows/boot-to-login.yaml
9+
- runFlow: subflows/login.yaml
10+
- runFlow: subflows/wait-for-home.yaml
11+
12+
# My Work → drafting tabs
13+
- runFlow: subflows/open-first-my-work-chapter.yaml
14+
- tapOn:
15+
id: 'drafting-tab-bible'
16+
- assertVisible:
17+
id: 'bible-tab'
18+
- tapOn:
19+
id: 'drafting-tab-resources'
20+
- assertVisible:
21+
id: 'resources-tab'
22+
- tapOn:
23+
id: 'drafting-tab-record'
24+
- assertVisible:
25+
id: 'record-tab'
26+
- back
27+
- extendedWaitUntil:
28+
visible:
29+
id: 'home-tab-my-work'
30+
timeout: 15000
31+
32+
# Projects → chapter → drafting
33+
- tapOn:
34+
id: 'home-tab-projects'
35+
- extendedWaitUntil:
36+
visible:
37+
id: 'project-row-.*'
38+
timeout: 60000
39+
- tapOn:
40+
id: 'project-row-.*'
41+
- extendedWaitUntil:
42+
visible:
43+
id: 'chapter-row-.*'
44+
timeout: 60000
45+
- tapOn:
46+
id: 'chapter-row-.*'
47+
- extendedWaitUntil:
48+
visible:
49+
id: 'drafting-tab-bar'
50+
timeout: 60000
51+
- assertVisible:
52+
id: 'drafting-tab-bible'
53+
- assertVisible:
54+
id: 'drafting-tab-resources'
55+
- assertVisible:
56+
id: 'drafting-tab-record'
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Record happy path: mic allow → record → stop → play → delete that take.
2+
# Does NOT tap stage-advance (destructive on shared dev). Needs ≥1 assignment.
3+
# Start vs new-take: idle-no-takes shows record-start-button; existing takes show
4+
# enabled record-new-take-button. At the 5-take cap new-take stays mounted but
5+
# disabled — fail fast (do not wait on record-stop-button). Cleanup deletes the
6+
# take this smoke created so re-runs stay under the cap.
7+
appId: com.eten.fluent
8+
tags:
9+
- smoke
10+
- record
11+
---
12+
- launchApp:
13+
clearState: true
14+
permissions:
15+
microphone: allow
16+
notifications: allow
17+
- runFlow: ../../helpers/dismiss-expo-dev-menu.yaml
18+
- extendedWaitUntil:
19+
visible:
20+
id: 'login-email-input'
21+
timeout: 60000
22+
- runFlow: subflows/login.yaml
23+
- runFlow: subflows/wait-for-home.yaml
24+
- runFlow: subflows/open-first-my-work-chapter.yaml
25+
- tapOn:
26+
id: 'drafting-tab-record'
27+
- assertVisible:
28+
id: 'record-tab'
29+
# Cap fail-fast: if start is absent, an *enabled* new-take must be present.
30+
- runFlow:
31+
when:
32+
notVisible:
33+
id: 'record-start-button'
34+
enabled: true
35+
commands:
36+
- assertVisible:
37+
id: 'record-new-take-button'
38+
enabled: true
39+
- runFlow:
40+
when:
41+
visible:
42+
id: 'record-start-button'
43+
enabled: true
44+
commands:
45+
- tapOn:
46+
id: 'record-start-button'
47+
- runFlow:
48+
when:
49+
visible:
50+
id: 'record-new-take-button'
51+
enabled: true
52+
commands:
53+
- tapOn:
54+
id: 'record-new-take-button'
55+
- extendedWaitUntil:
56+
visible:
57+
id: 'record-stop-button'
58+
timeout: 15000
59+
# Short capture so stop is deterministic
60+
- waitForAnimationToEnd
61+
- tapOn:
62+
id: 'record-stop-button'
63+
- extendedWaitUntil:
64+
visible:
65+
id: 'record-play-button'
66+
timeout: 30000
67+
- tapOn:
68+
id: 'record-play-button'
69+
- assertVisible:
70+
id: 'record-tab'
71+
# Remove the take this smoke created (selected after stop) for repeatable runs.
72+
- tapOn:
73+
id: 'record-delete-selected-button'
74+
- tapOn:
75+
text: 'Delete'
76+
- assertVisible:
77+
id: 'record-tab'
78+
# Explicitly avoid stage-advance-button on shared Maestro accounts
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Sync Now (+ pause/resume when visible) and Prepare-for-Offline primary chrome.
2+
appId: com.eten.fluent
3+
tags:
4+
- smoke
5+
- sync
6+
---
7+
- runFlow: subflows/boot-to-login.yaml
8+
- runFlow: subflows/login.yaml
9+
- runFlow: subflows/wait-for-home.yaml
10+
11+
# Sync screen
12+
- tapOn:
13+
id: 'home-sync-button'
14+
- extendedWaitUntil:
15+
visible:
16+
id: 'sync-screen'
17+
timeout: 30000
18+
- assertVisible:
19+
id: 'sync-action-sync-now'
20+
- tapOn:
21+
id: 'sync-action-sync-now'
22+
# Pause/resume only when upload/metadata sync surfaces controls (optional)
23+
- runFlow:
24+
when:
25+
visible:
26+
id: 'sync-action-pause'
27+
commands:
28+
- tapOn:
29+
id: 'sync-action-pause'
30+
- extendedWaitUntil:
31+
visible:
32+
id: 'sync-action-resume'
33+
timeout: 15000
34+
- tapOn:
35+
id: 'sync-action-resume'
36+
- back
37+
38+
# Prepare for Offline via Settings
39+
- tapOn:
40+
id: 'home-settings-button'
41+
- tapOn:
42+
id: 'settings-menu-more-settings'
43+
- scrollUntilVisible:
44+
element:
45+
id: 'settings-prepare-offline'
46+
direction: DOWN
47+
timeout: 15000
48+
- tapOn:
49+
id: 'settings-prepare-offline'
50+
- extendedWaitUntil:
51+
visible:
52+
id: 'prepare-offline-screen'
53+
timeout: 30000
54+
# Picker (no projectId in route) → pick first project → primary resources chrome
55+
- extendedWaitUntil:
56+
visible:
57+
id: 'project-row-.*'
58+
timeout: 60000
59+
- tapOn:
60+
id: 'project-row-.*'
61+
- extendedWaitUntil:
62+
visible:
63+
id: 'prepare-offline-resources-section'
64+
timeout: 60000
65+
- extendedWaitUntil:
66+
visible:
67+
id: 'prepare-offline-download-footer'
68+
timeout: 60000
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Cold-start to login screen (clearState). Shared by CI-shaped smokes.
2+
appId: com.eten.fluent
3+
---
4+
- runFlow: ../../../helpers/launch-android.yaml
5+
- runFlow: ../../../helpers/dismiss-expo-dev-menu.yaml
6+
- extendedWaitUntil:
7+
visible:
8+
id: 'login-email-input'
9+
timeout: 60000

0 commit comments

Comments
 (0)