From 4f4d5823dc9ac9727dd390ce2a996009e4c672d3 Mon Sep 17 00:00:00 2001 From: CleverAgents Bot Date: Thu, 18 Jun 2026 06:20:02 -0400 Subject: [PATCH] fix(tui): scope MainScreen behave steps --- features/steps/tui_main_screen_steps.py | 63 ++++++++++++++++++++++++- features/tui_main_screen.feature | 15 +++++- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/features/steps/tui_main_screen_steps.py b/features/steps/tui_main_screen_steps.py index fe1759baf..e6dd527c7 100644 --- a/features/steps/tui_main_screen_steps.py +++ b/features/steps/tui_main_screen_steps.py @@ -24,6 +24,7 @@ from cleveragents.tui.main_screen import ( Sidebar, SidebarState, Throbber, + _load_textual_attr, ) @@ -35,6 +36,24 @@ _WIDGET_NAME_TO_CLASS: dict[str, type] = { } +class _MainScreenActionHarness: + """Minimal object implementing the query API used by MainScreen actions.""" + + def __init__(self) -> None: + self.flash_bar = FlashBar() + self.session_tabs = SessionTabs() + self.session_tabs.add_session("Session 1") + self.session_tabs.add_session("Session 2") + + def query_one(self, selector, widget_type): + if selector == "#flash-bar" and widget_type is FlashBar: + return self.flash_bar + if selector == "#session-tabs" and widget_type is SessionTabs: + return self.session_tabs + msg = f"unexpected query_one({selector!r}, {widget_type!r})" + raise AssertionError(msg) + + def _app_theme() -> str: """Return ``CleverAgentsTuiApp.THEME`` or the expected default. @@ -100,7 +119,7 @@ def step_mainscreen_mounted(context): context.throbber = Throbber() -@then('the theme should be "{theme}"') +@then('the MainScreen theme should be "{theme}"') def step_theme_is(context, theme): """Verify the App's theme is the expected value.""" assert _app_theme() == theme, f"Expected theme {theme!r}, got {_app_theme()!r}" @@ -403,7 +422,7 @@ def step_session_tabs_count(context, count, session_name): ) -@then("there is no active session") +@then("the MainScreen has no active session") def step_no_active_session(context): """Verify the active session is None.""" assert context.session_tabs.active_session is None, ( @@ -416,3 +435,43 @@ def step_flash_bar_rendered_contains(context, expected): """Verify the raw rendered output of the flash bar contains ``expected``.""" rendered = context.flash_bar.render() assert expected in rendered, f"Expected {expected!r} in {rendered!r}" + + +@given("a MainScreen action harness") +def step_main_screen_action_harness(context): + """Create a minimal receiver for MainScreen action methods.""" + context.action_harness = _MainScreenActionHarness() + context.flash_bar = context.action_harness.flash_bar + context.session_tabs = context.action_harness.session_tabs + + +@when( + 'the MainScreen action shows a flash message "{message}" of type "{message_type}"' +) +def step_main_screen_action_show_flash_message(context, message, message_type): + """Invoke MainScreen.action_show_flash_message against the harness.""" + MainScreen.action_show_flash_message( + context.action_harness, + message, + message_type, + ) + + +@when('the MainScreen action sets "{session_name}" as the active session') +def step_main_screen_action_set_active_session(context, session_name): + """Invoke MainScreen.action_set_active_session against the harness.""" + MainScreen.action_set_active_session(context.action_harness, session_name) + + +@when('the MainScreen import helper loads "{attr}" from "{module_name}"') +def step_main_screen_import_helper_loads(context, attr, module_name): + """Load an existing attribute through the optional import helper.""" + context.loaded_attr = _load_textual_attr(module_name, attr) + + +@then("the loaded attribute should be callable") +def step_loaded_attribute_callable(context): + """Verify the import helper returned the requested attribute.""" + assert callable(context.loaded_attr), ( + f"Expected callable, got {context.loaded_attr!r}" + ) diff --git a/features/tui_main_screen.feature b/features/tui_main_screen.feature index fac61d1fd..1342af1c7 100644 --- a/features/tui_main_screen.feature +++ b/features/tui_main_screen.feature @@ -9,7 +9,7 @@ Feature: TUI MainScreen with Dracula theme and 3-state sidebar Scenario: MainScreen initializes with correct theme When the MainScreen is mounted - Then the theme should be "dracula" + Then the MainScreen theme should be "dracula" And the screen should have a session tabs widget And the screen should have a sidebar widget And the screen should have a flash bar widget @@ -141,9 +141,20 @@ Feature: TUI MainScreen with Dracula theme and 3-state sidebar And the session tabs contain "Session 1" When the user sets "Session 1" as the active session And the user removes the session "Session 1" - Then there is no active session + Then the MainScreen has no active session Scenario: Flash bar with unknown message type uses generic prefix Given the MainScreen is mounted When the user shows a flash message "ping" of type "mystery" Then the flash bar rendered output contains "* ping" + + Scenario: MainScreen actions delegate to mounted widgets + Given a MainScreen action harness + When the MainScreen action shows a flash message "Saved" of type "success" + Then the flash bar rendered output contains "(v) Saved" + When the MainScreen action sets "Session 2" as the active session + Then "Session 2" should be the active session + + Scenario: MainScreen import helper returns existing attributes + When the MainScreen import helper loads "import_module" from "importlib" + Then the loaded attribute should be callable