summaryrefslogtreecommitdiffhomepage
path: root/packages/frontend/tests/cache-warm-storage.test.ts
blob: 458d07dd4fa3e05fbbec5ca2d65870eb6b0f5e5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
 * Tests for `src/lib/cache-warm-storage.ts` — the per-tab localStorage
 * round-trip for the "keep prompt cache warm" toggle.
 *
 * As in `sidebar-storage.test.ts`, Bun's `localStorage` shim is partial, so we
 * install a clean in-memory polyfill per-test.
 */
import { beforeEach, describe, expect, it, vi } from "vitest";
import {
	clearCacheWarmEnabled,
	loadCacheWarmEnabled,
	saveCacheWarmEnabled,
} from "../src/lib/cache-warm-storage.js";

const LS_KEY = "dispatch-cache-warming";

function makeLocalStorageMock(): Storage {
	const store = new Map<string, string>();
	return {
		getItem: (k: string) => store.get(k) ?? null,
		setItem: (k: string, v: string) => {
			store.set(k, v);
		},
		removeItem: (k: string) => {
			store.delete(k);
		},
		clear: () => {
			store.clear();
		},
		get length() {
			return store.size;
		},
		key: (i: number) => Array.from(store.keys())[i] ?? null,
	};
}

beforeEach(() => {
	vi.stubGlobal("localStorage", makeLocalStorageMock());
});

describe("loadCacheWarmEnabled", () => {
	it("defaults to false when nothing is stored", () => {
		expect(loadCacheWarmEnabled("tab-1")).toBe(false);
	});

	it("returns true after enabling a tab", () => {
		saveCacheWarmEnabled("tab-1", true);
		expect(loadCacheWarmEnabled("tab-1")).toBe(true);
	});

	it("is scoped per-tab (one tab's flag doesn't leak to another)", () => {
		saveCacheWarmEnabled("tab-1", true);
		expect(loadCacheWarmEnabled("tab-2")).toBe(false);
	});

	it("returns false when the stored JSON is malformed", () => {
		localStorage.setItem(LS_KEY, "not json {[");
		expect(loadCacheWarmEnabled("tab-1")).toBe(false);
	});

	it("ignores non-boolean entries", () => {
		localStorage.setItem(LS_KEY, JSON.stringify({ "tab-1": "yes", "tab-2": true }));
		expect(loadCacheWarmEnabled("tab-1")).toBe(false);
		expect(loadCacheWarmEnabled("tab-2")).toBe(true);
	});
});

describe("saveCacheWarmEnabled", () => {
	it("removes the entry when set to false (default-off representation)", () => {
		saveCacheWarmEnabled("tab-1", true);
		saveCacheWarmEnabled("tab-1", false);
		const raw = localStorage.getItem(LS_KEY);
		expect(raw).toBe(JSON.stringify({}));
		expect(loadCacheWarmEnabled("tab-1")).toBe(false);
	});

	it("preserves other tabs' flags when toggling one", () => {
		saveCacheWarmEnabled("tab-1", true);
		saveCacheWarmEnabled("tab-2", true);
		saveCacheWarmEnabled("tab-1", false);
		expect(loadCacheWarmEnabled("tab-1")).toBe(false);
		expect(loadCacheWarmEnabled("tab-2")).toBe(true);
	});

	it("silently ignores storage write errors", () => {
		vi.stubGlobal("localStorage", {
			getItem: () => null,
			setItem: () => {
				throw new Error("QuotaExceededError");
			},
			removeItem: () => {},
			clear: () => {},
			length: 0,
			key: () => null,
		});
		expect(() => saveCacheWarmEnabled("tab-1", true)).not.toThrow();
	});
});

describe("clearCacheWarmEnabled", () => {
	it("drops a tab's persisted flag", () => {
		saveCacheWarmEnabled("tab-1", true);
		clearCacheWarmEnabled("tab-1");
		expect(loadCacheWarmEnabled("tab-1")).toBe(false);
	});

	it("is a no-op when the tab has no stored flag", () => {
		expect(() => clearCacheWarmEnabled("tab-x")).not.toThrow();
		expect(localStorage.getItem(LS_KEY)).toBeNull();
	});
});