feat: 添加测试框架及功能测试用例

test: 实现BDD测试框架及功能测试
docs: 添加测试配置文件及文档
refactor: 重构命令处理逻辑以支持测试
This commit is contained in:
Yuyao Huang (Sam)
2026-03-29 04:24:27 +08:00
parent 6cf2143987
commit 8dab229aaf
22 changed files with 906 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
Feature: Direct (passthrough) mode — bypass LLM for CC sessions
Background:
Given user "user_abc123" is sending commands
And run_claude returns "Done. Here is the result."
Scenario: Passthrough sends directly to CC without LLM
Given user has session "sess01" in "/tmp/proj1"
And active session is "sess01"
And direct mode is enabled for user "user_abc123"
When user sends agent message "run the tests"
Then run_claude was called
And reply contains "Done. Here is the result."
Scenario: Passthrough on missing session clears active conv
Given active session is "ghost_session_id" which does not exist
And direct mode is enabled for user "user_abc123"
When user sends agent message "hello"
Then active session for user "user_abc123" is None
+35
View File
@@ -0,0 +1,35 @@
Feature: LLM smart routing — agent routes messages to correct tools
Background:
Given user "user_abc123" is in smart mode
And run_claude returns "I created the component for you."
@vcr
Scenario: Agent creates new session for project task
Given vcr cassette "agent/routing_new_session.yaml"
When user sends agent message "create a React app in todo_app folder"
Then agent created a session for user "user_abc123"
And reply is not empty
@vcr
Scenario: Agent answers general question without creating session
Given vcr cassette "agent/routing_general_qa.yaml"
When user sends agent message "what is a Python generator?"
Then no session is created for user "user_abc123"
And reply is not empty
@vcr
Scenario: Agent sends follow-up to existing session
Given user has active session "sess01" in "/tmp/proj1"
And vcr cassette "agent/routing_follow_up.yaml"
When user sends agent message "now add tests for that"
Then run_claude was called
And reply is not empty
@vcr
Scenario: Agent answers direct QA without tools when no active session
Given no active session for user "user_abc123"
And vcr cassette "agent/routing_direct_qa.yaml"
When user sends agent message "explain async/await in Python"
Then reply is not empty
And reply does not contain "Max iterations"
+38
View File
@@ -0,0 +1,38 @@
Feature: /close command — terminate a session
Background:
Given user "user_abc123" is sending commands
Scenario: No sessions returns error
When user sends "/close"
Then reply contains "No sessions to close"
Scenario: Close active session by default
Given user has session "sess01" in "/tmp/proj1"
And active session is "sess01"
When user sends "/close"
Then reply contains "Closed session"
And session manager has 0 sessions for user "user_abc123"
Scenario: Close session by number
Given user has session "sess01" in "/tmp/proj1"
And user has session "sess02" in "/tmp/proj2"
When user sends "/close 1"
Then reply contains "Closed session"
And session manager has 1 session for user "user_abc123"
Scenario: Invalid number returns error
Given user has session "sess01" in "/tmp/proj1"
When user sends "/close 9"
Then reply contains "Invalid session number"
Scenario: Cannot close another user's session
Given session "sess01" in "/tmp/proj1" belongs to user "other_user"
When user sends "/close sess01"
Then reply contains "belongs to another user"
Scenario: Closing active session clears active conv
Given user has session "sess01" in "/tmp/proj1"
And active session is "sess01"
When user sends "/close"
Then active session for user "user_abc123" is None
@@ -0,0 +1,27 @@
Feature: /direct and /smart mode toggle
Background:
Given user "user_abc123" is sending commands
Scenario: /direct requires active session
When user sends "/direct"
Then reply contains "No active session"
Scenario: /direct enables passthrough mode
Given user has session "sess01" in "/tmp/proj1"
And active session is "sess01"
When user sends "/direct"
Then reply contains "Direct mode ON"
And passthrough mode is enabled for user "user_abc123"
Scenario: /smart disables passthrough mode
Given user has session "sess01" in "/tmp/proj1"
And active session is "sess01"
And direct mode is enabled for user "user_abc123"
When user sends "/smart"
Then reply contains "Smart mode ON"
And passthrough mode is disabled for user "user_abc123"
Scenario: /smart always succeeds even without active session
When user sends "/smart"
Then reply contains "Smart mode ON"
+25
View File
@@ -0,0 +1,25 @@
Feature: /help command — show command reference
Background:
Given user "user_abc123" is sending commands
Scenario: /help lists all commands
When user sends "/help"
Then reply contains "/new"
And reply contains "/status"
And reply contains "/close"
And reply contains "/switch"
And reply contains "/direct"
And reply contains "/smart"
And reply contains "/shell"
And reply contains "/remind"
And reply contains "/tasks"
And reply contains "/nodes"
Scenario: /h alias works
When user sends "/h"
Then reply contains "/new"
Scenario: Unknown command is not handled
When user sends "/unknown_xyz_cmd"
Then command is not handled
+37
View File
@@ -0,0 +1,37 @@
Feature: /new command — create a Claude Code session
Background:
Given user "user_abc123" is sending commands
Scenario: No arguments shows usage
When user sends "/new"
Then reply contains "Usage: /new"
Scenario: Creates session with valid directory
Given run_claude returns "Session ready."
When user sends "/new myproject"
Then reply contains "myproject"
And session manager has 1 session for user "user_abc123"
Scenario: Creates session with initial message
Given run_claude returns "Fixed the bug."
When user sends "/new myproject fix the login bug"
Then reply contains "myproject"
Scenario: Path traversal attempt is blocked
When user sends "/new ../../etc"
Then reply contains "Error"
And session manager has 0 sessions for user "user_abc123"
Scenario: Custom timeout is accepted
Given run_claude returns "Done."
When user sends "/new myproject --timeout 60"
Then reply contains "myproject"
And reply contains "timeout: 60s"
Scenario: Creates session and sends card when chat_id is set
Given the current chat_id is "chat_xyz"
And run_claude returns "Ready."
When user sends "/new myproject"
Then a sessions card is sent to chat "chat_xyz"
And text reply is empty
+13
View File
@@ -0,0 +1,13 @@
Feature: /nodes and /node commands — multi-host node management
Background:
Given user "user_abc123" is sending commands
And ROUTER_MODE is disabled
Scenario: /nodes outside router mode returns explanation
When user sends "/nodes"
Then reply contains "Not in router mode"
Scenario: /node outside router mode returns explanation
When user sends "/node myhost"
Then reply contains "Not in router mode"
+33
View File
@@ -0,0 +1,33 @@
Feature: /remind command — schedule a one-time reminder
Background:
Given user "user_abc123" is sending commands
And the current chat_id is "chat_xyz"
Scenario: No arguments shows usage
When user sends "/remind"
Then reply contains "Usage: /remind"
Scenario: Missing message part shows usage
When user sends "/remind 10m"
Then reply contains "Usage: /remind"
Scenario: Invalid time format returns error
When user sends "/remind badtime check build"
Then reply contains "Invalid time format"
Scenario: Valid reminder with seconds is scheduled
When user sends "/remind 30s check the build"
Then reply contains "Reminder #"
And reply contains "30s"
And scheduler has 1 pending job
Scenario: Valid reminder with minutes is scheduled
When user sends "/remind 5m deploy done"
Then reply contains "5m"
And scheduler has 1 pending job
Scenario: Valid reminder with hours is scheduled
When user sends "/remind 2h weekly report"
Then reply contains "2h"
And scheduler has 1 pending job
+22
View File
@@ -0,0 +1,22 @@
Feature: /shell command — run host shell commands
Background:
Given user "user_abc123" is sending commands
Scenario: No arguments shows usage
When user sends "/shell"
Then reply contains "Usage: /shell"
Scenario: Runs echo and returns output
When user sends "/shell echo hello"
Then reply contains "hello"
And reply contains "exit code: 0"
Scenario: Blocked dangerous command is rejected
When user sends "/shell rm -rf /"
Then reply contains "Blocked"
And reply does not contain "exit code"
Scenario: Non-zero exit code is reported
When user sends "/shell exit 1"
Then reply contains "exit code"
+40
View File
@@ -0,0 +1,40 @@
Feature: /status command — list sessions and current mode
Background:
Given user "user_abc123" is sending commands
Scenario: No sessions returns empty message
When user sends "/status"
Then reply contains "No active sessions"
Scenario: Shows session list
Given user has session "sess01" in "/tmp/proj1"
And user has session "sess02" in "/tmp/proj2"
When user sends "/status"
Then reply contains "sess01"
And reply contains "sess02"
Scenario: Shows active marker on current session
Given user has session "sess01" in "/tmp/proj1"
And active session is "sess01"
When user sends "/status"
Then reply contains ""
Scenario: Shows current mode as Smart by default
Given user has session "sess01" in "/tmp/proj1"
When user sends "/status"
Then reply contains "Smart"
Scenario: Shows Direct mode after /direct
Given user has session "sess01" in "/tmp/proj1"
And active session is "sess01"
And direct mode is enabled for user "user_abc123"
When user sends "/status"
Then reply contains "Direct"
Scenario: Sends card when chat_id is set
Given user has session "sess01" in "/tmp/proj1"
And the current chat_id is "chat_xyz"
When user sends "/status"
Then a sessions card is sent to chat "chat_xyz"
And text reply is empty
+30
View File
@@ -0,0 +1,30 @@
Feature: /switch command — activate a different session
Background:
Given user "user_abc123" is sending commands
Scenario: No sessions returns error
When user sends "/switch 1"
Then reply contains "No sessions available"
Scenario: Valid switch updates active session
Given user has session "sess01" in "/tmp/proj1"
And user has session "sess02" in "/tmp/proj2"
When user sends "/switch 2"
Then reply contains "Switched to session"
And active session for user "user_abc123" is "sess02"
Scenario: Out of range number returns error
Given user has session "sess01" in "/tmp/proj1"
When user sends "/switch 5"
Then reply contains "Invalid session number"
Scenario: Non-numeric argument returns error
Given user has session "sess01" in "/tmp/proj1"
When user sends "/switch notanumber"
Then reply contains "Invalid number"
Scenario: Missing argument shows usage
Given user has session "sess01" in "/tmp/proj1"
When user sends "/switch"
Then reply contains "Usage: /switch"
+27
View File
@@ -0,0 +1,27 @@
Feature: /tasks command — list background tasks
Background:
Given user "user_abc123" is sending commands
Scenario: No tasks returns empty message
When user sends "/tasks"
Then reply contains "No background tasks"
Scenario: Shows running task with spinner emoji
Given there is a running task "task001" described as "CC session abc: fix bug"
When user sends "/tasks"
Then reply contains "task001"
And reply contains "fix bug"
And reply contains ""
Scenario: Shows completed task with checkmark
Given there is a completed task "task002" described as "CC session xyz: deploy"
When user sends "/tasks"
Then reply contains "task002"
And reply contains ""
Scenario: Shows failed task with cross
Given there is a failed task "task003" described as "CC session err: bad cmd"
When user sends "/tasks"
Then reply contains "task003"
And reply contains ""