e0d445b92a
Remove empty toggle templates (length-toggle.html, theme-toggle.html, logo-toggle.html) that were just placeholders. The frontend uses hx-swap="none" so the response body was always ignored anyway. Now the handlers: - Set the preference cookie - Return 204 No Content immediately - Hyperscript handles the UI state toggle on the frontend This removes unnecessary template rendering overhead and cleans up dead code. Tests updated to expect 204 instead of 200.
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")
|
|
|
|
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")
|
|
|
|
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")
|
|
|
|
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")
|
|
|
|
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")
|
|
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|