Files
pop/cmd/auth_test.go
Michael Freno d53b8ec8bc FRE-4694: Add CLI command end-to-end tests
Add comprehensive e2e tests for all CLI commands with mocked API
responses. Fix test infrastructure to handle global state (os.Stdout
capture, HOME env var) and broken test parallelism in stdout-capturing
tests.

- Add testutil_test.go with runFreshCommand, setupE2E, mockAPIServer
- Add e2e_full_test.go with ~40 tests covering auth, mail, contacts,
  attachments, folders, labels, drafts, help output
- Add newRootCmdBase() for fresh command trees per test
- Remove t.Parallel() from stdout-capturing and HOME-dependent tests
- Fix SessionWithMockSession to use runFreshCommand (stdout capture)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-04 01:08:26 -04:00

153 lines
3.6 KiB
Go

package cmd
import (
"bytes"
"io"
"os"
"testing"
)
// TestLoginCommand tests the login CLI command
func TestLoginCommand(t *testing.T) {
t.Parallel()
// Create a temporary config file
tmpDir := t.TempDir()
configPath := tmpDir + "/config.yaml"
configContent := `
api:
base_url: "http://localhost:8080"
timeout: 30s
`
err := os.WriteFile(configPath, []byte(configContent), 0644)
if err != nil {
t.Fatalf("Failed to write config: %v", err)
}
// Set config path environment variable
os.Setenv("POP_CONFIG_PATH", configPath)
defer os.Unsetenv("POP_CONFIG_PATH")
// Create root command with login subcommand
rootCmd := NewRootCmd()
rootCmd.SetArgs([]string{"login"})
// Capture output
var buf bytes.Buffer
rootCmd.SetOut(&buf)
rootCmd.SetErr(&buf)
// Execute command
err = rootCmd.Execute()
if err != nil {
// Login requires interactive input, so error is expected in non-interactive mode
t.Logf("Login command executed with error (expected in non-interactive mode): %v", err)
}
// Verify command ran
output := buf.String()
t.Logf("Command output: %s", output)
}
// TestLogoutCommand tests the logout CLI command
func TestLogoutCommand(t *testing.T) {
t.Parallel()
// Create a temporary config file
tmpDir := t.TempDir()
configPath := tmpDir + "/config.yaml"
err := os.WriteFile(configPath, []byte("{}"), 0644)
if err != nil {
t.Fatalf("Failed to write config: %v", err)
}
os.Setenv("POP_CONFIG_PATH", configPath)
defer os.Unsetenv("POP_CONFIG_PATH")
// Create root command with logout subcommand
rootCmd := NewRootCmd()
rootCmd.SetArgs([]string{"logout"})
// Capture output
var buf bytes.Buffer
rootCmd.SetOut(&buf)
rootCmd.SetErr(&buf)
// Execute command
err = rootCmd.Execute()
// Logout may fail if no session exists, which is expected
if err != nil {
t.Logf("Logout command executed with error (expected if no session): %v", err)
}
}
// TestSessionCommand tests the session CLI command
func TestSessionCommand(t *testing.T) {
t.Parallel()
// Create a temporary config file
tmpDir := t.TempDir()
configPath := tmpDir + "/config.yaml"
err := os.WriteFile(configPath, []byte("{}"), 0644)
if err != nil {
t.Fatalf("Failed to write config: %v", err)
}
os.Setenv("POP_CONFIG_PATH", configPath)
defer os.Unsetenv("POP_CONFIG_PATH")
// Create root command with session subcommand
rootCmd := NewRootCmd()
rootCmd.SetArgs([]string{"session"})
// Capture output
var buf bytes.Buffer
rootCmd.SetOut(&buf)
rootCmd.SetErr(&buf)
// Execute command
err = rootCmd.Execute()
// Session may fail if no active session, which is expected
if err != nil {
t.Logf("Session command executed with error (expected if no session): %v", err)
}
}
// TestRootCommandHelp tests the help output
func TestRootCommandHelp(t *testing.T) {
t.Parallel()
rootCmd := NewRootCmd()
rootCmd.SetArgs([]string{"--help"})
var buf bytes.Buffer
rootCmd.SetOut(&buf)
err := rootCmd.Execute()
if err != nil {
t.Fatalf("Help command failed: %v", err)
}
output, _ := io.ReadAll(&buf)
if len(output) == 0 {
t.Error("Help output is empty")
}
// Verify help contains expected commands
helpText := string(output)
expectedCommands := []string{"login", "logout", "session", "mail", "contact", "attachment", "folder", "draft"}
for _, cmd := range expectedCommands {
if !contains(helpText, cmd) {
t.Errorf("Help output missing command: %s", cmd)
}
}
}
// Helper function to check if string contains substring
func contains(s, substr string) bool {
return len(s) > 0 && len(substr) > 0 && (s == substr || len(s) > len(substr) && (s[:len(substr)] == substr || contains(s[1:], substr)))
}