Test iOS apps (experimental)
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:
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.
To run this test, save it to a spec file and pass it to Doc Detective:
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.findgates readiness. The step holds until an element with the textSettingsexists. The next step then never runs against a screen that hasn’t drawn its controls.- The app that
startSurfaceopens becomes the active surface, so the later steps act on it with nosurfacefield. Pass an explicitsurfaceon a step, such as{ "app": "Preferences" }, to switch to a different surface. That switch sticks for the surface-less steps that follow.closeSurfacestill 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 namePreferencesfrom the final dot-segment of the bundle ID. Pass anameonstartSurfaceto choose your own. See Target an app surface. - The
screenshotstep 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:
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. Runningdoc-detective install iosbeforehand prebuilds WebDriverAgent so that cost disappears from the run.
Element not found
- Cause: iOS mirrors macOS, mapping element criteria onto accessibility properties.
elementTextmatches a control’s title, label, or value.elementIdmatches its AXIdentifier.elementAriamatches its XCUIElementType, and its accessible name when you provide one.elementTextandelementAriacollide 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
elementTextorelementAriawhen they’d target the same accessible name. See Target an app surface and thefindreference.
An element is off-screen
- Cause: The control you want isn’t in the visible viewport yet.
- Solution: Nothing extra: mobile
findauto-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
swipeaction, which drives iOS gestures.
What’s next
- Run on an iOS simulator: host requirements and device management.
swipe: perform mobile gestures.- Device keys on mobile app surfaces: press hardware keys.
- Test across platforms and browsers: gate tests by platform.
- Inline tests and Detected tests: author these startSurface, click, screenshot, and closeSurface steps inline in a doc source file instead of a standalone spec.
- Docker and headless: run app tests in CI.