Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e81eade2e1 |
@ -5,6 +5,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"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) {
|
func TestStripAnsi(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
input string
|
input string
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
{{else if eq .Action "approve"}}
|
{{else if eq .Action "approve"}}
|
||||||
<button class="btn btn-approve" hx-get="/task/{{.ID}}" hx-target="#task-detail" hx-swap="innerHTML" onclick="event.stopPropagation()">Pregledaj</button>
|
<button class="btn btn-approve" hx-get="/task/{{.ID}}" hx-target="#task-detail" hx-swap="innerHTML" onclick="event.stopPropagation()">Pregledaj</button>
|
||||||
{{else if eq .Action "done"}}
|
{{else if eq .Action "done"}}
|
||||||
<button class="btn btn-report" hx-get="/report/{{.ID}}" hx-target="#task-detail" hx-swap="innerHTML" onclick="event.stopPropagation()">Izvestaj</button>
|
<button class="btn btn-report" hx-get="/report/{{.ID}}" hx-target="#task-detail" hx-swap="innerHTML" onclick="event.stopPropagation()">📊 Izveštaj</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -8,9 +8,9 @@
|
|||||||
<p><strong>Zavisi od:</strong> {{joinDeps .Task.DependsOn}}</p>
|
<p><strong>Zavisi od:</strong> {{joinDeps .Task.DependsOn}}</p>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{if .HasReport}}
|
{{if or .HasReport (eq .Task.Status "done")}}
|
||||||
<div class="detail-actions">
|
<div class="detail-actions">
|
||||||
<button class="btn btn-report" hx-get="/report/{{.Task.ID}}" hx-target="#task-detail" hx-swap="innerHTML">Izvestaj</button>
|
<button class="btn btn-report" hx-get="/report/{{.Task.ID}}" hx-target="#task-detail" hx-swap="innerHTML">📊 Izveštaj</button>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="detail-actions">
|
<div class="detail-actions">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user