Add ticket time tracking with reports and entry management.
Support start/stop timer, manual durations, grouped reports, and per-ticket edit/delete of time entries with undo. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
package command_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"task/internal/command"
|
||||
"task/internal/ticket"
|
||||
)
|
||||
|
||||
func TestUpdateTimeEntryUndo(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
store := ticket.NewJSONTimeStore(dir)
|
||||
h := command.NewHistory()
|
||||
|
||||
created, err := store.Create(ticket.TimeEntry{
|
||||
TicketID: "t1",
|
||||
ProjectID: "inbox",
|
||||
Start: time.Now().UTC().Add(-time.Hour),
|
||||
Duration: time.Hour,
|
||||
Source: ticket.SourceManual,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
after := created
|
||||
after.Duration = 30 * time.Minute
|
||||
after.End = after.Start.Add(after.Duration)
|
||||
if err := h.Do(&command.UpdateTimeEntry{Store: store, Before: created, After: after}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
list, _ := store.ListByTicket("t1")
|
||||
if len(list) != 1 || list[0].Duration != 30*time.Minute {
|
||||
t.Fatalf("after update: %+v", list)
|
||||
}
|
||||
if err := h.Undo(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
list, _ = store.ListByTicket("t1")
|
||||
if len(list) != 1 || list[0].Duration != time.Hour {
|
||||
t.Fatalf("after undo: %+v", list)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveTimeEntryUndo(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
store := ticket.NewJSONTimeStore(dir)
|
||||
h := command.NewHistory()
|
||||
|
||||
created, err := store.Create(ticket.TimeEntry{
|
||||
TicketID: "t1",
|
||||
ProjectID: "inbox",
|
||||
Start: time.Now().UTC(),
|
||||
Duration: 15 * time.Minute,
|
||||
Source: ticket.SourceTimer,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := h.Do(&command.RemoveTimeEntry{Store: store, Snapshot: created}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
list, _ := store.List()
|
||||
if len(list) != 0 {
|
||||
t.Fatalf("expected empty after remove, got %d", len(list))
|
||||
}
|
||||
if err := h.Undo(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
list, _ = store.List()
|
||||
if len(list) != 1 || list[0].ID != created.ID {
|
||||
t.Fatalf("after undo: %+v", list)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user