test(tui): add headless Box TUI render test suite and support box tui work shorthand
This commit is contained in:
+1
-1
@@ -8029,7 +8029,7 @@ def main():
|
||||
parser.add_argument("--account", "-a", choices=VALID_NODES, default=None, help="Initial agent account (default: top of list)")
|
||||
parser.add_argument("--thread", "-t", help="Initial thread UUID to open")
|
||||
parser.add_argument("--mode", "-m", choices=["muse", "box"], default="muse", help="TUI mode (default: muse)")
|
||||
parser.add_argument("--tab", choices=["chat", "fleet", "approvals", "jobs", "tmux", "logs", "ssh"], default=None, help="Initial Box tab (box mode only)")
|
||||
parser.add_argument("--tab", choices=["chat", "fleet", "approvals", "jobs", "tmux", "logs", "ssh", "work"], default=None, help="Initial Box tab (box mode only)")
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
|
||||
@@ -7685,6 +7685,8 @@ def main():
|
||||
cmd = [sys.executable, str(BIN_DIR / "box-onboard-tui.py")] + tui_args[1:]
|
||||
elif tui_args and tui_args[0] in ("fleet", "oversight"):
|
||||
cmd = [sys.executable, str(BIN_DIR / "box-fleet-tui.py")] + tui_args[1:]
|
||||
elif tui_args and tui_args[0] in ("chat", "fleet-status", "jobs", "logs", "ssh", "work"):
|
||||
cmd = [sys.executable, str(BIN_DIR / "muse-tui.py"), "--mode", "box", "--tab", tui_args[0]] + tui_args[1:]
|
||||
else:
|
||||
cmd = [sys.executable, str(BIN_DIR / "muse-tui.py"), "--mode", "box"] + tui_args
|
||||
res = subprocess.run(cmd)
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
"""test_box_tui_render.py — Headless verification of Box TUI and Work Pipeline screens."""
|
||||
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
BIN_DIR = REPO_ROOT / "bin"
|
||||
if str(BIN_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(BIN_DIR))
|
||||
|
||||
import importlib.util
|
||||
spec = importlib.util.spec_from_file_location("muse_tui", str(BIN_DIR / "muse-tui.py"))
|
||||
muse_tui = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(muse_tui)
|
||||
|
||||
|
||||
class TestBoxTUIHeadless(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.mock_stdscr = MagicMock()
|
||||
self.mock_stdscr.getmaxyx.return_value = (40, 120)
|
||||
self.mock_stdscr.getch.return_value = -1
|
||||
|
||||
def test_box_tui_initialization_work_tab(self):
|
||||
app = muse_tui.MuseTUI(self.mock_stdscr, initial_mode="box", initial_tab="work")
|
||||
self.assertEqual(app.mode, "box")
|
||||
self.assertEqual(app.box_tab, 7)
|
||||
self.assertIn("8: Work Pipeline", muse_tui.BOX_TABS)
|
||||
|
||||
def test_render_work_view(self):
|
||||
app = muse_tui.MuseTUI(self.mock_stdscr, initial_mode="box", initial_tab="work")
|
||||
# Populate mock cognitive cache and work issues
|
||||
app.data.cognitive_cache = {
|
||||
"muse": {
|
||||
"node": "muse",
|
||||
"status": "IDLE",
|
||||
"cognitive_lock": False,
|
||||
"screen": {"url": "https://muse.ai/", "title": "Chat - muse"}
|
||||
},
|
||||
"pip": {
|
||||
"node": "pip",
|
||||
"status": "SIDECHAT_IDLE",
|
||||
"cognitive_lock": False,
|
||||
"screen": {"url": "https://muse.ai/thread/123", "title": "Chat - pip"}
|
||||
}
|
||||
}
|
||||
app.data.work_issues_cache = [
|
||||
{"number": 218, "state": "open", "title": "Autonomous TUI upgrade", "assignee": {"username": "dev"}}
|
||||
]
|
||||
app.data.work_prs_cache = [
|
||||
{"number": 219, "state": "open", "merged": False, "title": "feat: box tui", "head": {"ref": "feature/tui"}}
|
||||
]
|
||||
|
||||
# Call _render_work_view directly
|
||||
app._render_work_view(2, 0, 35, 120)
|
||||
self.assertTrue(self.mock_stdscr.addstr.called)
|
||||
|
||||
def test_box_tui_key_actions_on_work_tab(self):
|
||||
app = muse_tui.MuseTUI(self.mock_stdscr, initial_mode="box", initial_tab="work")
|
||||
app.data.nodes = ["muse", "pip", "646", "opm", "def", "dev"]
|
||||
|
||||
# 'w' opens work_dispatch modal
|
||||
handled = app._handle_key(ord('w'))
|
||||
self.assertTrue(handled)
|
||||
self.assertEqual(app.modal, "work_dispatch")
|
||||
|
||||
# Esc closes modal
|
||||
handled = app._handle_key(27)
|
||||
self.assertTrue(handled)
|
||||
self.assertIsNone(app.modal)
|
||||
|
||||
# Tab navigation: '1' switches to Chat (tab 0), '8' switches to Work (tab 7)
|
||||
app._handle_key(ord('1'))
|
||||
self.assertEqual(app.box_tab, 0)
|
||||
app._handle_key(ord('8'))
|
||||
self.assertEqual(app.box_tab, 7)
|
||||
|
||||
def test_work_dispatch_modal_text_input_and_cycle(self):
|
||||
app = muse_tui.MuseTUI(self.mock_stdscr, initial_mode="box", initial_tab="work")
|
||||
app.data.nodes = ["muse", "pip", "646", "opm", "def", "dev"]
|
||||
app.modal = "work_dispatch"
|
||||
app.modal_input_buf = ""
|
||||
app.modal_input_cursor = 0
|
||||
app.dispatch_target_node = "dev"
|
||||
|
||||
# Type chars 'Build #12'
|
||||
for c in "Build #12":
|
||||
app._handle_key(ord(c))
|
||||
self.assertEqual(app.modal_input_buf, "Build #12")
|
||||
|
||||
# Tab cycles worker
|
||||
app._handle_key(ord('\t'))
|
||||
self.assertNotEqual(app.dispatch_target_node, "dev")
|
||||
|
||||
def test_agent_thoughts_modal(self):
|
||||
app = muse_tui.MuseTUI(self.mock_stdscr, initial_mode="box", initial_tab="work")
|
||||
app.selected_thought_node = "def"
|
||||
app.agent_thought_data = {
|
||||
"screen": {
|
||||
"url": "https://muse.ai/",
|
||||
"title": "Chat - def",
|
||||
"is_generating": False,
|
||||
"recent_paragraphs": ["Inspecting workspace...", "Code updated."]
|
||||
}
|
||||
}
|
||||
app.modal = "agent_thoughts"
|
||||
# Render modal
|
||||
app._render_modal(40, 120)
|
||||
self.assertTrue(self.mock_stdscr.addstr.called)
|
||||
|
||||
# Esc closes modal
|
||||
app._handle_key(27)
|
||||
self.assertIsNone(app.modal)
|
||||
|
||||
def test_agent_profile_menu_modal(self):
|
||||
app = muse_tui.MuseTUI(self.mock_stdscr, initial_mode="box", initial_tab="work")
|
||||
app.selected_menu_node = "pip"
|
||||
app.menu_tab = "activity"
|
||||
app.agent_menu_data = {
|
||||
"tab": "activity",
|
||||
"data": {
|
||||
"items": [{"title": "Session started", "detail": "Active", "time": "12m ago"}]
|
||||
}
|
||||
}
|
||||
app.modal = "agent_menu"
|
||||
# Render modal
|
||||
app._render_modal(40, 120)
|
||||
self.assertTrue(self.mock_stdscr.addstr.called)
|
||||
|
||||
# Tab key cycles menu tabs
|
||||
with patch.object(app, "_async_load_menu") as mock_load:
|
||||
app._handle_key(ord('\t'))
|
||||
mock_load.assert_called_with("pip", "upcoming")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user