28 lines
1.6 KiB
TypeScript
28 lines
1.6 KiB
TypeScript
import { afterAll, afterEach, expect, spyOn, test } from "bun:test";
|
|
import { CalendarCache } from "./CalendarCache";
|
|
const fetchSpy = spyOn(globalThis, "fetch");
|
|
afterEach(() => fetchSpy.mockReset());
|
|
afterAll(() => fetchSpy.mockRestore());
|
|
const range = { from: "2026-07-01", to: "2026-09-30" };
|
|
test("calendar cache shares in-flight reads, retains wider history and invalidates changed versions", async () => {
|
|
fetchSpy.mockImplementation(Object.assign(async () => Response.json({ from: range.from, to: range.to, days: [{ date: "2026-07-01" }, { date: "2026-09-01" }] }), { preconnect: fetch.preconnect }));
|
|
const cache = new CalendarCache();
|
|
await Promise.all([cache.load("habit", "v1", range), cache.load("habit", "v1", range)]);
|
|
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
|
expect(String(fetchSpy.mock.calls[0]![0])).toContain("compact=true");
|
|
const subset = await cache.load("habit", "v1", { from: "2026-09-01", to: range.to });
|
|
expect(subset.days).toHaveLength(1);
|
|
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
|
await cache.load("habit", "v2", range);
|
|
expect(fetchSpy).toHaveBeenCalledTimes(2);
|
|
await new CalendarCache().load("habit", "v2", range);
|
|
expect(fetchSpy).toHaveBeenCalledTimes(3);
|
|
});
|
|
test("a failed history request can be retried without retaining a rejected cache entry", async () => {
|
|
fetchSpy.mockRejectedValueOnce(new Error("offline")).mockResolvedValue(Response.json({ ...range, days: [] }));
|
|
const cache = new CalendarCache();
|
|
await expect(cache.load("habit", "v1", range)).rejects.toThrow("offline");
|
|
await expect(cache.load("habit", "v1", range)).resolves.toMatchObject({ days: [] });
|
|
expect(fetchSpy).toHaveBeenCalledTimes(2);
|
|
});
|