fix(tui): apply ruff format and expand behave coverage for new TUI screens
- session_management.py: collapse three multi-line statements that
ruff format would otherwise reformat (CI lint gate was failing on
`ruff format --check`).
- features/tui_settings_session_screens.feature: add three scenarios
that exercise the previously uncovered paths reported by
diff_coverage on prior attempts:
- SettingsScreen.get_settings() returns a settings dict
- SessionManagementScreen renders sessions when visible+loaded
(covers the render-loop body + _render_session_details
non-None branch + the four detail lines)
- TuiCommandRouter routes "/settings" to _settings_command
- features/steps/tui_settings_session_screens_steps.py:
- Make `the selected_index should be {index:d}` look up whichever
screen the scenario created (the step was always referencing
`context.settings_screen`, which crashed in the
SessionManagementScreen scenarios).
- Reuse the existing TuiCommandRouter steps from
tui_commands_coverage_steps.py for the /settings scenario.
The unit_tests / integration_tests CI gates on the prior run were
red on tests unrelated to this PR (CheckpointRepository and
actor_run_signature.robot, neither touched here); the targeted
behave run for this PR's feature file passes locally with all 12
scenarios green.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
from behave import given, then, when
|
||||
|
||||
from cleveragents.tui.commands import TuiCommandRouter
|
||||
from cleveragents.tui.screens.session_management import (
|
||||
SessionInfo,
|
||||
SessionManagementScreen,
|
||||
@@ -110,8 +111,14 @@ def step_verify_settings_not_visible(context):
|
||||
|
||||
@then("the selected_index should be {index:d}")
|
||||
def step_verify_selected_index(context, index):
|
||||
"""Verify the selected index."""
|
||||
assert context.settings_screen.selected_index == index
|
||||
"""Verify the selected index on whichever screen was created in this scenario."""
|
||||
screen = getattr(context, "session_screen", None) or getattr(
|
||||
context, "settings_screen", None
|
||||
)
|
||||
assert screen is not None, "no screen widget created in this scenario"
|
||||
assert screen.selected_index == index, (
|
||||
f"expected selected_index={index}, got {screen.selected_index}"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -221,3 +228,51 @@ def step_verify_selected_session_none(context):
|
||||
"""Verify get_selected_session returns None."""
|
||||
session = context.session_screen.get_selected_session()
|
||||
assert session is None
|
||||
|
||||
|
||||
@then(
|
||||
'get_settings should return theme "{theme}", default_actor "{actor}", '
|
||||
'safety_level "{level}"'
|
||||
)
|
||||
def step_verify_get_settings(context, theme, actor, level):
|
||||
"""Verify get_settings returns the expected settings dict."""
|
||||
settings = context.settings_screen.get_settings()
|
||||
assert settings == {
|
||||
"theme": theme,
|
||||
"default_actor": actor,
|
||||
"safety_level": level,
|
||||
}
|
||||
|
||||
|
||||
@then('the session screen rendered text should contain "{text}"')
|
||||
def step_verify_session_rendered_text_contains(context, text):
|
||||
"""Verify the rendered SessionManagementScreen text contains the given fragment."""
|
||||
assert text in context.session_screen._text, (
|
||||
f"expected {text!r} in rendered text, got: {context.session_screen._text!r}"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TuiCommandRouter /settings route scenarios
|
||||
# ---------------------------------------------------------------------------
|
||||
class _FakePersonaRegistry:
|
||||
"""Minimal persona registry stub for /settings routing tests."""
|
||||
|
||||
def list_personas(self):
|
||||
return []
|
||||
|
||||
|
||||
class _FakePersonaState:
|
||||
"""Minimal persona state stub for /settings routing tests."""
|
||||
|
||||
def get_active(self, session_id):
|
||||
return None
|
||||
|
||||
|
||||
@given("a TuiCommandRouter for settings tests")
|
||||
def step_router_for_settings(context):
|
||||
"""Create a TuiCommandRouter with minimal stubs for the /settings route."""
|
||||
context.router = TuiCommandRouter(
|
||||
persona_registry=_FakePersonaRegistry(), # type: ignore[arg-type]
|
||||
persona_state=_FakePersonaState(), # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
@@ -36,6 +36,13 @@ Feature: TUI Settings and Session Management Screens
|
||||
And the default_actor should be "admin"
|
||||
And the safety_level should be "high"
|
||||
|
||||
Scenario: SettingsScreen returns current settings as dict
|
||||
Given a SettingsScreen widget
|
||||
When I set the theme to "light"
|
||||
And I set the default_actor to "admin"
|
||||
And I set the safety_level to "high"
|
||||
Then get_settings should return theme "light", default_actor "admin", safety_level "high"
|
||||
|
||||
# ---------- SessionManagementScreen ----------
|
||||
|
||||
Scenario: SessionManagementScreen initializes empty
|
||||
@@ -67,3 +74,18 @@ Feature: TUI Settings and Session Management Screens
|
||||
Scenario: SessionManagementScreen returns None when no sessions
|
||||
Given a SessionManagementScreen widget
|
||||
Then get_selected_session should return None
|
||||
|
||||
Scenario: SessionManagementScreen renders sessions when visible
|
||||
Given a SessionManagementScreen widget
|
||||
When I show the session management screen
|
||||
And I load 3 sessions
|
||||
Then the session screen rendered text should contain "Session 1"
|
||||
And the session screen rendered text should contain "10 msgs"
|
||||
And the session screen rendered text should contain "[CURRENT]"
|
||||
|
||||
# ---------- TuiCommandRouter /settings route ----------
|
||||
|
||||
Scenario: TuiCommandRouter routes /settings to settings command
|
||||
Given a TuiCommandRouter for settings tests
|
||||
When I call handle with raw input "settings"
|
||||
Then the handle result should be "Settings screen opened"
|
||||
|
||||
@@ -48,9 +48,7 @@ def _render_session_list(
|
||||
for i, session in enumerate(sessions):
|
||||
prefix = "❯ " if i == selected_index else " " # noqa: RUF001
|
||||
current = " [CURRENT]" if session.session_id == current_session_id else ""
|
||||
lines.append(
|
||||
f"{prefix}{session.name} ({session.message_count} msgs){current}"
|
||||
)
|
||||
lines.append(f"{prefix}{session.name} ({session.message_count} msgs){current}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
@@ -70,9 +68,7 @@ def _render_session_details(session: SessionInfo | None) -> str:
|
||||
|
||||
def _render_status_bar() -> str:
|
||||
"""Render the status bar at the bottom of the screen."""
|
||||
return (
|
||||
"j/k Nav │ enter Switch │ r Rename │ d Delete │ n New │ esc Close"
|
||||
)
|
||||
return "j/k Nav │ enter Switch │ r Rename │ d Delete │ n New │ esc Close"
|
||||
|
||||
|
||||
def _render_screen(
|
||||
@@ -85,9 +81,7 @@ def _render_screen(
|
||||
selected_session = sessions[selected_index] if sessions else None
|
||||
session_details = _render_session_details(selected_session)
|
||||
status_bar = _render_status_bar()
|
||||
return (
|
||||
f"Session Management\n\n{session_list}\n\n{session_details}\n\n{status_bar}"
|
||||
)
|
||||
return f"Session Management\n\n{session_list}\n\n{session_details}\n\n{status_bar}"
|
||||
|
||||
|
||||
class SessionManagementScreen(_StaticBase):
|
||||
|
||||
Reference in New Issue
Block a user