Skip to content

Quick start - Python

A full working test in under 20 lines.

Prerequisites

  • Your Qt application is running with the veriCue Runtime inside it - either started with vericue run ./your-qt-app (from 0.5.0) on Linux x64, or embedded (see Installation).
  • You know which transport it started: the local IPC endpoint it printed as VERICUE_ENDPOINT=<path>, or its TCP port.
  • pip install vericue done.

Your first test

Connecting is the only part that differs by transport. Use connect_local(endpoint) when the app runs on the same Linux or macOS machine, and connect(host, port) on Windows or across a host, container or device boundary:

python
import asyncio
from vericue import VeriCueClient

async def main():
    async with VeriCueClient() as client:
        # Same machine, Linux/macOS - the path the app printed
        await client.connect_local("/run/user/1000/vericue/vericue-4213.sock")
        # ... or over TCP (Windows, remote CI, containers, devices):
        # await client.connect("127.0.0.1", 4242)

        # Discover the OK button
        obj = await client.find_object(path="MainWindow/centralWidget/okButton")
        print("Found:", obj["className"])  # → QPushButton

        # Click it
        await client.mouse_click("MainWindow/centralWidget/okButton")

        # Assert the result
        props = await client.get_properties("MainWindow/statusLabel", ["text"])
        assert props["text"] == "Logged in"

asyncio.run(main())

Common operations

Discover objects

python
# By path
btn = await client.find_object(path="MainWindow/okButton")

# By class - returns a list
buttons = await client.list_objects(class_name="QPushButton")

# Browse the full tree from a root
tree = await client.get_object_tree(root="MainWindow", depth=3)

Interact

python
await client.mouse_click("MainWindow/okButton")
await client.type_text("MainWindow/searchBox", "hello world")
await client.key_press("MainWindow/searchBox", "Return")
await client.scroll("MainWindow/list", dy=-100)
await client.drag("MainWindow/canvas", 10, 10, 200, 150)  # drag within a widget

Read and write properties

python
# Read multiple properties at once
props = await client.get_properties(
    "MainWindow/usernameField", ["text", "enabled", "visible"]
)

# Write a property (triggers NOTIFY signal)
await client.set_property("MainWindow/themeSelector", "currentIndex", 2)

Wait for state changes

python
# Wait up to 5 s for a property to reach a value
await client.wait_for_property(
    "MainWindow/statusLabel", "text", "Ready",
    timeout=5000,
)

# Wait for a one-shot signal
await client.wait_for_signal(
    "MainWindow/loadButton", "clicked", timeout=10000,
)

Screenshots and visual regression

python
# Save a screenshot of a widget
data = await client.screenshot(path="MainWindow/canvas")
with open("canvas.png", "wb") as f:
    f.write(base64.b64decode(data["data"]))

# Compare against a baseline image file
result = await client.compare_screenshot_file(
    "canvas_baseline.png",
    path="MainWindow/canvas",
    threshold=0.02,  # allow 2% pixel difference
)
assert result["match"], f"Similarity: {result['similarity']}"

Subscribe to push events

For tests that drive UI flows and need to wait for any of N possible outcomes, use push subscriptions:

python
sub_id = await client.subscribe_signal(
    "MainWindow/okButton", "clicked",
    callback=lambda event: print("Clicked at", event["timestamp"]),
)

# ... trigger flow ...

await client.unsubscribe(sub_id)

See the Push events reference for full details.

Use it from pytest

veriCue ships a pytest plugin (auto-registered when vericue is installed). It provides three fixtures:

python
async def test_login(vericue_client):
    # Already connected, with handshake complete. Disconnects on teardown.
    await vericue_client.type_text("MainWindow/userField", "alice")
    await vericue_client.type_text("MainWindow/passField", "secret")
    await vericue_client.mouse_click("MainWindow/loginBtn")

    await vericue_client.wait_for_property(
        "MainWindow/statusLabel", "text", "Logged in",
        timeout=5000,
    )

For multi-connection scenarios use the vericue_client_factory fixture to make multiple clients in the same test.

The bundled fixtures spawn the app with --port 0 and connect over TCP on loopback, reading the port back from the app's VERICUE_PORT=<n> line. That keeps parallel jobs collision-free without any port bookkeeping. If your rig needs local IPC, connect explicitly with connect_local() in your own fixture.

For multi-process Qt applications use MultiVeriCueClient - see Multi-process testing.

Released under a commercial licence. Privacy · Terms