Files
callstack__agent-device/apple/runner
Michał Pierzchała d07b837621 test: classify the runner XCTests — pure decisions to a macOS host lane, simulator semantics gated os(iOS) (#1781 A7) (#1861)
Every declared AgentDeviceRunnerUITests method now belongs to a lane, and
the #if guard is the classification: AGENT_DEVICE_RUNNER_UNIT_TESTS alone
means a pure runner decision (runs on the macOS host on every PR — ci.yml's
existing compile job now executes the bundle it builds), '&& os(iOS)' means
runner/XCTest semantics (simulator lanes only). check:xctest-selection
evaluates the guards per platform, derives each lane's reach, and fails on
a flagged identifier that is undeclared or uncompiled on that lane, on a
declared test no lane reaches (found the two tvOS-only tests, dark since
birth — widened to os(tvOS) || os(macOS)), and on testCommand reaching any
lane. The host and nightly lanes assert executed == derived reach, so a
missing -D flag or a guard that compiles a file out reads red, not as a
smaller green. One duplicate test deleted (sparse-verdict assertions folded
into its twin).
2026-08-19 13:59:45 +02:00
..

agent-device iOS Runner

This folder contains the lightweight XCUITest runner used to provide element-level automation for Apple-family targets.

Intent

  • Provide a minimal XCTest target that exposes UI automation over a small HTTP server.
  • Allow local builds via xcodebuild and caching for faster subsequent runs.
  • Support simulator prebuilds where compatible.

Status

Current internal runner for iOS, tvOS, and macOS desktop automation.

Protocol and maintenance references:

UITest Runner File Map

AgentDeviceRunnerUITests/RunnerTests is split into focused files to reduce context size for contributors and LLM agents.

  • RunnerTests.swift: shared state/constants, setUp(), and testCommand() entry flow.
  • RunnerTests+Models.swift: wire protocol models (Command, Response, snapshot payload models).
  • RunnerTests+Environment.swift: environment and CLI argument helpers (RunnerEnv).
  • RunnerTests+Transport.swift: TCP request handling and HTTP parsing/encoding.
  • RunnerTests+CommandExecution.swift: command dispatch (execute*) and command switch.
  • RunnerTests+Lifecycle.swift: activation/retry/stabilization and recording lifecycle helpers.
  • RunnerTests+Interaction.swift: tap/drag/swipe/type/home/rotate/app-switcher helpers.
  • RunnerTests+Navigation.swift: back/navigation-control helpers.
  • RunnerTests+Snapshot.swift: fast/raw snapshot builders and include/filter helpers.
  • RunnerTests+SystemModal.swift: SpringBoard/system modal detection and modal snapshot shaping.
  • RunnerTests+ScreenRecorder.swift: nested ScreenRecorder implementation.

Snapshot Strategy

iOS snapshots have two explicit public capture modes:

  • full/raw snapshots use recursive XCTest snapshots for rich hierarchy and diagnostics;
  • interactive snapshots filter the same visible tree down to agent-facing refs.

Some iOS apps expose accessibility trees that lower-level AX services can inspect but XCTest cannot serialize reliably. In those cases interactive snapshots may return a sparse root quickly, while full snapshots preserve the XCTest error. A penalized simulator can recover through private AX; physical devices use a short XCTest probe because no non-XCTest semantic backend is available there. See ../../docs/adr/0004-ios-snapshot-backend-strategy.md for the backend boundary and future simulator AX-service direction.

Protocol Notes

  • The daemon posts JSON commands to POST /command on the runner's local HTTP listener.
  • The runner responds with a JSON envelope shaped as { ok, data?, error? }.
  • The protocol is internal to agent-device; when adding or renaming commands, update both wire models and the protocol tests/docs in the same change.