package main import ( "context" "net/http" "net/http/httptest" "strings" "testing" "time" "github.com/kami/maven/internal/ipc" ) // morningCore serves a canned checklist and day plan. type morningCore struct { ipc.UnimplementedCoreAPI status []ipc.MorningRoutineStatus plan ipc.DayPlan } func (c *morningCore) MorningStatus(context.Context) ([]ipc.MorningRoutineStatus, error) { return c.status, nil } func (c *morningCore) DayPlan(context.Context) (ipc.DayPlan, error) { return c.plan, nil } func TestMorningRendersPlanTimesInLocalZone(t *testing.T) { // A plan item's At is a calendar fact's Ts or a reminder's FireTs, and the // store hands both back as UTC. Printed raw, /morning named an hour for a // reminder that /reminders — which does call Local — disagreed with. away := awayFromLocal() at := time.Date(2026, 8, 1, 9, 0, 0, 0, time.UTC).In(away) core := &morningCore{plan: ipc.DayPlan{ Date: at, Items: []ipc.DayPlanItem{{At: at, Text: "выпить таблетки", Kind: "reminder"}}, }} w := httptest.NewRecorder() handleMorning(w, httptest.NewRequest(http.MethodGet, "/morning", nil), core) if w.Code != http.StatusOK { t.Fatalf("status = %d, want 200", w.Code) } body := w.Body.String() if !strings.Contains(body, at.Local().Format("15:04")) { t.Errorf("plan item not rendered in his clock (%s): %s", at.Local().Format("15:04"), body) } if strings.Contains(body, at.In(away).Format("15:04")) { t.Errorf("plan item rendered in the stored zone: %s", body) } }