Skip to content

Commit 0f8153b

Browse files
authored
Merge pull request #2 from abhishekanne/tests
Added comprehensive e2e tests for Q CLI commands
2 parents 827f050 + 1ffca35 commit 0f8153b

30 files changed

+1425
-0
lines changed

e2etests/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ session_mgmt = []
1919
integration = []
2020
mcp = []
2121
ai_prompts = []
22+
issue_reporting = []
23+
tools=[]
2224

2325
[[test]]
2426
name = "test_help_command"

e2etests/run_simple_categorized.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ RUN_SESSION_MGMT=true
1515
RUN_INTEGRATION=true
1616
RUN_MCP=true
1717
RUN_AI_PROMPTS=true
18+
RUN_ISSUE_REPORTING=true
19+
RUN_TOOLS=true
1820
# ============================================================================
1921

2022
Q_BINARY="q"
@@ -197,6 +199,22 @@ if [ "$RUN_AI_PROMPTS" = true ]; then
197199
fi
198200
fi
199201

202+
if [ "$RUN_ISSUE_REPORTING" = true ]; then
203+
if run_category "issue_reporting" "ISSUE REPORTING"; then
204+
((total_passed++))
205+
else
206+
((total_failed++))
207+
fi
208+
fi
209+
210+
if [ "$RUN_TOOLS" = true ]; then
211+
if run_category "tools" "TOOLS"; then
212+
((total_passed++))
213+
else
214+
((total_failed++))
215+
fi
216+
fi
217+
200218
# Final summary
201219
echo ""
202220
echo "🎯 FINAL SUMMARY"
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "context")]
5+
fn test_add_file_context() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /context add <filename> command...");
7+
8+
let test_file_path = "/tmp/test_context_file.py";
9+
10+
// Create a test file
11+
std::fs::write(test_file_path, "# Test file for context\nprint('Hello from test file')")?;
12+
println!("✅ Created test file at {}", test_file_path);
13+
14+
let mut chat = QChatSession::new()?;
15+
println!("✅ Q Chat session started");
16+
17+
// Add file to context
18+
let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?;
19+
20+
println!("📝 Context add response: {} bytes", add_response.len());
21+
println!("📝 ADD RESPONSE:");
22+
println!("{}", add_response);
23+
println!("📝 END ADD RESPONSE");
24+
25+
// Verify file was added successfully
26+
assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding file");
27+
println!("✅ File added to context successfully");
28+
29+
// Execute /context show to confirm file is present
30+
let show_response = chat.execute_command("/context show")?;
31+
32+
println!("📝 Context show response: {} bytes", show_response.len());
33+
println!("📝 SHOW RESPONSE:");
34+
println!("{}", show_response);
35+
println!("📝 END SHOW RESPONSE");
36+
37+
// Verify file is present in context
38+
assert!(show_response.contains(test_file_path), "File not found in context show output");
39+
assert!(show_response.contains("💬 Session (temporary):"), "Missing Session section");
40+
println!("✅ File confirmed present in context");
41+
42+
chat.quit()?;
43+
44+
// Clean up test file
45+
let _ = std::fs::remove_file(test_file_path);
46+
println!("✅ Cleaned up test file");
47+
48+
println!("✅ Test completed successfully");
49+
50+
Ok(())
51+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "context")]
5+
fn test_add_glob_pattern_file_context() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /context add *.py glob pattern command...");
7+
8+
let test_file1_path = "/tmp/test_context_file1.py";
9+
let test_file2_path = "/tmp/test_context_file2.py";
10+
let test_file3_path = "/tmp/test_context_file.js"; // Non-matching file
11+
let glob_pattern = "/tmp/*.py";
12+
13+
// Create test files
14+
std::fs::write(test_file1_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?;
15+
std::fs::write(test_file2_path, "# Test Python file 2 for context\nprint('Hello from Python file 2')")?;
16+
std::fs::write(test_file3_path, "// Test JavaScript file\nconsole.log('Hello from JS file');")?;
17+
println!("✅ Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path);
18+
19+
let mut chat = QChatSession::new()?;
20+
println!("✅ Q Chat session started");
21+
22+
// Add glob pattern to context
23+
let add_response = chat.execute_command(&format!("/context add {}", glob_pattern))?;
24+
25+
println!("📝 Context add response: {} bytes", add_response.len());
26+
println!("📝 ADD RESPONSE:");
27+
println!("{}", add_response);
28+
println!("📝 END ADD RESPONSE");
29+
30+
// Verify glob pattern was added successfully
31+
assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding glob pattern");
32+
println!("✅ Glob pattern added to context successfully");
33+
34+
// Execute /context show to confirm pattern matches files
35+
let show_response = chat.execute_command("/context show")?;
36+
37+
println!("📝 Context show response: {} bytes", show_response.len());
38+
println!("📝 SHOW RESPONSE:");
39+
println!("{}", show_response);
40+
println!("📝 END SHOW RESPONSE");
41+
42+
// Verify glob pattern is present and matches files
43+
assert!(show_response.contains(glob_pattern), "Glob pattern not found in context show output");
44+
assert!(show_response.contains("match"), "Missing match indicator for glob pattern");
45+
assert!(show_response.contains("💬 Session (temporary):"), "Missing Session section");
46+
println!("✅ Glob pattern confirmed present in context with matches");
47+
48+
chat.quit()?;
49+
50+
// Clean up test files
51+
let _ = std::fs::remove_file(test_file1_path);
52+
let _ = std::fs::remove_file(test_file2_path);
53+
let _ = std::fs::remove_file(test_file3_path);
54+
println!("✅ Cleaned up test files");
55+
56+
println!("✅ Test completed successfully");
57+
58+
Ok(())
59+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "context")]
5+
fn test_add_multiple_file_context() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /context add <filename1> <filename2> <filename3> command...");
7+
8+
let test_file1_path = "/tmp/test_context_file1.py";
9+
let test_file2_path = "/tmp/test_context_file2.js";
10+
let test_file3_path = "/tmp/test_context_file3.txt";
11+
12+
// Create multiple test files
13+
std::fs::write(test_file1_path, "# Test Python file for context\nprint('Hello from Python file')")?;
14+
std::fs::write(test_file2_path, "// Test JavaScript file for context\nconsole.log('Hello from JS file');")?;
15+
std::fs::write(test_file3_path, "Test text file for context\nHello from text file")?;
16+
println!("✅ Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path);
17+
18+
let mut chat = QChatSession::new()?;
19+
println!("✅ Q Chat session started");
20+
21+
// Add multiple files to context in one command
22+
let add_response = chat.execute_command(&format!("/context add {} {} {}", test_file1_path, test_file2_path, test_file3_path))?;
23+
24+
println!("📝 Context add response: {} bytes", add_response.len());
25+
println!("📝 ADD RESPONSE:");
26+
println!("{}", add_response);
27+
println!("📝 END ADD RESPONSE");
28+
29+
// Verify files were added successfully
30+
assert!(add_response.contains("Added 3 path(s) to context"), "Missing success message for adding multiple files");
31+
println!("✅ Multiple files added to context successfully");
32+
33+
// Execute /context show to confirm files are present
34+
let show_response = chat.execute_command("/context show")?;
35+
36+
println!("📝 Context show response: {} bytes", show_response.len());
37+
println!("📝 SHOW RESPONSE:");
38+
println!("{}", show_response);
39+
println!("📝 END SHOW RESPONSE");
40+
41+
// Verify all files are present in context
42+
assert!(show_response.contains(test_file1_path), "Python file not found in context show output");
43+
assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output");
44+
assert!(show_response.contains(test_file3_path), "Text file not found in context show output");
45+
assert!(show_response.contains("💬 Session (temporary):"), "Missing Session section");
46+
println!("✅ All files confirmed present in context");
47+
48+
chat.quit()?;
49+
50+
// Clean up test files
51+
let _ = std::fs::remove_file(test_file1_path);
52+
let _ = std::fs::remove_file(test_file2_path);
53+
let _ = std::fs::remove_file(test_file3_path);
54+
println!("✅ Cleaned up test files");
55+
56+
println!("✅ Test completed successfully");
57+
58+
Ok(())
59+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "context")]
5+
fn test_add_non_existing_file_context() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /context add non-existing file command...");
7+
8+
let non_existing_file_path = "/tmp/non_existing_file.py";
9+
10+
let mut chat = QChatSession::new()?;
11+
println!("✅ Q Chat session started");
12+
13+
// Try to add non-existing file to context
14+
let add_response = chat.execute_command(&format!("/context add {}", non_existing_file_path))?;
15+
16+
println!("📝 Context add response: {} bytes", add_response.len());
17+
println!("📝 ADD RESPONSE:");
18+
println!("{}", add_response);
19+
println!("📝 END ADD RESPONSE");
20+
21+
// Verify error message for non-existing file
22+
assert!(add_response.contains("Error:") && add_response.contains("Invalid path") && add_response.contains("does not exist"), "Missing error message for non-existing file");
23+
assert!(add_response.contains("Use --force to add anyway"), "Missing --force suggestion in error message");
24+
println!("✅ Found expected error message for non-existing file with --force suggestion");
25+
26+
chat.quit()?;
27+
28+
println!("✅ Test completed successfully");
29+
30+
Ok(())
31+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "context")]
5+
fn test_clear_context_command() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /context clear command...");
7+
8+
let test_file1_path = "/tmp/test_context_file1.py";
9+
let test_file2_path = "/tmp/test_context_file2.js";
10+
11+
// Create multiple test files
12+
std::fs::write(test_file1_path, "# Test Python file for context\nprint('Hello from Python file')")?;
13+
std::fs::write(test_file2_path, "// Test JavaScript file for context\nconsole.log('Hello from JS file');")?;
14+
println!("✅ Created test files at {}, {}", test_file1_path, test_file2_path);
15+
16+
let mut chat = QChatSession::new()?;
17+
println!("✅ Q Chat session started");
18+
19+
// Add multiple files to context
20+
let add_response = chat.execute_command(&format!("/context add {} {}", test_file1_path, test_file2_path))?;
21+
22+
println!("📝 Context add response: {} bytes", add_response.len());
23+
println!("📝 ADD RESPONSE:");
24+
println!("{}", add_response);
25+
println!("📝 END ADD RESPONSE");
26+
27+
// Verify files were added successfully
28+
assert!(add_response.contains("Added 2 path(s) to context"), "Missing success message for adding files");
29+
println!("✅ Files added to context successfully");
30+
31+
// Execute /context show to confirm files are present
32+
let show_response = chat.execute_command("/context show")?;
33+
34+
println!("📝 Context show response: {} bytes", show_response.len());
35+
println!("📝 SHOW RESPONSE:");
36+
println!("{}", show_response);
37+
println!("📝 END SHOW RESPONSE");
38+
39+
// Verify files are present in context
40+
assert!(show_response.contains(test_file1_path), "Python file not found in context show output");
41+
assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output");
42+
println!("✅ Files confirmed present in context");
43+
44+
// Execute /context clear to remove all files
45+
let clear_response = chat.execute_command("/context clear")?;
46+
47+
println!("📝 Context clear response: {} bytes", clear_response.len());
48+
println!("📝 CLEAR RESPONSE:");
49+
println!("{}", clear_response);
50+
println!("📝 END CLEAR RESPONSE");
51+
52+
// Verify context was cleared successfully
53+
assert!(clear_response.contains("Cleared context"), "Missing success message for clearing context");
54+
println!("✅ Context cleared successfully");
55+
56+
// Execute /context show to confirm no files remain
57+
let final_show_response = chat.execute_command("/context show")?;
58+
59+
println!("📝 Final context show response: {} bytes", final_show_response.len());
60+
println!("📝 FINAL SHOW RESPONSE:");
61+
println!("{}", final_show_response);
62+
println!("📝 END FINAL SHOW RESPONSE");
63+
64+
// Verify no files remain in context
65+
assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after clear");
66+
assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after clear");
67+
assert!(final_show_response.contains("👤 Agent (q_cli_default):"), "Missing Agent section");
68+
assert!(final_show_response.contains("💬 Session (temporary):"), "Missing Session section");
69+
assert!(final_show_response.contains("<none>"), "Missing <none> indicator for cleared context");
70+
println!("✅ All files confirmed removed from context and <none> sections present");
71+
72+
chat.quit()?;
73+
74+
// Clean up test files
75+
let _ = std::fs::remove_file(test_file1_path);
76+
let _ = std::fs::remove_file(test_file2_path);
77+
println!("✅ Cleaned up test files");
78+
79+
println!("✅ Test completed successfully");
80+
81+
Ok(())
82+
}

