d1318b9fb2
ISSUES CLOSED: #10371
325 lines
14 KiB
Gherkin
325 lines
14 KiB
Gherkin
Feature: TUI App Coverage
|
|
Scenarios exercising previously uncovered code paths in
|
|
cleveragents.tui.app module, including the Textual-based
|
|
application class behind a mocked Textual import gate.
|
|
|
|
Background:
|
|
Given the TUI app module is imported with mocked Textual
|
|
|
|
# --- Module-level import gate (lines 31-38) ---
|
|
|
|
Scenario: Mocked Textual import makes _TEXTUAL_AVAILABLE True
|
|
Then the reloaded app module should have _TEXTUAL_AVAILABLE True
|
|
|
|
Scenario: Mocked Textual import assigns _TextualApp from textual.app
|
|
Then the reloaded app module should expose _TextualCleverAgentsTuiApp
|
|
|
|
# --- textual_available function (line 43-45) ---
|
|
|
|
Scenario: textual_available returns True when Textual is mocked
|
|
Then textual_available should return True on the reloaded module
|
|
|
|
# --- SessionView dataclass (lines 48-54) ---
|
|
|
|
Scenario: SessionView can be created with session_id and transcript
|
|
When I create a SessionView with session_id "sess-1" and transcript entries
|
|
Then the SessionView session_id should be "sess-1"
|
|
And the SessionView transcript should contain 2 entries
|
|
|
|
# --- _CommandRouter protocol (lines 56-61) ---
|
|
|
|
Scenario: A class implementing _CommandRouter protocol can be used
|
|
When I create a _CommandRouter implementation
|
|
Then calling handle on the implementation should return a response
|
|
|
|
# --- _TextualCleverAgentsTuiApp.__init__ (lines 91-100) ---
|
|
|
|
Scenario: The Textual TUI app can be instantiated with mocked Textual
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
Then the app should have a _session with session_id "default"
|
|
And the app should store the command router
|
|
And the app should store the persona state
|
|
|
|
# --- CSS_PATH and BINDINGS class variables (lines 84-89) ---
|
|
|
|
Scenario: The Textual TUI app has correct class variables
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
Then the app class should have CSS_PATH set to "cleveragents.tcss"
|
|
And the app class should have 6 key bindings
|
|
|
|
# --- compose method (lines 102-112) ---
|
|
|
|
Scenario: compose yields the expected widget tree
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call compose on the app
|
|
Then compose should yield at least 5 widgets
|
|
|
|
# --- on_mount method (lines 114-121) ---
|
|
|
|
Scenario: on_mount initialises persona bar and overlays
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
Then the persona bar should have content set
|
|
And the help panel should be hidden on mount
|
|
And the reference picker should have suggestions initialised
|
|
And the slash overlay should be hidden on mount
|
|
|
|
# --- action_help method (lines 123-125) ---
|
|
|
|
Scenario: action_help opens a main-screen help panel
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I call action_help on the app
|
|
Then the help panel text should contain "Help: Main Screen"
|
|
And the help panel text should contain "ctrl+q"
|
|
|
|
Scenario: action_help reflects slash command context
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I set the prompt text to "/persona list"
|
|
And I call action_help on the app
|
|
Then the help panel text should contain "Help: Slash Commands"
|
|
|
|
Scenario: action_help reflects shell mode context
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I set the prompt text to "!ls"
|
|
And I call action_help on the app
|
|
Then the help panel text should contain "Help: Shell Mode"
|
|
|
|
Scenario: action_help toggles the visible help panel off
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I call action_help on the app
|
|
And I call action_help on the app
|
|
Then the help panel should be hidden on mount
|
|
|
|
# --- action_cycle_preset method (lines 127-129) ---
|
|
|
|
Scenario: action_cycle_preset cycles the preset and refreshes the bar
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I call action_cycle_preset on the app
|
|
Then the persona bar content should be refreshed
|
|
|
|
# --- _refresh_persona_bar method (lines 131-142) ---
|
|
|
|
Scenario: _refresh_persona_bar builds scope text from active persona
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call _refresh_persona_bar on the app
|
|
Then the persona bar should display the persona name and scope
|
|
|
|
# --- on_input_submitted with empty text (lines 144-150) ---
|
|
|
|
Scenario: on_input_submitted with empty text returns early
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I submit empty text to the app
|
|
Then the conversation widget should not be updated by input
|
|
|
|
# --- on_input_submitted with command mode (lines 152-167) ---
|
|
|
|
Scenario: on_input_submitted routes slash commands
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I submit "/help" to the app
|
|
Then the conversation widget should contain "handled:help"
|
|
|
|
# --- on_input_submitted with shell mode (lines 168-177) ---
|
|
|
|
Scenario: on_input_submitted routes shell commands
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I submit "!echo tui_shell_test" to the app
|
|
Then the conversation widget should contain "tui_shell_test"
|
|
|
|
Scenario: on_input_submitted surfaces shell safety warnings
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I submit "!rm -rf /tmp" to the app with shell execution mocked
|
|
Then the shell warning indicator should be visible
|
|
And the prompt should be marked as dangerous
|
|
|
|
Scenario: shell warning indicator is cleared after safe command
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I submit "!rm -rf /tmp" to the app with shell execution mocked
|
|
And I submit "!echo cleared" to the app with shell execution mocked
|
|
Then the shell warning indicator should not be visible
|
|
And the prompt should not be marked as dangerous
|
|
|
|
Scenario: shell danger warnings can be disabled via settings
|
|
Given shell danger warnings are disabled in settings
|
|
And a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I submit "!rm -rf /tmp" to the app with shell execution mocked
|
|
Then the shell warning indicator should not be visible
|
|
And the prompt should not be marked as dangerous
|
|
|
|
Scenario: ShellSafetyService owns dangerous command confirmation
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I ask the app to confirm shell command "rm -rf /tmp"
|
|
Then the shell confirmation result should be allowed
|
|
|
|
Scenario: shell confirmation allows safe commands without ShellSafetyService
|
|
Given shell danger warnings are disabled in settings
|
|
And a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I ask the app to confirm shell command "echo safe"
|
|
Then the shell confirmation result should be allowed
|
|
|
|
Scenario: shell confirmation uses the dangerous shell flag without ShellSafetyService
|
|
Given shell danger warnings are disabled in settings
|
|
And a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I ask the app to confirm shell command "rm -rf /tmp"
|
|
Then the shell confirmation result should be blocked
|
|
|
|
Scenario: shell warning callback allows execution when warnings are disabled
|
|
Given shell danger warnings are disabled in settings
|
|
And a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I ask the app to handle a shell warning
|
|
Then the shell warning callback result should be allowed
|
|
|
|
# --- on_input_submitted with shell returning None (lines 170-171) ---
|
|
|
|
Scenario: on_input_submitted handles None shell result
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I submit shell text that produces a None shell result
|
|
Then the conversation widget should contain "(no shell output)"
|
|
|
|
# --- on_input_submitted normal mode with @ reference (lines 179-185) ---
|
|
|
|
Scenario: on_input_submitted handles normal text with @ references
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I submit "check @README" to the app
|
|
Then the conversation widget should contain "check"
|
|
And the reference picker should have been updated
|
|
|
|
# --- on_input_submitted normal mode without @ (line 179, 185) ---
|
|
|
|
Scenario: on_input_submitted handles normal text without references
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I submit "plain message" to the app
|
|
Then the conversation widget should contain "plain message"
|
|
|
|
# --- CleverAgentsTuiApp alias (line 189) ---
|
|
|
|
Scenario: CleverAgentsTuiApp resolves to the Textual app when available
|
|
Then CleverAgentsTuiApp should be _TextualCleverAgentsTuiApp on the reloaded module
|
|
|
|
# --- on_input_submitted shell with stdout output (lines 173-176) ---
|
|
|
|
Scenario: on_input_submitted displays shell stdout and command
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I submit "!echo coverage_run" to the app
|
|
Then the conversation widget should contain "$ echo coverage_run"
|
|
|
|
# --- on_input_submitted shell with empty output (line 174) ---
|
|
|
|
Scenario: on_input_submitted shows empty output for silent shell commands
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I submit "!true" to the app
|
|
Then the conversation widget should contain "(empty output)"
|
|
|
|
# --- THEME class variable (issue #4742) ---
|
|
|
|
@tdd_issue @tdd_issue_4742
|
|
Scenario: The Textual TUI app has THEME set to dracula by default
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
Then the app class should have THEME set to "dracula"
|
|
|
|
# --- action_escape cascade (issue #6450) ---
|
|
|
|
Scenario: action_escape cascades overlays toward the prompt
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I set the prompt text to "draft @README.md"
|
|
And I show the actor selection overlay
|
|
And I show the help panel overlay for context "Main Screen"
|
|
And I show the slash overlay for query "help"
|
|
And I show the reference picker overlay for query "README.md"
|
|
And I call action_escape on the app
|
|
Then the actor selection overlay should be hidden
|
|
And the help panel should remain visible
|
|
When I call action_escape on the app
|
|
Then the help panel should be hidden on mount
|
|
And the slash overlay should remain visible
|
|
When I call action_escape on the app
|
|
Then the slash overlay should be hidden
|
|
And the reference picker overlay should remain visible
|
|
When I call action_escape on the app
|
|
Then the reference picker overlay should be hidden
|
|
And the prompt text should be "draft"
|
|
|
|
# --- on_input_changed handler (live overlay updates) ---
|
|
|
|
Scenario: on_input_changed with slash prefix filters slash commands live
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I trigger on_input_changed with text "/ses"
|
|
Then the slash overlay should show only commands matching "ses"
|
|
And the reference picker should be reset to empty
|
|
|
|
Scenario: on_input_changed with at-sign updates reference picker live
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I trigger on_input_changed with text "@proj"
|
|
Then the reference picker should have been updated
|
|
And the slash overlay should be reset to all commands
|
|
|
|
Scenario: on_input_changed with plain text resets both overlays
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I trigger on_input_changed with text "hello world"
|
|
Then the slash overlay should be reset to all commands
|
|
And the reference picker should be reset to empty
|
|
|
|
Scenario: on_input_changed with empty at-sign resets reference picker
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I trigger on_input_changed with text "send @"
|
|
Then the reference picker should be reset to empty
|
|
|
|
Scenario: on_input_changed with empty text resets both overlays
|
|
Given a mock command router and persona state
|
|
When I instantiate the Textual TUI app
|
|
And I call on_mount on the app
|
|
And I trigger on_input_changed with empty text
|
|
Then the slash overlay should be reset to all commands
|
|
And the reference picker should be reset to empty
|