diff --git a/backend/internal/web/handlers_tablos_test.go b/backend/internal/web/handlers_tablos_test.go index 2de1959..ede145b 100644 --- a/backend/internal/web/handlers_tablos_test.go +++ b/backend/internal/web/handlers_tablos_test.go @@ -768,6 +768,143 @@ func TestTablosDashboard_EmptyState(t *testing.T) { } } +// ---- TestTablosDashboard_ProgressBar ---- + +// LIST-01: progress bar — verifies that GET / renders a progress bar with label +// "Progression:" and the CSS class "project-card-progress-row" when at least one tablo exists. +func TestTablosDashboard_ProgressBar(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, "progressbar@example.com", "correct-horse-12") + + _, err := q.InsertTablo(ctx, sqlc.InsertTabloParams{ + UserID: user.ID, + Title: "Progress Bar 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, "Progression:") { + t.Errorf("body missing 'Progression:' progress bar label; body: %.500s", body) + } + if !strings.Contains(body, "project-card-progress-row") { + t.Errorf("body missing 'project-card-progress-row' CSS class; body: %.500s", body) + } +} + +// ---- TestTablosDashboard_ViewToggle ---- + +// LIST-02: view toggle — verifies that GET / renders the view toggle button and the +// initial data-view="grid" attribute on the #tablos-list container. +func TestTablosDashboard_ViewToggle(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, "viewtoggle@example.com", "correct-horse-12") + + 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, "view-toggle-btn") { + t.Errorf("body missing 'view-toggle-btn' toggle button class; body: %.500s", body) + } + if !strings.Contains(body, `data-view="grid"`) { + t.Errorf("body missing initial data-view=\"grid\" attribute on #tablos-list; body: %.500s", body) + } +} + +// ---- TestTablosDashboard_StatusBadge ---- + +// LIST-03: status badge — verifies that GET / with at least one tablo renders the "Active" +// status badge and the "tablo-list-row" dual-element structure. +func TestTablosDashboard_StatusBadge(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, "statusbadge@example.com", "correct-horse-12") + + _, err := q.InsertTablo(ctx, sqlc.InsertTabloParams{ + UserID: user.ID, + Title: "Status Badge 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, "Active") { + t.Errorf("body missing 'Active' status badge; body: %.500s", body) + } + if !strings.Contains(body, "tablo-list-row") { + t.Errorf("body missing 'tablo-list-row' dual-element structure; body: %.500s", body) + } +} + // ---- TestTabloDelete ---- // TestTabloDelete verifies that POST /tablos/{id}/delete hard-deletes the row (TABLO-05).