API 参考¶
godot-e2e Python API 完整参考文档。此处记录了所有公开的类、方法、类型和异常。
GodotE2E¶
godot_e2e.GodotE2E
高级端到端测试接口。这是你在测试中交互的主要类。
类方法¶
GodotE2E.launch(project_path, godot_path=None, port=0, timeout=10.0, extra_args=None, log_verbosity=None)¶
启动 Godot 进程并返回已连接的 GodotE2E 实例。返回一个上下文管理器(Context Manager)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
project_path |
str |
必需 | Godot 项目目录的路径(包含 project.godot 的目录)。 |
godot_path |
str |
None |
Godot 可执行文件的路径。如果为 None,则从 GODOT_PATH 环境变量或 PATH 中自动查找。 |
port |
int |
0 |
自动化服务器的 TCP 端口。0 表示自动分配空闲端口。 |
timeout |
float |
10.0 |
等待连接成功的秒数。 |
extra_args |
list |
None |
转发给 Godot 进程的额外命令行参数(放在 -- 用户参数分隔符之前)。 |
log_verbosity |
str |
None |
启动时的引擎日志捕获 verbosity:"error" / "warning" / "info"。None 沿用 addon 默认值("warning")。可在运行时通过 set_log_verbosity 调整。 |
返回值:GodotE2E(可配合 with 语句作为上下文管理器使用)。
异常:
- FileNotFoundError -- 无法找到 Godot 可执行文件。
- RuntimeError -- Godot 进程在建立连接之前就已退出。
- ConnectionError -- 在 timeout 秒内无法建立连接。
示例:
with GodotE2E.launch("./my_project") as game:
game.wait_for_node("/root/Main")
pos = game.get_property("/root/Main/Player", "position")
GodotE2E.connect(host="127.0.0.1", port=6008, token="")¶
连接到已在运行的 Godot 实例。当你手动以 --e2e 参数启动 Godot 时使用此方法。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
host |
str |
"127.0.0.1" |
主机地址。 |
port |
int |
6008 |
TCP 端口。 |
token |
str |
"" |
认证令牌(必须与 --e2e-token 设置的值匹配)。 |
返回值:GodotE2E。
生命周期方法¶
close()¶
终止 Godot 进程(如果是由本库启动的)并关闭 TCP 连接。作为上下文管理器使用时会自动调用。
节点操作¶
node_exists(path) -> bool¶
检查场景树(Scene Tree)中是否存在指定节点。
| 参数 | 类型 | 说明 |
|---|---|---|
path |
str |
绝对节点路径(例如 "/root/Main/Player")。 |
返回值:如果节点存在返回 True,否则返回 False。
get_property(path, property)¶
获取节点的属性值。支持 Godot 的冒号索引属性表示法。
| 参数 | 类型 | 说明 |
|---|---|---|
path |
str |
绝对节点路径。 |
property |
str |
属性名称。使用冒号表示法访问子属性(例如 "position:x")。 |
返回值:属性值,反序列化为相应的 Python 类型(参见类型)。
异常:
- NodeNotFoundError -- 节点不存在。
- CommandError -- 该属性在节点上不存在。
示例:
pos = game.get_property("/root/Main/Player", "position") # Returns Vector2
x = game.get_property("/root/Main/Player", "position:x") # Returns float
text = game.get_property("/root/Main/Label", "text") # Returns str
set_property(path, property, value)¶
设置节点的属性值。值在发送前会被序列化。
| 参数 | 类型 | 说明 |
|---|---|---|
path |
str |
绝对节点路径。 |
property |
str |
属性名称(支持冒号表示法)。 |
value |
any | 要设置的值。对于 Godot 特有类型,请使用 godot-e2e 的类型(如 Vector2)。 |
异常:NodeNotFoundError -- 节点不存在。
示例:
from godot_e2e import Vector2
game.set_property("/root/Main/Player", "position", Vector2(100.0, 200.0))
game.set_property("/root/Main", "score", 0)
call(path, method, args=None)¶
调用节点上的方法并返回结果。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
path |
str |
必需 | 绝对节点路径。 |
method |
str |
必需 | 要调用的方法名称。 |
args |
list |
None |
要传递的参数列表。每个参数在发送前会被序列化。 |
返回值:方法的返回值,已反序列化。
异常:
- NodeNotFoundError -- 节点不存在。
- CommandError -- 该方法在节点上不存在。
示例:
find_by_group(group) -> list¶
查找属于某个 Godot 分组(Group)的所有节点。
| 参数 | 类型 | 说明 |
|---|---|---|
group |
str |
分组名称。 |
返回值:绝对节点路径字符串的列表。
示例:
query_nodes(pattern="", group="") -> list¶
按名称模式、分组或两者组合查询节点。模式使用 Godot 的 String.match() 通配符语法(支持 * 和 ? 通配符)。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
pattern |
str |
"" |
匹配节点名称的通配符模式。 |
group |
str |
"" |
筛选属于此分组的节点。 |
返回值:绝对节点路径字符串的列表。
示例:
# All nodes whose name starts with "Enemy"
game.query_nodes(pattern="Enemy*")
# All nodes in the "enemies" group
game.query_nodes(group="enemies")
# Nodes in "enemies" group whose name matches "Boss*"
game.query_nodes(pattern="Boss*", group="enemies")
get_tree(path="/root", depth=4) -> dict¶
获取场景树的快照,返回嵌套字典。适用于调试。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
path |
str |
"/root" |
起始的根节点路径。 |
depth |
int |
4 |
最大遍历深度。 |
返回值:包含 "name"、"type"、"path" 和 "children"(子节点字典列表)的嵌套字典。
示例:
tree = game.get_tree("/root/Main", depth=2)
# {
# "name": "Main",
# "type": "Node2D",
# "path": "/root/Main",
# "children": [
# {"name": "Player", "type": "CharacterBody2D", "path": "/root/Main/Player", "children": []},
# {"name": "Label", "type": "Label", "path": "/root/Main/Label", "children": []},
# ...
# ]
# }
batch(commands) -> list¶
在单次网络往返中执行多个命令。批处理仅支持即时(非延迟)命令。延迟命令(输入、等待类)会返回错误条目。
| 参数 | 类型 | 说明 |
|---|---|---|
commands |
list |
命令列表。每个命令可以是包含 "action" 键的字典,也可以是 (action, params_dict) 形式的元组/列表。 |
返回值:结果列表,每个命令对应一个结果。每个结果是反序列化后的返回值。
示例:
results = game.batch([
("get_property", {"path": "/root/Main/Player", "property": "position:x"}),
("get_property", {"path": "/root/Main/Player", "property": "position:y"}),
{"action": "node_exists", "path": "/root/Main/Enemy"},
])
x, y, enemy_exists = results[0], results[1], results[2]
输入模拟¶
所有输入命令都是延迟执行的:服务器注入输入事件后会等待 2 个物理帧再响应,确保 Godot 在 _physics_process 中处理了该输入。
input_key(keycode, pressed, physical=False)¶
注入一个键盘事件。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
keycode |
int |
必需 | Godot 按键常量(例如 KEY_RIGHT、KEY_SPACE)。 |
pressed |
bool |
必需 | True 表示按下,False 表示释放。 |
physical |
bool |
False |
如果为 True,设置 physical_keycode 而非 keycode。 |
input_action(action_name, pressed, strength=1.0)¶
注入一个命名输入动作事件。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
action_name |
str |
必需 | Godot Input Map 中定义的动作名称(例如 "ui_right")。 |
pressed |
bool |
必需 | True 表示按下,False 表示释放。 |
strength |
float |
1.0 |
动作强度(0.0 到 1.0)。 |
input_mouse_button(x, y, button=1, pressed=True)¶
注入一个鼠标按钮事件到屏幕坐标。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x |
float |
必需 | 屏幕 X 坐标。 |
y |
float |
必需 | 屏幕 Y 坐标。 |
button |
int |
1 |
鼠标按钮索引(1 = 左键,2 = 右键,3 = 中键)。 |
pressed |
bool |
True |
True 表示按下,False 表示释放。 |
input_mouse_motion(x, y, relative_x=0, relative_y=0)¶
注入一个鼠标移动事件。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x |
float |
必需 | 屏幕 X 位置。 |
y |
float |
必需 | 屏幕 Y 位置。 |
relative_x |
float |
0 |
相对 X 移动量。 |
relative_y |
float |
0 |
相对 Y 移动量。 |
高级输入辅助方法¶
这些是按下并立即释放的便捷封装方法。
press_key(keycode)¶
一次调用完成按键的按下和释放。等同于先调用 input_key(keycode, True) 再调用 input_key(keycode, False)。
press_action(action_name, strength=1.0)¶
按下并释放一个命名动作。等同于先调用 input_action(action_name, True, strength) 再调用 input_action(action_name, False)。
click(x, y, button=1)¶
在屏幕坐标处点击。等同于先以 pressed=True 调用 input_mouse_button,再以 pressed=False 调用。
click_node(path)¶
点击节点的屏幕位置。服务器自动计算屏幕坐标:
- 对于 Control 节点:使用 get_global_rect() 的中心点。
- 对于 Node2D 节点:将全局位置转换为屏幕坐标。
| 参数 | 类型 | 说明 |
|---|---|---|
path |
str |
绝对节点路径。必须是 Control 或 Node2D。 |
异常:
- NodeNotFoundError -- 节点不存在。
- CommandError -- 该节点类型不支持屏幕位置计算。
帧同步¶
wait_process_frames(count=1)¶
等待指定数量的 _process 帧完成。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
count |
int |
1 |
要等待的处理帧数。 |
wait_physics_frames(count=1)¶
等待指定数量的 _physics_process 帧完成。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
count |
int |
1 |
要等待的物理帧数。 |
wait_seconds(seconds)¶
等待指定的游戏内时间(受 Engine.time_scale 影响)。
| 参数 | 类型 | 说明 |
|---|---|---|
seconds |
float |
要等待的游戏内秒数。 |
同步方法¶
wait_for_node(path, timeout=5.0)¶
阻塞等待直到场景树中出现指定节点。每个处理帧轮询一次。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
path |
str |
必需 | 要等待的绝对节点路径。 |
timeout |
float |
5.0 |
最大等待秒数。 |
异常:TimeoutError -- 节点在超时时间内未出现。异常的 scene_tree 属性包含超时时刻捕获的场景树快照(如果获取成功)。
wait_for_signal(path, signal_name, timeout=5.0)¶
等待信号(Signal)被发出。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
path |
str |
必需 | 发出信号的节点的绝对路径。 |
signal_name |
str |
必需 | 信号名称。 |
timeout |
float |
5.0 |
最大等待秒数。 |
返回值:信号参数的列表(可能为空)。
异常:
- NodeNotFoundError -- 源节点不存在。
- CommandError -- 该信号在节点上不存在。
- TimeoutError -- 信号在超时时间内未被发出。
wait_for_property(path, property, value, timeout=5.0)¶
等待属性等于期望值。每个处理帧轮询一次。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
path |
str |
必需 | 绝对节点路径。 |
property |
str |
必需 | 属性名称。 |
value |
any | 必需 | 期望值(比较前会被序列化)。 |
timeout |
float |
5.0 |
最大等待秒数。 |
异常:TimeoutError -- 属性在超时时间内未达到期望值。
场景管理¶
get_scene() -> str¶
获取当前加载场景的 res:// 路径。
返回值:场景文件路径字符串(例如 "res://main.tscn")。
change_scene(scene_path)¶
切换到另一个场景。这是一个延迟操作 -- 该方法会阻塞直到新场景加载完毕且其根节点可用。
| 参数 | 类型 | 说明 |
|---|---|---|
scene_path |
str |
场景资源路径(例如 "res://levels/level2.tscn")。 |
reload_scene()¶
重新加载当前场景。这是一个延迟操作 -- 该方法会阻塞直到场景重新加载完毕。适用于在测试之间重置状态。
截图¶
screenshot(save_path="") -> str¶
捕获当前视口(Viewport)的截图。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
save_path |
str |
"" |
PNG 文件的绝对保存路径。如果为空,则保存到 user://e2e_screenshots/ 并以时间戳命名。 |
返回值:已保存 PNG 文件的绝对路径。
Locator 构造方法¶
这些方法用于构造 Locator,本身不会发送命令。
locator(**kwargs) -> Locator¶
用一个或多个查询策略(AND 组合)构造一个 Locator。
| 关键字 | 说明 |
|---|---|
path |
绝对场景路径,0 或 1 个匹配。 |
name |
节点名。值含 * 或 ? 时按 glob,否则精确。 |
group |
组名。 |
text |
与 node.text 比较(如果节点有该属性)。glob/精确规则同 name。 |
script |
脚本资源路径(如 "res://player.gd"),精确匹配。 |
type |
类名。通过 is X 匹配,含子类。 |
返回值:Locator。
抛出:ValueError —— 未提供任何关键字或使用了未知关键字。
get_by_text(text) -> Locator¶
locator(text=text) 的语法糖。
get_by_button(text) -> Locator¶
locator(type="BaseButton", text=text) 的语法糖。覆盖 Button、CheckBox、OptionButton、MenuButton、LinkButton。
引擎日志捕获¶
godot-e2e 捕获游戏侧的 push_error、push_warning、脚本运行时错误、shader 错误,以及(info verbosity 下)print / printerr 输出,并在 Python 侧暴露。需要 Godot 4.5+(参见 Logger)。
默认 verbosity 是 warning(错误 + 警告)。普通的 print() 默认不捕获,避免淹没测试输出。
last_logs -> list[LogEntry]¶
最近一次命令调用期间捕获的日志条目。每次命令后会清空。
collected_logs -> list[LogEntry]¶
自上次重置以来捕获的所有日志条目。pytest 插件会在每个测试开始时清空它,因此使用标准 game / game_fresh fixture 时,列表只反映当前测试(含其 reload)期间产生的日志。
测试失败时同一个列表会被附加到 pytest 失败报告里的 captured godot logs section,与标准的 captured stdout / captured stderr 并列。
reset_collected_logs()¶
清空 collected_logs 与 last_logs。pytest fixture 会自动调用;通常只在你想把某个断言收窄到更小的窗口时才手动调用。
set_log_verbosity(level)¶
运行时调整捕获 verbosity。启动默认值由 launcher 的 --e2e-log-verbosity 标志决定。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
level |
str |
— | "error"、"warning"、"info" 三选一。 |
任何其他值都会抛 CommandError。
def test_print_visible_under_info(game):
game.set_log_verbosity("info")
game.call("/root/Player", "_announce") # 内部用了 print()
assert any("ready" in e.message for e in game.collected_logs)
set_log_buffer_size(size)¶
运行时调整引擎日志捕获 ring buffer 大小。默认 200 适合一般测试;错误密集的调试场景如果发现 drain 之间在丢条目,可以调高;想验证 overflow 处理时也可以反过来调低制造溢出。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
size |
int |
— | 正整数 ring buffer 大小。 |
size < 1 时 Python 侧直接抛 ValueError;如果绕过 wrapper 直接走 GodotClient.send_command,wire 侧会返回 invalid_argument。
drain 间 buffer 溢出时,响应里会带 _logs_dropped 计数,客户端把它合成为一条 warning 级别的标记条目("<N log entries dropped due to capture buffer overflow>")统一追加到 last_logs、collected_logs 和异常的 logs 上。
其他¶
quit(exit_code=0)¶
终止 Godot 进程。由此产生的 ConnectionLostError 会在内部被静默处理。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
exit_code |
int |
0 |
进程退出码。 |
Locator¶
godot_e2e.Locator
对运行中场景树里一个或多个节点的懒解析、多策略引用。Locator 每次 action 都重新解析,因此 reload_scene() 等树变更后老 Locator 仍然有效。
通过 GodotE2E.locator()、get_by_text()、get_by_button() 构造;构造函数本身不属于公开 API。
Refinement(链式细化)¶
每个方法都返回一个新的 Locator,原对象不会被修改。
filter(**kwargs) -> Locator¶
追加 AND 组合的谓词。关键字集合与 GodotE2E.locator() 相同。
first() -> Locator¶
总是取树遍历顺序里的第一个匹配。
nth(i) -> Locator¶
取第 i 个匹配(从 0 开始)。i < 0 抛 ValueError。
all() -> list[Locator]¶
立即解析,每个匹配返回一个 path-pinned 的 Locator。这是调用时刻的快照——后续树变更不会更新返回的列表。零匹配返回 [],不报错。
locator(**kwargs) -> Locator¶
链式子查询,scope 限制在当前 Locator 解析到的节点之下。父 Locator 每次 action 都重新解析(与非链式 Locator 一致),所以链式 Locator 也能 survive reload_scene()。
父 Locator 必须在 action 时刻 解析到正好 1 个节点,否则在 action 运行时抛 MultipleMatchesError / NodeNotFoundError,而不是在调用本方法时。(exists() 和 count() 会吞掉这些错误,返回 False / 0。)
Inspection(只读检查)¶
exists() -> bool¶
查询是否解析出 ≥1 个节点。在查找类问题上不抛异常——节点缺失、链式父级缺失/多匹配、服务器查找错误都返回 False。连接错误仍会抛出。
count() -> int¶
匹配数。在 exists() 返回 False 的相同条件下返回 0。
is_visible() -> bool¶
(要求单匹配)目标在场景树中是否可见。
抛出:MultipleMatchesError、NodeNotFoundError。
is_actionable() -> bool¶
(要求单匹配)目标是否通过全部三项 actionability 检查(visible_in_tree + mouse_filter + viewport 相交)。
抛出:MultipleMatchesError、NodeNotFoundError。
Action(每次都重新解析)¶
每个 action 都会先重跑查询。Locator 必须解析到正好 1 个节点,否则抛 MultipleMatchesError / NodeNotFoundError。
click(*, force=False, timeout=5.0)¶
点击节点的屏幕位置(左键)。Control 节点会轮询 actionability 直至 timeout,超时抛 NotActionableError。force=True 跳过检查。右键/中键作为未来工作跟踪;当前需要请直接使用 GodotE2E.input_mouse_button(...)。
hover()¶
在节点屏幕位置注入 InputEventMouseMotion。用于测试 tooltip / hover 效果。注意:会触发途经 Control 的 mouse_entered / _gui_input。
get_property(prop)¶
读取属性。支持 "position:x" 这样的子属性路径。
set_property(prop, value)¶
写入属性。Python 类型 wrapper(Vector2、Color 等)会自动序列化。
call(method, args=None)¶
在节点上调用方法并返回结果。
wait_visible(*, timeout=5.0)¶
阻塞直至(解析到的)目标通过 actionability 检查。超时或节点始终未出现都抛 NotActionableError(携带结构化 reasons 和 checks)。
wait_for_signal(signal_name, timeout=5.0)¶
阻塞直至(解析到的)节点发出指定信号,返回信号参数列表。超时抛 TimeoutError。
Auto-wait 范围¶
click() 和 wait_visible() 轮询服务端 actionability 快照。具体检查项随节点类型而定:
Control——全套三项检查:is_visible_in_tree()——父链全部可见。mouse_filter != MOUSE_FILTER_IGNORE——能接收鼠标事件。get_global_rect().intersects(viewport_rect)——位于可见区域内。Node2D——仅检查可见性(is_visible_in_tree())。Node2D 没有mouse_filter对等概念,且通用 bounding rect 不易获得,故不做 viewport 检查。Node3D/Window/ 普通Node——actionability 直接失败,reasons含"unclickable_node_type"。click_node/hover_node无法为这些节点类型计算屏幕位置,提前拒绝比让click()抛错更直接。改用子级Control或Node2D。
遮挡 / hit-test 检测作为单独 ROADMAP 任务跟踪。
expect¶
godot_e2e.expect
针对 Locator 的自动重试断言。每个 matcher 会在活跃游戏上轮询直到条件满足或超时,超时则抛 ExpectationFailedError——它同时继承 GodotE2EError 和 AssertionError,pytest 会按普通断言失败渲染。
from godot_e2e import expect
expect(game.locator(name="StatusLabel")).to_have_text("Ready")
expect(game.locator(name="HUD"), timeout=10.0).to_have_property("score", 100)
expect(game.locator(group="enemies")).to_satisfy(
lambda loc: loc.count() == 0,
description="all enemies cleared",
)
所有轮询都在客户端进行;matcher 复用 Locator 现有方法(get_property、is_visible、exists),不引入新的 wire 命令。轮询期间抛出的查找类异常(NodeNotFoundError、MultipleMatchesError、CommandError)会被吞掉视作"还没满足",循环继续——这让 matcher 能平滑跨过场景重载等瞬态。
expect(locator, *, timeout=5.0, poll_interval=0.05) -> LocatorAssertions¶
为 locator 构建轮询断言句柄。
| 参数 | 类型 | 说明 |
|---|---|---|
locator |
Locator |
待断言的 Locator。每次轮询都会重新解析,所以断言能跟随场景变化。 |
timeout |
float |
重试最大时长(秒),默认 5.0。 |
poll_interval |
float |
两次轮询间的等待(秒),默认 0.05。 |
抛出:locator 不是 Locator 实例时抛 TypeError;timeout < 0 或 poll_interval <= 0 时抛 ValueError。
Matchers¶
每个 matcher 成功返回 None,超时抛 ExpectationFailedError。错误信息包含最后观测值,error.scene_tree 携带 /root 处深度 4 的 dump 用于诊断。
to_have_property(name, value)¶
locator.get_property(name) == value 时通过。
to_have_text(text)¶
目标的 text 属性等于 text 时通过。是 to_have_property("text", text) 的语法糖。
to_be_visible()¶
目标在场景树中可见时通过(与 Locator auto-wait 的可见性检查一致)。Control 和 Node2D 下可靠(两者都用 is_visible_in_tree)。Node3D、Window 和普通 Node 的底层 actionability 检查会以 unclickable_node_type 拒绝,无法通过此 matcher 判定可见性——改用 to_satisfy(lambda l: l.get_property("visible"))。
to_exist()¶
Locator 查询解析到 1 个或更多节点时通过。不要求唯一匹配——如果你需要正好 1 个,用 to_satisfy(lambda l: l.count() == 1)。
to_satisfy(predicate, *, description=None)¶
predicate(locator) 返回真值时通过。predicate 接收 Locator 本身,因此可以组合属性读取、可见性检查和 count() 查询。
| 参数 | 类型 | 说明 |
|---|---|---|
predicate |
Callable[[Locator], Any] |
返回真值即满足。 |
description |
str \| None |
错误信息中的人类可读标签。不填时报告 repr(predicate),对 lambda 几乎没用。 |
predicate 内部抛出的查找类异常(NodeNotFoundError、MultipleMatchesError、CommandError)会被吞掉视作"还没满足",所以 predicate 可以放心调用要求节点存在的方法。
GodotClient¶
godot_e2e.GodotClient
低级 TCP 客户端,实现 godot-e2e 的通信协议。通常不需要直接使用此类 -- 请使用 GodotE2E。
构造函数¶
方法¶
connect(timeout=10.0)¶
打开到 Godot 自动化服务器的 TCP 连接。
异常:OSError -- 连接失败。
close()¶
关闭 TCP 连接。
hello(token) -> dict¶
发送握手(Handshake)消息。必须是连接后发送的第一条命令。
| 参数 | 类型 | 说明 |
|---|---|---|
token |
str |
认证令牌。 |
返回值:包含 "ok"、"godot_version" 和 "server_version" 键的响应字典。
send_command(action, **params) -> dict¶
发送命令并阻塞等待匹配的响应。
| 参数 | 类型 | 说明 |
|---|---|---|
action |
str |
命令动作名称。 |
**params |
any | 包含在 JSON 消息中的额外参数。 |
返回值:解析后的响应字典。
异常:
- NodeNotFoundError -- 服务器报告节点不存在。
- CommandError -- 其他服务器端错误。
- ConnectionLostError -- TCP 连接断开或超时。
GodotLauncher¶
godot_e2e.GodotLauncher
管理 Godot 子进程的启动和连接。由 GodotE2E.launch() 内部使用。
方法¶
launch(project_path, godot_path=None, port=0, timeout=10.0, extra_args=None, log_verbosity=None) -> GodotClient¶
启动 Godot 并返回已完成握手的 GodotClient。
启动器执行以下步骤:
1. 查找 Godot 二进制文件(从 godot_path、GODOT_PATH 环境变量或 PATH)。
2. 如果 port=0(默认),创建临时端口文件并传递 --e2e-port=0 --e2e-port-file=<path>,让 Godot 自动选择空闲端口并写入文件。
3. 生成随机认证令牌。
4. 以 --e2e、--e2e-port=N、--e2e-token=X(及适用时的 --e2e-port-file / --e2e-log-verbosity)参数启动 Godot。
5. 从端口文件读取实际端口(如果是自动分配的),然后轮询直到 TCP 连接成功且握手完成。
log_verbosity 非 None 时必须是 "error" / "warning" / "info" 之一——非法值会在启动子进程之前抛 ValueError,与运行时 set_log_verbosity 的契约保持一致。
异常:
- ValueError -- log_verbosity 不在合法集合内。
- FileNotFoundError -- 无法找到 Godot。
- RuntimeError -- Godot 进程在连接前退出。
- ConnectionError -- 在 timeout 内未能建立连接。
kill()¶
通过发送 quit 命令优雅关闭 Godot,然后终止进程。如果进程在 5 秒内未退出,则回退到 process.kill()。
类型¶
godot_e2e.types
映射 Godot 内置类型的 Python 数据类(Dataclass)。用于属性值的序列化和反序列化。
Vector2¶
Vector2i¶
Vector3¶
Vector3i¶
Rect2¶
Rect2i¶
Color¶
Transform2D¶
NodePath¶
序列化函数¶
serialize(value)¶
将 Python 类型转换为带有 _t 类型标签的 JSON 可序列化字典。基本类型、列表和普通字典直接传递。Godot 类型会被加上标签。
deserialize(value)¶
将带有 _t 类型标签的 JSON 字典转换回 Python 类型。包含 _t: "_unknown" 的未知标签将作为原始字典传递。
LogEntry¶
@dataclass
class LogEntry:
level: str # "error" | "warning" | "info" | "stderr"
message: str
function: str # 仅引擎错误条目带值
file: str # 仅引擎错误条目带值
line: int # 仅引擎错误条目带值
来自 Godot 进程的单条日志。function / file / line 仅 _log_error 回调(push_error、push_warning、运行时错误)会填充;info / stderr(print / printerr)条目里这三项是空的。__str__ 会渲染为 [LEVEL] message (file:line),便于直接放进失败报告。
LogVerbosity¶
set_log_verbosity 与 --e2e-log-verbosity 接受的 wire 协议字符串。
parse_log_entries(raw)¶
将 wire 上原始的 _logs 数组转换为 LogEntry 列表。GodotClient 内部使用;为绕过高层 API 的调用方暴露。
异常¶
所有异常继承自 GodotE2EError。
GodotE2EError¶
class GodotE2EError(Exception):
"""Base exception for all godot-e2e errors."""
logs: list[LogEntry] # 失败命令期间捕获的引擎日志
每个异常都带 logs 属性,由失败命令的 _logs 载荷填充。没有日志(或日志捕获未激活)时是空列表。
NodeNotFoundError¶
class NodeNotFoundError(GodotE2EError):
"""Raised when a node path doesn't resolve in the scene tree."""
触发场景:get_property、set_property、call、click_node、wait_for_signal。
TimeoutError¶
class TimeoutError(GodotE2EError):
def __init__(self, message: str, scene_tree=None):
self.scene_tree = scene_tree # dict or None
触发场景:wait_for_node、wait_for_signal、wait_for_property。
scene_tree 属性包含超时时刻捕获的场景树快照(如果可用),有助于诊断节点未找到的原因。
ConnectionLostError¶
class ConnectionLostError(GodotE2EError):
"""Raised when the Godot process crashes or the TCP connection drops."""
触发场景:send_command(以及所有发送命令的高级方法)。
CommandError¶
当 Godot 服务器返回非"节点未找到"的错误时触发。包括未知命令、无效属性、方法调用失败以及其他服务器端错误。
MultipleMatchesError¶
class MultipleMatchesError(GodotE2EError):
def __init__(self, message: str, paths: list):
self.paths = paths # list[str]
Locator action 在查询匹配到多个节点、且未使用 .first() / .nth(i) / .filter(...) 消歧时抛出。paths 属性带有全部匹配节点路径。
NotActionableError¶
class NotActionableError(GodotE2EError):
def __init__(self, message: str, path: str, reasons: list, checks: dict):
self.path = path
self.reasons = reasons # 例如 ["not_visible_in_tree"]
self.checks = checks # 各检查项布尔值字典
Locator.click() 和 Locator.wait_visible() 的 actionability 轮询超时时抛出。reasons 列出每一项失败的检查("not_visible_in_tree"、"mouse_filter_ignore"、"outside_viewport")。
ExpectationFailedError¶
class ExpectationFailedError(GodotE2EError, AssertionError):
actual: Any # 最后观测值(仅当 observation_captured 为 True 时有意义)
observation_captured: bool # 至少有一次 poll 返回过值则为 True
matcher: str # 例如 "to_have_text('Ready')"
scene_tree: dict | None # /root 深度 4 dump,dump 自身失败则为 None
timeout: float # 被超出的超时
last_error: Exception | None # 轮询期间吞掉的最后一个 CommandError(如有)
expect(locator).to_* matcher 在超时内未满足时抛出。同时继承 AssertionError,所以 pytest 渲染方式与普通 assert 失败一致——错误信息落在断言段落而非通用异常 traceback。需要把它当框架错误处理的工具仍可 except GodotE2EError。
observation_captured 用来区分"poll 观测到 None"和"从来没观测到值"(节点始终未解析、稳定多匹配未消歧、或持续服务端错误)。last_error 在轮询循环反复吞掉 CommandError 时被设置——典型场景是 get_property 读了一个该节点没有的属性,或瞬态命令错误持续到超时。
pytest 夹具¶
godot_e2e.fixtures 模块通过 pytest11 入口点自动注册为 pytest 插件。
game¶
作用域:function
函数作用域夹具,后台由模块作用域的 Godot 进程支持。在每个测试前重新加载场景,测试失败时自动截图。
Godot 项目路径按以下优先顺序解析:
1. @pytest.mark.godot_project("path") 标记。
2. pytest 配置中的 godot_e2e_project_path。
3. GODOT_E2E_PROJECT_PATH 环境变量。
4. 在常见位置自动检测 project.godot。
Godot 可执行文件从 GODOT_PATH 环境变量或 PATH 中解析。
game_fresh¶
作用域:function
函数作用域夹具,为每个测试启动一个全新的 Godot 进程。以速度为代价提供最大隔离。测试失败时自动截图。
失败时截图¶
两个夹具在测试失败时都会自动截图。截图保存到当前工作目录的 test_output/<test_name>_failure.png。