f3842a3486
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
327 lines
7.6 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|