diff --git a/.maestro/config.yaml b/.maestro/config.yaml index 8d157a8..a09cad5 100644 --- a/.maestro/config.yaml +++ b/.maestro/config.yaml @@ -10,6 +10,8 @@ # prerequisite adb push recipe in that flow's header comment). # f5_empty_profile is NOT in the order: it needs an adb-fired deep link # first (MainActivity has no VIEW intent filter) — see its header comment. +# h1_video_post needs emulator internet access and a live Streamable clip +# (see its header); it seeds one video post per run, like e1 does. # g1_legal_gates is NOT in the order: it launches with clearState (fresh # install), wiping the legal acceptances AND the signed-in session every # stateful flow depends on. Run it standalone, then a1_login_session — @@ -39,6 +41,8 @@ executionOrder: - f3_edit_profile_persist - f4_avatar_gallery - g3_report_dialog + - h1_video_post + - h2_rich_text_linkbars - a2_signout_landing - d4_discovery_guest - a3_wrong_password diff --git a/.maestro/h1_video_post.yaml b/.maestro/h1_video_post.yaml new file mode 100644 index 0000000..2f765aa --- /dev/null +++ b/.maestro/h1_video_post.yaml @@ -0,0 +1,122 @@ +# Section H — check 1: video post playback. Seeds its own video post (compose +# with a Streamable URL; the backend unfurls it to embedType=video + +# provider=streamable + thumb), then from post detail taps the "Play video" +# overlay (Semantics label added for a11y/testability), asserts the fullscreen +# player renders its scrubber time labels, and BACK-exits back to the detail +# screen cleanly. +# Requires: emulator internet access (api.streamable.com + CDN) and a live +# Streamable shortcode below — replace the URL if the clip ever expires +# (verify with: curl https://api.streamable.com/videos/). +# Assumes a signed-in session (suite order: after a1). +# NOTE: never use hideKeyboard on the compose screen — it's a BACK press. +appId: social.coves.dev +--- +# --- seed: create a video post via compose --- +# The whole entry is inside the retry: the semantics tree is sometimes +# partial right after launch (nav-bar nodes missing) and only a full app +# restart reliably rebuilds it. +- retry: + maxRetries: 3 + commands: + - launchApp: + stopApp: true + - extendedWaitUntil: + visible: "Discover feed.*" + timeout: 30000 + - waitForAnimationToEnd: + timeout: 5000 + - tapOn: "Create" + - extendedWaitUntil: + visible: "Create Post" + timeout: 15000 +- tapOn: "Select a community" +- extendedWaitUntil: + visible: "Post to" + timeout: 15000 +- tapOn: "Search for a community" +- inputText: "scien" +- extendedWaitUntil: + visible: "Science[\\s\\S]*" + timeout: 15000 +- tapOn: "Science[\\s\\S]*" +- extendedWaitUntil: + visible: "Create Post" + timeout: 15000 +- evalScript: ${output.h1Title = 'QA H1 video ' + Date.now()} +- tapOn: "Title" +- inputText: ${output.h1Title} +- tapOn: "URL" +- inputText: "https://streamable.com/c4tyc7" +- takeScreenshot: build/maestro/h1_filled +- tapOn: "Post" +# optimistic detail renders (no video yet — embed is hydrated server-side) +- extendedWaitUntil: + visible: "[\\s\\S]*${output.h1Title}[\\s\\S]*" + timeout: 20000 +# (skip backing out of the optimistic detail — the keyboard can eat the +# first BACK; the relaunch below resets navigation anyway) +# --- relaunch; poll the feed until the indexed post appears --- +# Relaunch-per-attempt: the semantics tree can come up partial (nav nodes +# missing) and the discover feed can be transiently empty if the appview is +# mid-restart — a fresh launch retries both. +- retry: + maxRetries: 3 + commands: + - launchApp: + stopApp: true + - extendedWaitUntil: + visible: "Discover feed.*" + timeout: 30000 +- retry: + maxRetries: 5 + commands: + - swipe: + start: 50%, 30% + end: 50%, 80% + duration: 400 + - extendedWaitUntil: + visible: "Feed post in [\\s\\S]*${output.h1Title}[\\s\\S]*" + timeout: 10000 +# feed card carries the video play overlay once unfurled +- extendedWaitUntil: + visible: "Play video" + timeout: 15000 +- takeScreenshot: build/maestro/h1_feed_card +# --- play straight from the feed card --- +- tapOn: + text: "Play video" + index: 0 +# fullscreen player: scrubber time labels render once initialized +- extendedWaitUntil: + visible: "[0-9]+:[0-9]{2}" + timeout: 30000 +- waitForAnimationToEnd: + timeout: 3000 +- takeScreenshot: build/maestro/h1_player_from_feed +# back exits the player cleanly; feed is intact +- back +- extendedWaitUntil: + visible: "Discover feed.*" + timeout: 15000 +- assertVisible: "Play video" +# --- open post detail (via the comment-count button, which never overlaps +# the embed) and play from there too --- +- tapOn: + text: "View [0-9]+ comments?[\\s\\S]*" + index: 0 +- extendedWaitUntil: + visible: "Play video" + timeout: 15000 +- takeScreenshot: build/maestro/h1_detail_thumb +- tapOn: "Play video" +- extendedWaitUntil: + visible: "[0-9]+:[0-9]{2}" + timeout: 30000 +- takeScreenshot: build/maestro/h1_player_from_detail +# --- back exits the player cleanly, detail is intact --- +- back +- extendedWaitUntil: + visible: "Play video" + timeout: 15000 +- takeScreenshot: build/maestro/h1_after_exit +- back diff --git a/.maestro/h2_rich_text_linkbars.yaml b/.maestro/h2_rich_text_linkbars.yaml new file mode 100644 index 0000000..5e936cd --- /dev/null +++ b/.maestro/h2_rich_text_linkbars.yaml @@ -0,0 +1,51 @@ +# Section H — checks 2 + 3 (render halves): rich text facets and link bars. +# - Feed: post-card external link bars render with an "Open link to +# in external browser" semantics label (ExternalLinkBar) — the aggregator +# posts guarantee at least one is always present. +# - NASA aggregator post detail: body facets render as individual tappable +# link nodes ("[dawn.com]" etc. — RichTextRenderer creates one semantics +# node per recognizer span) and the detail link bar shows the source URL. +# Tap-through (link opens Chrome on the right URL) is verified manually via +# adb in the QA loop — keeping Chrome out of this flow keeps it hermetic. +# Assumes a signed-in session. +appId: social.coves.dev +--- +- launchApp: + stopApp: true +- extendedWaitUntil: + visible: "Discover feed.*" + timeout: 30000 +# --- feed-card external link bar (favicon + domain, labeled button) --- +- scrollUntilVisible: + element: + text: "Open link to [\\s\\S]* in external browser[\\s\\S]*" + direction: DOWN + timeout: 30000 +- takeScreenshot: build/maestro/h2_feed_linkbar +# --- NASA post: rich text facets --- +- scrollUntilVisible: + element: + text: "Feed post in [\\s\\S]*NASA delays[\\s\\S]*" + direction: DOWN + timeout: 30000 +- tapOn: + text: "Feed post in [\\s\\S]*NASA delays[\\s\\S]*" + index: 0 +- extendedWaitUntil: + visible: "NASA delays[\\s\\S]*" + timeout: 15000 +# link bar under the title shows the source domain +- assertVisible: "kite\\.kagi\\.com[\\s\\S]*" +# body facets render as separate link nodes +- assertVisible: + text: "\\[dawn\\.com\\]" +- assertVisible: + text: "\\[aawsat\\.com\\]" +- takeScreenshot: build/maestro/h2_nasa_facets +- back +- extendedWaitUntil: + visible: "Discover feed.*" + timeout: 15000 +# (The two-bar case — external URL bar + source domain bar on one detail, +# seeded Telegraph post — sits ~45 posts deep with no scheme intent filter +# for deep-linking from Maestro; the QA loop's adb pass covers it.)