From 96d9d54cc94d733f68d07229e7b586f01334cb17 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Thu, 22 Oct 2026 03:55:43 +0200 Subject: [PATCH] ci: type the first character alone in ios flows and answer the webmail hand-over prompt --- .maestro/subflows/clear-field.yaml | 18 +++++------ .maestro/subflows/go-to-folder.yaml | 3 +- .maestro/subflows/inbox.yaml | 3 +- .maestro/subflows/open-drawer.yaml | 2 +- .maestro/subflows/stalwart-login-page.yaml | 14 ++++++--- .maestro/subflows/type-secret.yaml | 15 +++++++--- .maestro/subflows/type-web.yaml | 14 +++++++++ .maestro/subflows/type.yaml | 35 +++++++++++++++------- .maestro/subflows/webmail-login-page.yaml | 20 ++++++++++--- 9 files changed, 88 insertions(+), 36 deletions(-) create mode 100644 .maestro/subflows/type-web.yaml diff --git a/.maestro/subflows/clear-field.yaml b/.maestro/subflows/clear-field.yaml index 3fb6022d..f56abd4d 100644 --- a/.maestro/subflows/clear-field.yaml +++ b/.maestro/subflows/clear-field.yaml @@ -1,13 +1,11 @@ -# Empty the field with id FIELD. A tap puts the cursor where it lands, and -# eraseText only deletes before the cursor, so select everything first. +# Empty the field with id FIELD. A tap puts the cursor where it lands and +# eraseText only deletes before the cursor, so erase in passes: each tap +# lands in the middle of what is left. appId: org.bulwarkmail.mobile --- -- longPressOn: - id: ${FIELD} -- runFlow: - when: - visible: "Select All" +- repeat: + times: 4 commands: - - tapOn: "Select All" - - pressKey: Backspace -- eraseText: 120 + - tapOn: + id: ${FIELD} + - eraseText: 100 diff --git a/.maestro/subflows/go-to-folder.yaml b/.maestro/subflows/go-to-folder.yaml index f660cf30..77587690 100644 --- a/.maestro/subflows/go-to-folder.yaml +++ b/.maestro/subflows/go-to-folder.yaml @@ -2,7 +2,8 @@ appId: org.bulwarkmail.mobile --- - runFlow: open-drawer.yaml -- tapOn: ${FOLDER} +# A folder row reads " / ". +- tapOn: ${FOLDER}( .*)? - extendedWaitUntil: visible: ${FOLDER} timeout: 15000 diff --git a/.maestro/subflows/inbox.yaml b/.maestro/subflows/inbox.yaml index 0e132000..83b7905c 100644 --- a/.maestro/subflows/inbox.yaml +++ b/.maestro/subflows/inbox.yaml @@ -15,4 +15,5 @@ appId: org.bulwarkmail.mobile visible: id: email-row timeout: 60000 -- assertVisible: ${INBOX_TEXT || 'Your verification code'} +# Rows are one element: sender, subject and preview together. +- assertVisible: ${INBOX_TEXT || '.*Your verification code.*'} diff --git a/.maestro/subflows/open-drawer.yaml b/.maestro/subflows/open-drawer.yaml index 853414fc..6858053e 100644 --- a/.maestro/subflows/open-drawer.yaml +++ b/.maestro/subflows/open-drawer.yaml @@ -8,5 +8,5 @@ appId: org.bulwarkmail.mobile commands: - tapOn: "Toggle menu" - extendedWaitUntil: - visible: "Scheduled" + visible: "Scheduled.*" timeout: 10000 diff --git a/.maestro/subflows/stalwart-login-page.yaml b/.maestro/subflows/stalwart-login-page.yaml index d8db349a..48758942 100644 --- a/.maestro/subflows/stalwart-login-page.yaml +++ b/.maestro/subflows/stalwart-login-page.yaml @@ -6,10 +6,16 @@ appId: org.bulwarkmail.mobile visible: "you@example.com" timeout: 60000 - takeScreenshot: stalwart-login-page -- tapOn: "you@example.com" -- inputText: ${LOGIN} -- tapOn: "••••••••" -- inputText: ${PASSWORD} +- runFlow: + file: type-web.yaml + env: + HINT: "you@example.com" + TEXT: ${LOGIN} +- runFlow: + file: type-web.yaml + env: + HINT: "••••••••" + TEXT: ${PASSWORD} - runFlow: when: true: ${TOTP == 'yes'} diff --git a/.maestro/subflows/type-secret.yaml b/.maestro/subflows/type-secret.yaml index bbde88fe..3200c6c5 100644 --- a/.maestro/subflows/type-secret.yaml +++ b/.maestro/subflows/type-secret.yaml @@ -1,9 +1,10 @@ # Type a secret into the field with id FIELD (TAP=no for a field that focuses -# itself, see type.yaml). The value can't be checked (a secure field shows -# dots) and must never be shown, so a lost keystroke surfaces as a failed -# sign-in. +# itself; see type.yaml for why the first character goes alone). The value +# can't be checked (a secure field shows dots) and must never be shown, so a +# lost keystroke surfaces as a failed sign-in. appId: org.bulwarkmail.mobile --- +- evalScript: ${output.secretHead = TEXT.slice(0, 1); output.secretTail = TEXT.slice(1)} - runFlow: when: true: ${TAP != 'no'} @@ -12,4 +13,10 @@ appId: org.bulwarkmail.mobile id: ${FIELD} - waitForAnimationToEnd: timeout: 3000 -- inputText: ${TEXT} +- inputText: ${output.secretHead} +# A short pause: wait for something that never shows. +- extendedWaitUntil: + visible: "zz-no-such-element-zz" + timeout: 1000 + optional: true +- inputText: ${output.secretTail} diff --git a/.maestro/subflows/type-web.yaml b/.maestro/subflows/type-web.yaml new file mode 100644 index 00000000..d8026ea1 --- /dev/null +++ b/.maestro/subflows/type-web.yaml @@ -0,0 +1,14 @@ +# Type TEXT into a web page field found by its placeholder HINT (the sign-in +# pages in the auth session). First character alone, as in type.yaml. +appId: org.bulwarkmail.mobile +--- +- evalScript: ${output.webHead = TEXT.slice(0, 1); output.webTail = TEXT.slice(1)} +- tapOn: ${HINT} +- waitForAnimationToEnd: + timeout: 3000 +- inputText: ${output.webHead} +- extendedWaitUntil: + visible: "zz-no-such-element-zz" + timeout: 1000 + optional: true +- inputText: ${output.webTail} diff --git a/.maestro/subflows/type.yaml b/.maestro/subflows/type.yaml index 6eed294d..f5ebb2e2 100644 --- a/.maestro/subflows/type.yaml +++ b/.maestro/subflows/type.yaml @@ -1,12 +1,14 @@ # Type TEXT into the field with id FIELD and check it arrived in full. # -# iOS drops keystrokes while the edit menu (the "AutoFill" bubble) opens, -# which happens when a flow taps a field that already has focus. Maestro -# can't see the focus of a React Native field, so a caller passes TAP=no for -# a field that focuses itself. Retyped up to twice if text got lost (the -# retry taps: by then the field has focus and the menu is harmless). +# iOS drops keystrokes in two situations seen on the CI simulator: while the +# edit menu (the "AutoFill" bubble) opens, which happens when a flow taps a +# field that already has focus, and right after the first character, while +# the field re-renders. So: no tap for a field that focuses itself (TAP=no; +# Maestro can't see a React Native field's focus), type the first character, +# wait until it shows, then type the rest. Retyped up to twice. appId: org.bulwarkmail.mobile --- +- evalScript: ${output.typeHead = TEXT.slice(0, 1); output.typeTail = TEXT.slice(1)} - runFlow: when: true: ${TAP != 'no'} @@ -21,7 +23,14 @@ appId: org.bulwarkmail.mobile true: ${ERASE == 'yes'} commands: - runFlow: clear-field.yaml -- inputText: ${TEXT} +- inputText: ${output.typeHead} +- extendedWaitUntil: + visible: + id: ${FIELD} + text: "${output.typeHead}.*" + timeout: 5000 + optional: true +- inputText: ${output.typeTail} - runFlow: when: notVisible: @@ -31,11 +40,15 @@ appId: org.bulwarkmail.mobile - retry: maxRetries: 2 commands: - - runFlow: - file: clear-field.yaml - - waitForAnimationToEnd: - timeout: 1000 - - inputText: ${TEXT} + - runFlow: clear-field.yaml + - inputText: ${output.typeHead} + - extendedWaitUntil: + visible: + id: ${FIELD} + text: "${output.typeHead}.*" + timeout: 5000 + optional: true + - inputText: ${output.typeTail} - assertVisible: id: ${FIELD} text: ${TEXT_PATTERN || TEXT} diff --git a/.maestro/subflows/webmail-login-page.yaml b/.maestro/subflows/webmail-login-page.yaml index cb939892..33829d38 100644 --- a/.maestro/subflows/webmail-login-page.yaml +++ b/.maestro/subflows/webmail-login-page.yaml @@ -6,10 +6,16 @@ appId: org.bulwarkmail.mobile visible: "user@example.com" timeout: 60000 - takeScreenshot: webmail-login-page -- tapOn: "user@example.com" -- inputText: ${LOGIN} -- tapOn: "Enter your password" -- inputText: ${PASSWORD} +- runFlow: + file: type-web.yaml + env: + HINT: "user@example.com" + TEXT: ${LOGIN} +- runFlow: + file: type-web.yaml + env: + HINT: "Enter your password" + TEXT: ${PASSWORD} - tapOn: "Sign in" - runFlow: when: @@ -26,3 +32,9 @@ appId: org.bulwarkmail.mobile - inputText: ${output.helper.code} - tapOn: "Sign in|Verify" +# Before handing over, the webmail asks whether the app may take the sign-in. +- extendedWaitUntil: + visible: "Hand over to the app" + timeout: 60000 +- takeScreenshot: webmail-handover-prompt +- tapOn: "Hand over to the app"