- 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
142 lines
3.5 KiB
Go
142 lines
3.5 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"html/template"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"custom-start-page/internal/middleware"
|
|
"custom-start-page/internal/models"
|
|
)
|
|
|
|
// mockPageService is a mock implementation of PageService for testing
|
|
type mockPageService struct {
|
|
pages []*models.Page
|
|
err error
|
|
}
|
|
|
|
func (m *mockPageService) GetPages(ctx context.Context, userID string) ([]*models.Page, error) {
|
|
if m.err != nil {
|
|
return nil, m.err
|
|
}
|
|
return m.pages, nil
|
|
}
|
|
|
|
func (m *mockPageService) CreatePage(ctx context.Context, userID, name string) (*models.Page, error) {
|
|
if m.err != nil {
|
|
return nil, m.err
|
|
}
|
|
page := &models.Page{
|
|
ID: "new-page-id",
|
|
UserID: userID,
|
|
Name: name,
|
|
Order: len(m.pages),
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
m.pages = append(m.pages, page)
|
|
return page, nil
|
|
}
|
|
|
|
func (m *mockPageService) CreateDefaultPage(ctx context.Context, userID string) (*models.Page, error) {
|
|
return m.CreatePage(ctx, userID, "Home")
|
|
}
|
|
|
|
func (m *mockPageService) UpdatePage(ctx context.Context, userID, pageID, name string) (*models.Page, error) {
|
|
if m.err != nil {
|
|
return nil, m.err
|
|
}
|
|
for _, page := range m.pages {
|
|
if page.ID == pageID && page.UserID == userID {
|
|
page.Name = name
|
|
page.UpdatedAt = time.Now()
|
|
return page, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockPageService) DeletePage(ctx context.Context, userID, pageID string) error {
|
|
return m.err
|
|
}
|
|
|
|
func (m *mockPageService) ReorderPages(ctx context.Context, userID string, pageOrder []string) error {
|
|
return m.err
|
|
}
|
|
|
|
// createMockDashboardTemplate creates a simple mock template for testing
|
|
func createMockDashboardTemplate() *template.Template {
|
|
tmpl := template.New("dashboard.html")
|
|
template.Must(tmpl.Parse(`<!DOCTYPE html><html><body><h1>Dashboard</h1><div>User: {{.UserID}}</div></body></html>`))
|
|
return tmpl
|
|
}
|
|
|
|
// TestHandleDashboard_WithAuthenticatedUser tests that authenticated users see the dashboard
|
|
func TestHandleDashboard_WithAuthenticatedUser(t *testing.T) {
|
|
// Setup
|
|
mockTemplate := createMockDashboardTemplate()
|
|
mockPages := []*models.Page{
|
|
{
|
|
ID: "page-1",
|
|
UserID: "test-user-123",
|
|
Name: "Home",
|
|
Order: 0,
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
},
|
|
}
|
|
mockService := &mockPageService{pages: mockPages}
|
|
|
|
handler := &DashboardHandler{
|
|
pageService: mockService,
|
|
templates: mockTemplate,
|
|
}
|
|
|
|
// Create request with user ID in context
|
|
req := httptest.NewRequest(http.MethodGet, "/dashboard", nil)
|
|
ctx := context.WithValue(req.Context(), middleware.GetUserIDContextKey(), "test-user-123")
|
|
req = req.WithContext(ctx)
|
|
w := httptest.NewRecorder()
|
|
|
|
// Execute
|
|
handler.HandleDashboard(w, req)
|
|
|
|
// Assert
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("Expected status 200, got %d", w.Code)
|
|
}
|
|
|
|
// Check that response contains dashboard content
|
|
body := w.Body.String()
|
|
if body == "" {
|
|
t.Error("Expected non-empty response body")
|
|
}
|
|
}
|
|
|
|
// TestHandleDashboard_WithoutUserID tests that requests without user ID fail
|
|
func TestHandleDashboard_WithoutUserID(t *testing.T) {
|
|
// Setup
|
|
mockTemplate := createMockDashboardTemplate()
|
|
mockService := &mockPageService{}
|
|
|
|
handler := &DashboardHandler{
|
|
pageService: mockService,
|
|
templates: mockTemplate,
|
|
}
|
|
|
|
// Create request without user ID in context
|
|
req := httptest.NewRequest(http.MethodGet, "/dashboard", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
// Execute
|
|
handler.HandleDashboard(w, req)
|
|
|
|
// Assert
|
|
if w.Code != http.StatusInternalServerError {
|
|
t.Errorf("Expected status 500, got %d", w.Code)
|
|
}
|
|
}
|