Run Godot scenes with runtime testing via command-line flags. Set properties, call methods, emit signals, capture signals, and assert expectations—all without editing source files.
Test Godot scenes at runtime without modifying source files. Perfect for:
All output uses [RT:*] prefix for easy filtering:
# Get ONLY RuntimeTest output
godot ... 2>&1 | grep "\[RT:"
# Filter by type
grep "\[RT:PASS\]" # Passed assertions
grep "\[RT:FAIL\]" # Failed assertions
grep "\[RT:OK\]" # Successful operations
grep "\[RT:ERR\]" # Failed operations
grep "\[RT:SIGNAL\]" # Captured signals
grep "\[RT:RESULTS\]" # Summary line
--set:Path:prop=value # Set property
--call:Path:method:arg1 # Call method
--emit:Path:signal:arg1 # Emit signal
--print:Path:prop # Print property once
--listen:Path:signal # Capture signal emissions (up to 5 args)
--watchprop:Path:prop # Print on property change
--expect:Path:prop=value # Assert property equals value
--expect-signal:Path:sig # Assert signal was emitted
--expect-signal:Path:sig:a:b # Assert signal with specific args
--expect-no-signal:Path:sig # Assert signal NOT emitted
--wait:500 # Wait 500ms
--wait-frames:10 # Wait 10 frames
--watch # Keep running, Q to quit
. = scene rootPlayer = direct childPlayer/Health = nested path# Headless test (CI-friendly)
godot --path . --headless scene.tscn -- --set:.:health=50 --expect:.:health=50
# With window (debugging)
godot --path . scene.tscn -- --watch --watchprop:.:state
Key: -- separates Godot flags from RuntimeTest flags.
# Set and verify
godot --path . --headless scene.tscn -- \
--set:.:health=50 \
--expect:.:health=50
# Output:
# [RT:OK] set .:health = 50
# [RT:PASS] .:health = 50
# [RT:RESULTS] Done: 1 OK, 0 ERR, 1 PASS, 0 FAIL
# Listen FIRST, then trigger, then assert
godot --path . --headless scene.tscn -- \
--listen:.:health_changed \
--call:.:take_damage:30 \
--expect-signal:.:health_changed
# Output:
# [RT:OK] listen .:health_changed
# [RT:SIGNAL] .:health_changed([100, 70])
# [RT:OK] call .:take_damage([30])
# [RT:PASS] signal .:health_changed was emitted (1 times)
godot --path . --headless scene.tscn -- \
--listen:.:died \
--set:.:health=100 \
--call:.:take_damage:10 \
--expect-no-signal:.:died
# [RT:PASS] signal .:died was not emitted
godot --path . --headless scene.tscn -- \
--listen:.:animation_finished \
--call:.:play_death \
--wait:500 \
--expect-signal:.:animation_finished
godot --path . scene.tscn -- \
--watch \
--watchprop:.:state \
--set:.:debug=true
# Press Q to quit
| Marker | Meaning |
|---|---|
[RT:OK] |
Operation succeeded |
[RT:ERR] |
Operation failed |
[RT:PASS] |
Assertion passed |
[RT:FAIL] |
Assertion failed |
[RT:PRINT] |
Property printed |
[RT:CHANGE] |
Watched property changed |
[RT:SIGNAL] |
Signal captured |
[RT:WAIT] |
Waiting |
[RT:WATCH] |
Watch mode info |
[RT:RESULTS] |
Summary/system message |
0 = All assertions passed1 = One or more assertions failed| Input | Parsed As |
|---|---|
true/false |
bool |
123 |
int |
1.5 |
float |
IDLE |
enum (looked up in script) |
| anything else | String |
# Run test
godot --path . --headless scene.tscn -- \
--set:.:health=50 \
--expect:.:health=50
# Check exit code
if [ $? -ne 0 ]; then
echo "Tests failed!"
exit 1
fi
# Or grep for failures
godot ... 2>&1 | grep -q "\[RT:FAIL\]" && exit 1
godot --path . --headless scene.tscn -- \
--listen:.:state_changed \
--call:.:transition_to:ATTACKING \
--expect-signal:.:state_changed
godot --path . --headless scene.tscn -- \
--listen:.:health_changed \
--listen:.:died \
--set:.:health=100 \
--call:.:take_damage:150 \
--expect:.:health=0 \
--expect-signal:.:died
godot --path . --xr-mode on scene.tscn -- \
--watch \
--set:.:debug_mode=true
[RT:ERR] property not found[RT:ERR] wrong arg count[RT:FAIL] signal not listening--listen:Path:signal BEFORE the action that emits[RT:OK] set ... (coerced from X)When user asks to test a scene:
--headless for automated tests--listen must come before actions that emit--expect comes after --set/--callgrep "\[RT:FAIL\]"Example:
godot --path . --headless Scenes/Player.tscn -- \
--listen:.:health_changed \
--set:.:health=50 \
--expect:.:health=50 \
--expect-signal:.:health_changed