Files
cv-site/internal/handlers/cv_cmdk_test.go
T

203 lines
5.9 KiB
Go
Raw Normal View History

package handlers
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
// TestCmdKData tests the CmdKData handler
// NOTE: This test requires running from project root due to data file path resolution
// Run with: go test ./internal/handlers/ -run TestCmdKData -v
func TestCmdKData(t *testing.T) {
// Skip if running in short mode (CI) - requires project root
if testing.Short() {
t.Skip("Skipping CmdKData test - requires running from project root")
}
handler := newTestCVHandler(t, "localhost:8080", nil)
tests := []struct {
name string
lang string
expectStatus int
expectExperiences bool // should have experiences
expectProjects bool // should have projects
expectCourses bool // should have courses
expectMinExp int // minimum expected experiences
expectMinProj int // minimum expected projects
expectMinCourses int // minimum expected courses
}{
{
name: "Default language (English)",
lang: "",
expectStatus: http.StatusOK,
expectExperiences: true,
expectProjects: true,
expectCourses: true,
expectMinExp: 5,
expectMinProj: 3,
expectMinCourses: 2,
},
{
name: "English language",
lang: "en",
expectStatus: http.StatusOK,
expectExperiences: true,
expectProjects: true,
expectCourses: true,
expectMinExp: 5,
expectMinProj: 3,
expectMinCourses: 2,
},
{
name: "Spanish language",
lang: "es",
expectStatus: http.StatusOK,
expectExperiences: true,
expectProjects: true,
expectCourses: true,
expectMinExp: 5,
expectMinProj: 3,
expectMinCourses: 2,
},
{
name: "Invalid language defaults to English",
lang: "fr",
expectStatus: http.StatusOK,
expectExperiences: true,
expectProjects: true,
expectCourses: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Build query string
query := "/api/cmd-k"
if tt.lang != "" {
query += "?lang=" + tt.lang
}
req := httptest.NewRequest(http.MethodGet, query, nil)
rec := httptest.NewRecorder()
handler.CmdKData(rec, req)
// Check status code
if rec.Code != tt.expectStatus {
t.Errorf("Expected status %d, got %d", tt.expectStatus, rec.Code)
}
// If success, validate JSON response
if rec.Code == http.StatusOK {
// Check content type
contentType := rec.Header().Get("Content-Type")
if contentType != "application/json" {
t.Errorf("Expected Content-Type application/json, got %s", contentType)
}
// Parse JSON response
var response CmdKResponse
if err := json.Unmarshal(rec.Body.Bytes(), &response); err != nil {
t.Fatalf("Failed to parse JSON response: %v", err)
}
// Validate experiences
if tt.expectExperiences && len(response.Experiences) == 0 {
t.Error("Expected experiences but got none")
}
if tt.expectMinExp > 0 && len(response.Experiences) < tt.expectMinExp {
t.Errorf("Expected at least %d experiences, got %d", tt.expectMinExp, len(response.Experiences))
}
// Validate projects
if tt.expectProjects && len(response.Projects) == 0 {
t.Error("Expected projects but got none")
}
if tt.expectMinProj > 0 && len(response.Projects) < tt.expectMinProj {
t.Errorf("Expected at least %d projects, got %d", tt.expectMinProj, len(response.Projects))
}
// Validate courses
if tt.expectCourses && len(response.Courses) == 0 {
t.Error("Expected courses but got none")
}
if tt.expectMinCourses > 0 && len(response.Courses) < tt.expectMinCourses {
t.Errorf("Expected at least %d courses, got %d", tt.expectMinCourses, len(response.Courses))
}
// Validate structure of first experience (if present)
if len(response.Experiences) > 0 {
exp := response.Experiences[0]
if exp.ID == "" {
t.Error("Experience ID should not be empty")
}
if exp.Title == "" {
t.Error("Experience Title should not be empty")
}
if exp.Section != "Experience" {
t.Errorf("Experience Section should be 'Experience', got '%s'", exp.Section)
}
}
// Validate structure of first project (if present)
if len(response.Projects) > 0 {
proj := response.Projects[0]
if proj.ID == "" {
t.Error("Project ID should not be empty")
}
if proj.Title == "" {
t.Error("Project Title should not be empty")
}
if proj.Section != "Projects" {
t.Errorf("Project Section should be 'Projects', got '%s'", proj.Section)
}
}
// Validate structure of first course (if present)
if len(response.Courses) > 0 {
course := response.Courses[0]
if course.ID == "" {
t.Error("Course ID should not be empty")
}
if course.Title == "" {
t.Error("Course Title should not be empty")
}
if course.Section != "Courses" {
t.Errorf("Course Section should be 'Courses', got '%s'", course.Section)
}
}
// Log counts for debugging
t.Logf("Response: %d experiences, %d projects, %d courses",
len(response.Experiences), len(response.Projects), len(response.Courses))
}
})
}
}
// TestCmdKDataCaching tests that the response has proper cache headers
func TestCmdKDataCaching(t *testing.T) {
if testing.Short() {
t.Skip("Skipping CmdKDataCaching test - requires running from project root")
}
handler := newTestCVHandler(t, "localhost:8080", nil)
req := httptest.NewRequest(http.MethodGet, "/api/cmd-k", nil)
rec := httptest.NewRecorder()
handler.CmdKData(rec, req)
// Check cache header
cacheControl := rec.Header().Get("Cache-Control")
if cacheControl == "" {
t.Error("Expected Cache-Control header to be set")
}
if cacheControl != "public, max-age=3600" {
t.Errorf("Expected Cache-Control 'public, max-age=3600', got '%s'", cacheControl)
}
}