flow_recording_action
Perform and record one action step on the device. Performs the action and records it with automatic page source + element capture. Coordinates are in video / iOS-automation space — use flow_recording_start's windowSize as the reference.
Actions:
tap / doubleTap / longPress / swipe — gesture actions (require x,y; swipe also needs toX,toY)
sendKeys — type text into the focused field
keyPress — press an Android keycode (e.g. 3=HOME, 4=BACK)
wait — pause for waitMs milliseconds
pressButton — press a hardware button by name ('home', 'volumeUp', 'volumeDown', 'lock'). Performed live on the device during recording. Android maps to hardware keycodes; iOS invokes the native hardware-button command.
assert — record a UI assertion check (no device gesture). Identifies the target element at (x,y), then at replay time verifies the assertion condition. Assertion failures mark the step as FAILED and surface the mismatch in errorMessage. Makes the recording a real verifiable test. assertType 'visualMatch' is the exception: it takes no x/y and no expected, and at replay time compares the whole screen against the screenshot captured now.
scrollToElement — record a scroll-until-visible checkpoint (no device gesture). Binds the element at (x,y) now; at replay time it scrolls until that element is back on screen, searching downwards first and then upwards, and reports the element's live coordinates. Use it before acting on something whose position varies between runs (a row in a long list, a button below the fold). This FAILS the run if the element never comes into view, because the step exists to bring a target into view for the step that follows it. Note you do NOT need a separate step to resolve an element before acting on it — every element-bound action re-resolves its own target at replay; use scrollToElement only when the target is genuinely off screen, and assert/exists when its absence should fail the run.
appLaunch — launch an app mid-flow by appId (Android package name, iOS bundle id; optional appActivity on Android). Launches live during recording and relaunches the same app at replay time. Use it to switch apps or to return to the app under test after leaving it.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| x | No | X coordinate (tap/doubleTap/longPress/swipe start; assert & scrollToElement target element) | |
| y | No | Y coordinate (tap/doubleTap/longPress/swipe start; assert & scrollToElement target element) | |
| toX | No | Swipe end X | |
| toY | No | Swipe end Y | |
| text | No | Text to type (sendKeys) | |
| appId | No | App to launch for an appLaunch step: Android package name, iOS bundle id. Required when action=appLaunch. | |
| action | Yes | Action type | |
| waitMs | No | Wait duration ms (for wait action) | |
| keyCode | No | Android keycode (keyPress, e.g. 3=HOME, 4=BACK) | |
| keyName | No | Hardware button name for pressButton (e.g. 'home', 'volumeUp', 'volumeDown', 'lock'). Required when action=pressButton. | |
| expected | No | Expected value (required for textEquals and textContains assertions). | |
| optional | No | Mark this step as one whose target is EXPECTED to be absent sometimes — a cookie banner, a first-run tutorial, an occasional interstitial. When the element cannot be found at replay the step is SKIPPED instead of failing, and no gesture is dispatched at the recorded position. Leave it off for anything whose absence is a bug: a step that is NOT optional now FAILS the replay when its element is missing, which is what tells a real regression apart from a banner that simply did not appear this run. | |
| attribute | No | Attribute to read for text assertions. iOS: label, value, name. Android: text, content-desc, resource-id. Defaults to the platform primary text attribute when omitted. | |
| assertType | No | Assertion type (required when action=assert). exists/notExists check element presence; textEquals/textContains compare an attribute value; visualMatch compares the whole screen against the screenshot captured now (takes no x/y and no expected). | |
| durationMs | No | Swipe/longPress duration ms (default 300) | |
| appActivity | No | Optional Android activity to launch with appId. Ignored on iOS. | |
| recordingId | Yes | Recording ID from flow_recording_start | |
| visionFallback | No | Let a vision model settle this assertion when the accessibility tree cannot find the element. Off by default, and only honoured for assertType 'exists' and 'notExists'. Turn it on for UI the tree cannot describe — canvas/WebGL screens, game engines, image-only controls with their text baked into the bitmap — where 'a person can see it' is the only check available. Leave it off for ordinary native UI: an assertion's value is that it reports what is really there, and a model asked to find something tends to find it. Ignored for text assertions, which compare exact strings that OCR cannot supply reliably. |