From fdb08b36ebfdb5c2d95ecdc8eaae354c880896f4 Mon Sep 17 00:00:00 2001 From: Sivert <316918682+grytchat@users.noreply.github.com> Date: Sun, 1 Nov 2026 15:18:15 +0100 Subject: [PATCH 1/9] test: tap through the phone app with Maestro (GRYT-1999) Two flows to start with: Add a server from the server drawer, which froze the app until mobile#481, and sending and long-pressing a message. Putting the freeze back makes the first one fail at the sheet. CI runs them nightly and on PRs that change them, against a server built from source, since macOS runners have no Docker. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/discord-ci-notify.yml | 1 + .github/workflows/phone-flows.yml | 103 ++++++++++++++++++++++++ .maestro/add-server-from-drawer.yaml | 14 ++++ .maestro/config.yaml | 4 + .maestro/message-long-press.yaml | 18 +++++ .maestro/subflows/join.yaml | 24 ++++++ README.md | 10 +++ 7 files changed, 174 insertions(+) create mode 100644 .github/workflows/phone-flows.yml create mode 100644 .maestro/add-server-from-drawer.yaml create mode 100644 .maestro/config.yaml create mode 100644 .maestro/message-long-press.yaml create mode 100644 .maestro/subflows/join.yaml diff --git a/.github/workflows/discord-ci-notify.yml b/.github/workflows/discord-ci-notify.yml index 5286e337..e1b27d01 100644 --- a/.github/workflows/discord-ci-notify.yml +++ b/.github/workflows/discord-ci-notify.yml @@ -10,6 +10,7 @@ on: - CI - Expo versions - Gryt Git notification + - Phone flows - Release Android - Release iOS - Release Mobile diff --git a/.github/workflows/phone-flows.yml b/.github/workflows/phone-flows.yml new file mode 100644 index 00000000..bcff072a --- /dev/null +++ b/.github/workflows/phone-flows.yml @@ -0,0 +1,103 @@ +name: Phone flows + +on: + schedule: + - cron: "0 3 * * *" + workflow_dispatch: + pull_request: + paths: + - ".maestro/**" + - ".github/workflows/phone-flows.yml" + +concurrency: + group: phone-flows + cancel-in-progress: true + +jobs: + flows: + name: Tap through the app + runs-on: xcode-27 + timeout-minutes: 60 + env: + LANG: en_US.UTF-8 + LC_ALL: en_US.UTF-8 + MAESTRO_CLI_NO_ANALYTICS: "1" + DEVICE: iPhone 17 Pro + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 17 + + - name: Select Xcode 27.1 + run: sudo xcode-select -s /Applications/Xcode_27.1.app + + - run: yarn install --frozen-lockfile + + - name: Install Maestro + run: | + curl -fsSL -o maestro.zip https://github.com/mobile-dev-inc/maestro/releases/download/cli-2.12.0/maestro.zip + echo "a6044a84542f522f434c5dc3d609e60c7446d423f3ed1b2ae513f5c48663ec5e maestro.zip" | shasum -a 256 -c - + unzip -q maestro.zip -d "$HOME/maestro-cli" + echo "$HOME/maestro-cli/maestro/bin" >> "$GITHUB_PATH" + + - uses: actions/checkout@v4 + with: + repository: Gryt-chat/server + path: test-server + + # There is no Docker on macOS runners, so the server runs from source. + - name: Start a throwaway Gryt server + working-directory: test-server + env: + PORT: "5077" + HOST: 127.0.0.1 + DATA_DIR: ${{ runner.temp }}/gryt-data + DISABLE_S3: "true" + GRYT_IDENTITY_TIERS: local,account + run: | + yarn install --frozen-lockfile + export JWT_SECRET=$(openssl rand -hex 32) + start() { nohup node -r ts-node/register src/index.ts > "$RUNNER_TEMP/server.log" 2>&1 & echo $! > "$RUNNER_TEMP/server.pid"; } + ready() { for _ in $(seq 1 60); do curl -sf http://127.0.0.1:5077/info > /dev/null && return 0; sleep 2; done; return 1; } + start + ready + # A new server only takes invites, and no env var changes that. /info reads it at boot. + sqlite3 "$DATA_DIR/gryt.db" "UPDATE server_config SET join_policy='open', display_name='Maestro test', is_configured=1" + kill "$(cat "$RUNNER_TEMP/server.pid")" + sleep 2 + start + ready + curl -s http://127.0.0.1:5077/info | grep -q '"joinPolicy":"open"' + + - name: Build for the simulator + run: | + yarn expo prebuild --platform ios --no-install + (cd ios && pod install) + xcodebuild -workspace ios/Gryt.xcworkspace -scheme Gryt -configuration Release \ + -destination "platform=iOS Simulator,name=$DEVICE" -derivedDataPath build/sim \ + CODE_SIGN_IDENTITY=- CODE_SIGN_STYLE=Manual DEVELOPMENT_TEAM=8883W2XTQ8 PROVISIONING_PROFILE_SPECIFIER= \ + build | tail -20 + + - name: Run the flows + run: | + xcrun simctl boot "$DEVICE" + xcrun simctl bootstatus "$DEVICE" + xcrun simctl install "$DEVICE" build/sim/Build/Products/Release-iphonesimulator/Gryt.app + maestro test -e GRYT_TEST_SERVER=127.0.0.1:5077 .maestro + + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: maestro-debug + path: | + ~/.maestro/tests + ${{ runner.temp }}/server.log diff --git a/.maestro/add-server-from-drawer.yaml b/.maestro/add-server-from-drawer.yaml new file mode 100644 index 00000000..cf5eca5b --- /dev/null +++ b/.maestro/add-server-from-drawer.yaml @@ -0,0 +1,14 @@ +appId: chat.gryt.app +name: Add a server from the server drawer +--- +- runFlow: subflows/join.yaml +- tapOn: "Maestro test.*" +- tapOn: + point: "25%,86%" +- extendedWaitUntil: + visible: "Invite link or server address" + timeout: 5000 +- tapOn: "Close" +# It froze here once: the sheet never showed and no touch got through. +- tapOn: "General" +- assertVisible: "Pinned messages" diff --git a/.maestro/config.yaml b/.maestro/config.yaml new file mode 100644 index 00000000..f1896ff6 --- /dev/null +++ b/.maestro/config.yaml @@ -0,0 +1,4 @@ +flows: + - "*.yaml" +excludeTags: + - subflow diff --git a/.maestro/message-long-press.yaml b/.maestro/message-long-press.yaml new file mode 100644 index 00000000..103b1ab5 --- /dev/null +++ b/.maestro/message-long-press.yaml @@ -0,0 +1,18 @@ +appId: chat.gryt.app +name: Send a message and long-press it +--- +- runFlow: subflows/join.yaml +- tapOn: "General" +- tapOn: "Message #General.*" +- inputText: "**bold** hello" +- tapOn: "Send" +- tapOn: + point: "80%,59%" +- extendedWaitUntil: + visible: ".*bold hello. Hold for actions" + timeout: 5000 +- longPressOn: ".*bold hello. Hold for actions" +- assertVisible: "Reply" +- assertVisible: "Copy text" +- assertVisible: ".*bold hello.*" +- assertNotVisible: ".*\\*\\*bold.*" diff --git a/.maestro/subflows/join.yaml b/.maestro/subflows/join.yaml new file mode 100644 index 00000000..5043067d --- /dev/null +++ b/.maestro/subflows/join.yaml @@ -0,0 +1,24 @@ +appId: chat.gryt.app +tags: + - subflow +--- +- launchApp: + clearState: true + clearKeychain: true +# Dialog and Drawer content is hidden from the accessibility tree, so these go by position (GRYT-2000). +- extendedWaitUntil: + visible: "Gryt" + timeout: 15000 +- tapOn: + point: "50%,69%" +- tapOn: "Add a server" +- inputText: ${GRYT_TEST_SERVER} +- extendedWaitUntil: + visible: "Add Maestro test" + timeout: 10000 +- tapOn: "Add Maestro test" +- tapOn: "Not now" +- tapOn: "Skip" +- extendedWaitUntil: + visible: "General" + timeout: 20000 diff --git a/README.md b/README.md index 54b2d523..d91c720b 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,16 @@ CocoaPods reading its own path, not anything about this project: LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 npx expo prebuild --platform ios ``` +## Tapping through it: Maestro + +The flows in `.maestro/` go through the app on a simulator the way a person would. CI runs them every night and on any PR that changes them. To run them yourself you need Java 17, the [Maestro CLI](https://github.com/mobile-dev-inc/maestro), a Release simulator build and a Gryt server called "Maestro test" with open joining. The flows are in `.github/workflows/phone-flows.yml` step by step if you need the server setup. + +```sh +maestro test -e GRYT_TEST_SERVER=127.0.0.1:5077 .maestro +``` + +A failed run leaves its screenshots in `~/.maestro/tests`. Every flow starts from a wiped app and joins the server again. Some taps go by position, because `Dialog` and `Drawer` hide their contents from the accessibility tree (GRYT-2000). + ## Giving it to somebody else: TestFlight `expo run:ios --device` above installs onto a phone you're holding. This is the From 4d7ed5ddef856b1bf7e654779e68ea64bd0c9902 Mon Sep 17 00:00:00 2001 From: Sivert <316918682+grytchat@users.noreply.github.com> Date: Sun, 1 Nov 2026 15:30:49 +0100 Subject: [PATCH 2/9] test: find buttons by name in the phone flows (GRYT-2000) @gryt/ui-native 0.18.2 shows Dialog and Drawer contents to the accessibility tree, so the position taps go. The drawer flow also checks that tapping outside still closes it. CI picks an iPhone the runner has, and a failed build now fails the job. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/phone-flows.yml | 17 +++++++++++++++-- .maestro/add-server-from-drawer.yaml | 11 +++++++++-- .maestro/message-long-press.yaml | 3 +-- .maestro/subflows/join.yaml | 6 ++---- README.md | 2 +- package.json | 2 +- yarn.lock | 8 ++++---- 7 files changed, 33 insertions(+), 16 deletions(-) diff --git a/.github/workflows/phone-flows.yml b/.github/workflows/phone-flows.yml index bcff072a..dd8b383b 100644 --- a/.github/workflows/phone-flows.yml +++ b/.github/workflows/phone-flows.yml @@ -22,7 +22,6 @@ jobs: LANG: en_US.UTF-8 LC_ALL: en_US.UTF-8 MAESTRO_CLI_NO_ANALYTICS: "1" - DEVICE: iPhone 17 Pro steps: - uses: actions/checkout@v4 @@ -78,12 +77,26 @@ jobs: ready curl -s http://127.0.0.1:5077/info | grep -q '"joinPolicy":"open"' + # Named devices differ between runner images, so take an iPhone on the newest runtime it has. + - name: Pick a simulator + run: | + DEVICE=$(xcrun simctl list devices available -j | node -e ' + const { devices } = JSON.parse(require("fs").readFileSync(0, "utf8")); + const version = (k) => k.split("iOS-")[1].split("-").map(Number); + const newest = Object.keys(devices).filter((k) => k.includes("iOS-") && devices[k].some((d) => d.name.startsWith("iPhone"))) + .sort((a, b) => version(b)[0] - version(a)[0] || version(b)[1] - version(a)[1])[0]; + console.log(devices[newest].find((d) => d.name.startsWith("iPhone")).udid); + ') + test -n "$DEVICE" + echo "DEVICE=$DEVICE" >> "$GITHUB_ENV" + - name: Build for the simulator run: | + set -o pipefail yarn expo prebuild --platform ios --no-install (cd ios && pod install) xcodebuild -workspace ios/Gryt.xcworkspace -scheme Gryt -configuration Release \ - -destination "platform=iOS Simulator,name=$DEVICE" -derivedDataPath build/sim \ + -destination "platform=iOS Simulator,id=$DEVICE" -derivedDataPath build/sim \ CODE_SIGN_IDENTITY=- CODE_SIGN_STYLE=Manual DEVELOPMENT_TEAM=8883W2XTQ8 PROVISIONING_PROFILE_SPECIFIER= \ build | tail -20 diff --git a/.maestro/add-server-from-drawer.yaml b/.maestro/add-server-from-drawer.yaml index cf5eca5b..f8798744 100644 --- a/.maestro/add-server-from-drawer.yaml +++ b/.maestro/add-server-from-drawer.yaml @@ -3,8 +3,7 @@ name: Add a server from the server drawer --- - runFlow: subflows/join.yaml - tapOn: "Maestro test.*" -- tapOn: - point: "25%,86%" +- tapOn: "Add a server" - extendedWaitUntil: visible: "Invite link or server address" timeout: 5000 @@ -12,3 +11,11 @@ name: Add a server from the server drawer # It froze here once: the sheet never showed and no touch got through. - tapOn: "General" - assertVisible: "Pinned messages" +- tapOn: "Back" +- tapOn: "Maestro test.*" +- assertVisible: "Your servers" +# Outside the drawer, which has to close it. +- tapOn: + point: "90%,50%" +- assertNotVisible: "Your servers" +- assertVisible: "General" diff --git a/.maestro/message-long-press.yaml b/.maestro/message-long-press.yaml index 103b1ab5..8fc82740 100644 --- a/.maestro/message-long-press.yaml +++ b/.maestro/message-long-press.yaml @@ -6,8 +6,7 @@ name: Send a message and long-press it - tapOn: "Message #General.*" - inputText: "**bold** hello" - tapOn: "Send" -- tapOn: - point: "80%,59%" +- tapOn: "Agree" - extendedWaitUntil: visible: ".*bold hello. Hold for actions" timeout: 5000 diff --git a/.maestro/subflows/join.yaml b/.maestro/subflows/join.yaml index 5043067d..5f0a931f 100644 --- a/.maestro/subflows/join.yaml +++ b/.maestro/subflows/join.yaml @@ -5,12 +5,10 @@ tags: - launchApp: clearState: true clearKeychain: true -# Dialog and Drawer content is hidden from the accessibility tree, so these go by position (GRYT-2000). - extendedWaitUntil: - visible: "Gryt" + visible: "Get started" timeout: 15000 -- tapOn: - point: "50%,69%" +- tapOn: "Get started" - tapOn: "Add a server" - inputText: ${GRYT_TEST_SERVER} - extendedWaitUntil: diff --git a/README.md b/README.md index d91c720b..e3eabd6d 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ The flows in `.maestro/` go through the app on a simulator the way a person woul maestro test -e GRYT_TEST_SERVER=127.0.0.1:5077 .maestro ``` -A failed run leaves its screenshots in `~/.maestro/tests`. Every flow starts from a wiped app and joins the server again. Some taps go by position, because `Dialog` and `Drawer` hide their contents from the accessibility tree (GRYT-2000). +A failed run leaves its screenshots in `~/.maestro/tests`. Every flow starts from a wiped app and joins the server again. ## Giving it to somebody else: TestFlight diff --git a/package.json b/package.json index 95e41100..095a7162 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "@gryt/owl": "^0.7.0", "@gryt/theme": "^0.13.0", "@gryt/ui": "^0.46.0", - "@gryt/ui-native": "^0.18.1", + "@gryt/ui-native": "^0.18.2", "@gryt/voice": "0.9.1", "@noble/ciphers": "^2.4.0", "@noble/curves": "^2.3.0", diff --git a/yarn.lock b/yarn.lock index e4e3f537..687f399f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1357,10 +1357,10 @@ resolved "https://registry.yarnpkg.com/@gryt/theme/-/theme-0.13.0.tgz#640f3049b53cfe427f0067cfc5faeffbd04d36aa" integrity sha512-7CW/wBKZFL1bfk5xQcJtvdoD+rbCvmHeA0U2uTQMQ9gfXAvIbPx7GL+TjMYYouTtLdJ/OKFARK+NXuS0RaBveg== -"@gryt/ui-native@^0.18.1": - version "0.18.1" - resolved "https://registry.yarnpkg.com/@gryt/ui-native/-/ui-native-0.18.1.tgz#a2c7eb1097951330fc719c41b179ac3dd11513d5" - integrity sha512-5KLrUEY2gMIaapTy7LRyX2V7cLbU5Uf03dyoz0KVmW5kIfqEUu8AXinEliczUUREEL6Isbh7GIM/hrMSDtDCxQ== +"@gryt/ui-native@^0.18.2": + version "0.18.2" + resolved "https://registry.yarnpkg.com/@gryt/ui-native/-/ui-native-0.18.2.tgz#ee468e0af96e93b90c06ddb44b0617dd8c5c6fb7" + integrity sha512-6QN/ZesYfsvbTPq2sibguPIoCavY9M3eJiCAqXdoNy8G2BLsJGLJi7Bcaf/gmnwsy3/0NcYnlhxgfGDkQZn47w== dependencies: "@gryt/owl" "^0.7.0" "@gryt/theme" "^0.13.0" From 7df76ac111939bb46011a6b9571bcda667fb48ef Mon Sep 17 00:00:00 2001 From: Sivert <316918682+grytchat@users.noreply.github.com> Date: Sun, 1 Nov 2026 16:08:43 +0100 Subject: [PATCH 3/9] test: keep the flows' server up on CI and pass the keyboard tip The runner has no multicast route, and the server's log stops at an mDNS send error, so the test server no longer advertises itself. A fresh simulator also shows a keyboard tip that covers the screen. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/phone-flows.yml | 1 + .maestro/subflows/join.yaml | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/.github/workflows/phone-flows.yml b/.github/workflows/phone-flows.yml index dd8b383b..c8816a6d 100644 --- a/.github/workflows/phone-flows.yml +++ b/.github/workflows/phone-flows.yml @@ -62,6 +62,7 @@ jobs: DATA_DIR: ${{ runner.temp }}/gryt-data DISABLE_S3: "true" GRYT_IDENTITY_TIERS: local,account + SERVER_DISCOVERABLE: "false" run: | yarn install --frozen-lockfile export JWT_SECRET=$(openssl rand -hex 32) diff --git a/.maestro/subflows/join.yaml b/.maestro/subflows/join.yaml index 5f0a931f..964a6e58 100644 --- a/.maestro/subflows/join.yaml +++ b/.maestro/subflows/join.yaml @@ -11,6 +11,12 @@ tags: - tapOn: "Get started" - tapOn: "Add a server" - inputText: ${GRYT_TEST_SERVER} +# iOS's first-run keyboard tip, which covers the bottom half of a fresh simulator. +- runFlow: + when: + visible: "Continue" + commands: + - tapOn: "Continue" - extendedWaitUntil: visible: "Add Maestro test" timeout: 10000 From 3845ef63afaae5fd6b84a9cb2054686071ac6635 Mon Sep 17 00:00:00 2001 From: Sivert <316918682+grytchat@users.noreply.github.com> Date: Sun, 1 Nov 2026 16:13:23 +0100 Subject: [PATCH 4/9] test: give the flows' server a multicast route instead of hiding it SERVER_DISCOVERABLE=false also takes /info away, so the server check timed out. A route over loopback keeps discovery on and the mDNS send working. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/phone-flows.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/phone-flows.yml b/.github/workflows/phone-flows.yml index c8816a6d..00115ae6 100644 --- a/.github/workflows/phone-flows.yml +++ b/.github/workflows/phone-flows.yml @@ -62,9 +62,10 @@ jobs: DATA_DIR: ${{ runner.temp }}/gryt-data DISABLE_S3: "true" GRYT_IDENTITY_TIERS: local,account - SERVER_DISCOVERABLE: "false" run: | yarn install --frozen-lockfile + # The server's mDNS send dies without a multicast route (GRYT-2001), and turning discovery off hides /info. + sudo route -n add -net 224.0.0.0/4 -interface lo0 export JWT_SECRET=$(openssl rand -hex 32) start() { nohup node -r ts-node/register src/index.ts > "$RUNNER_TEMP/server.log" 2>&1 & echo $! > "$RUNNER_TEMP/server.pid"; } ready() { for _ in $(seq 1 60); do curl -sf http://127.0.0.1:5077/info > /dev/null && return 0; sleep 2; done; return 1; } @@ -76,6 +77,8 @@ jobs: sleep 2 start ready + # Long enough to see it survive its first mDNS send, before half an hour of building. + sleep 20 curl -s http://127.0.0.1:5077/info | grep -q '"joinPolicy":"open"' # Named devices differ between runner images, so take an iPhone on the newest runtime it has. From 88b0eaf0d51364334fbb6d6495253af1bfe92cb6 Mon Sep 17 00:00:00 2001 From: Sivert <316918682+grytchat@users.noreply.github.com> Date: Sun, 1 Nov 2026 16:52:35 +0100 Subject: [PATCH 5/9] test: give Maestro's iOS driver longer to start on CI Its two-minute default ran out on the runner. The Maestro download also retries now, after a DNS failure on the runner. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/phone-flows.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/phone-flows.yml b/.github/workflows/phone-flows.yml index 00115ae6..f8bb68af 100644 --- a/.github/workflows/phone-flows.yml +++ b/.github/workflows/phone-flows.yml @@ -22,6 +22,7 @@ jobs: LANG: en_US.UTF-8 LC_ALL: en_US.UTF-8 MAESTRO_CLI_NO_ANALYTICS: "1" + MAESTRO_DRIVER_STARTUP_TIMEOUT: "300000" steps: - uses: actions/checkout@v4 @@ -43,7 +44,7 @@ jobs: - name: Install Maestro run: | - curl -fsSL -o maestro.zip https://github.com/mobile-dev-inc/maestro/releases/download/cli-2.12.0/maestro.zip + curl -fsSL --retry 5 --retry-all-errors -o maestro.zip https://github.com/mobile-dev-inc/maestro/releases/download/cli-2.12.0/maestro.zip echo "a6044a84542f522f434c5dc3d609e60c7446d423f3ed1b2ae513f5c48663ec5e maestro.zip" | shasum -a 256 -c - unzip -q maestro.zip -d "$HOME/maestro-cli" echo "$HOME/maestro-cli/maestro/bin" >> "$GITHUB_PATH" From ac38e5223296b8f98e092665f12bf8545300e56f Mon Sep 17 00:00:00 2001 From: Sivert <316918682+grytchat@users.noreply.github.com> Date: Sun, 1 Nov 2026 17:35:59 +0100 Subject: [PATCH 6/9] test: drop the multicast route from the flows' server It didn't stop the crash. Gryt-chat/server#356 fixes that in the server, which this job checks out from main. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/phone-flows.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/phone-flows.yml b/.github/workflows/phone-flows.yml index f8bb68af..0b5eef9c 100644 --- a/.github/workflows/phone-flows.yml +++ b/.github/workflows/phone-flows.yml @@ -65,8 +65,6 @@ jobs: GRYT_IDENTITY_TIERS: local,account run: | yarn install --frozen-lockfile - # The server's mDNS send dies without a multicast route (GRYT-2001), and turning discovery off hides /info. - sudo route -n add -net 224.0.0.0/4 -interface lo0 export JWT_SECRET=$(openssl rand -hex 32) start() { nohup node -r ts-node/register src/index.ts > "$RUNNER_TEMP/server.log" 2>&1 & echo $! > "$RUNNER_TEMP/server.pid"; } ready() { for _ in $(seq 1 60); do curl -sf http://127.0.0.1:5077/info > /dev/null && return 0; sleep 2; done; return 1; } @@ -78,8 +76,6 @@ jobs: sleep 2 start ready - # Long enough to see it survive its first mDNS send, before half an hour of building. - sleep 20 curl -s http://127.0.0.1:5077/info | grep -q '"joinPolicy":"open"' # Named devices differ between runner images, so take an iPhone on the newest runtime it has. From 8d2a8c5c4492b01193d4f02dff989f6477ebdcf7 Mon Sep 17 00:00:00 2001 From: Sivert <316918682+grytchat@users.noreply.github.com> Date: Sun, 1 Nov 2026 18:13:32 +0100 Subject: [PATCH 7/9] test: hide the keyboard before closing the add-server sheet On CI the Close tap opened Control Center instead of reaching the app. Co-Authored-By: Claude Opus 5.5 --- .maestro/add-server-from-drawer.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.maestro/add-server-from-drawer.yaml b/.maestro/add-server-from-drawer.yaml index f8798744..011c0a0e 100644 --- a/.maestro/add-server-from-drawer.yaml +++ b/.maestro/add-server-from-drawer.yaml @@ -7,6 +7,8 @@ name: Add a server from the server drawer - extendedWaitUntil: visible: "Invite link or server address" timeout: 5000 +# With the keyboard up, Close can sit where iOS takes the tap for Control Center. +- hideKeyboard - tapOn: "Close" # It froze here once: the sheet never showed and no touch got through. - tapOn: "General" From 02368dfc7c8659a94732b59ec0695a9253448b0d Mon Sep 17 00:00:00 2001 From: Sivert <316918682+grytchat@users.noreply.github.com> Date: Sun, 1 Nov 2026 18:15:56 +0100 Subject: [PATCH 8/9] test: only tap Close if hiding the keyboard left the sheet open Co-Authored-By: Claude Opus 5.5 --- .maestro/add-server-from-drawer.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.maestro/add-server-from-drawer.yaml b/.maestro/add-server-from-drawer.yaml index 011c0a0e..3b599b74 100644 --- a/.maestro/add-server-from-drawer.yaml +++ b/.maestro/add-server-from-drawer.yaml @@ -8,8 +8,13 @@ name: Add a server from the server drawer visible: "Invite link or server address" timeout: 5000 # With the keyboard up, Close can sit where iOS takes the tap for Control Center. +# Hiding it can also close the sheet, so Close is only tapped if it's still there. - hideKeyboard -- tapOn: "Close" +- runFlow: + when: + visible: "Close" + commands: + - tapOn: "Close" # It froze here once: the sheet never showed and no touch got through. - tapOn: "General" - assertVisible: "Pinned messages" From 1f5f980f151c1cc3d27779cc49da525b8d983e28 Mon Sep 17 00:00:00 2001 From: Sivert <316918682+grytchat@users.noreply.github.com> Date: Sun, 1 Nov 2026 19:03:24 +0100 Subject: [PATCH 9/9] test: end the drawer flow on the sheet working, not on closing it Hiding the keyboard behaves differently on the runner, and closing the sheet isn't what this flow is for. It now checks that the sheet shows and takes typing, and that tapping outside closes the drawer. Co-Authored-By: Claude Opus 5.5 --- .maestro/add-server-from-drawer.yaml | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/.maestro/add-server-from-drawer.yaml b/.maestro/add-server-from-drawer.yaml index 3b599b74..73b399ae 100644 --- a/.maestro/add-server-from-drawer.yaml +++ b/.maestro/add-server-from-drawer.yaml @@ -3,26 +3,18 @@ name: Add a server from the server drawer --- - runFlow: subflows/join.yaml - tapOn: "Maestro test.*" -- tapOn: "Add a server" -- extendedWaitUntil: - visible: "Invite link or server address" - timeout: 5000 -# With the keyboard up, Close can sit where iOS takes the tap for Control Center. -# Hiding it can also close the sheet, so Close is only tapped if it's still there. -- hideKeyboard -- runFlow: - when: - visible: "Close" - commands: - - tapOn: "Close" -# It froze here once: the sheet never showed and no touch got through. -- tapOn: "General" -- assertVisible: "Pinned messages" -- tapOn: "Back" -- tapOn: "Maestro test.*" - assertVisible: "Your servers" # Outside the drawer, which has to close it. - tapOn: point: "90%,50%" - assertNotVisible: "Your servers" -- assertVisible: "General" +- tapOn: "Maestro test.*" +- tapOn: "Add a server" +# It froze here once: the sheet never showed and no touch got through. +- extendedWaitUntil: + visible: "Invite link or server address" + timeout: 5000 +- inputText: "127.0.0.1:5077" +- extendedWaitUntil: + visible: "Maestro test" + timeout: 10000