import groupEvents from "../../Gtd/groupEvents"; import { GtdEvent } from "../../Gtd/types"; function makeEvent(overrides: Partial): GtdEvent { return { id: "id", title: "Event", date: null, isTodo: false, completed: false, bgColour: null, fgColour: null, icon: null, text: null, updatedTime: 0, isRecurring: false, ...overrides, }; } const TODAY = new Date(2026, 5, 12); // Jun 12 2026 describe("groupEvents — day view", () => { test("one group per calendar day across the span, empty groups included", () => { const events = [ makeEvent({ id: "a", date: "2026-06-10" }), makeEvent({ id: "b", date: "2026-06-14" }), ]; const result = groupEvents(events, "day", TODAY); // Jun 10 .. Jun 14 (today Jun 12 is inside the span) expect(result.groups).toHaveLength(5); expect(result.groups[0].events.map((e) => e.id)).toEqual(["a"]); expect(result.groups[1].events).toHaveLength(0); expect(result.groups[4].events.map((e) => e.id)).toEqual(["b"]); }); test("span always includes today", () => { const events = [makeEvent({ id: "past", date: "2026-06-08" })]; const result = groupEvents(events, "day", TODAY); // Jun 8 .. Jun 12 expect(result.groups).toHaveLength(5); expect(result.groups[4].isCurrent).toBe(true); expect(result.groups[4].dateISO).toBe("2026-06-12"); }); test("first-of-month label is the month name and primary", () => { const events = [ makeEvent({ id: "a", date: "2026-06-30" }), makeEvent({ id: "b", date: "2026-07-02" }), ]; const result = groupEvents(events, "day", new Date(2026, 6, 1)); const firstOfJuly = result.groups.find( (g) => g.dateISO === "2026-07-01" )!; expect(firstOfJuly.labelPrimary).toBe(true); expect(firstOfJuly.label.toLowerCase()).toContain("jul"); expect(firstOfJuly.monthIndex).toBe(6); }); test("multiple events on one day share a group, order preserved", () => { const events = [ makeEvent({ id: "x", date: "2026-06-12" }), makeEvent({ id: "y", date: "2026-06-12" }), ]; const result = groupEvents(events, "day", TODAY); expect(result.groups).toHaveLength(1); expect(result.groups[0].events.map((e) => e.id)).toEqual(["x", "y"]); }); }); describe("groupEvents — week and month views", () => { test("week view groups by calendar week with current-week flag", () => { const events = [ makeEvent({ id: "a", date: "2026-06-01" }), makeEvent({ id: "b", date: "2026-06-19" }), ]; const result = groupEvents(events, "week", TODAY); // Weeks of May 31, Jun 7, Jun 14 → 3 groups expect(result.groups).toHaveLength(3); expect(result.groups[1].isCurrent).toBe(true); // week containing Jun 12 expect(result.groups[0].events.map((e) => e.id)).toEqual(["a"]); expect(result.groups[2].events.map((e) => e.id)).toEqual(["b"]); }); test("month view groups by calendar month", () => { const events = [ makeEvent({ id: "a", date: "2026-04-20" }), makeEvent({ id: "b", date: "2026-08-03" }), ]; const result = groupEvents(events, "month", TODAY); // Apr, May, Jun, Jul, Aug expect(result.groups).toHaveLength(5); expect(result.groups[2].isCurrent).toBe(true); // June expect(result.groups[0].events.map((e) => e.id)).toEqual(["a"]); expect(result.groups[4].events.map((e) => e.id)).toEqual(["b"]); }); test("january month label is the year and primary", () => { const events = [ makeEvent({ id: "a", date: "2025-12-15" }), makeEvent({ id: "b", date: "2026-01-10" }), ]; const result = groupEvents(events, "month", new Date(2026, 0, 5)); const january = result.groups.find((g) => g.monthIndex === 0)!; expect(january.label).toBe("2026"); expect(january.labelPrimary).toBe(true); }); }); describe("groupEvents — unscheduled", () => { test("dateless events pass through in order; no groups without scheduled events", () => { const events = [ makeEvent({ id: "u1" }), makeEvent({ id: "u2" }), ]; const result = groupEvents(events, "day", TODAY); expect(result.groups).toHaveLength(0); expect(result.unscheduled.map((e) => e.id)).toEqual(["u1", "u2"]); }); test("mixed: scheduled grouped, dateless set aside", () => { const events = [ makeEvent({ id: "s", date: "2026-06-12" }), makeEvent({ id: "u" }), ]; const result = groupEvents(events, "day", TODAY); expect(result.groups[0].events.map((e) => e.id)).toEqual(["s"]); expect(result.unscheduled.map((e) => e.id)).toEqual(["u"]); }); }); describe("groupEvents — month-grid view", () => { test("covers the whole current month padded to full weeks", () => { const result = groupEvents([], "month-grid", TODAY); const grid = result.grid!; expect(grid.cells.length % 7).toBe(0); expect(grid.weekdays).toHaveLength(7); expect(grid.monthLabel).toContain("2026"); const inMonth = grid.cells.filter((c) => c.inMonth); expect(inMonth).toHaveLength(30); // June 2026 expect(inMonth[0].dayNumber).toBe(1); expect(inMonth[29].dayNumber).toBe(30); }); test("flags today and buckets events into the right cells", () => { const events = [ makeEvent({ id: "a", date: "2026-06-12" }), makeEvent({ id: "b", date: "2026-06-12" }), makeEvent({ id: "c", date: "2026-06-25" }), ]; const grid = groupEvents(events, "month-grid", TODAY).grid!; const todayCell = grid.cells.find((c) => c.isToday)!; expect(todayCell.dateISO).toBe("2026-06-12"); expect(todayCell.events.map((e) => e.id)).toEqual(["a", "b"]); const cell25 = grid.cells.find((c) => c.dateISO === "2026-06-25")!; expect(cell25.events.map((e) => e.id)).toEqual(["c"]); }); test("events outside the displayed window are counted, not shown", () => { const events = [ makeEvent({ id: "in", date: "2026-06-05" }), makeEvent({ id: "out", date: "2026-09-01" }), ]; const grid = groupEvents(events, "month-grid", TODAY).grid!; expect(grid.outsideCount).toBe(1); const allShown = grid.cells.flatMap((c) => c.events.map((e) => e.id)); expect(allShown).toEqual(["in"]); }); test("adjacent-month padding days can still hold events", () => { // June 2026 starts on a Monday; the grid window starts Sunday May 31. const events = [makeEvent({ id: "pad", date: "2026-05-31" })]; const grid = groupEvents(events, "month-grid", TODAY).grid!; const padCell = grid.cells.find((c) => c.dateISO === "2026-05-31")!; expect(padCell.inMonth).toBe(false); expect(padCell.events.map((e) => e.id)).toEqual(["pad"]); expect(grid.outsideCount).toBe(0); }); test("unscheduled events still pass through in month-grid view", () => { const events = [makeEvent({ id: "u" })]; const result = groupEvents(events, "month-grid", TODAY); expect(result.unscheduled.map((e) => e.id)).toEqual(["u"]); expect(result.groups).toHaveLength(0); }); });