diff --git a/backend/internal/web/handlers_tablos_test.go b/backend/internal/web/handlers_tablos_test.go index cb6eaf1..c888fd1 100644 --- a/backend/internal/web/handlers_tablos_test.go +++ b/backend/internal/web/handlers_tablos_test.go @@ -596,6 +596,127 @@ func TestTabloDeleteConfirm(t *testing.T) { } } +// ---- TestTablosDashboard_Sidebar ---- + +// TestTablosDashboard_Sidebar verifies that authenticated GET / renders the dashboard +// sidebar shell (DASH-01). Fails RED until AppLayout renders the sidebar components. +func TestTablosDashboard_Sidebar(t *testing.T) { + pool, cleanup := setupTestDB(t) + defer cleanup() + + ctx := context.Background() + q := sqlc.New(pool) + store := auth.NewStore(q) + router := newTabloTestRouter(q, store) + + user := preInsertUser(t, ctx, q, "sidebar@example.com", "correct-horse-12") + cookieVal, _, err := store.Create(ctx, user.ID) + if err != nil { + t.Fatalf("store.Create: %v", err) + } + sessionCookie := &http.Cookie{Name: auth.SessionCookieName, Value: cookieVal} + + req := httptest.NewRequest(http.MethodGet, "/", nil) + req.AddCookie(sessionCookie) + rec := httptest.NewRecorder() + router.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + t.Fatalf("GET / status = %d; want 200", rec.Code) + } + + body := rec.Body.String() + if !strings.Contains(body, "dashboard-sidebar") { + t.Errorf("body missing 'dashboard-sidebar'; body: %.300s", body) + } + if !strings.Contains(body, "sidebar-nav-shell") { + t.Errorf("body missing 'sidebar-nav-shell'; body: %.300s", body) + } +} + +// ---- TestTablosDashboard_ProjectCards ---- + +// TestTablosDashboard_ProjectCards verifies that authenticated GET / with at least +// one tablo renders project-card elements (DASH-02). Fails RED until TabloProjectCard +// template is implemented. +func TestTablosDashboard_ProjectCards(t *testing.T) { + pool, cleanup := setupTestDB(t) + defer cleanup() + + ctx := context.Background() + q := sqlc.New(pool) + store := auth.NewStore(q) + router := newTabloTestRouter(q, store) + + user := preInsertUser(t, ctx, q, "projectcards@example.com", "correct-horse-12") + + _, err := q.InsertTablo(ctx, sqlc.InsertTabloParams{ + UserID: user.ID, + Title: "Project Card Tablo", + Description: pgtype.Text{Valid: false}, + Color: pgtype.Text{Valid: false}, + }) + if err != nil { + t.Fatalf("InsertTablo: %v", err) + } + + cookieVal, _, storeErr := store.Create(ctx, user.ID) + if storeErr != nil { + t.Fatalf("store.Create: %v", storeErr) + } + sessionCookie := &http.Cookie{Name: auth.SessionCookieName, Value: cookieVal} + + req := httptest.NewRequest(http.MethodGet, "/", nil) + req.AddCookie(sessionCookie) + rec := httptest.NewRecorder() + router.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + t.Fatalf("GET / status = %d; want 200", rec.Code) + } + + body := rec.Body.String() + if !strings.Contains(body, "project-card") { + t.Errorf("body missing 'project-card'; body: %.300s", body) + } +} + +// ---- TestTablosDashboard_EmptyState ---- + +// TestTablosDashboard_EmptyState verifies that authenticated GET / with zero tablos +// renders a ui-empty-state element (DASH-03). Fails RED until TablosEmptyState uses +// @ui.EmptyState. +func TestTablosDashboard_EmptyState(t *testing.T) { + pool, cleanup := setupTestDB(t) + defer cleanup() + + ctx := context.Background() + q := sqlc.New(pool) + store := auth.NewStore(q) + router := newTabloTestRouter(q, store) + + user := preInsertUser(t, ctx, q, "emptystate@example.com", "correct-horse-12") + cookieVal, _, err := store.Create(ctx, user.ID) + if err != nil { + t.Fatalf("store.Create: %v", err) + } + sessionCookie := &http.Cookie{Name: auth.SessionCookieName, Value: cookieVal} + + req := httptest.NewRequest(http.MethodGet, "/", nil) + req.AddCookie(sessionCookie) + rec := httptest.NewRecorder() + router.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + t.Fatalf("GET / status = %d; want 200", rec.Code) + } + + body := rec.Body.String() + if !strings.Contains(body, "ui-empty-state") { + t.Errorf("body missing 'ui-empty-state'; body: %.300s", body) + } +} + // ---- TestTabloDelete ---- // TestTabloDelete verifies that POST /tablos/{id}/delete hard-deletes the row (TABLO-05).