Repository navigation
fix(ios): read system dialogs from a throwing snapshot so the location prompt cannot kill the runner - #8
Merged
jochen-testingbot merged 1 commit intoNov 13, 2026
Conversation
…n prompt cannot kill the runner
On a physical iPhone, the iOS location prompt with a map ("Precise: On", Allow Once /
Allow While Using App / Don't Allow) made the runner exit on the next view-hierarchy
request. Every later flow then failed its launchApp with "Unable to set permissions ...
Connection reset".
SystemPermissionHelper.handleSystemPermissionAlertIfNeeded runs on every request. It read
SpringBoard's alerts with non-throwing XCUIElement APIs (`.exists`, `.label`,
`allElementsBoundByIndex`, `element(boundBy:)`). These resolve each element again. The
map part of the prompt is a remote view hosted by
CoreLocationVanillaWhenInUseAuthPromptPlugin, and it appears twice in the tree. When such
an element cannot be resolved, these APIs record an XCTest failure instead of throwing,
which ends testHttpServer. Device logs show 8 matching queries into that process and then
the runner exiting, before the helper logged anything. The Apple Account check (#5) ran
first, on every request.
Now ViewHierarchyHandler takes one throwing SpringBoard snapshot per request. When
SpringBoard is in front, it reuses the app hierarchy. Both the dialog check and the status
bars (#6) use that snapshot. The matching logic moved to MaestroDriverLib as
SystemDialogMatcher: pure functions over AXElement, unit-tested with the prompt's tree.
Dialogs are matched on their title first, then their static texts. Answer buttons are
counted from the end of the dialog, so the "Precise: On" buttons cannot shift the index.
The only live interaction left is the tap, made at the button's frame center through
RunnerDaemonProxy. The interruption handler also reads from a throwing snapshot now, and
taps the button by its label.
Verified on an iPhone 17 / iOS 26.3 simulator with a small app that requests location.
With `location: unset`, the flow taps the prompt itself while hierarchy reads continue.
With default permissions, the helper taps "Allow While Using App" and the next flow
passes. The runner log has no "Failed to resolve query". The simulator prompt has no map,
so it does not reproduce the original crash; that still needs a physical device.
Also rebuilds the simulator driver zips.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On a physical iPhone, the iOS location prompt with a map ("Precise: On", Allow Once / Allow While Using App / Don't Allow) made the XCTest runner exit on the next view-hierarchy request. Every later flow then failed its
launchAppwithUnable to set permissions … Connection reset(TestingBot session f3ffd402, FR8BOT).SystemPermissionHelper.handleSystemPermissionAlertIfNeededruns on every request and read SpringBoard's alerts with non-throwing XCUIElement APIs (.exists,.label,allElementsBoundByIndex,element(boundBy:)). The map part of the prompt is a remote view hosted byCoreLocationVanillaWhenInUseAuthPromptPlugin. When such an element cannot be resolved, these APIs record an XCTest failure instead of throwing, which endstestHttpServer. This is the same class of failure as #6.Fix
ViewHierarchyHandlertakes one throwing SpringBoard snapshot per request, or reuses the app hierarchy when SpringBoard is in front. The system dialog check and the status bars (fix(ios): read status bars from a throwing snapshot so a keyboard race cannot kill the runner #6) both use it.SystemDialogMatcherin MaestroDriverLib: pure functions overAXElementfor permission dialogs and Apple Account alerts (fix(ios): dismiss Apple Account password alerts with Not Now #5).RunnerDaemonProxy. A failed snapshot is logged and skipped.Verification
MaestroDriverLib: 62 tests pass, including 12 newSystemDialogMatcherTestsbuilt on the prompt's real tree (duplicated map subtree, 3-button order)../gradlew :maestro-ios-driver:test :maestro-cli:testpasses.location: unset, the flow taps the prompt itself.ios18driver from Actions run 43401360652:Found alert 'Allow “FR8BOT” to use your location?' buttons: ["Precise: On", "Allow Once", "Allow Whi…and thenTapping 'Allow While Using App'.view_pager,backButtonids on iOS). Those are in the customer's flows, not the runner.Follow-ups (not in this PR)
fullScreenAlertHierarchy,keyboardHierarchyandfindRecoveryElementstill use.exists.launchAppfor an app that isn't installed hangs for about 4.5 minutes and then fails the runner's test.