From 2ebad19b2171dc53774eccb2610ca0332ecfe63a Mon Sep 17 00:00:00 2001 From: spacedandy-agents-simplex <342056592+spacedandy-agents-simplex@users.noreply.github.com> Date: Wed, 14 Oct 2026 12:20:10 +0000 Subject: [PATCH] ci: search the test directory from the chat list in the smoke test The app is built with DIRECTORY_SERVICE_LINK set to the test directory's short address (sed in the workflow). The smoke test types "ci seed", taps "Search in Directory", accepts the first-search consent alert with "Search", and expects the Directory results with #ci_group (Join group) and #ci_channel (Join channel), retrying once if the search fails. The steps now use scripts/ci/ios-sim/ui, which wraps AXe (tap by label or value, type, wait, screenshot, compact accessibility tree) for scripts and for an agent on the runner. Later steps get SIM_UDID and UI_OUT. This run tests: the onboarding and typing steps on the new helper, the consent alert, and the directory results in the app. --- .github/workflows/ios-sim.yml | 7 ++ scripts/ci/ios-sim/smoke-test.sh | 155 +++++++++++++++---------------- scripts/ci/ios-sim/ui | 62 +++++++++++++ 3 files changed, 145 insertions(+), 79 deletions(-) create mode 100755 scripts/ci/ios-sim/ui diff --git a/.github/workflows/ios-sim.yml b/.github/workflows/ios-sim.yml index 82dd383400..f49f89f4c3 100644 --- a/.github/workflows/ios-sim.yml +++ b/.github/workflows/ios-sim.yml @@ -204,6 +204,13 @@ jobs: timeout-minutes: 30 run: scripts/ci/ios-sim/backend.sh start ~/Downloads/${{ env.BACKEND_PKG }} "$RUNNER_TEMP/backend" + - name: Point the app at the test directory + run: | + link=$(cat "$RUNNER_TEMP/backend/directory-link") + file=apps/ios/Shared/Model/DirectorySearch.swift + sed -i '' "s|^let DIRECTORY_SERVICE_LINK = \".*\"$|let DIRECTORY_SERVICE_LINK = \"$link\"|" "$file" + grep -F "let DIRECTORY_SERVICE_LINK = \"$link\"" "$file" + - name: Build app run: | xcodebuild build -quiet \ diff --git a/scripts/ci/ios-sim/smoke-test.sh b/scripts/ci/ios-sim/smoke-test.sh index 18c1598147..b3a7f7e7db 100755 --- a/scripts/ci/ios-sim/smoke-test.sh +++ b/scripts/ci/ios-sim/smoke-test.sh @@ -1,70 +1,45 @@ #!/bin/bash -# Installs the app in a new iPhone simulator and drives it with AXe: onboarding, chat list, typing in the search field. +# Installs the app in a new iPhone simulator and runs the scripted UI cases with the ui helper: +# onboarding to the chat list, typing in the search field, and searching the test directory. # Usage: scripts/ci/ios-sim/smoke-test.sh # Each step saves a screenshot and an accessibility tree to the output dir and prints the tree to the log. +# Later steps of the job get SIM_UDID and UI_OUT, with the simulator still running. set -euo pipefail app=$1 -out=$2 +export UI_OUT=$2 bundle_id=chat.simplex.app -search_text="ci smoke" -mkdir -p "$out" +search_text="ci seed" +ui=$(dirname "$0")/ui +mkdir -p "$UI_OUT" axe --version runtime=com.apple.CoreSimulator.SimRuntime.iOS-$(xcrun --sdk iphonesimulator --show-sdk-version | tr . -) -udid=$(xcrun simctl create ci-iphone com.apple.CoreSimulator.SimDeviceType.iPhone-17 "$runtime") -echo "simulator $udid, runtime $runtime" -xcrun simctl boot "$udid" -xcrun simctl bootstatus "$udid" -b -open -a Simulator --args -CurrentDeviceUDID "$udid" +SIM_UDID=$(xcrun simctl create ci-iphone com.apple.CoreSimulator.SimDeviceType.iPhone-17 "$runtime") +export SIM_UDID +echo "simulator $SIM_UDID, runtime $runtime" +if [ -n "${GITHUB_ENV:-}" ]; then + echo "SIM_UDID=$SIM_UDID" >> "$GITHUB_ENV" + echo "UI_OUT=$UI_OUT" >> "$GITHUB_ENV" +fi +xcrun simctl boot "$SIM_UDID" +xcrun simctl bootstatus "$SIM_UDID" -b +open -a Simulator --args -CurrentDeviceUDID "$SIM_UDID" -xcrun simctl spawn "$udid" log stream --level debug --style compact --predicate 'process == "SimpleX"' > "$out/app.log" 2>&1 & +xcrun simctl spawn "$SIM_UDID" log stream --level debug --style compact --predicate 'process == "SimpleX"' > "$UI_OUT/app.log" 2>&1 & log_pid=$! -step=0 -snap() { - step=$((step + 1)) - local f - f=$(printf '%s/%02d-%s' "$out" "$step" "$1") - xcrun simctl io "$udid" screenshot "$f.png" > /dev/null - axe describe-ui --udid "$udid" > "$f.json" - echo "::group::accessibility tree: $1" - cat "$f.json" - echo "::endgroup::" -} - -wait_for() { - local deadline=$((SECONDS + $2)) - local tree="$out/wait.json" - until axe describe-ui --udid "$udid" > "$tree" && grep -qF "$1" "$tree"; do - if [ "$SECONDS" -ge "$deadline" ]; then - echo "error: \"$1\" not shown after $2 s" - return 1 - fi - sleep 2 - done -} - -tap_label() { - axe tap --label "$1" --wait-timeout "$2" --post-delay 2 --udid "$udid" -} - -# SwiftUI text fields have no accessibility label; an empty field exposes its placeholder as the value -tap_field() { - axe tap --value "$1" --wait-timeout "$2" --post-delay 2 --udid "$udid" -} - finish() { local status=$? - snap final || true + "$ui" shot final || true kill "$log_pid" || true echo "::group::core start in the app log" - grep -E 'chatMigrateInit|startChat' "$out/app.log" || true + grep -E 'chatMigrateInit|startChat' "$UI_OUT/app.log" || true echo "::endgroup::" echo "::group::app log, last 300 lines" - tail -n 300 "$out/app.log" + tail -n 300 "$UI_OUT/app.log" echo "::endgroup::" find ~/Library/Logs/DiagnosticReports -name 'SimpleX*' -newer "$app" 2>/dev/null | while read -r report; do echo "::group::crash report $report" @@ -75,46 +50,68 @@ finish() { } trap finish EXIT -xcrun simctl install "$udid" "$app" -xcrun simctl launch "$udid" "$bundle_id" +expect_in_tree() { + local tree + tree=$("$ui" tree) + if ! grep -q "$@" <<< "$tree"; then + echo "error: ${*: -1} is not in the accessibility tree" + exit 1 + fi +} -wait_for "Get started" 180 -snap first-screen -tap_label "Get started" 10 +xcrun simctl install "$SIM_UDID" "$app" +xcrun simctl launch "$SIM_UDID" "$bundle_id" -wait_for "Create profile" 30 -tap_field "Enter profile name..." 10 -axe type 'citester' --udid "$udid" -snap profile-name -tap_label "Create profile" 10 +# onboarding to the chat list +"$ui" wait "Get started" 180 +"$ui" shot first-screen +"$ui" tap "Get started" -wait_for "Continue" 60 -snap your-network -tap_label "Continue" 10 +"$ui" wait "Create profile" 30 +"$ui" tap-value "Enter profile name..." +"$ui" type citester +"$ui" shot profile-name +"$ui" tap "Create profile" -wait_for "Accept" 30 -snap network-commitments -tap_label "Accept" 10 +"$ui" wait "Continue" 60 +"$ui" shot your-network +"$ui" tap "Continue" + +"$ui" wait "Accept" 30 +"$ui" shot network-commitments +"$ui" tap "Accept" sleep 5 -snap after-onboarding -tap_label "Allow" 20 || echo "no notifications alert to allow" +"$ui" shot after-onboarding +"$ui" tap "Allow" 20 || echo "no notifications alert to allow" -wait_for "Search or paste SimpleX link" 60 -snap chat-list -tap_field "Search or paste SimpleX link" 10 -axe type "$search_text" --udid "$udid" +"$ui" wait "Search or paste SimpleX link" 60 +"$ui" shot chat-list + +# typed text that is not a SimpleX name offers the directory +"$ui" tap-value "Search or paste SimpleX link" +"$ui" type "$search_text" sleep 2 -snap search-typed - +"$ui" shot search-typed # the keyboard capitalizes the first letter -tree=$(ls "$out"/*-search-typed.json) -if ! grep -qiF "$search_text" "$tree"; then - echo "error: \"$search_text\" is not in the accessibility tree after typing" - exit 1 +expect_in_tree -iF "\"$search_text\"" +expect_in_tree -F '"Search in Directory"' + +# the directory finds the seeded group and channel, after the first-search consent +"$ui" tap "Search in Directory" +"$ui" wait "Search in Directory?" 10 +"$ui" shot search-consent +"$ui" tap "Search" +if ! "$ui" wait "Join channel" 60; then + "$ui" shot search-failed + "$ui" tap "Search failed, tap to retry" + "$ui" wait "Join channel" 60 fi -if ! grep -qF "Search in Directory" "$tree"; then - echo "error: no \"Search in Directory\" row after typing" - exit 1 -fi -echo "smoke test passed: the chat list search field shows \"$search_text\"" +"$ui" shot directory-results +# the header alone is matched exactly: "Search in Directory" stays shown above the field +expect_in_tree -F '"Directory"' +expect_in_tree -F '#ci_group' +expect_in_tree -F 'Join group' +expect_in_tree -F '#ci_channel' +expect_in_tree -F 'Join channel' +echo "smoke test passed: the directory search for \"$search_text\" shows #ci_group (Join group) and #ci_channel (Join channel)" diff --git a/scripts/ci/ios-sim/ui b/scripts/ci/ios-sim/ui new file mode 100755 index 0000000000..6184162bde --- /dev/null +++ b/scripts/ci/ios-sim/ui @@ -0,0 +1,62 @@ +#!/bin/bash + +# Drives the app in the simulator SIM_UDID with AXe, for the scripted cases and for an agent on the runner. +# Screenshots and accessibility trees go to UI_OUT. +# +# ui tap