xtablo-source/backend/internal/web/handlers_etapes_test.go
2026-05-15 22:33:40 +02:00

225 lines
6.6 KiB
Go

package web
import (
"context"
"net/http"
"net/http/httptest"
"net/url"
"os"
"strings"
"testing"
"backend/internal/auth"
"backend/internal/db/sqlc"
"github.com/jackc/pgx/v5/pgtype"
)
func newEtapeTestRouter(q *sqlc.Queries, store *auth.Store) http.Handler {
authDeps := AuthDeps{Queries: q, Store: store, Secure: false}
tabloDeps := TablosDeps{Queries: q}
taskDeps := TasksDeps{Queries: q}
etapeDeps := EtapesDeps{Queries: q}
router, err := NewRouter(stubPinger{}, os.DirFS("./static"), authDeps, tabloDeps, taskDeps, etapeDeps, FilesDeps{Queries: q}, testCSRFKey, "dev", "localhost")
if err != nil {
panic("newEtapeTestRouter: " + err.Error())
}
return router
}
func TestEtapeCreateRendersChipAndCount(t *testing.T) {
pool, cleanup := setupTestDB(t)
defer cleanup()
ctx := context.Background()
q := sqlc.New(pool)
store := auth.NewStore(q)
router := newEtapeTestRouter(q, store)
user := preInsertUser(t, ctx, q, "etapecreate@example.com", "correct-horse-12")
tablo, err := q.InsertTablo(ctx, sqlc.InsertTabloParams{
UserID: user.ID,
Title: "Etape Create Tablo",
Description: pgtype.Text{Valid: false},
Color: pgtype.Text{Valid: false},
})
if err != nil {
t.Fatalf("InsertTablo: %v", err)
}
cookieVal, _, err := store.Create(ctx, user.ID)
if err != nil {
t.Fatalf("store.Create: %v", err)
}
sessionCookie := &http.Cookie{Name: auth.SessionCookieName, Value: cookieVal}
csrfToken, csrfCookies := getCSRFToken(t, router, "/tablos/"+tablo.ID.String()+"/tasks", []*http.Cookie{sessionCookie})
form := url.Values{
"title": {"Design"},
"_csrf": {csrfToken},
}
req := httptest.NewRequest(http.MethodPost, "/tablos/"+tablo.ID.String()+"/etapes", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("HX-Request", "true")
for _, c := range csrfCookies {
req.AddCookie(c)
}
rec := httptest.NewRecorder()
router.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("POST /tablos/{id}/etapes status = %d; want 200", rec.Code)
}
body := rec.Body.String()
for _, want := range []string{"Design", "Unassigned", "All"} {
if !strings.Contains(body, want) {
t.Errorf("response body missing %q; body: %.500s", want, body)
}
}
}
func TestTaskCreateAssignsEtape(t *testing.T) {
pool, cleanup := setupTestDB(t)
defer cleanup()
ctx := context.Background()
q := sqlc.New(pool)
store := auth.NewStore(q)
router := newEtapeTestRouter(q, store)
user := preInsertUser(t, ctx, q, "tasketapecreate@example.com", "correct-horse-12")
tablo, err := q.InsertTablo(ctx, sqlc.InsertTabloParams{
UserID: user.ID,
Title: "Task Etape Create Tablo",
Description: pgtype.Text{Valid: false},
Color: pgtype.Text{Valid: false},
})
if err != nil {
t.Fatalf("InsertTablo: %v", err)
}
etape, err := q.InsertEtape(ctx, sqlc.InsertEtapeParams{
TabloID: tablo.ID,
Title: "Design",
Description: pgtype.Text{Valid: false},
Position: 100,
})
if err != nil {
t.Fatalf("InsertEtape: %v", err)
}
cookieVal, _, err := store.Create(ctx, user.ID)
if err != nil {
t.Fatalf("store.Create: %v", err)
}
sessionCookie := &http.Cookie{Name: auth.SessionCookieName, Value: cookieVal}
csrfToken, csrfCookies := getCSRFToken(t, router, "/tablos/"+tablo.ID.String()+"/tasks", []*http.Cookie{sessionCookie})
form := url.Values{
"title": {"Assigned Task"},
"status": {"todo"},
"etape_id": {etape.ID.String()},
"_csrf": {csrfToken},
}
req := httptest.NewRequest(http.MethodPost, "/tablos/"+tablo.ID.String()+"/tasks", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("HX-Request", "true")
for _, c := range csrfCookies {
req.AddCookie(c)
}
rec := httptest.NewRecorder()
router.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("POST /tablos/{id}/tasks status = %d; want 200", rec.Code)
}
tasks, err := q.ListTasksByTablo(ctx, tablo.ID)
if err != nil {
t.Fatalf("ListTasksByTablo: %v", err)
}
if len(tasks) != 1 {
t.Fatalf("task count = %d; want 1", len(tasks))
}
if !tasks[0].EtapeID.Valid || tasks[0].EtapeID.Bytes != etape.ID {
t.Fatalf("task etape_id = %+v; want %s", tasks[0].EtapeID, etape.ID)
}
}
func TestEtapeFilterRendersExistingKanbanColumns(t *testing.T) {
pool, cleanup := setupTestDB(t)
defer cleanup()
ctx := context.Background()
q := sqlc.New(pool)
store := auth.NewStore(q)
router := newEtapeTestRouter(q, store)
user := preInsertUser(t, ctx, q, "etapefilter@example.com", "correct-horse-12")
tablo, err := q.InsertTablo(ctx, sqlc.InsertTabloParams{
UserID: user.ID,
Title: "Etape Filter Tablo",
Description: pgtype.Text{Valid: false},
Color: pgtype.Text{Valid: false},
})
if err != nil {
t.Fatalf("InsertTablo: %v", err)
}
etape, err := q.InsertEtape(ctx, sqlc.InsertEtapeParams{
TabloID: tablo.ID,
Title: "Design",
Description: pgtype.Text{Valid: false},
Position: 100,
})
if err != nil {
t.Fatalf("InsertEtape: %v", err)
}
_, err = q.InsertTask(ctx, sqlc.InsertTaskParams{
TabloID: tablo.ID,
Title: "Assigned Task",
Description: pgtype.Text{Valid: false},
Status: sqlc.TaskStatusTodo,
Position: 100,
EtapeID: pgtype.UUID{Bytes: etape.ID, Valid: true},
})
if err != nil {
t.Fatalf("InsertTask assigned: %v", err)
}
_, err = q.InsertTask(ctx, sqlc.InsertTaskParams{
TabloID: tablo.ID,
Title: "Unassigned Task",
Description: pgtype.Text{Valid: false},
Status: sqlc.TaskStatusTodo,
Position: 200,
EtapeID: pgtype.UUID{Valid: false},
})
if err != nil {
t.Fatalf("InsertTask unassigned: %v", err)
}
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, "/tablos/"+tablo.ID.String()+"/tasks?etape="+etape.ID.String(), nil)
req.Header.Set("HX-Request", "true")
req.AddCookie(sessionCookie)
rec := httptest.NewRecorder()
router.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("GET /tablos/{id}/tasks?etape status = %d; want 200", rec.Code)
}
body := rec.Body.String()
for _, col := range []string{"To do", "In progress", "In review", "Done"} {
if !strings.Contains(body, col) {
t.Errorf("filtered kanban missing column header %q", col)
}
}
if !strings.Contains(body, "Assigned Task") {
t.Errorf("filtered body missing assigned task; body: %.500s", body)
}
if strings.Contains(body, "Unassigned Task") {
t.Errorf("filtered body includes unassigned task; body: %.500s", body)
}
}