Skip to navigation

Doc Detective can open and drive iOS apps on a managed simulator as part of a test. This experimental workflow launches an app with startSurface, acts on it with the same find, click, and type steps you already use in the browser, and closes it with closeSurface.

Experimental: Native and mobile app testing is experimental and subject to change.

Before you begin

iOS app tests run only on a macOS host. On any other platform, Doc Detective skips the test with a reason rather than failing it, so a mixed-platform spec stays green. The host needs three more things:

  • The Xcode command-line tools configured (xcode-select -p).
  • The simulator control tool available (xcrun simctl).
  • At least one installed iOS runtime to boot a simulator against.

Prepare the host ahead of time:

doc-detective install ios --yes

This installs the automation driver and prebuilds WebDriverAgent. It’s macOS-only and isn’t part of install all. If you skip it, the driver still installs on demand the first time an iOS app surface starts. See install ios.

Run your first iOS test

This test targets the ios platform and launches the Settings app by its bundle ID on the context’s default simulator. It opens a settings screen, takes a screenshot of the window, and closes the app. Settings ships with iOS, so the test needs nothing else installed.

{
"tests": [
{
"runOn": [
{
"platforms": ["ios"]
}
],
"steps": [
{
"description": "Launch the app and wait until it's ready.",
"startSurface": {
"app": "com.apple.Preferences",
"timeout": 180000,
"waitUntil": {
"find": { "elementText": "Settings" }
}
}
},
{
"description": "Open a settings screen.",
"click": {
"elementText": "General"
}
},
{
"description": "Take a screenshot of the window.",
"screenshot": {
"path": "ios-settings.png"
}
},
{
"description": "Close the app.",
"closeSurface": { "app": "Preferences" }
}
]
}
]
}

To run this test, save it to a spec file and pass it to Doc Detective:

doc-detective --input ios-app.spec.json

A few things to notice:

  • The generous timeout (180,000 ms) leaves room for a cold simulator boot and the first-run WebDriverAgent build.
  • waitUntil.find gates readiness. The step holds until an element with the text Settings exists. The next step then never runs against a screen that hasn’t drawn its controls.
  • The app that startSurface opens becomes the active surface, so the later steps act on it with no surface field. Pass an explicit surface on a step, such as { "app": "Preferences" }, to switch to a different surface. That switch sticks for the surface-less steps that follow. closeSurface still names the surface to close ({ "app": "Preferences" }) because it’s a lifecycle step, not an interaction on the active surface. Doc Detective derives the default name Preferences from the final dot-segment of the bundle ID. Pass a name on startSurface to choose your own. See Target an app surface.
  • The screenshot step takes a fresh screenshot of the app every run, so the picture never drifts out of sync with the current build.

To test an app that isn’t already on the simulator, point install at an .app or .ipa bundle. See the app descriptor reference for the install field.

Choose the simulator

Without a device, an iOS app runs on the context’s default simulator, which Doc Detective boots or creates on first use. Set device on the context or the startSurface step to name a simulator or refine it by deviceType (phone or tablet) and osVersion. See Choose the simulator and the device descriptor reference for the full list of fields.

Target only iOS

Because an app targets one platform, gate the test with a context so it runs only where it can:

{
"runOn": [
{
"platforms": ["ios"]
}
]
}

On a host that isn’t macOS, the test skips with a reason rather than failing. See Test across platforms and browsers for the full context grammar.

Troubleshooting

The first app launch is slow

  • Cause: The first app surface of a run builds WebDriverAgent for the simulator, which can take several minutes on a cold machine.
  • Solution: Give the first surface a generous timeout. Running doc-detective install ios beforehand prebuilds WebDriverAgent so that cost disappears from the run.

Element not found

  • Cause: iOS mirrors macOS, mapping element criteria onto accessibility properties. elementText matches a control’s title, label, or value. elementId matches its AXIdentifier. elementAria matches its XCUIElementType, and its accessible name when you provide one. elementText and elementAria collide when a control’s accessible name is the same for both, so setting the two fields with different values on one step fails.
  • Solution: Match against the property that carries the value you want, and specify only one of elementText or elementAria when they’d target the same accessible name. See Target an app surface and the find reference.

An element is off-screen

  • Cause: The control you want isn’t in the visible viewport yet.
  • Solution: Nothing extra: mobile find auto-scrolls toward an off-screen element (up to five steps within the step’s timeout) before giving up.

Pressing a hardware key

  • Cause: iOS hardware keys aren’t on-screen elements, and not every token works on iOS.
  • Solution: Send a device-key token with type: $HOME$, $VOLUME_UP$, and $VOLUME_DOWN$ work on iOS. $BACK$ and $APP_SWITCH$ fail on iOS; there’s no equivalent key.

A permission dialog blocks the test

  • Cause: iOS shows a runtime permission dialog that sits in front of the app.
  • Solution: Treat the dialog as an element and click it. See Mobile app surfaces.

Performing a gesture

  • Cause: Swipes and scrolls aren’t clicks.
  • Solution: Use the swipe action, which drives iOS gestures.

What’s next