syntax = "proto3"; package yaze.test; // ImGuiTestHarness service for remote GUI testing // Allows z3ed CLI to interact with YAZE's GUI for automated testing service ImGuiTestHarness { // Health check - verifies the service is running rpc Ping(PingRequest) returns (PingResponse); // Click a button or interactive element rpc Click(ClickRequest) returns (ClickResponse); // Type text into an input field rpc Type(TypeRequest) returns (TypeResponse); // Wait for a condition to be true rpc Wait(WaitRequest) returns (WaitResponse); // Assert that a condition is true rpc Assert(AssertRequest) returns (AssertResponse); // Capture a screenshot rpc Screenshot(ScreenshotRequest) returns (ScreenshotResponse); // Test introspection APIs (IT-05) rpc GetTestStatus(GetTestStatusRequest) returns (GetTestStatusResponse); rpc ListTests(ListTestsRequest) returns (ListTestsResponse); rpc GetTestResults(GetTestResultsRequest) returns (GetTestResultsResponse); // Widget discovery API (IT-06) rpc DiscoverWidgets(DiscoverWidgetsRequest) returns (DiscoverWidgetsResponse); // Test recording & replay (IT-07) rpc StartRecording(StartRecordingRequest) returns (StartRecordingResponse); rpc StopRecording(StopRecordingRequest) returns (StopRecordingResponse); rpc ReplayTest(ReplayTestRequest) returns (ReplayTestResponse); } // ============================================================================ // Ping - Health Check // ============================================================================ message PingRequest { string message = 1; // Message to echo back } message PingResponse { string message = 1; // Echoed message with "Pong: " prefix int64 timestamp_ms = 2; // Server timestamp in milliseconds string yaze_version = 3; // YAZE version string (e.g., "0.3.2") } // ============================================================================ // Click - Interact with GUI elements // ============================================================================ message ClickRequest { string target = 1; // Target element (e.g., "button:Open ROM") ClickType type = 2; // Type of click enum ClickType { CLICK_TYPE_UNSPECIFIED = 0; // Default/unspecified click type CLICK_TYPE_LEFT = 1; // Single left click CLICK_TYPE_RIGHT = 2; // Single right click CLICK_TYPE_DOUBLE = 3; // Double click CLICK_TYPE_MIDDLE = 4; // Middle mouse button } } message ClickResponse { bool success = 1; // Whether the click succeeded string message = 2; // Human-readable result message int32 execution_time_ms = 3; // Time taken to execute (for debugging) string test_id = 4; // Unique test identifier for introspection } // ============================================================================ // Type - Send keyboard input // ============================================================================ message TypeRequest { string target = 1; // Target input field (e.g., "textbox:File Path") string text = 2; // Text to type bool clear_first = 3; // Clear existing text before typing } message TypeResponse { bool success = 1; string message = 2; int32 execution_time_ms = 3; string test_id = 4; } // ============================================================================ // Wait - Poll for conditions // ============================================================================ message WaitRequest { string condition = 1; // Condition to wait for (e.g., "window:Overworld") int32 timeout_ms = 2; // Maximum time to wait (default 5000ms) int32 poll_interval_ms = 3; // How often to check (default 100ms) } message WaitResponse { bool success = 1; // Whether condition was met before timeout string message = 2; int32 elapsed_ms = 3; // Time taken before condition met (or timeout) string test_id = 4; // Unique test identifier for introspection } // ============================================================================ // Assert - Validate GUI state // ============================================================================ message AssertRequest { string condition = 1; // Condition to assert (e.g., "visible:button:Save") string failure_message = 2; // Custom message if assertion fails } message AssertResponse { bool success = 1; // Whether assertion passed string message = 2; // Diagnostic message string actual_value = 3; // Actual value found (for debugging) string expected_value = 4; // Expected value (for debugging) string test_id = 5; // Unique test identifier for introspection } // ============================================================================ // Screenshot - Capture window state // ============================================================================ message ScreenshotRequest { string window_title = 1; // Window to capture (empty = main window) string output_path = 2; // Where to save screenshot ImageFormat format = 3; // Image format enum ImageFormat { IMAGE_FORMAT_UNSPECIFIED = 0; IMAGE_FORMAT_PNG = 1; IMAGE_FORMAT_JPEG = 2; } } message ScreenshotResponse { bool success = 1; string message = 2; string file_path = 3; // Absolute path to saved screenshot int64 file_size_bytes = 4; } // ============================================================================ // GetTestStatus - Query test execution state // ============================================================================ message GetTestStatusRequest { string test_id = 1; // Test ID from Click/Type/Wait/Assert response } message GetTestStatusResponse { enum TestStatus { TEST_STATUS_UNSPECIFIED = 0; // Test ID not found or unspecified TEST_STATUS_QUEUED = 1; // Waiting to execute TEST_STATUS_RUNNING = 2; // Currently executing TEST_STATUS_PASSED = 3; // Completed successfully TEST_STATUS_FAILED = 4; // Assertion failed or error TEST_STATUS_TIMEOUT = 5; // Exceeded timeout } TestStatus status = 1; int64 queued_at_ms = 2; // When test was queued int64 started_at_ms = 3; // When test started (0 if not started) int64 completed_at_ms = 4; // When test completed (0 if not complete) int32 execution_time_ms = 5; // Total execution time string error_message = 6; // Error details if FAILED/TIMEOUT repeated string assertion_failures = 7; // Failed assertion details } // ============================================================================ // ListTests - Enumerate available tests // ============================================================================ message ListTestsRequest { string category_filter = 1; // Optional: "grpc", "unit", "integration", "e2e" int32 page_size = 2; // Number of results per page (default 100) string page_token = 3; // Pagination token from previous response } message ListTestsResponse { repeated TestInfo tests = 1; string next_page_token = 2; // Token for next page (empty if no more) int32 total_count = 3; // Total number of matching tests } message TestInfo { string test_id = 1; // Unique test identifier string name = 2; // Human-readable test name string category = 3; // Category: grpc, unit, integration, e2e int64 last_run_timestamp_ms = 4; // When test last executed int32 total_runs = 5; // Total number of executions int32 pass_count = 6; // Number of successful runs int32 fail_count = 7; // Number of failed runs int32 average_duration_ms = 8; // Average execution time } // ============================================================================ // GetTestResults - Retrieve detailed results // ============================================================================ message GetTestResultsRequest { string test_id = 1; bool include_logs = 2; // Include full execution logs } message GetTestResultsResponse { bool success = 1; // Overall test result string test_name = 2; string category = 3; int64 executed_at_ms = 4; int32 duration_ms = 5; repeated AssertionResult assertions = 6; repeated string logs = 7; // If include_logs=true map metrics = 8; // e.g., "frame_count": 123 // IT-08b: Failure diagnostics string screenshot_path = 9; // Path to failure screenshot (if captured) int64 screenshot_size_bytes = 10; // Size of screenshot file string failure_context = 11; // Execution context at failure time string widget_state = 12; // Widget state dump (IT-08c - future) } message AssertionResult { string description = 1; bool passed = 2; string expected_value = 3; string actual_value = 4; string error_message = 5; } // ============================================================================ // DiscoverWidgets - Enumerate discoverable GUI widgets // ============================================================================ message DiscoverWidgetsRequest { // Optional: Limit to a window name (case-insensitive) string window_filter = 1; // Optional: Limit to widget type WidgetType type_filter = 2; // Optional: Require widget path to start with prefix string path_prefix = 3; // Include widgets that are currently not visible bool include_invisible = 4; // Include widgets that are currently disabled bool include_disabled = 5; } enum WidgetType { WIDGET_TYPE_UNSPECIFIED = 0; WIDGET_TYPE_ALL = 1; WIDGET_TYPE_BUTTON = 2; WIDGET_TYPE_INPUT = 3; WIDGET_TYPE_MENU = 4; WIDGET_TYPE_TAB = 5; WIDGET_TYPE_CHECKBOX = 6; WIDGET_TYPE_SLIDER = 7; WIDGET_TYPE_CANVAS = 8; WIDGET_TYPE_SELECTABLE = 9; WIDGET_TYPE_OTHER = 10; } message WidgetBounds { float min_x = 1; float min_y = 2; float max_x = 3; float max_y = 4; } message DiscoveredWidget { // Full hierarchical path (e.g. Overworld/Toolset/button:Pan) string path = 1; // Human-readable label (e.g. Pan) string label = 2; // Widget type string (button, input, ...) string type = 3; // Description provided by registry (if any) string description = 4; // Suggested action for automation (e.g. "Click button:Pan") string suggested_action = 5; bool visible = 6; // Currently visible in UI bool enabled = 7; // Currently enabled for interaction WidgetBounds bounds = 8; // Bounding rectangle in screen coordinates uint32 widget_id = 9; // ImGui ID (debugging / direct access) int64 last_seen_frame = 10; // Frame number when widget was last observed int64 last_seen_at_ms = 11; // Wall-clock timestamp of last observation bool stale = 12; // True if widget not seen in the current frame } message DiscoveredWindow { // Window name (first segment of path) string name = 1; // Whether the window is currently visible bool visible = 2; // Widgets contained in this window repeated DiscoveredWidget widgets = 3; } message DiscoverWidgetsResponse { repeated DiscoveredWindow windows = 1; int32 total_widgets = 2; // Total number of widgets returned int64 generated_at_ms = 3; // Snapshot timestamp (Unix ms) } // ============================================================================ // Test Recording & Replay (IT-07) // ============================================================================ message StartRecordingRequest { string output_path = 1; // Where to store the JSON script string session_name = 2; // Optional friendly name for the recording string description = 3; // Optional description stored alongside metadata } message StartRecordingResponse { bool success = 1; string message = 2; string recording_id = 3; // Identifier required when stopping int64 started_at_ms = 4; } message StopRecordingRequest { string recording_id = 1; // Recording session to stop bool discard = 2; // If true, delete steps instead of writing file } message StopRecordingResponse { bool success = 1; string message = 2; string output_path = 3; // Final location of saved script (if any) int32 step_count = 4; // Total steps captured during session int64 duration_ms = 5; // Duration of the recording session } message ReplayTestRequest { string script_path = 1; // Path to JSON script bool ci_mode = 2; // Suppress interactive prompts map parameter_overrides = 3; // Optional parameter overrides } message ReplayTestResponse { bool success = 1; string message = 2; string replay_session_id = 3; int32 steps_executed = 4; repeated AssertionResult assertions = 5; // Aggregated assertion outcomes repeated string logs = 6; // Replay log entries }