- 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.
9.7 KiB
IT-01 Phase 3: ImGuiTestEngine Integration - COMPLETE ✅
Date: October 2, 2025
Status: ✅ COMPLETE - All RPC handlers implemented with ImGuiTestEngine
Time Spent: ~3 hours (implementation + testing)
Overview
Phase 3 successfully implements full ImGuiTestEngine integration for all gRPC RPC handlers. The test harness can now automate GUI interactions, wait for conditions, and validate widget state through remote procedure calls.
Implementation Summary
1. Type RPC ✅
Purpose: Input text into GUI widgets
Implementation:
- Uses
ItemInfo()to find target widget (returns by value, checkID != 0) - Clicks widget to focus before typing
- Supports
clear_firstflag usingKeyPress(ImGuiMod_Shortcut | ImGuiKey_A)+KeyPress(ImGuiKey_Delete) - Types text using
ItemInputValue() - Dynamic test registration with timeout and status polling
Example:
grpcurl -plaintext -d '{
"target":"input:Filename",
"text":"zelda3.sfc",
"clear_first":true
}' 127.0.0.1:50052 yaze.test.ImGuiTestHarness/Type
2. Wait RPC ✅
Purpose: Poll for UI conditions with timeout
Implementation:
- Supports three condition types:
window_visible:WindowName- checks window exists and not hiddenelement_visible:ElementLabel- checks element exists and has visible rectelement_enabled:ElementLabel- checks element not disabled
- Configurable timeout (default 5000ms) and poll interval (default 100ms)
- Uses
ctx->Yield()to allow ImGui event processing during polling - Returns elapsed time in milliseconds
Example:
grpcurl -plaintext -d '{
"condition":"window_visible:Overworld Editor",
"timeout_ms":5000,
"poll_interval_ms":100
}' 127.0.0.1:50052 yaze.test.ImGuiTestHarness/Wait
3. Assert RPC ✅
Purpose: Validate GUI state and return actual vs expected values
Implementation:
- Supports multiple assertion types:
visible:WindowName- checks window visibilityenabled:ElementLabel- checks if element is enabledexists:ElementLabel- checks if element existstext_contains:InputLabel:ExpectedText- validates text content (partial implementation)
- Returns structured response with success, message, actual_value, expected_value
- Detailed error messages for debugging
Example:
grpcurl -plaintext -d '{
"condition":"visible:Main Window"
}' 127.0.0.1:50052 yaze.test.ImGuiTestHarness/Assert
Key API Learnings
ImGuiTestEngine API Patterns
-
ItemInfo Returns By Value:
// WRONG: ImGuiTestItemInfo* item = ctx->ItemInfo(label); // RIGHT: ImGuiTestItemInfo item = ctx->ItemInfo(label); if (item.ID == 0) { /* not found */ } -
Flag Names Changed:
- Use
ItemFlagsinstead ofInFlags(obsolete) - Use
ImGuiItemFlags_Disabledinstead ofImGuiItemStatusFlags_Disabled
- Use
-
Visibility Check:
// Check if element is visible (has non-zero clipped rect) bool visible = (item.ID != 0 && item.RectClipped.GetWidth() > 0 && item.RectClipped.GetHeight() > 0); -
Dynamic Test Registration:
auto test_data = std::make_shared<DynamicTestData>(); test_data->test_func = [=](ImGuiTestContext* ctx) { /* test logic */ }; ImGuiTest* test = IM_REGISTER_TEST(engine, "grpc", test_name.c_str()); test->TestFunc = RunDynamicTest; test->UserData = test_data.get(); ImGuiTestEngine_QueueTest(engine, test, ImGuiTestRunFlags_RunFromGui); -
Test Status Polling:
while (test->Output.Status == ImGuiTestStatus_Queued || test->Output.Status == ImGuiTestStatus_Running) { if (timeout_reached) break; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } // Cleanup ImGuiTestEngine_UnregisterTest(engine, test);
Build and Test
Build Command
cd /Users/scawful/Code/yaze
cmake --build build-grpc-test --target yaze -j$(sysctl -n hw.ncpu)
Build Status: ✅ Success (with deprecation warnings in imgui_memory_editor.h - unrelated)
Start Test Harness
./build-grpc-test/bin/yaze.app/Contents/MacOS/yaze \
--enable_test_harness \
--test_harness_port=50052 \
--rom_file=assets/zelda3.sfc &
Test All RPCs
# 1. Ping - Health check
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"message":"test"}' 127.0.0.1:50052 yaze.test.ImGuiTestHarness/Ping
# 2. Click - 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
# 3. Type - Input text
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"target":"input:Filename","text":"zelda3.sfc","clear_first":true}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Type
# 4. Wait - Wait for condition
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"condition":"window_visible:Main Window","timeout_ms":5000}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Wait
# 5. Assert - Validate 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
# 6. Screenshot - Capture (not yet implemented)
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
-d '{"region":"full","format":"PNG"}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Screenshot
Files Modified
Core Implementation
src/app/core/imgui_test_harness_service.cc- Type RPC: Full implementation with ItemInfo, focus, clear, and input
- Wait RPC: Polling loop with multiple condition types
- Assert RPC: State validation with structured responses
- Total: ~300 lines of new GUI automation code
No Changes Required
src/app/core/imgui_test_harness_service.h- interface unchangedsrc/app/test/test_manager.{h,cc}- initialization already correct- Proto files - schema unchanged
Known Limitations
1. Text Retrieval (Assert RPC)
text_containsassertion returns placeholder string- Requires deeper investigation of ImGuiTestEngine text query APIs
- Current workaround: manually check text after typing with Type RPC
2. Screenshot RPC
- Not implemented (returns "not yet implemented" message)
- Requires framebuffer access and image encoding
- Planned for future enhancement
3. Error Handling
- Test failures may not always provide detailed context
- Consider adding more verbose logging in debug mode
Success Metrics
✅ All Core RPCs Implemented: Ping, Click, Type, Wait, Assert
✅ Build Successful: No compilation errors
✅ API Compatibility: Correct ImGuiTestEngine usage patterns
✅ Dynamic Test Registration: Tests created on-demand without pre-registration
✅ Timeout Handling: All RPCs have configurable timeouts
✅ Stub Fallback: Works without ImGuiTestEngine (compile-time flag)
Next Steps (Phase 4)
Priority 1: End-to-End Testing (2-3 hours)
-
Manual Workflow Testing:
- Start YAZE with test harness
- Execute full workflow: Click → Type → Wait → Assert
- Validate responses match expected behavior
- Test error cases (widget not found, timeout, etc.)
-
Create Test Script:
#!/bin/bash # test_harness_e2e.sh # Start YAZE in background ./build-grpc-test/bin/yaze.app/Contents/MacOS/yaze \ --enable_test_harness --test_harness_port=50052 \ --rom_file=assets/zelda3.sfc & YAZE_PID=$! sleep 2 # Wait for startup # Test Ping grpcurl -plaintext -d '{"message":"test"}' \ 127.0.0.1:50052 yaze.test.ImGuiTestHarness/Ping # Test Click grpcurl -plaintext -d '{"target":"button:Overworld","type":"LEFT"}' \ 127.0.0.1:50052 yaze.test.ImGuiTestHarness/Click # Test Wait grpcurl -plaintext -d '{"condition":"window_visible:Overworld Editor","timeout_ms":5000}' \ 127.0.0.1:50052 yaze.test.ImGuiTestHarness/Wait # Cleanup kill $YAZE_PID
Priority 2: CLI Agent Integration (3-4 hours)
-
Create
z3ed agent testcommand:- Translate natural language prompts to gRPC calls
- Chain multiple RPCs for complex workflows
- Capture screenshots for LLM feedback
-
Example Agent Test:
z3ed agent test --prompt "Open the Overworld editor and verify it's visible" \ --rom zelda3.sfc # Generated workflow: # 1. Click "button:Overworld" # 2. Wait "window_visible:Overworld Editor" (5s timeout) # 3. Assert "visible:Overworld Editor" # 4. Screenshot "full"
Priority 3: Documentation Update (1 hour)
- Update
E6-z3ed-implementation-plan.mdwith Phase 3 completion - Update
STATE_SUMMARY_2025-10-01.md→STATE_SUMMARY_2025-10-02.md - Add IT-01-PHASE3-COMPLETE.md to documentation index
Priority 4: Windows Testing (2-3 hours)
- Build on Windows with vcpkg
- Validate gRPC service startup
- Test all RPCs on Windows
- Document platform-specific issues
Conclusion
Phase 3 is complete with all core GUI automation capabilities implemented. The ImGuiTestHarness can now:
- ✅ Click buttons and interactive elements
- ✅ Type text into input fields
- ✅ Wait for UI conditions (window visibility, element state)
- ✅ Assert widget state with detailed validation
- ✅ Handle timeouts and errors gracefully
The foundation is ready for AI-driven GUI testing and automation workflows. Next phase will focus on end-to-end integration and CLI agent tooling.
Completed: October 2, 2025
Contributors: @scawful, GitHub Copilot
License: Same as YAZE (see ../../LICENSE)