Choosing a package
| Package | Use | Location |
|---|---|---|
addons/gua | Automatically collect the Godot Control tree and dispatch external actions to real UI | Godot project |
Gua.Testing.Godot | Launch, connect to, and stop Godot; collect output, screenshots, and diagnostics | External .NET test |
Gua.Testing | Engine-neutral locators, waits, assertions, and remote connections | External .NET test |
Gua.Testing.Visual | PNG baseline comparison and diff artifacts, shared by Godot and Unity | Optional external .NET tests |
Gua.Testing.Recording | Semantic action recording and request-correlated replay, shared by Godot and Unity | Optional external .NET tests |
Godot public types
| Type / setting | Contract |
|---|---|
GuaAutoAdapter | Accepts the root Control through attach(root) and publishes current UI through update(screen); also exposes bridge, screenshot, action, and reset APIs |
GuaContext | Native type registered with ClassDB by the GDExtension; exposes frame, node, action, event, screenshot, and Inspector bridge operations to GDScript |
gua_id metadata | Assigns a stable Control ID independent of NodePath |
gua_sensitive metadata | Omits input values from UI snapshots and diagnostics; it does not hide pixels already rendered into a PNG |
GuaGodotRuntime | Experimental C# adapter over shared Gua.Runtime; the GDScript addon is recommended for new Godot integrations |
Godot runtime surface
| File | Responsibility |
|---|---|
gua_auto_adapter.gd | Recursive Control collection, state reflection, action dispatch, events, and screenshots |
gua.gdextension | Declares the Godot entry point and platform-specific native library |
gua_godot.windows.debug.x86_64.dll | C++ GDExtension that registers GuaContext as a Godot type |
gua_runtime.dll | Shared runtime that owns Gua core, request/event queues, diagnostics, and the Inspector WebSocket bridge |
plugin.cfg / plugin.gd | EditorPlugin shell used to load the Godot addon |
gua_godot... translates Godot and GDScript types, while gua_runtime.dll is the engine-neutral runtime. The former links to the latter, so Windows packages place both under addons/gua/bin.
cmake --preset windows-msvc-debug
cmake --build --preset windows-msvc-debug --target gua-godotTest-host API
| Type / member | Meaning |
|---|---|
GodotSceneTestHost.Load | Launch Godot with a project and scene, then connect to its bridge |
GodotSceneTestHostOptions | Configure executable, project path, headless mode, port, environment, and reset policy |
Context / RemoteContext | Shared IGuaContext / WebSocket connection used by locators and actions |
CaptureScreenshot | Capture an on-demand PNG from the Godot viewport |
CreateDiagnosticsSession | Write UI tree, operation history, runtime data, and Godot stdout/stderr to artifacts |
Dispose | Close the bridge, stop the Godot process, and apply strict teardown |
UI mapping
| Role | Godot Control | Primary actions |
|---|---|---|
| button | BaseButton / Button | click, focus |
| checkbox | CheckBox | click, focus, set_checked |
| textbox | LineEdit / TextEdit | focus, set_value, press_key |
| slider | Slider / SpinBox | focus, set_value |
| combobox | OptionButton | focus, select |
| list / listitem | ItemList and each item | focus, select, scroll |
| tablist / tab | TabContainer and each tab | select |
| scrollarea | ScrollContainer | scroll |
| text / panel | Label / other Controls | Observe only |
Every frame recollects role, label, text/value, visibility, enabled and focused state, selection, range, scroll, parent ID, and viewport bounds. IDs default to NodePath relative to the root; use gua_id only where identity must remain stable.
Actions and completion
External requests are consumed during update(screen) and applied through normal Godot properties, signals, and input events. The adapter then returns a result event with the same requestId. Clicks emit BaseButton pressed, selections use ItemList and OptionButton selection signals, and key input is routed to the focused Control.
press_key modifier bits are 1=Shift, 2=Alt, 4=Control, and 8=Command. Hidden or disabled Controls and unsupported values or actions produce explicit results rather than being reported as successful.
Engine-neutral specification
- The Semantic UI Tree, roles, action/request/event model, and JSON schemas are shared with every adapter, including Unity.
- Bounds use physical viewport pixels with a top-left origin and positive right/down axes.
- Inspector, MCP, and external tests connect to the same WebSocket bridge. The default port is
8765andGUA_BRIDGE_PORTcan override it. - Screenshot completion checks frame sequence and session, and reports headless or disabled rendering explicitly.
Extending another engine
Gua.Core, Gua.Runtime, Gua.Testing, and the protocol can be reused. Godot's GDExtension, GDScript, Control traversal, and signals cannot. Each engine needs an adapter that collects its UI types and applies operations through native events. Unity has a separate Unity API and adapter.
Lifecycle and ownership
The game owns GuaAutoAdapter. Create it in _ready(), pass the root Control to attach, and call update(screen) from _process(). The adapter loads the GDExtension and creates the native context through ClassDB.instantiate("GuaContext").
const GuaAutoAdapterScript := preload(
"res://addons/gua/gua_auto_adapter.gd"
)
var ui := GuaAutoAdapterScript.new()
func _ready() -> void:
ui.attach(self)
ui.start_inspector_bridge(8765)
ui.update("title")
func _process(_delta: float) -> void:
ui.update("title")Key parts of the main.gd sample
View the complete main.gd on GitHub ↗
| Function / setting | Purpose |
|---|---|
start_inspector_bridge_on_ready | Whether to start the in-game WebSocket bridge from Ready |
inspector_bridge_port | Inspector and MCP port; can be overridden through the environment |
_ready() | Build UI, attach the adapter, publish once, and start the bridge |
_process(delta) | Publish current Controls and the logical screen name every frame |
_build_visual_e2e_controls() | Add sensitive input, CheckBox, and OptionButton visual fixtures |
_build_v2_e2e_controls() | Add TextEdit, selection, tab, and scroll action fixtures |
_capture_visual_e2e() | Wait for rendered frames and publish a viewport PNG |
Usage notes
- Use the GDScript addon for new Godot integrations. The experimental C# sample is not a feature-equivalent replacement.
gua_sensitivehides semantic values but does not automatically mask text already rendered into a PNG.- When running multiple Godot processes in parallel, allocate an available port per test instead of sharing one fixed port.
- A missing, stale, or platform-incompatible native DLL prevents creation of
GuaContext.