diff --git a/code/internal/server/timestamp_test.go b/code/internal/server/timestamp_test.go index 44308f7..bdc29c2 100644 --- a/code/internal/server/timestamp_test.go +++ b/code/internal/server/timestamp_test.go @@ -5,6 +5,7 @@ import ( "net/http/httptest" "os" "path/filepath" + "regexp" "strings" "testing" ) @@ -135,6 +136,139 @@ func TestRunTask_AddsTimestamp(t *testing.T) { } } +func TestAppendTimestamp_Format(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "test.md") + os.WriteFile(path, []byte("# T01: Test\n"), 0644) + + appendTimestamp(path, "Pokrenut (→active)") + + content, _ := os.ReadFile(path) + text := string(content) + + // Verify timestamp format YYYY-MM-DD HH:MM + re := regexp.MustCompile(`\| Pokrenut \(→active\) \| \d{4}-\d{2}-\d{2} \d{2}:\d{2} \|`) + if !re.MatchString(text) { + t.Errorf("expected timestamp format YYYY-MM-DD HH:MM, got:\n%s", text) + } +} + +func TestAppendTimestamp_FileNotFound(t *testing.T) { + err := appendTimestamp("/nonexistent/path/task.md", "test") + if err == nil { + t.Error("expected error for nonexistent file") + } +} + +func TestMoveEventLabel_AllFolders(t *testing.T) { + expected := map[string]string{ + "ready": "Odobren (→ready)", + "active": "Pokrenut (→active)", + "review": "Završen (→review)", + "done": "Odobren (→done)", + } + + for folder, label := range expected { + got, ok := moveEventLabel[folder] + if !ok { + t.Errorf("missing label for folder %s", folder) + continue + } + if got != label { + t.Errorf("folder %s: expected %q, got %q", folder, label, got) + } + } +} + +func TestDoneTimestamp_ReviewToDone(t *testing.T) { + srv := setupTestServer(t) + + // Put T08 in review + os.Rename( + filepath.Join(srv.Config.TasksDir, "backlog", "T08.md"), + filepath.Join(srv.Config.TasksDir, "review", "T08.md"), + ) + + req := httptest.NewRequest(http.MethodPost, "/api/task/T08/move?to=done", nil) + w := httptest.NewRecorder() + srv.Router.ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String()) + } + + content, _ := os.ReadFile(filepath.Join(srv.Config.TasksDir, "done", "T08.md")) + text := string(content) + + if !containsStr(text, "Odobren (→done)") { + t.Error("expected 'Odobren (→done)' timestamp") + } +} + +func TestTaskDetail_DoneShowsReportButton(t *testing.T) { + srv := setupTestServer(t) + + // T01 is in done and has a report + req := httptest.NewRequest(http.MethodGet, "/task/T01", nil) + w := httptest.NewRecorder() + srv.Router.ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Fatalf("expected 200, got %d", w.Code) + } + + body := w.Body.String() + if !containsStr(body, "/report/T01") { + t.Error("expected report link for done task") + } +} + +func TestTaskDetail_DoneWithoutReportShowsButton(t *testing.T) { + srv := setupTestServer(t) + + // Create a done task without a report + os.WriteFile( + filepath.Join(srv.Config.TasksDir, "done", "T02.md"), + []byte("# T02: Bez reporta\n\n**Agent:** coder\n**Model:** Sonnet\n**Zavisi od:** —\n\n---\n\n## Opis\n\nTest task bez reporta.\n"), + 0644, + ) + + req := httptest.NewRequest(http.MethodGet, "/task/T02", nil) + w := httptest.NewRecorder() + srv.Router.ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Fatalf("expected 200, got %d", w.Code) + } + + body := w.Body.String() + if !containsStr(body, "/report/T02") { + t.Error("expected report button for done task even without report file") + } +} + +func TestTimestampVisibleInTaskDetail(t *testing.T) { + srv := setupTestServer(t) + + // Add timestamps to T01 (done task) + taskPath := filepath.Join(srv.Config.TasksDir, "done", "T01.md") + appendTimestamp(taskPath, "Kreiran") + appendTimestamp(taskPath, "Pokrenut (→active)") + + req := httptest.NewRequest(http.MethodGet, "/task/T01", nil) + w := httptest.NewRecorder() + srv.Router.ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Fatalf("expected 200, got %d", w.Code) + } + + body := w.Body.String() + if !containsStr(body, "Vremena") { + t.Error("expected Vremena section visible in task detail") + } +} + func TestStripAnsi(t *testing.T) { tests := []struct { input string diff --git a/code/web/templates/partials/task-card.html b/code/web/templates/partials/task-card.html index d6b32fb..347449b 100644 --- a/code/web/templates/partials/task-card.html +++ b/code/web/templates/partials/task-card.html @@ -18,7 +18,7 @@ {{else if eq .Action "approve"}} {{else if eq .Action "done"}} - + {{end}} diff --git a/code/web/templates/partials/task-detail.html b/code/web/templates/partials/task-detail.html index 8584be0..7cf8a42 100644 --- a/code/web/templates/partials/task-detail.html +++ b/code/web/templates/partials/task-detail.html @@ -8,9 +8,9 @@
Zavisi od: {{joinDeps .Task.DependsOn}}
{{end}} - {{if .HasReport}} + {{if or .HasReport (eq .Task.Status "done")}}