e2etests/tests/test_hooks_command.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "integration")]
5+
fn test_hooks_command() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /hooks command...");
7+
8+
let mut chat = QChatSession::new()?;
9+
println!("✅ Q Chat session started");
10+
11+
let response = chat.execute_command("/hooks")?;
12+
13+
println!("📝 Hooks command response: {} bytes", response.len());
14+
println!("📝 FULL OUTPUT:");
15+
println!("{}", response);
16+
println!("📝 END OUTPUT");
17+
18+
// Verify no hooks configured message
19+
assert!(response.contains("No hooks are configured."), "Missing no hooks configured message");
20+
println!("✅ Found no hooks configured message");
21+
22+
// Verify documentation reference
23+
assert!(response.contains("Refer to the documentation"), "Missing documentation reference");
24+
assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#hooks-field"), "Missing documentation URL");
25+
println!("✅ Found documentation reference and URL");
26+
27+
// Verify hooks field reference
28+
assert!(response.contains("hooks-field"), "Missing hooks field reference");
29+
println!("✅ Found hooks field reference");
30+
31+
println!("✅ All hooks command functionality verified!");
32+
33+
chat.quit()?;
34+
println!("✅ Test completed successfully");
35+
36+
Ok(())
37+
}

e2etests/tests/test_issue_command.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use q_cli_e2e_tests::q_chat_helper::QChatSession;
2+
3+
#[test]
4+
#[cfg(feature = "issue_reporting")]
5+
fn test_issue_command() -> Result<(), Box<dyn std::error::Error>> {
6+
println!("🔍 Testing /issue command with bug report...");
7+
8+
let mut chat = QChatSession::new()?;
9+
println!("✅ Q Chat session started");
10+
11+
let response = chat.execute_command("/issue \"Bug: Q CLI crashes when using large files\"")?;
12+
13+
println!("📝 Issue command response: {} bytes", response.len());
14+
println!("📝 FULL OUTPUT:");
15+
println!("{}", response);
16+
println!("📝 END OUTPUT");
17+
18+
// Verify command executed successfully (GitHub opens automatically)
19+
assert!(response.contains("Heading over to GitHub..."), "Missing browser opening confirmation");
20+
println!("✅ Found browser opening confirmation");
21+
22+
println!("✅ All issue command functionality verified!");
23+
24+
chat.quit()?;
25+
println!("✅ Test completed successfully");
26+
27+
Ok(())
28+
}

0 commit comments

Comments
 (0)