Files
yaze/docs/z3ed/IT-01-QUICKSTART.md
scawful 286efdec6a Enhance ImGuiTestHarness with dynamic test integration and end-to-end validation
- Updated README.md to reflect the completion of IT-01 and the transition to end-to-end validation phase.
- Introduced a new end-to-end test script (scripts/test_harness_e2e.sh) for validating all RPC methods of the ImGuiTestHarness gRPC service.
- Implemented dynamic test functionality in ImGuiTestHarnessService for Type, Wait, and Assert methods, utilizing ImGuiTestEngine.
- Enhanced error handling and response messages for better clarity during test execution.
- Updated existing methods to support dynamic test registration and execution, ensuring robust interaction with the GUI elements.
2025-10-02 00:49:28 -04:00

382 lines
9.0 KiB
Markdown

# ImGuiTestHarness Quick Start Guide
**Last Updated**: October 2, 2025
**Status**: IT-01 Phase 3 Complete ✅
## Overview
The ImGuiTestHarness provides a gRPC service for automated GUI testing and AI-driven workflows. This guide shows you how to quickly get started with testing YAZE through remote procedure calls.
## Prerequisites
```bash
# Install grpcurl (for testing)
brew install grpcurl
# Build YAZE with gRPC support
cd /Users/scawful/Code/yaze
cmake -B build-grpc-test -DYAZE_WITH_GRPC=ON
cmake --build build-grpc-test --target yaze -j$(sysctl -n hw.ncpu)
```
## Quick Start
### 1. Start YAZE with Test Harness
```bash
./build-grpc-test/bin/yaze.app/Contents/MacOS/yaze \
--enable_test_harness \
--test_harness_port=50052 \
--rom_file=assets/zelda3.sfc &
```
**Output**:
```
✓ ImGuiTestHarness gRPC server listening on 0.0.0.0:50052 (with TestManager integration)
Use 'grpcurl -plaintext -d '{"message":"test"}' 0.0.0.0:50052 yaze.test.ImGuiTestHarness/Ping' to test
```
### 2. Run Automated Test Script
```bash
./scripts/test_harness_e2e.sh
```
This will test all RPC methods and report pass/fail status.
### 3. Manual Testing
Test individual RPCs with grpcurl:
```bash
# Health check
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"message":"Hello"}' 127.0.0.1:50052 yaze.test.ImGuiTestHarness/Ping
# Click button
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"target":"button:Overworld","type":"LEFT"}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Click
# Type text
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"target":"input:Search","text":"tile16","clear_first":true}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Type
# Wait for window
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"condition":"window_visible:Overworld Editor","timeout_ms":5000}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Wait
# Assert state
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"condition":"visible:Main Window"}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Assert
```
## RPC Reference
### Ping - Health Check
**Purpose**: Verify service is running and get version info
**Request**:
```json
{
"message": "test"
}
```
**Response**:
```json
{
"message": "Pong: test",
"timestampMs": "1696262400000",
"yazeVersion": "0.3.2"
}
```
### Click - GUI Interaction
**Purpose**: Click buttons, menu items, and other interactive elements
**Request**:
```json
{
"target": "button:Open ROM",
"type": "LEFT"
}
```
**Target Format**: `<widget_type>:<label>`
**Click Types**: `LEFT`, `RIGHT`, `MIDDLE`, `DOUBLE`
**Response**:
```json
{
"success": true,
"message": "Clicked button 'Open ROM'",
"executionTimeMs": "125"
}
```
### Type - Text Input
**Purpose**: Enter text into input fields
**Request**:
```json
{
"target": "input:Filename",
"text": "zelda3.sfc",
"clear_first": true
}
```
**Parameters**:
- `target`: Input field identifier (format: `input:<label>`)
- `text`: Text to type
- `clear_first`: Clear existing text before typing (default: false)
**Response**:
```json
{
"success": true,
"message": "Typed 'zelda3.sfc' into input 'Filename' (cleared first)",
"executionTimeMs": "250"
}
```
### Wait - Condition Polling
**Purpose**: Wait for UI conditions with timeout
**Request**:
```json
{
"condition": "window_visible:Overworld Editor",
"timeout_ms": 5000,
"poll_interval_ms": 100
}
```
**Condition Types**:
- `window_visible:<WindowName>` - Window exists and not hidden
- `element_visible:<ElementLabel>` - Element exists and has visible rect
- `element_enabled:<ElementLabel>` - Element exists and not disabled
**Response**:
```json
{
"success": true,
"message": "Condition 'window_visible:Overworld Editor' met after 1250 ms",
"elapsedMs": "1250"
}
```
### Assert - State Validation
**Purpose**: Validate GUI state and return actual vs expected values
**Request**:
```json
{
"condition": "visible:Main Window"
}
```
**Assertion Types**:
- `visible:<WindowName>` - Check window visibility
- `enabled:<ElementLabel>` - Check if element is enabled
- `exists:<ElementLabel>` - Check if element exists
- `text_contains:<InputLabel>:<ExpectedText>` - Validate text content
**Response**:
```json
{
"success": true,
"message": "'Main Window' is visible",
"actualValue": "visible",
"expectedValue": "visible"
}
```
### Screenshot - Screen Capture
**Purpose**: Capture screenshot of YAZE window (NOT YET IMPLEMENTED)
**Request**:
```json
{
"region": "full",
"format": "PNG"
}
```
**Response**:
```json
{
"success": false,
"message": "Screenshot not yet implemented",
"filePath": "",
"fileSizeBytes": 0
}
```
## Common Workflows
### Workflow 1: Open Editor and Validate
```bash
# 1. Click Overworld button
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"target":"button:Overworld","type":"LEFT"}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Click
# 2. Wait for Overworld Editor window
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"condition":"window_visible:Overworld Editor","timeout_ms":5000}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Wait
# 3. Assert window is visible
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"condition":"visible:Overworld Editor"}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Assert
```
### Workflow 2: Search and Filter
```bash
# 1. Click search input
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"target":"input:Search","type":"LEFT"}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Click
# 2. Type search query
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"target":"input:Search","text":"tile16","clear_first":true}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Type
# 3. Wait for results
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"condition":"element_visible:Results","timeout_ms":2000}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Wait
```
## Troubleshooting
### Server Not Starting
**Problem**: "Failed to start gRPC server"
**Solutions**:
1. Check if port is already in use: `lsof -i :50052`
2. Kill existing YAZE instances: `killall yaze`
3. Try a different port: `--test_harness_port=50053`
### Connection Refused
**Problem**: "Error connecting to server"
**Solutions**:
1. Verify server is running: `lsof -i :50052`
2. Check logs for startup errors
3. Ensure firewall allows connections
### Widget Not Found
**Problem**: "Input field 'XYZ' not found"
**Solutions**:
1. Verify widget label is correct (case-sensitive)
2. Check if widget is in a different window (use full path)
3. Wait for window to be visible first
4. Use Assert to check if widget exists before interacting
### Timeout Errors
**Problem**: "Condition not met after timeout"
**Solutions**:
1. Increase timeout value: `"timeout_ms": 10000`
2. Check if condition is realistic (e.g., window actually opens)
3. Verify window/element names are correct
4. Reduce poll interval for faster detection: `"poll_interval_ms": 50`
## Advanced Usage
### Chaining RPCs in Shell Scripts
```bash
#!/bin/bash
# Example: Automated Overworld Editor Test
set -e
PORT=50052
PROTO_PATH="src/app/core/proto"
PROTO_FILE="imgui_test_harness.proto"
rpc() {
grpcurl -plaintext -import-path $PROTO_PATH -proto $PROTO_FILE \
-d "$2" 127.0.0.1:$PORT yaze.test.ImGuiTestHarness/$1
}
# Health check
rpc Ping '{"message":"Starting test"}'
# Open Overworld Editor
rpc Click '{"target":"button:Overworld","type":"LEFT"}'
# Wait for window
rpc Wait '{"condition":"window_visible:Overworld Editor","timeout_ms":5000}'
# Validate
rpc Assert '{"condition":"visible:Overworld Editor"}'
echo "✓ All tests passed"
```
### Python Client (Future)
```python
import grpc
from proto import imgui_test_harness_pb2
from proto import imgui_test_harness_pb2_grpc
# Connect to test harness
channel = grpc.insecure_channel('localhost:50052')
stub = imgui_test_harness_pb2_grpc.ImGuiTestHarnessStub(channel)
# Ping
response = stub.Ping(imgui_test_harness_pb2.PingRequest(message="test"))
print(f"Version: {response.yaze_version}")
# Click
response = stub.Click(imgui_test_harness_pb2.ClickRequest(
target="button:Overworld",
type=imgui_test_harness_pb2.ClickRequest.LEFT
))
print(f"Click success: {response.success}")
```
## Next Steps
- **IT-02**: CLI agent integration (`z3ed agent test`)
- **IT-03**: Screenshot implementation
- **VP-02**: Integration tests with replay scripts
- **Windows Testing**: Cross-platform validation
## References
- **Implementation**: `src/app/core/imgui_test_harness_service.{h,cc}`
- **Proto Schema**: `src/app/core/proto/imgui_test_harness.proto`
- **Test Script**: `scripts/test_harness_e2e.sh`
- **Phase 3 Details**: `IT-01-PHASE3-COMPLETE.md`
---
**Last Updated**: October 2, 2025
**Contributors**: @scawful, GitHub Copilot
**License**: Same as YAZE (see ../../LICENSE)