Files
hermes-agent/tests/tools/test_tip_tool.py
T
Teknium c1762ff11c test: sweep sibling tests stale on the tool renames + deferral default
The rename sweep in the base commit missed the sibling-test blast radius
(18 red files on CI). Three classes, all fixed:

1. Stale old names in tests (todo/cronjob/process/tour/tip) — updated to
   todo_list/cronjob_manage/process_manage/gui_tour/show_tip at every
   registry.get_entry/dispatch/coerce/preview/allowlist call site, plus
   the coding-brief sentence in agent/coding_context.py now names
   todo_list (and its gating test).
2. Missed rename in production: AGENT_RUNTIME_POST_HOOK_TOOL_NAMES still
   held 'tour' — post-hook ownership would have double-emitted for
   gui_tour via the bridge path.
3. Tests pinning pre-deferral assembly (blank-slate surface, modal
   sandbox resolution, desktop diet, HUD note) now pin their ACTUAL
   contract under the legacy defer:[] override, or assert on granted
   tool names instead of visible schemas.

Also fixes a pre-existing ordering flake surfaced by the sweep:
test_holds_exactly_the_gui_affordances depended on whether an earlier
test had imported apply_layout_tool (registry-registered, not in the
static desktop_ui list) — now forces discovery and pins the full set.

649 tests green locally across all touched files, both orderings.
2026-08-29 18:23:07 -07:00

88 lines
2.6 KiB
Python

"""Tests for the GUI-surface ``tip`` tool."""
import json
import pytest
from tools import tip_tool as tt
from tools.registry import registry
@pytest.fixture
def emitted(monkeypatch):
"""Capture what the desktop bridge is asked to send, and say it landed."""
sent = []
def _emit(event, payload):
sent.append((event, payload))
return True
monkeypatch.setattr(tt.desktop_ui, "emit", _emit)
return sent
def test_lives_in_the_gui_surface_toolset(monkeypatch):
"""Scoped by toolset, not by the backend's env — see AGENTS.md."""
monkeypatch.delenv("HERMES_DESKTOP", raising=False)
entry = registry.get_entry("show_tip")
assert entry is not None
assert entry.toolset == "desktop_ui"
def test_is_ungated_like_tour():
"""The Appearance switch governs the app's idle rotation, not this."""
entry = registry.get_entry("show_tip")
assert entry is not None
assert entry.check_fn is None
def test_requires_the_desktop_bridge(monkeypatch):
"""Outside the desktop GUI there is no emitter — a clear error, no crash."""
monkeypatch.setattr(tt.desktop_ui, "emit", lambda _event, _payload: False)
result = json.loads(tt.tip_tool(text="Over here", selector="#composer"))
assert "desktop" in result["error"]
def test_needs_both_something_to_say_and_somewhere_to_point(emitted):
assert "tip needs text" in json.loads(tt.tip_tool(text="", selector="#a"))["error"]
assert "tip needs a selector" in json.loads(tt.tip_tool(text="Hi", selector=" "))["error"]
assert not emitted
def test_rejects_an_unknown_side(emitted):
result = json.loads(tt.tip_tool(text="Hi", selector="#a", side="diagonal"))
assert "side must be one of" in result["error"]
assert not emitted
def test_emits_the_renderer_event_omitting_unset_fields(emitted):
result = json.loads(tt.tip_tool(text=" The model name is a button ", selector=" #model "))
assert result == {"success": True, "selector": "#model"}
assert emitted == [("tip.show", {"selector": "#model", "text": "The model name is a button"})]
def test_carries_title_and_side_when_given(emitted):
tt.tip_tool(text="Type here", selector="#composer", title="Composer", side="top")
assert emitted[0][1] == {
"selector": "#composer",
"text": "Type here",
"title": "Composer",
"side": "top",
}
def test_bridge_failure_is_reported(monkeypatch):
def _boom(_event, _payload):
raise RuntimeError("renderer went away")
monkeypatch.setattr(tt.desktop_ui, "emit", _boom)
assert "renderer went away" in json.loads(tt.tip_tool(text="Hi", selector="#a"))["error"]