summaryrefslogtreecommitdiff
path: root/internal/handlers/widget_test.go
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-07-12 10:21:36 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-07-12 10:21:36 +0000
commit437ee6b10462909fb2db677a64be264d811a2e1c (patch)
tree29291d12c3590e5611eaf11e0a8182324fa7c42e /internal/handlers/widget_test.go
parentc0454371a044ef4f20bfe44ee9f183fb336656dd (diff)
feat(widget): add DueDate field for doot tasks to the widget API
Diffstat (limited to 'internal/handlers/widget_test.go')
-rw-r--r--internal/handlers/widget_test.go71
1 files changed, 71 insertions, 0 deletions
diff --git a/internal/handlers/widget_test.go b/internal/handlers/widget_test.go
index 06e1749..14dd396 100644
--- a/internal/handlers/widget_test.go
+++ b/internal/handlers/widget_test.go
@@ -210,6 +210,77 @@ func TestTimelineItemToWidgetItem_NotOverdueByDefault(t *testing.T) {
}
}
+// TestTimelineItemToWidgetItem_DootTaskGetsDueDate proves the 2026-07-12
+// clickable-reschedule fix: a doot task's raw due date must reach the
+// client via a NEW field (DueDate) that is independent of Start/IsAllDay --
+// Start is deliberately left nil for doot tasks (see
+// TestTimelineItemToWidgetItem_AllDayTask_KeepsFloatingBehavior) so the
+// client's floating-task SlotPacker can position it, and that must keep
+// working unchanged. Before this fix there was no way for the Android
+// detail popup to know a doot task's current due date at all.
+func TestTimelineItemToWidgetItem_DootTaskGetsDueDate(t *testing.T) {
+ due := time.Date(2026, 7, 15, 0, 0, 0, 0, time.Local)
+ item := models.TimelineItem{
+ ID: "doot-1",
+ Title: "Pay the water bill",
+ Source: "doot",
+ Type: models.TimelineItemTypeTask,
+ Time: due,
+ IsAllDay: true,
+ }
+
+ wi := TimelineItemToWidgetItem(item)
+
+ if wi.DueDate == nil {
+ t.Fatal("expected DueDate to be set for a doot task with a real due date")
+ }
+ if !wi.DueDate.Equal(due) {
+ t.Errorf("DueDate = %v, want %v", *wi.DueDate, due)
+ }
+ // Start must stay nil -- this is the pre-existing floating-task
+ // behavior and this feature must not change it.
+ if wi.Start != nil {
+ t.Error("Start must remain nil for a doot task -- DueDate is a separate field, not a replacement")
+ }
+}
+
+func TestTimelineItemToWidgetItem_UndatedDootTask_NilDueDate(t *testing.T) {
+ item := models.TimelineItem{
+ ID: "doot-undated",
+ Title: "Someday task",
+ Source: "doot",
+ Type: models.TimelineItemTypeTask,
+ Time: time.Now(),
+ IsAllDay: true,
+ }
+ // Zero Time simulates the "no real due date" case at the field level;
+ // TimelineItemToWidgetItem's DueDate logic must guard on !Time.IsZero().
+ item.Time = time.Time{}
+
+ wi := TimelineItemToWidgetItem(item)
+
+ if wi.DueDate != nil {
+ t.Error("expected DueDate to be nil when the source item has a zero Time")
+ }
+}
+
+func TestTimelineItemToWidgetItem_CalendarEvent_NilDueDate(t *testing.T) {
+ start := time.Now()
+ item := models.TimelineItem{
+ ID: "cal-1",
+ Title: "Team sync",
+ Source: "calendar",
+ Type: models.TimelineItemTypeEvent,
+ Time: start,
+ }
+
+ wi := TimelineItemToWidgetItem(item)
+
+ if wi.DueDate != nil {
+ t.Error("expected DueDate to stay nil for a non-doot item (calendar event)")
+ }
+}
+
func TestHandleWidgetComplete_NonCompletable(t *testing.T) {
h := &Handler{}
body := `{"id":"x","source":"calendar"}`