Skip to content

ProbeScript Syntax

ProbeScript is a natural language test syntax with indent-based blocks (like Python). Test files use the .probe extension.

Every test starts with test followed by a quoted name, with steps indented below:

test "user sees welcome screen"
open the app
wait 3 seconds
see "Welcome"
don't see "Error"

Add tags with @ after the test declaration:

test "critical login flow"
@smoke @critical
open the app
tap "Sign In"
see "Dashboard"

Run tagged tests with probe test tests/ --tag smoke.

ProbeScript supports multiple strategies for identifying widgets:

SelectorSyntaxExample
Text match"text"tap "Submit"
Widget key#keyNametap #loginButton
Widget type<TypeName>tap <ElevatedButton>
Ordinal1st "Item", 2nd "Item"tap 2nd "Add"
Positional"text" in "Container"tap "Edit" in "Settings"
type "hello@world.com" into "Email"
type "secret123" into the "Password" field
see "Dashboard" # text is visible
don't see "Error" # text is NOT visible
see 3 "Item" # exactly 3 matches
see "Submit" is enabled # widget state
see "Terms" is checked # checkbox state
see "Price" contains "$9.99" # partial text match
tap "Button"
double tap "Image"
long press "Item"
swipe left
swipe up on "Card"
scroll down
scroll up on "ListView"
drag "Item A" to "Item B"
wait 5 seconds
wait until "Dashboard" appears
wait until "Loading" disappears
wait for the page to load
wait for network idle
if "Accept Cookies" appears
tap "Accept Cookies"

With an else branch:

if "Welcome Back" appears
tap "Continue"
else
tap "Sign In"
repeat 3 times
swipe left
wait 1 second

For anything ProbeScript doesn’t cover natively, use a dart: block:

dart:
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
when the app calls POST "/api/auth/login"
respond with 503 and body "{ \"error\": \"Service Unavailable\" }"
take screenshot "checkout_page" # save PNG to screenshots folder
dump tree # dump widget tree for debugging
save logs # save app logs
go back # device back button
rotate landscape # rotate device
log "checkpoint reached" # print to test output
pause # 1-second pause
clear app data # wipe data and relaunch
restart the app # force-stop and relaunch (preserves data)
kill the app # force-stop only (no relaunch)
open the app # launch the app (CLI-side) and reconnect
copy "user@example.com" to clipboard
paste from clipboard # stores result in <clipboard> variable
type "<clipboard>" into "Email" # use the pasted value
set location 37.7749, -122.4194 # set GPS coordinates (lat, lng)
verify external browser opened # assert url_launcher was called

Make real HTTP requests to APIs (runs on the CLI, not the device):

call GET "https://api.example.com/health"
call POST "https://api.example.com/seed" with body "{\"env\":\"test\"}"
call PUT "https://api.example.com/users/1" with body "{\"name\":\"updated\"}"
call DELETE "https://api.example.com/sessions"

Responses are stored in variables:

  • <response.status> — HTTP status code (e.g., 200)
  • <response.body> — response body as a string

Generate random data for form-heavy tests:

type "<random.email>" into "Email" # e.g., user_x7k2m@test.probe
type "<random.name>" into "Name" # e.g., Alice Johnson
type "<random.phone>" into "Phone" # e.g., +1-555-042-7831
type "<random.uuid>" into "Reference" # UUID v4
type "<random.number(1,100)>" into "Age" # random int in range
type "<random.text(8)>" into "Code" # random alphanumeric string
allow permission "notifications"
deny permission "camera"
grant all permissions
revoke all permissions

See App Lifecycle for details on how these work across platforms.