Out-of-process E2E testing tool for Godot
Project description
English | 中文
godot-e2e
Out-of-process E2E testing tool for Godot
Quick Start
1. Install the addon
Copy addons/godot_e2e/ into your Godot project's addons/ directory. Add AutomationServer
as an Autoload in your project settings:
- Path:
*res://addons/godot_e2e/automation_server.gd - Name:
AutomationServer
The * prefix means the script is used directly (not a scene). The server is completely dormant
unless the game is launched with the --e2e flag, so it has no effect in production builds.
2. Install the Python package
pip install godot-e2e
Or install from source:
pip install -e .
3. Write a test
from godot_e2e import GodotE2E
def test_player_moves(game):
initial_x = game.get_property("/root/Main/Player", "position:x")
game.press_action("move_right")
game.wait_physics_frames(10)
new_x = game.get_property("/root/Main/Player", "position:x")
assert new_x > initial_x
Run:
pytest tests/ -v
Features
- Out-of-process — game runs in a separate process; crashes are isolated and timeouts are safe
- No engine modifications — works with standard Godot 4.x binaries
- Synchronous Python API — no async/await required in test code
- Input simulation — keyboard, mouse clicks, named actions
- Node operations — get/set properties, call methods, group lookup, node existence checks
- Frame synchronization — wait for process frames, physics frames, or game time
- Scene management — change scene, reload scene
- Screenshot capture — manual or automatic on test failure (pytest integration)
- pytest fixtures — built-in fixtures with configurable test isolation strategies
How It Works
Two processes communicate over a local TCP connection:
- Python (pytest) — sends JSON-encoded commands and waits for responses
- Godot (AutomationServer) — an Autoload that listens on a TCP port, executes commands on the main thread, and sends back results
The AutomationServer only opens its socket when the game is started with --e2e (and
optionally --e2e-port <port>). In normal play or exported builds without that flag, the autoload
does nothing.
pytest ──── TCP (localhost) ──── AutomationServer (Godot Autoload)
sends: {"cmd": "get_property", "path": "/root/Main/Player", "prop": "position:x"}
gets: {"ok": true, "value": 400.0}
pytest Fixtures
Three isolation strategies are available depending on your needs.
Strategy 1: reload_scene (default, fast)
Reloads the current scene between each test. Cheap and usually sufficient.
# conftest.py
import pytest
from godot_e2e import GodotE2E
GODOT_PROJECT = "/path/to/your/project"
@pytest.fixture(scope="module")
def _game_process():
with GodotE2E.launch(GODOT_PROJECT) as game:
game.wait_for_node("/root/Main", timeout=10.0)
yield game
@pytest.fixture(scope="function")
def game(_game_process):
_game_process.reload_scene()
_game_process.wait_for_node("/root/Main", timeout=5.0)
yield _game_process
Strategy 2: game_fresh (strongest isolation)
Launches a brand new Godot process for each test. Slowest but fully isolated.
@pytest.fixture(scope="function")
def game_fresh():
with GodotE2E.launch(GODOT_PROJECT) as game:
game.wait_for_node("/root/Main", timeout=10.0)
yield game
Strategy 3: Shared session (fastest)
One process for the entire test session. Use when tests are carefully ordered and do not share mutable state.
@pytest.fixture(scope="session")
def game_session():
with GodotE2E.launch(GODOT_PROJECT) as game:
game.wait_for_node("/root/Main", timeout=10.0)
yield game
CI Configuration
Linux (GitHub Actions, headless via Xvfb)
- name: Install Godot
run: |
wget -q https://github.com/godotengine/godot-builds/releases/download/4.4-stable/Godot_v4.4-stable_linux.x86_64.zip
unzip -q Godot_v4.4-stable_linux.x86_64.zip
sudo mv Godot_v4.4-stable_linux.x86_64 /usr/local/bin/godot
- name: Run E2E tests
run: |
pip install -e .
xvfb-run --auto-servernum pytest tests/e2e/ -v
Windows (GitHub Actions)
- name: Install Godot
run: |
Invoke-WebRequest -Uri "https://github.com/godotengine/godot-builds/releases/download/4.4-stable/Godot_v4.4-stable_win64.exe.zip" -OutFile godot.zip
Expand-Archive godot.zip -DestinationPath C:\godot
shell: pwsh
- name: Run E2E tests
run: |
pip install -e .
pytest tests/e2e/ -v
env:
GODOT_BIN: C:\godot\Godot_v4.4-stable_win64.exe
macOS (GitHub Actions)
- name: Install Godot
run: |
wget -q https://github.com/godotengine/godot-builds/releases/download/4.4-stable/Godot_v4.4-stable_macos.universal.zip
unzip -q Godot_v4.4-stable_macos.universal.zip
sudo mv "Godot.app" /Applications/Godot.app
- name: Run E2E tests
run: |
pip install -e .
pytest tests/e2e/ -v
env:
GODOT_BIN: /Applications/Godot.app/Contents/MacOS/Godot
Set GODOT_BIN to override the default Godot executable path. The default search order is:
godot4, godot, then platform-specific standard locations.
API Reference
Launch / Lifecycle
| Method | Description |
|---|---|
GodotE2E.launch(project_path, **kwargs) |
Context manager. Launches Godot and returns a connected GodotE2E instance. |
game.close() |
Terminate the Godot process and close the connection. |
Node Operations
| Method | Description |
|---|---|
game.node_exists(path) |
Returns True if the node at path exists in the scene tree. |
game.wait_for_node(path, timeout=5.0) |
Blocks until the node exists or timeout is reached. |
game.get_property(path, prop) |
Get a property value. Supports dotted paths like "position:x". |
game.set_property(path, prop, value) |
Set a property value on a node. |
game.call_method(path, method, *args) |
Call a method on a node and return the result. |
game.find_by_group(group) |
Return a list of node paths for all nodes in the given group. |
Input Simulation
| Method | Description |
|---|---|
game.press_action(action) |
Press and immediately release a named input action. |
game.input_action(action, pressed) |
Set a named input action pressed state. |
game.key_press(scancode) |
Press and release a key by scancode. |
game.mouse_click(x, y, button=1) |
Click a mouse button at the given screen coordinates. |
Frame Synchronization
| Method | Description |
|---|---|
game.wait_frames(n) |
Wait for n process (_process) frames to complete. |
game.wait_physics_frames(n) |
Wait for n physics (_physics_process) frames to complete. |
game.wait_seconds(t) |
Wait for t in-game seconds (affected by Engine.time_scale). |
Scene Management
| Method | Description |
|---|---|
game.change_scene(scene_path) |
Change to a scene by res:// path. |
game.reload_scene() |
Reload the current scene. |
Diagnostics
| Method | Description |
|---|---|
game.screenshot(path=None) |
Capture a screenshot. Returns PNG bytes; saves to path if given. |
Examples
| Example | Description |
|---|---|
| minimal | Simplest setup — node checks, property reading, method calls (3 tests) |
| platformer | Player movement, scoring, groups, scene reload (5 tests) |
| ui_testing | Button clicks, label verification, scene navigation (5 tests) |
Run any example:
cd examples/minimal
pytest tests/e2e/ -v
License
Apache 2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file godot_e2e-1.0.0.tar.gz.
File metadata
- Download URL: godot_e2e-1.0.0.tar.gz
- Upload date:
- Size: 22.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1fcc5c16be494e0aa07239852bb774967a7dfe5b893afd94544c4d36e95b73d
|
|
| MD5 |
6c9a9402c874935064f70a5e3dd95344
|
|
| BLAKE2b-256 |
d2c47b8647e872c5e440594359d5d40fc4ea920f95a7fdebe0bb0e8623547b65
|
Provenance
The following attestation bundles were made for godot_e2e-1.0.0.tar.gz:
Publisher:
publish.yml on RandallLiuXin/godot-e2e
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
godot_e2e-1.0.0.tar.gz -
Subject digest:
b1fcc5c16be494e0aa07239852bb774967a7dfe5b893afd94544c4d36e95b73d - Sigstore transparency entry: 1323466648
- Sigstore integration time:
-
Permalink:
RandallLiuXin/godot-e2e@fe1902a3286c7766985f7c01f00441acdd78a137 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/RandallLiuXin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fe1902a3286c7766985f7c01f00441acdd78a137 -
Trigger Event:
push
-
Statement type:
File details
Details for the file godot_e2e-1.0.0-py3-none-any.whl.
File metadata
- Download URL: godot_e2e-1.0.0-py3-none-any.whl
- Upload date:
- Size: 19.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
807bb856806e9ea4f616debc8651ab196e02752a8806500da5bfa0bc74f83ae6
|
|
| MD5 |
b74e6b5927113885518178b3b9c90f46
|
|
| BLAKE2b-256 |
efc415ed1cd47a17519f762fc81b10529ff90bb00dd3a29b8140f798803bceb7
|
Provenance
The following attestation bundles were made for godot_e2e-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on RandallLiuXin/godot-e2e
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
godot_e2e-1.0.0-py3-none-any.whl -
Subject digest:
807bb856806e9ea4f616debc8651ab196e02752a8806500da5bfa0bc74f83ae6 - Sigstore transparency entry: 1323466715
- Sigstore integration time:
-
Permalink:
RandallLiuXin/godot-e2e@fe1902a3286c7766985f7c01f00441acdd78a137 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/RandallLiuXin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fe1902a3286c7766985f7c01f00441acdd78a137 -
Trigger Event:
push
-
Statement type: