Spaces:
Running
Running
| import { describe, expect, it } from "vitest"; | |
| import { buildActivity, intensityLevel } from "./searchActivity"; | |
| /** Local timestamp for a given calendar day (noon avoids DST edges). */ | |
| const at = (year: number, month1: number, day: number, hour = 12) => | |
| new Date(year, month1 - 1, day, hour).getTime(); | |
| const NOW = at(2026, 7, 8); // Wed, 8 Jul 2026, local noon | |
| describe("intensityLevel", () => { | |
| it("returns 0 for empty days or an empty window", () => { | |
| expect(intensityLevel(0, 6)).toBe(0); | |
| expect(intensityLevel(3, 0)).toBe(0); | |
| }); | |
| it("scales 1-4 relative to the busiest day", () => { | |
| expect(intensityLevel(1, 6)).toBe(1); | |
| expect(intensityLevel(6, 6)).toBe(4); | |
| expect(intensityLevel(3, 6)).toBe(2); | |
| }); | |
| }); | |
| describe("buildActivity", () => { | |
| const timestamps = [ | |
| at(2026, 7, 8), | |
| at(2026, 7, 8), // today: 2 | |
| at(2026, 7, 7), // 1 | |
| at(2026, 7, 6), // 1 | |
| at(2026, 7, 5), // 1 | |
| at(2026, 7, 3), | |
| at(2026, 7, 3), | |
| at(2026, 7, 3), // 3 | |
| at(2026, 7, 2), // 1 | |
| at(2026, 6, 28), // 6 -> six entries below | |
| at(2026, 6, 28), | |
| at(2026, 6, 28), | |
| at(2026, 6, 28), | |
| at(2026, 6, 28), | |
| at(2026, 6, 28), | |
| ]; | |
| it("clamps a short span up to the minimum window and squares off weeks", () => { | |
| const data = buildActivity(timestamps, NOW); | |
| expect(data.weeks).toBe(12); | |
| expect(data.columns).toHaveLength(12); | |
| for (const column of data.columns) { | |
| expect(column).toHaveLength(7); | |
| } | |
| }); | |
| it("buckets searches onto the correct local day", () => { | |
| const data = buildActivity(timestamps, NOW); | |
| const cells = data.columns.flat(); | |
| expect(cells.find((c) => c.date === "2026-07-08")?.count).toBe(2); | |
| expect(cells.find((c) => c.date === "2026-06-28")?.count).toBe(6); | |
| expect(cells.find((c) => c.date === "2026-07-04")?.count).toBe(0); | |
| }); | |
| it("computes streaks, active days, and the busiest day", () => { | |
| const { stats } = buildActivity(timestamps, NOW); | |
| expect(stats.currentStreak).toBe(4); // Jul 5,6,7,8 | |
| expect(stats.longestStreak).toBe(4); | |
| expect(stats.daysActive).toBe(7); | |
| expect(stats.busiestCount).toBe(6); | |
| expect(stats.total).toBe(15); | |
| }); | |
| it("marks days after today as future filler, not zero activity", () => { | |
| const data = buildActivity(timestamps, NOW); | |
| const future = data.columns.flat().filter((c) => c.future); | |
| expect(future.every((c) => c.count === 0)).toBe(true); | |
| // Wed 8 Jul -> Thu/Fri/Sat remain in the trailing week. | |
| expect(future).toHaveLength(3); | |
| }); | |
| it("labels the month only when it changes across columns", () => { | |
| const data = buildActivity(timestamps, NOW); | |
| const labels = data.monthLabels.filter(Boolean); | |
| expect(labels).toContain("Jul"); | |
| // No month name repeats in consecutive labelled columns. | |
| expect(new Set(labels).size).toBe(labels.length); | |
| }); | |
| it("returns an empty-but-valid grid with no searches", () => { | |
| const data = buildActivity([], NOW); | |
| expect(data.weeks).toBe(12); | |
| expect(data.maxCount).toBe(0); | |
| expect(data.stats.currentStreak).toBe(0); | |
| expect(data.columns.flat().every((c) => c.count === 0)).toBe(true); | |
| }); | |
| }); | |