xtablo-source/go-backend/internal/web/views/tablo_detail_view_test.go
Arthur Belleville f24e1c4d35
test(20-01): add failing tests for TabloDetailViewModel + GetTabloDetailPage handler
- TestComputeTabloProgress_{Empty,AllDone,Half,EtapesIgnored}
- TestNewTabloDetailViewModel_{GroupsTasksByStatus,EtapesExcludedFromColumns,EtapesPopulated}
- TestGetTabloDetailPage_{Returns200,Returns404,Returns400,Unauthenticated}
- TestTabloDetailKanbanColumns
- TestGetTabloDetailPage_ContainsSortableScript
2026-05-18 15:44:53 +02:00

244 lines
6 KiB
Go

package views
import (
"testing"
"time"
"github.com/google/uuid"
tablomodel "xtablo-backend/internal/tablos"
taskmodel "xtablo-backend/internal/tasks"
)
func makeTask(status taskmodel.Status, isEtape bool) taskmodel.Record {
return taskmodel.Record{
ID: uuid.New(),
TabloID: uuid.New(),
OwnerID: uuid.New(),
Title: "Task " + string(status),
Status: status,
IsEtape: isEtape,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
}
func makeTablo() tablomodel.Record {
return tablomodel.Record{
ID: uuid.New(),
OwnerID: uuid.New(),
Name: "Test Tablo",
Color: "#3B82F6",
Status: tablomodel.StatusTodo,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
}
func TestComputeTabloProgress_Empty(t *testing.T) {
got := computeTabloProgress([]taskmodel.Record{})
if got != 0 {
t.Fatalf("expected 0, got %d", got)
}
}
func TestComputeTabloProgress_AllDone(t *testing.T) {
tasks := []taskmodel.Record{
makeTask(taskmodel.StatusDone, false),
makeTask(taskmodel.StatusDone, false),
}
got := computeTabloProgress(tasks)
if got != 100 {
t.Fatalf("expected 100, got %d", got)
}
}
func TestComputeTabloProgress_Half(t *testing.T) {
tasks := []taskmodel.Record{
makeTask(taskmodel.StatusDone, false),
makeTask(taskmodel.StatusTodo, false),
}
got := computeTabloProgress(tasks)
if got != 50 {
t.Fatalf("expected 50, got %d", got)
}
}
func TestComputeTabloProgress_EtapesIgnored(t *testing.T) {
tasks := []taskmodel.Record{
makeTask(taskmodel.StatusDone, false),
// etape task — should be excluded from denominator and numerator
makeTask(taskmodel.StatusTodo, true),
}
got := computeTabloProgress(tasks)
if got != 100 {
t.Fatalf("expected 100 (etape ignored), got %d", got)
}
}
func TestNewTabloDetailViewModel_GroupsTasksByStatus(t *testing.T) {
tablo := makeTablo()
todoTask := makeTask(taskmodel.StatusTodo, false)
todoTask.TabloID = tablo.ID
inProgressTask := makeTask(taskmodel.StatusInProgress, false)
inProgressTask.TabloID = tablo.ID
doneTask := makeTask(taskmodel.StatusDone, false)
doneTask.TabloID = tablo.ID
tasks := []taskmodel.Record{todoTask, inProgressTask, doneTask}
vm := NewTabloDetailViewModel(tablo, tasks, "Test User")
if len(vm.Columns) != 4 {
t.Fatalf("expected 4 columns, got %d", len(vm.Columns))
}
columnIDs := []string{"todo", "in_progress", "in_review", "done"}
for i, col := range vm.Columns {
if col.ID != columnIDs[i] {
t.Errorf("column[%d]: expected ID %q, got %q", i, columnIDs[i], col.ID)
}
}
// Column 0 = todo — 1 task
if len(vm.Columns[0].Tasks) != 1 {
t.Errorf("todo column: expected 1 task, got %d", len(vm.Columns[0].Tasks))
}
// Column 1 = in_progress — 1 task
if len(vm.Columns[1].Tasks) != 1 {
t.Errorf("in_progress column: expected 1 task, got %d", len(vm.Columns[1].Tasks))
}
// Column 2 = in_review — 0 tasks
if len(vm.Columns[2].Tasks) != 0 {
t.Errorf("in_review column: expected 0 tasks, got %d", len(vm.Columns[2].Tasks))
}
// Column 3 = done — 1 task
if len(vm.Columns[3].Tasks) != 1 {
t.Errorf("done column: expected 1 task, got %d", len(vm.Columns[3].Tasks))
}
}
func TestNewTabloDetailViewModel_EtapesExcludedFromColumns(t *testing.T) {
tablo := makeTablo()
etapeTask := makeTask(taskmodel.StatusTodo, true)
etapeTask.TabloID = tablo.ID
regularTask := makeTask(taskmodel.StatusTodo, false)
regularTask.TabloID = tablo.ID
tasks := []taskmodel.Record{etapeTask, regularTask}
vm := NewTabloDetailViewModel(tablo, tasks, "")
// Only regular task in todo column
if len(vm.Columns[0].Tasks) != 1 {
t.Errorf("todo column: expected 1 task (etape excluded), got %d", len(vm.Columns[0].Tasks))
}
}
func TestNewTabloDetailViewModel_EtapesPopulated(t *testing.T) {
tablo := makeTablo()
etape1 := taskmodel.Record{
ID: uuid.New(),
TabloID: tablo.ID,
OwnerID: tablo.OwnerID,
Title: "Etape One",
Status: taskmodel.StatusTodo,
IsEtape: true,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
etape2 := taskmodel.Record{
ID: uuid.New(),
TabloID: tablo.ID,
OwnerID: tablo.OwnerID,
Title: "Etape Two",
Status: taskmodel.StatusTodo,
IsEtape: true,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
child1 := taskmodel.Record{
ID: uuid.New(),
TabloID: tablo.ID,
OwnerID: tablo.OwnerID,
Title: "Child A",
Status: taskmodel.StatusTodo,
IsEtape: false,
ParentTaskID: &etape1.ID,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
child2 := taskmodel.Record{
ID: uuid.New(),
TabloID: tablo.ID,
OwnerID: tablo.OwnerID,
Title: "Child B",
Status: taskmodel.StatusInProgress,
IsEtape: false,
ParentTaskID: &etape1.ID,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
orphan := taskmodel.Record{
ID: uuid.New(),
TabloID: tablo.ID,
OwnerID: tablo.OwnerID,
Title: "No Etape",
Status: taskmodel.StatusTodo,
IsEtape: false,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
tasks := []taskmodel.Record{etape1, etape2, child1, child2, orphan}
vm := NewTabloDetailViewModel(tablo, tasks, "")
if len(vm.Etapes) != 2 {
t.Fatalf("expected 2 etapes, got %d", len(vm.Etapes))
}
// Find etape1 in the Etapes slice
var foundEtape1 *TabloDetailEtapeView
for i := range vm.Etapes {
if vm.Etapes[i].ID == etape1.ID.String() {
foundEtape1 = &vm.Etapes[i]
break
}
}
if foundEtape1 == nil {
t.Fatal("etape1 not found in vm.Etapes")
}
if foundEtape1.TaskCount != 2 {
t.Errorf("etape1: expected TaskCount=2, got %d", foundEtape1.TaskCount)
}
// Find etape2 — should have TaskCount=0
var foundEtape2 *TabloDetailEtapeView
for i := range vm.Etapes {
if vm.Etapes[i].ID == etape2.ID.String() {
foundEtape2 = &vm.Etapes[i]
break
}
}
if foundEtape2 == nil {
t.Fatal("etape2 not found in vm.Etapes")
}
if foundEtape2.TaskCount != 0 {
t.Errorf("etape2: expected TaskCount=0, got %d", foundEtape2.TaskCount)
}
}