Skip to navigation

Test native macOS apps (experimental)

Doc Detective can open and drive native macOS apps 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

macOS 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.

Doc Detective drives macOS apps through an automation driver. It installs automatically the first time a macOS app surface starts, so you don’t have to prepare anything for a first run. There’s no separate pre-install command for this driver. See the install command reference for the runtime packages that do support pre-installation.

One requirement matters before your first run. The process that runs Doc Detective needs macOS Accessibility (TCC) permission. That process is your terminal, IDE, or CI runner. Without it the driver can’t drive apps, and the test skips with a walkthrough. Grant it under System Settings before you run. For the step-by-step walkthrough, see Grant Accessibility permission on macOS.

Run your first macOS test

This test targets the mac platform, launches Calculator by its .app path, waits until a digit button exists, clicks it, and closes the app. Calculator ships with macOS, so the test needs nothing else installed.

{
"tests": [
{
"runOn": [
{
"platforms": ["mac"]
}
],
"steps": [
{
"description": "Launch the app and wait until it's ready.",
"startSurface": {
"app": "/System/Applications/Calculator.app",
"timeout": 180000,
"waitUntil": {
"find": { "elementAria": "1" }
}
}
},
{
"description": "Click a control.",
"click": {
"elementAria": "1"
}
},
{
"description": "Take a screenshot of the window.",
"screenshot": {
"path": "calculator.png"
}
},
{
"description": "Close the app.",
"closeSurface": { "app": "Calculator" }
}
]
}
]
}

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

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

A few things to notice:

  • The generous timeout (180,000 ms) leaves room for the first-run WebDriverAgentMac build and for the driver to install.
  • waitUntil.find gates readiness. The step holds until a digit button, matched by elementAria, exists. The next step then never runs against a window 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": "Calculator" }, to switch to a different surface. That switch sticks for the surface-less steps that follow. closeSurface still names the surface to close ({ "app": "Calculator" }) because it’s a lifecycle step, not an interaction on the active surface. Doc Detective derives the default name Calculator from the .app base name. 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 launch an app by its bundle ID instead of a .app path, set app to the identifier, such as "com.apple.TextEdit". See the app descriptor reference for the identifier syntax.

Target only macOS

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

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

Doc Detective maps the host’s darwin platform to mac, so a macOS runner matches this context. See Test across platforms and browsers for the full context grammar.

Troubleshooting

macOS app tests skip instead of running

  • Cause: The process that runs Doc Detective doesn’t have Accessibility (TCC) permission, so the driver can’t control apps.
  • Solution: Grant the permission to your terminal, IDE, or CI runner process, then rerun. See Grant Accessibility permission on macOS.

The first app launch is slow

  • Cause: The first app surface of a run builds the automation agent (WebDriverAgentMac) with Xcode, which can take several minutes on a cold machine.
  • Solution: Give the first surface a generous timeout (the default is 60,000 ms). Doc Detective already raises its own server-startup ceiling for that first build, but a higher timeout keeps the step from aborting early.

Element not found

  • Cause: macOS exposes controls through the accessibility (AX) tree, so element criteria map onto AX properties. elementText matches a control’s title, label, or value. elementId matches its AXIdentifier. elementAria matches its AXRole, and its accessible name when you provide one. The worked example above matches the 1 button by its accessible name. 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 AX property that carries the value you want. Specify only one of elementText or elementAria when they’d target the same accessible name. See Target an app surface and the find reference.

Launch arguments or environment variables aren’t applied

  • Cause: On macOS, args reaches the app as a real argument array, and Doc Detective supports env only on macOS. Elsewhere, env fails the step.
  • Solution: Pass args as an array and set env only in macOS specs. See the app descriptor reference.

What’s next