C++ client
Qt-native async client (QObject signals/slots). This is the reference; for a guided first test see the C++ quick start.
Linking
The distribution tarball ships a CMake package config:
find_package(vericue REQUIRED)
target_link_libraries(my_tests PRIVATE vericue::vericue-client)Headers live under include/vericue/; the client needs Qt Core + Network.
Programming model
Every command method is non-blocking: it returns a request ID (QString) immediately, and the result arrives later on a signal. Match the ID to correlate:
#include <vericue/client.h>
vericue::VeriCueClient client;
QObject::connect(&client, &vericue::VeriCueClient::connected, [&]() {
// Handshake done - safe to send commands.
QString id = client.mouseClick("MainWindow/okButton");
});
QObject::connect(&client, &vericue::VeriCueClient::responseReceived,
[](const QString &id, const QJsonObject &result) { /* success */ });
QObject::connect(&client, &vericue::VeriCueClient::errorReceived,
[](const QString &id, int code, const QString &message) { /* command failed */ });
client.connectToServer("127.0.0.1", 4242, /*token=*/QString());Connection API
| Method / signal | Purpose |
|---|---|
connectToServer(host, port, token = {}) | Connect; handshake is sent automatically |
disconnectFromServer() | Close the connection |
isConnected() | true once connected and handshake completed |
connected() (signal) | Handshake succeeded - safe to send commands |
handshakeCompleted(int version) (signal) | Negotiated protocol version |
disconnected() (signal) | Connection closed |
connectionError(QString) (signal) | Transport-level failure (refused, timeout, ...) |
sendRequest(method, params = {}) | Raw escape hatch for any protocol command |
Commands
All methods return the request ID. Optional coordinates use -1 for "center of the object".
// Discovery
client.listObjects(objectName, className, root);
client.findObject(path, objectName, className);
client.getProperties(path, {"text", "enabled"});
client.getChildren(path, className);
client.getParent(path);
client.getObjectTree(root, /*depth=*/-1);
// Interaction
client.mouseClick(path, "left", "single", /*x=*/-1, /*y=*/-1);
client.typeText(path, "hello");
client.keyPress(path, "ctrl+s", /*repeat=*/1);
client.drag(path, fromX, fromY, toX, toY, "left");
client.scroll(path, /*dx=*/0, /*dy=*/-3);
client.screenshot(path); // empty path = first visible window
client.highlightObject(path, 2000, "red");
// Touch & gestures
client.touchTap(path, -1, -1, /*duration=*/50);
client.touchLongPress(path, -1, -1, /*duration=*/800);
client.swipe(path, fromX, fromY, toX, toY, /*duration=*/300, /*steps=*/10);
client.pinch(path, startDistance, endDistance, centerX, centerY, /*duration=*/300);
client.multiTouch(path, touchesArray); // [{id, x, y, action}, ...]
// Model/view
client.getModelInfo(path);
client.getModelData(path, row, column, "display");
// Visual verification
client.screenshotCompare(baselineBase64, path, /*threshold=*/0.02);
// Extended automation
client.setProperty(path, "text", QJsonValue("new"));
client.invokeMethod(path, "clear");
client.waitForProperty(path, "enabled", QJsonValue(true), /*timeout=*/5000);
client.waitForSignal(path, "clicked()", /*timeout=*/5000);
// Performance
client.frameTime(path, /*durationMs=*/1000);
client.paintCount(path, /*durationMs=*/1000);
client.memorySnapshot();
// Mocking / helpers
client.emitSignal(path, "timeout()", QJsonArray{});
client.setClipboard("text");
client.getClipboard();
// Multi-window
client.listWindows();
// Recording
client.startRecording();
client.stopRecording();Push events
Subscriptions deliver server-pushed events on the eventReceived signal (see Push events):
client.subscribeSignal(path, "clicked()");
client.subscribeProperty(path, "text");
client.subscribeDestroyed(path);
client.unsubscribe(subscriptionId);
client.listSubscriptions();
QObject::connect(&client, &vericue::VeriCueClient::eventReceived,
[](const QString &subscriptionId, const QString &eventName,
const QString &path, const QJsonObject &data) {
// eventName: "signal_emitted" | "property_changed" | "object_destroyed"
});Subscriptions are cleaned up server-side when the connection closes.
GoogleTest fixture
vericue/gtest_fixture.h turns the async client into a synchronous test fixture - each test gets a connected client, and invoke() blocks (by pumping the event loop) until the response arrives:
#include <vericue/gtest_fixture.h>
class LoginTest : public vericue::VeriCueTest {};
TEST_F(LoginTest, OkButtonClicksSucceed) {
// Synchronous wrappers:
EXPECT_TRUE(click("MainWindow/okButton"));
EXPECT_EQ(prop("MainWindow/statusLabel", "text").toString(), "Logged in");
// Any command via invoke() - throws vericue::CommandFailed on error:
QJsonObject r = invoke("get_properties", QJsonObject{
{"path", "MainWindow/okButton"},
{"properties", QJsonArray{"enabled"}},
});
EXPECT_TRUE(r["enabled"].toBool());
}Fixture API: invoke(method, params, timeoutMs = 5000), click(path), prop(path, propertyName), and client() for direct access. Command failures throw vericue::CommandFailed (with .code() / .message()).
Configuration comes from environment variables:
| Variable | Default |
|---|---|
VERICUE_HOST | 127.0.0.1 |
VERICUE_PORT | 4242 |
VERICUE_TOKEN | (empty) |
If your build vendors GoogleTest differently, define VERICUE_GTEST_NO_INCLUDE and include gtest/gtest.h yourself before the fixture header.

