/ tests / cli / test_cli_loading_indicator.py
test_cli_loading_indicator.py
 1  """Regression tests for loading feedback on slow slash commands."""
 2  
 3  from unittest.mock import patch
 4  
 5  from cli import HermesCLI
 6  
 7  
 8  class TestCLILoadingIndicator:
 9      def _make_cli(self):
10          cli_obj = HermesCLI.__new__(HermesCLI)
11          cli_obj._app = None
12          cli_obj._last_invalidate = 0.0
13          cli_obj._command_running = False
14          cli_obj._command_status = ""
15          return cli_obj
16  
17      def test_skills_command_sets_busy_state_and_prints_status(self, capsys):
18          cli_obj = self._make_cli()
19          seen = {}
20  
21          def fake_handle(cmd: str):
22              seen["cmd"] = cmd
23              seen["running"] = cli_obj._command_running
24              seen["status"] = cli_obj._command_status
25              print("skills done")
26  
27          with patch.object(cli_obj, "_handle_skills_command", side_effect=fake_handle), \
28               patch.object(cli_obj, "_invalidate") as invalidate_mock:
29              assert cli_obj.process_command("/skills search kubernetes")
30  
31          output = capsys.readouterr().out
32          assert "⏳ Searching skills..." in output
33          assert "skills done" in output
34          assert seen == {
35              "cmd": "/skills search kubernetes",
36              "running": True,
37              "status": "Searching skills...",
38          }
39          assert cli_obj._command_running is False
40          assert cli_obj._command_status == ""
41          assert invalidate_mock.call_count == 2
42  
43      def test_reload_mcp_sets_busy_state_and_prints_status(self, capsys):
44          cli_obj = self._make_cli()
45          seen = {}
46  
47          def fake_reload():
48              seen["running"] = cli_obj._command_running
49              seen["status"] = cli_obj._command_status
50              print("reload done")
51  
52          # /reload-mcp now wraps the actual reload in a prompt-cache-invalidation
53          # confirmation prompt (commit 4d7fc0f37).  This test exercises the
54          # loading-indicator path, not the confirmation UX, so pre-approve the
55          # reload via config so the handler goes straight into _reload_mcp().
56          fake_cfg = {"approvals": {"mcp_reload_confirm": False}}
57  
58          with patch.object(cli_obj, "_reload_mcp", side_effect=fake_reload), \
59               patch.object(cli_obj, "_invalidate") as invalidate_mock, \
60               patch("cli.load_cli_config", return_value=fake_cfg):
61              assert cli_obj.process_command("/reload-mcp")
62  
63          output = capsys.readouterr().out
64          assert "⏳ Reloading MCP servers..." in output
65          assert "reload done" in output
66          assert seen == {
67              "running": True,
68              "status": "Reloading MCP servers...",
69          }
70          assert cli_obj._command_running is False
71          assert cli_obj._command_status == ""
72          assert invalidate_mock.call_count == 2