跳转至

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 -- 该方法在节点上不存在。

示例

result = game.call("/root/Main", "get_counter")
game.call("/root/Main", "add_to_counter", [5])

find_by_group(group) -> list

查找属于某个 Godot 分组(Group)的所有节点。

参数 类型 说明
group str 分组名称。

返回值:绝对节点路径字符串的列表。

示例

enemies = game.find_by_group("enemies")
# ["/root/Main/Enemy1", "/root/Main/Enemy2"]

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_RIGHTKEY_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 绝对节点路径。必须是 ControlNode2D

异常: - 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) 的语法糖。覆盖 ButtonCheckBoxOptionButtonMenuButtonLinkButton


引擎日志捕获

godot-e2e 捕获游戏侧的 push_errorpush_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_logslast_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_logscollected_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 < 0ValueError

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

(要求单匹配)目标在场景树中是否可见。

抛出MultipleMatchesErrorNodeNotFoundError

is_actionable() -> bool

(要求单匹配)目标是否通过全部三项 actionability 检查(visible_in_tree + mouse_filter + viewport 相交)。

抛出MultipleMatchesErrorNodeNotFoundError


Action(每次都重新解析)

每个 action 都会先重跑查询。Locator 必须解析到正好 1 个节点,否则抛 MultipleMatchesError / NodeNotFoundError

click(*, force=False, timeout=5.0)

点击节点的屏幕位置(左键)。Control 节点会轮询 actionability 直至 timeout,超时抛 NotActionableErrorforce=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(Vector2Color 等)会自动序列化。

call(method, args=None)

在节点上调用方法并返回结果。

wait_visible(*, timeout=5.0)

阻塞直至(解析到的)目标通过 actionability 检查。超时或节点始终未出现都抛 NotActionableError(携带结构化 reasonschecks)。

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() 抛错更直接。改用子级 ControlNode2D

遮挡 / hit-test 检测作为单独 ROADMAP 任务跟踪。


expect

godot_e2e.expect

针对 Locator 的自动重试断言。每个 matcher 会在活跃游戏上轮询直到条件满足或超时,超时则抛 ExpectationFailedError——它同时继承 GodotE2EErrorAssertionError,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_propertyis_visibleexists),不引入新的 wire 命令。轮询期间抛出的查找类异常(NodeNotFoundErrorMultipleMatchesErrorCommandError)会被吞掉视作"还没满足",循环继续——这让 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 实例时抛 TypeErrortimeout < 0poll_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 的可见性检查一致)。ControlNode2D 下可靠(两者都用 is_visible_in_tree)。Node3DWindow 和普通 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 内部抛出的查找类异常(NodeNotFoundErrorMultipleMatchesErrorCommandError)会被吞掉视作"还没满足",所以 predicate 可以放心调用要求节点存在的方法。


GodotClient

godot_e2e.GodotClient

低级 TCP 客户端,实现 godot-e2e 的通信协议。通常不需要直接使用此类 -- 请使用 GodotE2E

构造函数

GodotClient(host="127.0.0.1", port=6008)

方法

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_pathGODOT_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_verbosityNone 时必须是 "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

@dataclass
class Vector2:
    x: float
    y: float

Vector2i

@dataclass
class Vector2i:
    x: int
    y: int

Vector3

@dataclass
class Vector3:
    x: float
    y: float
    z: float

Vector3i

@dataclass
class Vector3i:
    x: int
    y: int
    z: int

Rect2

@dataclass
class Rect2:
    x: float
    y: float
    w: float
    h: float

Rect2i

@dataclass
class Rect2i:
    x: int
    y: int
    w: int
    h: int

Color

@dataclass
class Color:
    r: float
    g: float
    b: float
    a: float = 1.0

Transform2D

@dataclass
class Transform2D:
    x: Vector2
    y: Vector2
    origin: Vector2

NodePath

@dataclass
class NodePath:
    path: str

序列化函数

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 / stderrprint / printerr)条目里这三项是空的。__str__ 会渲染为 [LEVEL] message (file:line),便于直接放进失败报告。

LogVerbosity

class LogVerbosity(str, Enum):
    ERROR = "error"
    WARNING = "warning"   # 默认
    INFO = "info"

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_propertyset_propertycallclick_nodewait_for_signal

TimeoutError

class TimeoutError(GodotE2EError):
    def __init__(self, message: str, scene_tree=None):
        self.scene_tree = scene_tree  # dict or None

触发场景:wait_for_nodewait_for_signalwait_for_property

scene_tree 属性包含超时时刻捕获的场景树快照(如果可用),有助于诊断节点未找到的原因。

ConnectionLostError

class ConnectionLostError(GodotE2EError):
    """Raised when the Godot process crashes or the TCP connection drops."""

触发场景:send_command(以及所有发送命令的高级方法)。

CommandError

class CommandError(GodotE2EError):
    """Raised when the server returns an error response."""

当 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