Skip to content

Latest commit

 

History

History
153 lines (123 loc) · 5.58 KB

File metadata and controls

153 lines (123 loc) · 5.58 KB

ControlKit runners

ControlKit is the native XCTest runner used by the CLI's Apple-platform MCP tools. The public runner project is xcrs-controlkit. It uses one Xcode project generated by XcodeGen, with platform-specific targets and schemes:

Platform Scheme App product
iOS / iPadOS ControlKit-iOS ControlKit.app
tvOS ControlKit-tvOS ControlKit.app
visionOS ControlKit-visionOS ControlKit.app
watchOS ControlKit-watchOS ControlKit.app
macOS ControlKit-macOS ControlKit.app

The scheme and target names keep their platform suffixes so Xcode can select the correct SDK, while each built app is named ControlKit.

Build a runner

Install XcodeGen once, clone the runner project, and generate the Xcode project:

brew install xcodegen
cd <path-to-xcrs-controlkit>/Runners
xcodegen generate

Build the simulator runner for the platform you need:

xcodebuild -project XCRSControlKitRunner.xcodeproj \
  -scheme ControlKit-<platform> \
  -destination 'generic/platform=<platform> Simulator' \
  build-for-testing

Replace <platform> with iOS, tvOS, watchOS, or visionOS. macOS is built with -destination 'platform=macOS' and runs on the local Mac rather than a simulator.

Start the runner

Boot a compatible simulator and run the UI-test host:

xcodebuild -project XCRSControlKitRunner.xcodeproj \
  -scheme ControlKit-<platform> \
  -destination 'id=<simulator-udid>' \
  test-without-building

The shared XCTest runner starts a local ControlKit JSON-RPC server on 127.0.0.1:12004. Keep that test process running while calling the MCP tools. The macOS UI-test target includes the network-server entitlement required to bind the local port.

Run on a physical device

The same runner also works installed on a real iOS, tvOS, watchOS, or visionOS device, not just a simulator. Build and start it against the device's UDID (find it with xcrun devicectl list devices) instead of a simulator destination:

xcodebuild -project XCRSControlKitRunner.xcodeproj \
  -scheme ControlKit-<platform> \
  -destination 'id=<device-udid>' \
  build-for-testing

TEST_RUNNER_CONTROLKIT_LISTEN_HOST=0.0.0.0 xcodebuild \
  -project XCRSControlKitRunner.xcodeproj \
  -scheme ControlKit-<platform> \
  -destination 'id=<device-udid>' \
  test-without-building

The CONTROLKIT_LISTEN_HOST environment variable controls what the in-process RPC server binds to (Shared/ControlKitRPCServer.swift) — it defaults to 127.0.0.1, which is loopback-only on the device itself and unreachable from your Mac. xcodebuild forwards any TEST_RUNNER_-prefixed environment variable into the test process with the prefix stripped, so setting TEST_RUNNER_CONTROLKIT_LISTEN_HOST=0.0.0.0 makes the server bind on every interface, including the one reachable over your LAN. Find the device's address with its Bonjour hostname (<device-name>.local, discoverable via dns-sd -B _airplay._tcp local for an Apple TV) or its CoreDevice tunnel address (xcrun devicectl device info details --device <udid>, under Tunnel IP Address).

Connect through the automation MCP profile

Start either automation server:

xcrs --mcp
# or
smb --mcp --scope automation

The runner tools accept either simulator_name or simulator_udid for a simulator, or host (plus controlkit_port, defaulting to 12004) for a physical device or any other remote runner. Call device_select once to remember the target so later tools need no target arguments. Both commands expose the same unprefixed tool names.

Tool Runner Purpose
device_select All platforms Remember the active simulator or device for later tools.
device_capabilities All platforms Read platform and capability information.
input_click macOS Click at screen coordinates.
input_spatial_tap visionOS Perform a spatial tap.
input_tap iOS / tvOS / watchOS, simulator or physical Perform a touch tap.
input_text iOS / tvOS, simulator or physical Type into the focused field.
input_swipe iOS / tvOS, simulator or physical Swipe between coordinates.
input_button iOS / tvOS, simulator or physical Press a Home or tvOS remote button.
app_launch/app_terminate simulator or physical Launch/terminate an app by bundle ID. On a physical device this calls the runner's device.apps.launch/device.apps.terminate RPC methods instead of simctl.
screen_capture Simulator or physical Capture a PNG screenshot. Uses simctl for a simulator, or devicectl device capture screenshot when a device identifier is given.
ui_describe All UI-test runners Read the accessibility hierarchy.
ui_element_list All UI-test runners Read only actionable elements with tap coordinates.

For a local macOS runner, omit simulator fields and pass host and controlkit_port when needed:

{
  "host": "127.0.0.1",
  "controlkit_port": 12004,
  "x": 400,
  "y": 300
}

For a physical device, pass its Bonjour hostname or tunnel address as host instead:

{
  "host": "<device-name>.local",
  "controlkit_port": 12004,
  "button": "select"
}

Platform-specific operations intentionally reject unsupported input. For example, visionOS rejects raw touch, watchOS rejects pointer and spatial input, and macOS rejects touch and Home-button requests.

See also

For the product-level overview of end-to-end testing with xcrs and ControlKit, see smbcloud.xyz/xcrs-end-to-end-testing.