Maestro Driver

SootSim runs Maestro-compatible YAML flows through the sootsim maestro CLI, a drop-in for the real maestro CLI. Point it at your existing .maestro/ folder and it runs the flows against the browser simulator, no Mac or device needed.

terminal

sootsim maestro # auto-discovers ./.maestro or ./maestro and runs every flow
sootsim maestro test <flow-or-dir> # run one flow file, or every *.yaml/*.yml in a dir
sootsim maestro init # scaffold a starter .maestro/login.yaml
sootsim maestro --list-compat # print the full verb support matrix

Useful flags: --env KEY=VALUE (repeatable), --headed, --record, --preview / --preview-open (upload a shareable recording), --slow <ms>. The --format / --output / --device flags are accepted and ignored for maestro command-line compatibility.

There is no programmatic driver class; the CLI is the surface. Run sootsim maestro --list-compat for the authoritative, always-current matrix; the summary below is a guide.

Supported steps

Interaction and input:

- tapOn: 'Button Text'
- tapOn: { id: 'my-button' }
- tapOn: { text: 'Submit', index: 1 }
- tapOn: { text: 'Row', childOf: { id: 'list' } }
- tapAtCoords: { x: 100, y: 200 }
- longPressOn: 'Item'
- inputText: 'hello world'
- eraseText: 5
- pressKey: 'Enter'
- dispatchKey: 'Escape'
- hideKeyboard: true
- back: true

Navigation and scrolling:

- swipe: { direction: 'LEFT' }
- scroll: { direction: 'DOWN' }
- scrollTo: { id: 'footer' }
- scrollUntilVisible:
element: 'Target Text'
direction: 'DOWN'
timeout: 10000
- pinch: { scale: 2 }

Assertions and waiting:

- assertVisible: 'Welcome'
- assertVisible: { id: 'header' }
- assertNotVisible: 'Loading'
- assertTreeContains: 'Submit' # sootsim extension
- waitFor: { text: 'Ready', timeout: 5000 }
- extendedWaitUntil: { visible: 'Done', timeout: 10000 }
- waitForAnimationToEnd: true
- wait: 2000 # sootsim extension: wait ms

Control flow, scripting, and capture:

- repeat:
times: 3
commands:
- tapOn: 'Next'
- waitForAnimationToEnd: true
- runFlow: 'sub-flow.yaml'
- runScript: 'setup.js' # full Maestro JS: http, json(), output, env, console.log
- evalScript: '${output.token = "abc"}'
- copyTextFrom: { id: 'code' } # then use ${maestro.copiedText}
- openLink: 'myapp://profile/42' # dispatched through Linking (react-navigation deep links)
- takeScreenshot: 'home-screen'
- takeScreenshot: { path: 'home.png', withFrame: true } # sootsim: framed export
- dumpTree: 5 # sootsim extension: dump tree to depth

Conditionals, lifecycle hooks, workspace mode, and ${...} JS-expression interpolation are supported: when: { visible / notVisible / platform / true }, optional: true, label:, onFlowStart / onFlowComplete, and a config.yaml workspace with flows: globs plus includeTags / excludeTags.

Partial support

  • clearKeychain: warn-only; SootSim has no keychain surface.
  • when.platform: SootSim always reports iOS.
  • openLink: dispatched into the app through Linking emulation (deep links work); there is no OS-level Safari fallback.
  • launchApp.arguments: ignored; there is no native process to pass them to.
  • env: seeded from your full shell environment, so ${SOOTSIM_*} and the like resolve. A bare ${NAME} that is undefined fails the step loudly rather than substituting "undefined".

Not implemented

These throw an “unsupported” error: travel, setLocation, setAirplaneMode, killApp, faker, addMedia, startRecording / stopRecording (use the --record flag instead), and repeat.while (only repeat.times is supported).

Ready to build?

Run your React Native app in the browser. No simulators, no native toolchain, no waiting.

curl -fsSL https://sootsim.com/install.sh | sh