- Implemented PageService with full CRUD operations - Added GetPages, CreatePage, UpdatePage, DeletePage, ReorderPages methods - Cascade deletion of widgets when page is deleted - Prevention of last page deletion - Created page HTTP endpoints (GET, POST, PUT, DELETE, reorder) - HTMX-friendly HTML fragment responses - Comprehensive unit tests for service and handlers - Updated dashboard to use PageService and create default pages
252 lines
7.1 KiB
Go
252 lines
7.1 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"html/template"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"custom-start-page/internal/middleware"
|
|
)
|
|
|
|
// createMockPageTemplate creates a simple mock template for testing
|
|
func createMockPageTemplate() *template.Template {
|
|
tmpl := template.New("base")
|
|
|
|
// Define page-tabs template
|
|
template.Must(tmpl.New("page-tabs.html").Parse(`{{define "page-tabs.html"}}{{range .Pages}}<button>{{.Name}}</button>{{end}}{{end}}`))
|
|
|
|
// Define widget-grid template
|
|
template.Must(tmpl.New("widget-grid.html").Parse(`{{define "widget-grid.html"}}<div>Widgets for page {{.PageID}}</div>{{end}}`))
|
|
|
|
// Define page-tab template
|
|
template.Must(tmpl.New("page-tab.html").Parse(`{{define "page-tab.html"}}<button>{{.Page.Name}}</button>{{end}}`))
|
|
|
|
return tmpl
|
|
}
|
|
|
|
// TestHandleGetPage tests retrieving a page's widget grid
|
|
func TestHandleGetPage(t *testing.T) {
|
|
// Setup
|
|
mockTemplate := createMockPageTemplate()
|
|
mockService := &mockPageService{}
|
|
|
|
handler := &PageHandler{
|
|
pageService: mockService,
|
|
templates: mockTemplate,
|
|
}
|
|
|
|
// Create request with user ID in context
|
|
req := httptest.NewRequest(http.MethodGet, "/pages/page-1", nil)
|
|
req.SetPathValue("id", "page-1")
|
|
ctx := context.WithValue(req.Context(), middleware.GetUserIDContextKey(), "test-user-123")
|
|
req = req.WithContext(ctx)
|
|
w := httptest.NewRecorder()
|
|
|
|
// Execute
|
|
handler.HandleGetPage(w, req)
|
|
|
|
// Assert
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("Expected status 200, got %d", w.Code)
|
|
}
|
|
|
|
body := w.Body.String()
|
|
if !strings.Contains(body, "page-1") {
|
|
t.Errorf("Expected response to contain page ID, got: %s", body)
|
|
}
|
|
}
|
|
|
|
// TestHandleCreatePage tests creating a new page
|
|
func TestHandleCreatePage(t *testing.T) {
|
|
// Setup
|
|
mockTemplate := createMockPageTemplate()
|
|
mockService := &mockPageService{}
|
|
|
|
handler := &PageHandler{
|
|
pageService: mockService,
|
|
templates: mockTemplate,
|
|
}
|
|
|
|
// Create form data
|
|
form := url.Values{}
|
|
form.Add("name", "New Page")
|
|
|
|
// Create request with user ID in context
|
|
req := httptest.NewRequest(http.MethodPost, "/pages", strings.NewReader(form.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
ctx := context.WithValue(req.Context(), middleware.GetUserIDContextKey(), "test-user-123")
|
|
req = req.WithContext(ctx)
|
|
w := httptest.NewRecorder()
|
|
|
|
// Execute
|
|
handler.HandleCreatePage(w, req)
|
|
|
|
// Assert
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("Expected status 200, got %d", w.Code)
|
|
}
|
|
|
|
// Verify page was created
|
|
if len(mockService.pages) != 1 {
|
|
t.Errorf("Expected 1 page to be created, got %d", len(mockService.pages))
|
|
}
|
|
|
|
if mockService.pages[0].Name != "New Page" {
|
|
t.Errorf("Expected page name 'New Page', got '%s'", mockService.pages[0].Name)
|
|
}
|
|
}
|
|
|
|
// TestHandleCreatePage_InvalidName tests creating a page with invalid name
|
|
func TestHandleCreatePage_InvalidName(t *testing.T) {
|
|
// Setup
|
|
mockTemplate := createMockPageTemplate()
|
|
mockService := &mockPageService{}
|
|
|
|
handler := &PageHandler{
|
|
pageService: mockService,
|
|
templates: mockTemplate,
|
|
}
|
|
|
|
// Test empty name
|
|
form := url.Values{}
|
|
form.Add("name", "")
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/pages", strings.NewReader(form.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
ctx := context.WithValue(req.Context(), middleware.GetUserIDContextKey(), "test-user-123")
|
|
req = req.WithContext(ctx)
|
|
w := httptest.NewRecorder()
|
|
|
|
handler.HandleCreatePage(w, req)
|
|
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("Expected status 400 for empty name, got %d", w.Code)
|
|
}
|
|
|
|
// Test name too long
|
|
form = url.Values{}
|
|
form.Add("name", strings.Repeat("a", 51))
|
|
|
|
req = httptest.NewRequest(http.MethodPost, "/pages", strings.NewReader(form.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
ctx = context.WithValue(req.Context(), middleware.GetUserIDContextKey(), "test-user-123")
|
|
req = req.WithContext(ctx)
|
|
w = httptest.NewRecorder()
|
|
|
|
handler.HandleCreatePage(w, req)
|
|
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("Expected status 400 for name too long, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
// TestHandleUpdatePage tests updating a page
|
|
func TestHandleUpdatePage(t *testing.T) {
|
|
// Setup
|
|
mockTemplate := createMockPageTemplate()
|
|
mockService := &mockPageService{}
|
|
|
|
// Create initial page
|
|
_, _ = mockService.CreatePage(context.Background(), "test-user-123", "Old Name")
|
|
|
|
handler := &PageHandler{
|
|
pageService: mockService,
|
|
templates: mockTemplate,
|
|
}
|
|
|
|
// Create form data
|
|
form := url.Values{}
|
|
form.Add("name", "Updated Name")
|
|
|
|
// Create request with user ID in context
|
|
req := httptest.NewRequest(http.MethodPut, "/pages/new-page-id", strings.NewReader(form.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
req.SetPathValue("id", "new-page-id")
|
|
ctx := context.WithValue(req.Context(), middleware.GetUserIDContextKey(), "test-user-123")
|
|
req = req.WithContext(ctx)
|
|
w := httptest.NewRecorder()
|
|
|
|
// Execute
|
|
handler.HandleUpdatePage(w, req)
|
|
|
|
// Assert
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("Expected status 200, got %d", w.Code)
|
|
}
|
|
|
|
// Verify page was updated
|
|
if mockService.pages[0].Name != "Updated Name" {
|
|
t.Errorf("Expected page name 'Updated Name', got '%s'", mockService.pages[0].Name)
|
|
}
|
|
}
|
|
|
|
// TestHandleDeletePage tests deleting a page
|
|
func TestHandleDeletePage(t *testing.T) {
|
|
// Setup
|
|
mockTemplate := createMockPageTemplate()
|
|
mockService := &mockPageService{}
|
|
|
|
// Create two pages
|
|
_, _ = mockService.CreatePage(context.Background(), "test-user-123", "Page 1")
|
|
_, _ = mockService.CreatePage(context.Background(), "test-user-123", "Page 2")
|
|
|
|
handler := &PageHandler{
|
|
pageService: mockService,
|
|
templates: mockTemplate,
|
|
}
|
|
|
|
// Create request with user ID in context
|
|
req := httptest.NewRequest(http.MethodDelete, "/pages/page-1", nil)
|
|
req.SetPathValue("id", "page-1")
|
|
ctx := context.WithValue(req.Context(), middleware.GetUserIDContextKey(), "test-user-123")
|
|
req = req.WithContext(ctx)
|
|
w := httptest.NewRecorder()
|
|
|
|
// Execute
|
|
handler.HandleDeletePage(w, req)
|
|
|
|
// Assert
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("Expected status 200, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
// TestHandleReorderPages tests reordering pages
|
|
func TestHandleReorderPages(t *testing.T) {
|
|
// Setup
|
|
mockTemplate := createMockPageTemplate()
|
|
mockService := &mockPageService{}
|
|
|
|
// Create pages
|
|
_, _ = mockService.CreatePage(context.Background(), "test-user-123", "Page 1")
|
|
_, _ = mockService.CreatePage(context.Background(), "test-user-123", "Page 2")
|
|
|
|
handler := &PageHandler{
|
|
pageService: mockService,
|
|
templates: mockTemplate,
|
|
}
|
|
|
|
// Create form data with JSON array
|
|
form := url.Values{}
|
|
form.Add("order", `["page-2", "page-1"]`)
|
|
|
|
// Create request with user ID in context
|
|
req := httptest.NewRequest(http.MethodPost, "/pages/reorder", strings.NewReader(form.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
ctx := context.WithValue(req.Context(), middleware.GetUserIDContextKey(), "test-user-123")
|
|
req = req.WithContext(ctx)
|
|
w := httptest.NewRecorder()
|
|
|
|
// Execute
|
|
handler.HandleReorderPages(w, req)
|
|
|
|
// Assert
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("Expected status 200, got %d", w.Code)
|
|
}
|
|
}
|