fix(ios): route synthesized gestures to the sole screen when no window resolves

Merged
TH
2d ago
+170-12

Summary

On a deep app tree, XCTest's windows query fails with kAXErrorIllegalArgument. Bluesky's real home feed reaches that at accessibility depth 62. Synthesized taps and scrolls need no tree, but the runner could not name the window to route them. It paid about 2 s of XCTest retries per app.frame read, then:

  • scroll failed after 7.8 s ("could not resolve a usable interaction frame");
  • press fell back to an XCTest coordinate tap and failed after 18 s with NSInternalInconsistencyException, ending the runner test.

When no window resolves on an iPhone with exactly one screen, the runner now uses that screen, laid out in the app's interface orientation, as the reference frame and routes the event record to that screen's display ID. iPad and multi-screen devices still require a window. The synthesized-context lookup no longer falls back to app.frame.

7 files (Swift/ObjC runner).

Validation

  • pnpm check:affected --run --head e9f7502012: passed, including xctest-selection and packaged-runner-swift.
  • New runner unit tests (frame per orientation, refusal on unknown orientation or empty screen) pass on an iOS 27.0 simulator.
  • Live, Bluesky 1.136.0 (real account), iPhone 17 Pro simulator, iOS 27.0, on a feed screen where a forced XCTest tree capture returns sparse after 3.4 s:
    • base origin/main runner: scroll down failed in 7844 ms; press @ref failed in 17968 ms (24 "Find the Application" retries).
    • head: scrolls 632โ€“920 ms and taps ~0.9 s on the sole-screen route, 0 retries. All 3 sampled sole-screen taps landed on the Search screen.
  • Healthy screens still resolve their window (no route log line).

๐Ÿค– Generated with Claude Code