Files
cv-site/internal/handlers/cv_htmx_test.go
T
juanatsap f3842a3486 fix: connect EmailService to contact form handler
The contact form was logging submissions but never actually sending emails.
This commit:
- Adds EmailService field to CVHandler
- Initializes EmailService in main.go with SMTP config
- Calls SendContactForm in HandleContact handler
- Updates all test files to pass nil for emailService parameter
2025-12-02 14:27:03 +00:00

327 lines
7.6 KiB
Go

package handlers
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/juanatsap/cv-site/internal/config"
"github.com/juanatsap/cv-site/internal/templates"
)
// TestToggleLength tests the ToggleLength handler
func TestToggleLength(t *testing.T) {
cfg := &config.TemplateConfig{
Dir: "../../templates",
PartialsDir: "../../templates/partials",
HotReload: true,
}
tmplManager, err := templates.NewManager(cfg)
if err != nil {
t.Fatalf("Failed to create template manager: %v", err)
}
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
tests := []struct {
name string
currentLength string
expectedToggle string
}{
{
name: "Toggle from short to long",
currentLength: "short",
expectedToggle: "long",
},
{
name: "Toggle from long to short",
currentLength: "long",
expectedToggle: "short",
},
{
name: "Toggle from extended (migrated) to short",
currentLength: "extended",
expectedToggle: "short", // extended becomes long, then toggles to short
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/toggle-length", nil)
// Set current length cookie
if tt.currentLength != "" {
req.AddCookie(&http.Cookie{
Name: "cv-length",
Value: tt.currentLength,
})
}
w := httptest.NewRecorder()
handler.ToggleLength(w, req)
// 204 No Content - frontend uses hx-swap="none" so response body is ignored
if w.Code != http.StatusNoContent {
t.Errorf("Expected status No Content (204), got %d", w.Code)
}
// Check that response sets the toggled cookie
cookies := w.Result().Cookies()
found := false
for _, cookie := range cookies {
if cookie.Name == "cv-length" {
found = true
// Note: We can't easily verify the exact value without parsing the template
// But we can verify the cookie was set
}
}
if !found {
t.Error("Expected cv-length cookie to be set in response")
}
})
}
}
// TestToggleIcons tests the ToggleIcons handler
func TestToggleIcons(t *testing.T) {
cfg := &config.TemplateConfig{
Dir: "../../templates",
PartialsDir: "../../templates/partials",
HotReload: true,
}
tmplManager, err := templates.NewManager(cfg)
if err != nil {
t.Fatalf("Failed to create template manager: %v", err)
}
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
tests := []struct {
name string
currentIcons string
}{
{
name: "Toggle from show to hide",
currentIcons: "show",
},
{
name: "Toggle from hide to show",
currentIcons: "hide",
},
{
name: "Toggle from true (migrated)",
currentIcons: "true",
},
{
name: "Toggle from false (migrated)",
currentIcons: "false",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/toggle-icons", nil)
if tt.currentIcons != "" {
req.AddCookie(&http.Cookie{
Name: "cv-icons",
Value: tt.currentIcons,
})
}
w := httptest.NewRecorder()
handler.ToggleIcons(w, req)
// 204 No Content - frontend uses hx-swap="none" so response body is ignored
if w.Code != http.StatusNoContent {
t.Errorf("Expected status No Content (204), got %d", w.Code)
}
})
}
}
// TestSwitchLanguage tests the SwitchLanguage handler
func TestSwitchLanguage(t *testing.T) {
cfg := &config.TemplateConfig{
Dir: "../../templates",
PartialsDir: "../../templates/partials",
HotReload: true,
}
tmplManager, err := templates.NewManager(cfg)
if err != nil {
t.Fatalf("Failed to create template manager: %v", err)
}
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
tests := []struct {
name string
lang string
expectStatus int
}{
{
name: "Switch to English",
lang: "en",
expectStatus: http.StatusOK,
},
{
name: "Switch to Spanish",
lang: "es",
expectStatus: http.StatusOK,
},
{
name: "Invalid language",
lang: "fr",
expectStatus: http.StatusBadRequest,
},
{
name: "Default to English",
lang: "",
expectStatus: http.StatusOK,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/switch-language?lang="+tt.lang, nil)
w := httptest.NewRecorder()
handler.SwitchLanguage(w, req)
if w.Code != tt.expectStatus {
t.Errorf("Expected status %d, got %d", tt.expectStatus, w.Code)
}
if tt.expectStatus == http.StatusOK {
// Verify language cookie was set
cookies := w.Result().Cookies()
found := false
for _, cookie := range cookies {
if cookie.Name == "cv-language" {
found = true
}
}
if !found {
t.Error("Expected cv-language cookie to be set")
}
}
})
}
}
// TestToggleTheme tests the ToggleTheme handler
func TestToggleTheme(t *testing.T) {
cfg := &config.TemplateConfig{
Dir: "../../templates",
PartialsDir: "../../templates/partials",
HotReload: true,
}
tmplManager, err := templates.NewManager(cfg)
if err != nil {
t.Fatalf("Failed to create template manager: %v", err)
}
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
tests := []struct {
name string
currentTheme string
}{
{
name: "Toggle from default to clean",
currentTheme: "default",
},
{
name: "Toggle from clean to default",
currentTheme: "clean",
},
{
name: "Toggle with no cookie (default)",
currentTheme: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/toggle-theme", nil)
if tt.currentTheme != "" {
req.AddCookie(&http.Cookie{
Name: "cv-theme",
Value: tt.currentTheme,
})
}
w := httptest.NewRecorder()
handler.ToggleTheme(w, req)
// 204 No Content - frontend uses hx-swap="none" so response body is ignored
if w.Code != http.StatusNoContent {
t.Errorf("Expected status No Content (204), got %d", w.Code)
}
// Verify theme cookie was set
cookies := w.Result().Cookies()
found := false
for _, cookie := range cookies {
if cookie.Name == "cv-theme" {
found = true
}
}
if !found {
t.Error("Expected cv-theme cookie to be set")
}
})
}
}
// TestHTMXHandlersRequirePost tests that all HTMX handlers reject GET requests
func TestHTMXHandlersRequirePost(t *testing.T) {
cfg := &config.TemplateConfig{
Dir: "../../templates",
PartialsDir: "../../templates/partials",
HotReload: true,
}
tmplManager, err := templates.NewManager(cfg)
if err != nil {
t.Fatalf("Failed to create template manager: %v", err)
}
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
tests := []struct {
name string
handlerFunc func(http.ResponseWriter, *http.Request)
endpoint string
}{
{
name: "ToggleLength rejects GET",
handlerFunc: handler.ToggleLength,
endpoint: "/toggle-length",
},
{
name: "ToggleIcons rejects GET",
handlerFunc: handler.ToggleIcons,
endpoint: "/toggle-icons",
},
{
name: "ToggleTheme rejects GET",
handlerFunc: handler.ToggleTheme,
endpoint: "/toggle-theme",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, tt.endpoint, nil)
w := httptest.NewRecorder()
tt.handlerFunc(w, req)
if w.Code != http.StatusMethodNotAllowed {
t.Errorf("Expected status MethodNotAllowed (405), got %d", w.Code)
}
})
}
}