1import { describe, expect, it } from "vite-plus/test";
2
3import { applyUsageLimitsUpdate, resolveUsageLimitsAfterProbe } from "./usageLimits.ts";
4
5const checkedAt = "2026-09-03T12:00:00.000Z";
6const session = {
7 id: "five_hour",
8 kind: "session",
9 label: "Session",
10 usedPercent: 40,
11 windowDurationMins: 300,
12 resetsAt: "2026-09-03T14:00:00.000Z",
13} as const;
14const weekly = {
15 id: "seven_day",
16 kind: "weekly",
17 label: "Weekly",
18 usedPercent: 20,
19 windowDurationMins: 10_080,
20} as const;
21const published = { checkedAt, windows: [session, weekly] };
22
23describe("applyUsageLimitsUpdate", () => {
24 it("returns the published object itself when no window moved", () => {
25 // Codex repeats the same numbers beside every token-usage tick; the
26 // ingestion path relies on identity to skip the publish.
27 const next = applyUsageLimitsUpdate({
28 previous: published,
29 checkedAt: "2026-09-03T12:00:05.000Z",
30 update: {
31 windows: [
32 { ...weekly },
33 { id: "five_hour", kind: "session", label: "Session", usedPercent: 40 },
34 ],
35 },
36 });
37 expect(next).toBe(published);
38 });
39
40 it("upserts by id and keeps the reset a percent-only update omits", () => {
41 const next = applyUsageLimitsUpdate({
42 previous: published,
43 checkedAt: "2026-09-03T12:00:05.000Z",
44 update: {
45 windows: [{ id: "five_hour", kind: "session", label: "Session", usedPercent: 55 }],
46 },
47 });
48 expect(next).not.toBe(published);
49 expect(next).toEqual({
50 checkedAt: "2026-09-03T12:00:05.000Z",
51 windows: [{ ...session, usedPercent: 55 }, weekly],
52 });
53 });
54
55 it("leaves an unsupported account and an empty update alone", () => {
56 const unsupported = { checkedAt, windows: [], unavailable: { reason: "unsupported" as const } };
57 expect(
58 applyUsageLimitsUpdate({ previous: unsupported, checkedAt, update: { windows: [session] } }),
59 ).toBe(unsupported);
60 expect(
61 applyUsageLimitsUpdate({ previous: published, checkedAt, update: { windows: [] } }),
62 ).toBe(published);
63 });
64
65 it("preserves reset credits when a streamed window update changes usage", () => {
66 const resetCredits = { availableCount: 2, nextExpiresAt: "2026-10-01T00:00:00.000Z" };
67 const next = applyUsageLimitsUpdate({
68 previous: { ...published, resetCredits },
69 checkedAt: "2026-09-03T12:00:05.000Z",
70 update: { windows: [{ ...session, usedPercent: 55 }] },
71 });
72
73 expect(next).toEqual({
74 checkedAt: "2026-09-03T12:00:05.000Z",
75 windows: [{ ...session, usedPercent: 55 }, weekly],
76 resetCredits,
77 });
78 });
79});
80
81describe("resolveUsageLimitsAfterProbe", () => {
82 it("keeps the last good windows through a failed probe but not an unsupported one", () => {
83 const failed = { checkedAt, windows: [], unavailable: { reason: "probeFailed" as const } };
84 const unsupported = { checkedAt, windows: [], unavailable: { reason: "unsupported" as const } };
85 expect(resolveUsageLimitsAfterProbe({ published, probed: failed })).toBe(published);
86 expect(resolveUsageLimitsAfterProbe({ published, probed: unsupported })).toBe(unsupported);
87 expect(resolveUsageLimitsAfterProbe({ published: undefined, probed: failed })).toBe(failed);
88 });
89});