A comprehensive guide for testing the OpenClaw Godot Plugin.
- Test Environment Setup
- Manual Testing
- Automated Testing
- Tool-Specific Test Cases
- Integration Testing
- Performance Testing
# Create dedicated test project
mkdir -p /Users/Shared/godot-test-project
cd /Users/Shared/godot-test-project
# Copy plugin
cp -r /Users/Shared/openclaw-godot-plugin/addons .
# Create project.godot
cat > project.godot << 'EOF'
[gd_resource type="ProjectSettings" format=3]
[application]
config/name="OpenClaw Test Project"
[editor_plugins]
enabled=PackedStringArray("res://addons/openclaw/plugin.cfg")
EOF# Install extension
cp -r /Users/Shared/openclaw-godot-plugin/OpenClawPlugin~/* ~/.openclaw/extensions/godot/
# Restart gateway
openclaw gateway restart
# Verify connection
openclaw godot statusCreate test scenes in Godot:
test_scene.tscn (2D testing):
Node2D (TestRoot)
├── Sprite2D (Player)
│ └── Camera2D (Cam)
├── Label (UI)
└── Area2D (TriggerZone)
test_3d_scene.tscn (3D testing):
Node3D (Level)
├── CharacterBody3D (Player3D)
│ └── Camera3D (Cam3D)
├── MeshInstance3D (Ground)
└── DirectionalLight3D (Sun)
# 1. Check gateway status
openclaw gateway status
# 2. List Godot sessions
openclaw godot sessionsExpected output:
{
"sessions": [
{
"sessionId": "godot_1234567890_abc123",
"project": "OpenClaw Test Project",
"version": "4.6-stable",
"tools": 30
}
]
}You: Check Godot editor state
OpenClaw:
[Executes editor.getState]
Godot 4.6-stable running
- Project: OpenClaw Test Project
- Current scene: res://test_scene.tscn
- Play mode: inactive
addons/openclaw/tests/test_tools.gd:
@tool
extends EditorScript
## OpenClaw Tools Automated Test
## Usage: Script → Run (Ctrl+Shift+X)
var tools: Node
var passed = 0
var failed = 0
var results = []
func _run():
print("\n" + "=".repeat(50))
print("🧪 OpenClaw Tools Test Suite")
print("=".repeat(50) + "\n")
# Create Tools instance
var Tools = load("res://addons/openclaw/tools.gd")
tools = Tools.new()
tools.editor_interface = get_editor_interface()
# Run tests
_test_editor_tools()
_test_scene_tools()
_test_node_tools()
_test_transform_tools()
_test_debug_tools()
# Print results
_print_summary()
# Cleanup
tools.queue_free()
func _test_editor_tools():
_section("Editor Tools")
# editor.getState
var state = tools.execute("editor.getState", {})
_assert(state.success, "editor.getState returns success")
_assert(state.has("version"), "editor.getState has version")
_assert(state.has("isPlaying"), "editor.getState has isPlaying")
func _test_scene_tools():
_section("Scene Tools")
# scene.list
var list = tools.execute("scene.list", {})
_assert(list.success, "scene.list returns success")
_assert(list.has("scenes"), "scene.list has scenes array")
# scene.getCurrent
var current = tools.execute("scene.getCurrent", {})
_assert(current.success, "scene.getCurrent returns success")
_assert(current.has("path"), "scene.getCurrent has path")
# scene.create
var created = tools.execute("scene.create", {
"rootType": "Node2D",
"name": "AutoTestScene"
})
_assert(created.success, "scene.create creates scene")
_assert(created.path == "res://auto_test_scene.tscn", "scene.create correct path")
# scene.save
var saved = tools.execute("scene.save", {})
_assert(saved.success, "scene.save saves scene")
func _test_node_tools():
_section("Node Tools")
# Create clean scene
tools.execute("scene.create", {"rootType": "Node2D", "name": "NodeTest"})
# node.create
var created = tools.execute("node.create", {
"type": "Sprite2D",
"name": "TestSprite"
})
_assert(created.success, "node.create creates node")
_assert(created.name == "TestSprite", "node.create correct name")
# node.find
var found = tools.execute("node.find", {"name": "TestSprite"})
_assert(found.success, "node.find finds node")
_assert(found.nodes.size() > 0, "node.find returns results")
# node.getData
var data = tools.execute("node.getData", {"path": "TestSprite"})
_assert(data.success, "node.getData returns data")
_assert(data.data.type == "Sprite2D", "node.getData correct type")
# node.setProperty
var setProp = tools.execute("node.setProperty", {
"path": "TestSprite",
"property": "modulate",
"value": {"r": 1.0, "g": 0.5, "b": 0.5, "a": 1.0}
})
_assert(setProp.success, "node.setProperty sets property")
# node.getProperty
var getProp = tools.execute("node.getProperty", {
"path": "TestSprite",
"property": "modulate"
})
_assert(getProp.success, "node.getProperty gets property")
# node.delete
var deleted = tools.execute("node.delete", {"path": "TestSprite"})
_assert(deleted.success, "node.delete deletes node")
# Confirm deletion
var notFound = tools.execute("node.find", {"name": "TestSprite"})
_assert(notFound.nodes.size() == 0, "node.delete confirmed")
func _test_transform_tools():
_section("Transform Tools")
# Create test node
tools.execute("scene.create", {"rootType": "Node2D", "name": "TransformTest"})
tools.execute("node.create", {"type": "Sprite2D", "name": "Mover"})
# transform.setPosition
var pos = tools.execute("transform.setPosition", {
"path": "Mover",
"x": 100,
"y": 200
})
_assert(pos.success, "transform.setPosition works")
# Verify position
var data = tools.execute("node.getData", {"path": "Mover"})
_assert(data.data.position.x == 100, "setPosition x correct")
_assert(data.data.position.y == 200, "setPosition y correct")
# transform.setRotation
var rot = tools.execute("transform.setRotation", {
"path": "Mover",
"degrees": 45
})
_assert(rot.success, "transform.setRotation works")
data = tools.execute("node.getData", {"path": "Mover"})
_assert(abs(data.data.rotation - 45) < 0.1, "setRotation correct")
# transform.setScale
var scale = tools.execute("transform.setScale", {
"path": "Mover",
"x": 2.0,
"y": 2.0
})
_assert(scale.success, "transform.setScale works")
data = tools.execute("node.getData", {"path": "Mover"})
_assert(data.data.scale.x == 2.0, "setScale x correct")
_assert(data.data.scale.y == 2.0, "setScale y correct")
func _test_debug_tools():
_section("Debug Tools")
# debug.tree
var tree = tools.execute("debug.tree", {})
_assert(tree.success, "debug.tree returns success")
_assert(tree.has("tree"), "debug.tree has tree string")
# debug.log
var log = tools.execute("debug.log", {"message": "Test log message"})
_assert(log.success, "debug.log works")
# debug.screenshot
var screenshot = tools.execute("debug.screenshot", {})
_assert(screenshot.success, "debug.screenshot works")
_assert(screenshot.has("path"), "debug.screenshot returns path")
# console.getLogs
var logs = tools.execute("console.getLogs", {"limit": 10})
_assert(logs.success, "console.getLogs works")
_assert(logs.has("logs"), "console.getLogs has logs")
# Helper functions
func _section(name: String):
print("\n📦 %s" % name)
print("-".repeat(40))
func _assert(condition: bool, message: String):
if condition:
passed += 1
print(" ✅ %s" % message)
else:
failed += 1
print(" ❌ %s" % message)
results.append({"pass": condition, "message": message})
func _print_summary():
print("\n" + "=".repeat(50))
print("📊 Test Results")
print("=".repeat(50))
print(" Passed: %d" % passed)
print(" Failed: %d" % failed)
print(" Total: %d" % (passed + failed))
print("")
if failed == 0:
print("🎉 All tests passed!")
else:
print("⚠️ Some tests failed:")
for r in results:
if not r.pass:
print(" - %s" % r.message)In Godot:
- Open
addons/openclaw/tests/test_tools.gd - Script → Run (Ctrl+Shift+X)
Expected output:
==================================================
🧪 OpenClaw Tools Test Suite
==================================================
📦 Editor Tools
----------------------------------------
✅ editor.getState returns success
✅ editor.getState has version
✅ editor.getState has isPlaying
📦 Scene Tools
----------------------------------------
✅ scene.list returns success
...
==================================================
📊 Test Results
==================================================
Passed: 28
Failed: 0
Total: 28
🎉 All tests passed!
| Tool | Test Case | Expected Result |
|---|---|---|
scene.getCurrent |
Call with scene open | Returns name, path, nodeCount |
scene.getCurrent |
Call with no scene | success: false, error message |
scene.list |
Project has scenes | Returns scenes array |
scene.open |
Valid scene path | Scene opens, success: true |
scene.open |
Invalid path | success: false, error message |
scene.save |
Modified scene | File saved, success: true |
scene.create |
Node2D root | New scene created, path returned |
scene.create |
Node3D root | 3D scene created |
scene.create |
Duplicate name | Overwrite or add number |
| Tool | Test Case | Expected Result |
|---|---|---|
node.find |
Search by name | Matching node list |
node.find |
Search by type | Nodes of that type |
node.find |
Search by group | Group members |
node.find |
Nonexistent node | Empty array |
node.create |
Create Sprite2D | Node added |
node.create |
Create with parent | Added under correct parent |
node.delete |
Delete existing node | Node removed |
node.delete |
Delete root node | Fail or warning |
node.setProperty |
Set Vector2 | Dictionary→Vector2 conversion |
node.setProperty |
Set Color | RGBA dictionary→Color conversion |
| Tool | Test Case | Expected Result |
|---|---|---|
input.keyPress |
"W" key | Key event triggered |
input.keyDown + keyUp |
SHIFT hold | Modifier works |
input.mouseClick |
Left click (400, 300) | Click event triggered |
input.mouseMove |
(0, 0) → (800, 600) | Mouse moves |
input.actionPress |
"jump" action | Works if action mapped |
input.actionPress |
Nonexistent action | Warning or ignored |
1. scene.create {rootType: "Node2D", name: "Level1"}
2. node.create {type: "CharacterBody2D", name: "Player"}
3. node.create {type: "Camera2D", name: "Cam", parent: "Player"}
4. transform.setPosition {path: "Player", x: 400, y: 300}
5. scene.save
6. editor.play
7. input.keyPress {key: "W"}
8. debug.screenshot
9. editor.stop
Expected results:
- Level1.tscn created
- Player → Cam hierarchy
- Screenshot shows player at (400, 300)
1. scene.open {path: "res://main.tscn"}
2. debug.tree
3. node.find {type: "Sprite2D"}
4. node.getData {path: "Player"}
5. console.getLogs {type: "error", limit: 20}
6. debug.screenshot
1. editor.play
2. (wait 30 seconds - heartbeat interval)
3. editor.getState # Verify connection maintained
4. input.keyPress {key: "ESCAPE"}
5. editor.stop
# 10-minute connection maintenance test
for i in {1..20}; do
echo "Iteration $i"
openclaw godot execute editor.getState
sleep 30
done# Add to tools.gd (development only)
var start_time: int
func execute(tool_name: String, args: Dictionary) -> Dictionary:
start_time = Time.get_ticks_msec()
var result = _execute_internal(tool_name, args)
var elapsed = Time.get_ticks_msec() - start_time
print("[OpenClaw] %s took %dms" % [tool_name, elapsed])
return result| Tool | Expected Response Time |
|---|---|
| editor.getState | < 10ms |
| scene.getCurrent | < 20ms |
| node.find | < 50ms (100 nodes) |
| debug.screenshot | < 200ms |
| scene.save | < 500ms |
- Plugin enable/disable
- Gateway connect/reconnect
- All 30 tools basic operation
- Connection maintained during Play mode transition
- Command execution after 30s+ idle
- Proper error messages on failures
- No memory leaks (extended run)
- node.getData on empty scene
- Node names with special characters
- Very deep node hierarchy (10+)
- Large scene (1000+ nodes)
- Concurrent multiple commands
- Reconnection after Gateway restart
- DEVELOPMENT.md - Development Guide
- CONTRIBUTING.md - Contribution Guide
Documentation Updated: 2026-02-08