7474 xcrun simctl bootstatus "$UDID"
7575 echo "SIMULATOR_UDID=$UDID" >> "$GITHUB_ENV"
7676
77+ - name : Disable keyboard intelligence on the simulator
78+ run : |
79+ KEYS=(
80+ KeyboardPrediction
81+ KeyboardAutocorrection
82+ KeyboardCheckSpelling
83+ KeyboardAutocapitalization
84+ KeyboardPeriodShortcut
85+ KeyboardCapsLock
86+ KeyboardContinuousPathEnabled
87+ )
88+ for key in "${KEYS[@]}"; do
89+ xcrun simctl spawn "$SIMULATOR_UDID" defaults write "Apple Global Domain" "$key" -bool false
90+ xcrun simctl spawn "$SIMULATOR_UDID" defaults write com.apple.Preferences "$key" -bool false
91+ done
92+ # Suppress the slide-to-type intro overlay a fresh sim shows on first keyboard use
93+ xcrun simctl spawn "$SIMULATOR_UDID" defaults write com.apple.keyboard.preferences \
94+ DidShowContinuousPathIntroduction -bool true
95+ xcrun simctl spawn "$SIMULATOR_UDID" defaults read "Apple Global Domain" | grep Keyboard || true
96+
7797 - name : Install app on simulator
7898 run : |
7999 echo "Installing $APP_PATH on $SIMULATOR_UDID"
@@ -85,6 +105,61 @@ jobs:
85105 - name : Run E2E tests
86106 run : argent flow run ./.argent/flows --device $SIMULATOR_UDID
87107
108+ # Interpreting the artifacts:
109+ # - screen.png taken first, closest to the failure state (software keyboard
110+ # still visible = the dismissal never completed).
111+ # - probe-flow.txt distinguishes wedged from recovered: "ViewInspector RPC
112+ # timed out" = the app STILL cannot serve a main-thread read minutes after
113+ # the failure (true wedge); a plain "not visible" assert failure = the
114+ # tree was readable again (bounded stall that recovered).
115+ # - sample-app.txt runs WHILE the probe is in flight, so a wedged main
116+ # thread is caught parked in the culprit frames.
117+ # - spindump-system.txt covers the XPC peers (keyboard daemon, backboardd)
118+ # in case main is waiting on another process.
119+ - name : Capture app diagnostics
120+ if : ${{ !success() }}
121+ run : |
122+ DIAG="$RUNNER_TEMP/diagnostics"
123+ mkdir -p "$DIAG"
124+
125+ xcrun simctl io "$SIMULATOR_UDID" screenshot "$DIAG/screen.png" || true
126+
127+ BUNDLE_ID=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$APP_PATH/Info.plist")
128+ PID=$(xcrun simctl spawn "$SIMULATOR_UDID" launchctl list 2>/dev/null \
129+ | awk -v label="UIKitApplication:$BUNDLE_ID" '$3 ~ label {print $1}' | head -1)
130+
131+ # One-step throwaway flow: reads the UI tree through the same
132+ # native-devtools path the real flows use. The assert is expected to
133+ # fail either way; only the failure REASON matters (see above).
134+ mkdir -p "$RUNNER_TEMP/probe-flow"
135+ cat > "$RUNNER_TEMP/probe-flow/probe.yaml" <<'EOF'
136+ steps:
137+ - assert: { visible: "argent-diagnostic-probe-nonexistent" }
138+ EOF
139+
140+ if [ -n "$PID" ] && [ "$PID" != "-" ]; then
141+ echo "Sampling $BUNDLE_ID (pid $PID) while probing the UI tree"
142+ sample "$PID" 15 -file "$DIAG/sample-app.txt" &
143+ SAMPLE_JOB=$!
144+ argent flow run "$RUNNER_TEMP/probe-flow" --device "$SIMULATOR_UDID" \
145+ 2>&1 | tee "$DIAG/probe-flow.txt" || true
146+ wait "$SAMPLE_JOB" || true
147+ else
148+ echo "$BUNDLE_ID is not running; nothing to sample" | tee "$DIAG/app-not-running.txt"
149+ argent flow run "$RUNNER_TEMP/probe-flow" --device "$SIMULATOR_UDID" \
150+ 2>&1 | tee "$DIAG/probe-flow.txt" || true
151+ fi
152+
153+ sudo spindump -notarget 5 20 -file "$DIAG/spindump-system.txt" || true
154+
155+ - name : Upload diagnostics
156+ if : ${{ !success() }}
157+ uses : actions/upload-artifact@v4
158+ with :
159+ name : e2e-ios-diagnostics-${{ inputs.artifact-name }}
160+ path : ${{ runner.temp }}/diagnostics/
161+ if-no-files-found : ignore
162+
88163 # The tool-server log also carries the device backend's stderr
89164 # (`[sim <udid>]` lines), where a failed connection to the simulator is
90165 # explained.
0 commit comments