macOS apps
Prepare a Mac for native tests, configure an app and check its controls and task data.
Use a macOS target to test your native desktop app through its accessibility elements. This page prepares the Mac for input and capture, then shows a test using XCTest and the macOS runner of appium-mac2-driver.
Requirements
Use Node.js 24.12 or later on an Apple silicon Mac with Xcode 26.5 build 17F42 and your app's .app bundle. Native tests require this pinned Xcode build.
Prepare the Mac Link to Prepare the Mac
Build the native executor first, then prepare the Mac for unattended input. The executor needs clean pinned checkouts of appium-mac2-driver and WebDriverAgent, including the licence files Retest checks.
npx retest install mac2The installer builds existing sources and downloads nothing. If a checkout is missing or at the wrong commit, follow the paths and commands in its failure message, then run the command again.
Automation Mode must work without an administrator answering a prompt. On a Mac dedicated to unattended tests, enable that setting once:
sudo automationmodetool enable-automationmode-without-authenticationFor screenshots, grant Screen Recording to the terminal or agent that runs Retest in System Settings, Privacy & Security, Screen & System Audio Recording. That app may need a relaunch. A rebuilt macOS executor also needs its permissions granted again.
Desktop input
Native tests use the Mac's interactive desktop and display the Automation Mode overlay. Run them on a Mac nobody is using during the test.
Configure the app Link to Configure the app
This config launches TaskDesk from the cross-platform fixture. Its arguments ask the app to reset local state and connect to the task service; your app may use different launch settings.
import { defineConfig, env } from '@rehearsal-labs/retest'const config = defineConfig({ apps: { desk: { platform: 'macos', appPath: './TaskDesk.app', arguments: ['-reset', '-serviceURL', 'http://127.0.0.1:4310'], }, }, secrets: { password: env('TASK_APP_PASSWORD') }, secretOrigins: { password: ['dev.retest.fixtures.taskdesk'] },})export default configdeclare module '@rehearsal-labs/retest' { interface Register { config: typeof config }}appPath is relative to the config. The bundle identifier in secretOrigins authorises password entry into that app. Native targets take no web address, browser viewport or emulation settings.
npx retest doctorDoctor checks the cached executor, the app bundle's presence and Screen Recording without starting a native session. Xcode, Automation Mode and the app's launch are checked by the run.
Check a task Link to Check a task
TaskDesk reads tasks from the shared service. This test signs in and opens a seeded task by its id, using the accessibility identifiers the fixture app exposes.
import { expect, secret, test } from '@rehearsal-labs/retest'test('shows a saved task', { apps: ['desk'] }, async ({ desk }) => { await desk.getByTestId('account-field').fill('ada') await desk.getByTestId('password-field').fill(secret('password')) await desk.getByTestId('sign-in-button').click() await expect(desk.getByTestId('signed-in-account')).toHaveText('ada') await desk.getByTestId('task-id-field').fill('seed-ada-1') await desk.getByTestId('show-task-button').click() await expect(desk.getByTestId('selected-task-id')).toHaveText('seed-ada-1') await expect(desk.getByTestId('selected-task-state')).toHaveText('Open')})macOS elements take click(), while fill() enters a field's value. Check an editable field with toHaveValue, and displayed text with toHaveText. A check repeats its reads until the expected state arrives or its deadline expires.
npx retest run tests/desk.retest.tsState and capture Link to State and capture
App data and keychain entries remain between tests. A reset argument asks the app to clear what it supports, so prepare backend data separately. Retest launches its own copy and leaves any copy you already opened alone.
Native macOS sessions take turns on the desktop. A test asking for two macOS apps cannot start because it would need both sessions at once. You can still combine one macOS app with web and iOS apps.
Window capture uses the app's own window number, so another window covering it does not appear in the picture. Screen Recording must be allowed for the process running Retest. Native screenshot baseline comparisons are not available.
Native finders support accessibility ids, roles, labels and text, with scoping and positional selection. CSS, placeholder lookup, goto, browser saved state, swipe and software keyboard helpers are unavailable on macOS. Labelled alert helpers exist, but have been exercised only with a stand-in executor.