Recording & replay
veriCue can watch a human interact with the application and turn the session into a runnable Python test script. The recorder is an event filter installed on the application - it observes real input without consuming it, resolves each event's target to a veriCue object path, and emits both a structured event list and generated code.
Quick start
from vericue import VeriCueClient
from vericue.recorder import RecordingSession
async with VeriCueClient() as client:
await client.connect("127.0.0.1", 4242)
async with RecordingSession(client) as session:
input("Interact with the app, then press Enter to stop... ")
print(session.script) # generated Python
session.save_script("recorded_test.py")Or drive the raw commands directly:
await client.start_recording()
# ... user interacts with the app ...
result = await client.stop_recording()stop_recording returns:
| Field | Meaning |
|---|---|
events | Structured event list: {type, path, params, timestamp} per event |
script | Ready-to-run Python script using the veriCue client API |
event_count | Number of raw events captured (before coalescing) |
duration_ms | Recording length |
What gets captured
| Input | Recorded as |
|---|---|
| Mouse click (on release) | mouse_click with button and local coords |
| Double click | mouse_click with click_type="double" |
| Printable typing | type_text - consecutive keystrokes into the same widget are coalesced into one call with the full string |
| Special keys & shortcuts | key_press with combo syntax (enter, tab, ctrl+s, ctrl+shift+z, f1–f12, arrows, …) |
| Mouse wheel | scroll with dx/dy in notches |
Each event's target is resolved to a path (MainWindow/centralWidget/…) at capture time using the same resolver the rest of veriCue uses, so the generated script replays against the same objects.
A generated script looks like:
import asyncio
from vericue import VeriCueClient
async def main():
async with VeriCueClient() as client:
await client.connect("127.0.0.1", 4242)
await client.mouse_click("MainWindow/loginButton")
await client.type_text("MainWindow/userField", "alice")
await client.key_press("MainWindow/userField", "tab")
await client.type_text("MainWindow/passField", "secret")
await client.key_press("MainWindow/passField", "enter")
asyncio.run(main())Treat it as a starting point: add assertions (get_properties, wait_for_property, screenshot_compare) after the interactions - a recording captures what you did, not what you expected to see.
Limitations
Be aware of what the recorder does not capture:
- Touch gestures - only mouse, keyboard, and wheel events are recorded. Swipes/pinches must be scripted by hand (see Touch & gestures).
- Drags - a press-move-release sequence is recorded as a single click at the release position, not as a
dragcommand. - Timing - timestamps are kept in the event list, but the generated script replays as fast as the server accepts commands. Insert
wait_for_property/wait_for_signalcalls where the app needs time. - Modifier-only presses are skipped; unknown special keys outside the supported set (letters, digits-as-text, F-keys, navigation keys) are dropped.
- Unresolvable targets - events on objects the resolver cannot produce a path for (e.g. transient popups that are gone by resolve time) are skipped.
- One recording at a time; starting a new one clears the previous buffer.
Workflow tips
- Record short, focused flows (one scenario per recording) - long sessions produce scripts that are hard to review and brittle to replay.
- Generated
mouse_clickcalls click the target's center; exact capture coordinates are preserved in theeventslist if you need them (e.g. for clicks on specific cells of a custom-painted widget). - Recordings are a fast way to discover object paths for hand-written tests - even when you discard the generated script itself.

