Repeatable flows

For AI agents: this page is Markdown at https://squiggle.sh/docs/flows/repeatable.md. Every docs page is listed at https://squiggle.sh/llms.txt, and all of them are one file at https://squiggle.sh/llms-full.txt.

A flow should pass on the tenth run as it did on the first. Declare where it starts, stub the network when the data changes, reuse flows instead of copying them, and mark the steps that may not apply.

Start from a known screen

A flow starts wherever the last run left the app. If that was a different screen, or a form still holding the last run’s text, the flow fails for a reason that has nothing to do with your app. Declare the starting point with prerequisite:

YAML
flow: edit profileprerequisite:  route: Home  reset: autosteps: …

Before step 1, Squiggle takes the app to that screen. It reports this on its own line, so getting there never changes the flow’s result. reset says how:

resetWhat it does
autoThe default. Scrolls to the top, then goes back, then relaunches the app, stopping as soon as the screen is reached.
scrollOnly scrolls to the top.
backOnly goes back.
relaunchAlways relaunches the app, even when it is already on the screen. Use it for forms: typing adds to what a field already holds, and only a fresh launch clears it.

squiggle flow does this whenever the flow declares a prerequisite; --no-auto-correct skips it. In Studio, turn on Return to start screen in the Replay options. When you record in Studio, the screen you start on is saved as the prerequisite.

For a screen deep in the app, with data behind it, a save slot is faster than tapping your way there. Get the app there once and run squiggle save cart-full; before a run, squiggle load cart-full puts the screen and its stores back. See Save and load app state, and App state for finding which saved values make a flow fail.

Stub the network

When a screen shows data from a server, the data changes and the flow breaks. Answer the request yourself:

YAML
- network.stub:    urlMatch: /api/orders    status: 200    body: '{"orders":[]}'- tap: { testID: refresh }- waitFor: { networkIdle: true }- assert: { visible: { text: "No orders yet" } }- network.stub: clear

Stubs need the app launched with network capture: run with --capture-net, or turn on Capture network in Studio’s Replay options. The same launch makes waitFor: { networkIdle: true } work. urlMatch is part of the request’s URL, matched anywhere in it and ignoring case; the first stub that matches answers.

To stub every request a flow makes, build the stubs from a run instead of writing them: --stubs in Run settings. To see what your app does when requests fail, see Find what breaks on a bad network.

Reuse flows

Call another flow with runFlow, and pass env to change its test data:

YAML
flow: checkoutenv:  USER: dana@example.comsecrets:  PASS: correct-horsesteps:  - runFlow:      file: login.yaml      env: { USER: admin@example.com }

Give each flow defaults that let it run on its own. Then squiggle flow login still works by itself, and the caller decides which account to use. Put passwords and tokens under secrets instead of env: they work the same way, but their values are never written to recordings or run logs.

Steps that may not apply

YAML
- tap: { text: Accept, when: { visible: { text: Cookies } } }- tap: { testID: dismiss-promo, optional: true, label: close the promo }- repeat:    times: 3    commands:      - tap: { testID: load-more }- retry:    maxRetries: 2    commands:      - tap: { testID: submit }      - assert: { route: Done }- branch:    if: { visible: { text: Signed in } }    then:      - tap: { testID: continue }    else:      - runFlow: { file: login.yaml }
KeyWhat it does
whenRuns the step only if the condition holds. Takes the same checks as assert.
optionalThe step may fail without failing the run.
labelNames the step in the report.
repeatRuns its commands a number of times.
retryRuns its commands again if one fails, up to maxRetries times.
branchRuns then or else, depending on a condition.

For every key, see the Flow syntax reference.