Gestures and scrolling
For AI agents: this page is Markdown at https://squiggle.sh/docs/flows/gestures.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.
Swipe, scroll and drag in a flow, reach controls further down a list, and deal with a tap on a control that is off screen.
swipe and scroll go opposite ways
swipe names where your finger goes. scroll names where the content goes. To see what’s further down a list, you scroll: down, and the finger moves up. Pick a step to see which way each one moves, and a position to see a drag to it:
The finger moves up, and you see items further down the list.
swipe says where the finger goes. scroll says which way you move through the content, like a mouse wheel. swipe: up and scroll: down are the same drag.
- swipe: { testID: volume, to: 25% }The drag starts at the slider’s centre and ends 25% of the way across its own width, so it lands on the same value on every screen size. Assert the value afterwards: a swipe that passes was sent, which is not the same as the slider moving.
- swipe: { direction: left } # the finger moves left- scroll: { direction: down, amount: 300 } # the content moves down 300 pointsamount is in points. A scroll holds the finger still before lifting it, so the content moves exactly that far, with no momentum. A swipe lifts while the finger is still moving, as a flick does, so a list keeps going and a sheet that closes on a fast swipe closes.
Drag to a position
For a slider, a segmented control or a colour picker, the value is where the finger stops. A distance in points means something different on every device, so say where the drag ends instead, as a percentage of the control:
- swipe: { testID: brightness, to: 25% } # a quarter of the way across- swipe: { testID: brightness, to: 100% } # all the way right- swipe: { testID: canvas, to: "10%, 75%" } # across and downThe drag starts at the control’s centre. One value sets how far across and keeps the finger centred vertically. Use either to or direction, not both. Then assert the new value: a swipe that passes only proves the drag was sent.
Drag after a long press
A list you reorder by holding a row and then dragging it only picks the row up after the finger has stayed still for a moment. A drag that moves at once scrolls the list instead. Add hold, in milliseconds, to press and hold before the drag starts. A held drag starts at the middle of the control you name and moves amount from there, so you pick up the row itself:
- swipe: { testID: row-milk, direction: down, amount: 88, hold: 400 }Make hold longer than the list’s long-press delay. It takes a whole number from 1 to 3000, and only on a swipe: a held finger picks something up, which is not a scroll. On a macOS app the step fails rather than drag without the hold.
Drag slowly
A swipe takes about 300 milliseconds, as a flick does. Add duration, in milliseconds, to make the drag take longer. The finger also lifts more slowly, so a sheet that closes on a fast flick stays open unless the drag went far enough:
- swipe: { testID: sheet, direction: down, amount: 400, duration: 1500 }It takes a whole number from 50 to 5000, and only on a swipe: a scroll holds the finger still before it lifts, so its speed changes nothing. With hold, the hold comes first and duration times the drag after it.
Scroll until a control appears
- scrollUntilVisible: element: { text: Log out } direction: down maxScrolls: 10scrollUntilVisible scrolls until the control is fully on screen and a tap at its centre would reach it, up to maxScrolls times (15 by default). If the control is already visible, it returns at once. If it still isn’t visible after the last scroll, the step fails with not visible after 15 scroll(s). If it still isn’t visible after the last scroll, the step fails with not visible after 15 scroll(s).
Add mode: direct to move the list in one step instead of dragging, which is much faster. Leave it out when scrolling is what you’re testing: a direct scroll skips momentum, paging, snapping and pull-to-refresh. To make direct the default for a run, see Run settings.
A tap on an off-screen control
When a tap or type targets a control outside the screen, the step fails and names the control’s position and the screen size. Squiggle won’t tap it anyway, because the tap would land on whatever is at the edge of the screen instead.
Add a scrollUntilVisible step before it. Or run with --auto-scroll, which scrolls the control into view and tries again, and marks the step scrolled into view. In Studio, it is Auto-scroll in the Replay options.