Open History to see the last commit
1import {
2 EnvironmentId,
3 ProviderDriverKind,
4 ProviderInstanceId,
5 UsageLimitSourceId,
6 type ServerProvider,
7} from "@t3tools/contracts";
8import { describe, expect, it, vi } from "vite-plus/test";
9import {
10 buildSubscriptionUsageSnapshot,
11 createWidgetRefresher,
12 WIDGET_REFRESH_INTERVAL,
13} from "./subscriptionUsageSnapshot";
14
15const checkedAt = "2026-09-05T12:00:00.000Z";
16const now = Date.parse(checkedAt);
17const window = {
18 id: "session",
19 kind: "session",
20 label: "5 hours",
21 usedPercent: 40,
22 resetsAt: "2026-09-05T12:10:00.000Z",
23} as const;
24const limits = { checkedAt, windows: [window] };
25const deepLink = "t3code-dev://settings/usage?tab=limits";
26function provider(overrides: Partial<ServerProvider> = {}): ServerProvider {
27 return {
28 instanceId: ProviderInstanceId.make("codex"),
29 driver: ProviderDriverKind.make("codex"),
30 enabled: true,
31 installed: true,
32 version: null,
33 status: "ready",
34 auth: { status: "authenticated", email: "private@example.com" },
35 checkedAt,
36 models: [],
37 slashCommands: [],
38 skills: [],
39 usageLimits: limits,
40 ...overrides,
41 };
42}
43function presentations(providers: readonly ServerProvider[] = [provider()]) {
44 return new Map([
45 [
46 EnvironmentId.make("env"),
47 { entry: { target: { label: "Remote" } }, serverConfig: { providers } },
48 ],
49 ]);
50}
51
52describe("subscription widget snapshots", () => {
53 it("uses provider data and its observation time without exposing account emails", () => {
54 const snapshot = buildSubscriptionUsageSnapshot(
55 presentations([provider({ displayName: "private@example.com" })]),
56 deepLink,
57 );
58 expect(snapshot.checkedAt).toBe(now);
59 expect(snapshot.providers[0]).toMatchObject({
60 name: "Codex",
61 windows: [{ remaining: 60 }],
62 expiresAt: now + 10 * 60_000,
63 });
64 expect(snapshot.url).toBe(deepLink);
65 expect(JSON.stringify(snapshot)).not.toContain("private@example.com");
66 });
67 it("uses upstream deduplication for a native account also present in a proxy hub", () => {
68 const input = new Map([
69 [
70 EnvironmentId.make("env"),
71 {
72 entry: { target: { label: "Remote" } },
73 serverConfig: {
74 providers: [provider()],
75 usageLimitSources: [
76 {
77 id: UsageLimitSourceId.make("hub"),
78 kind: "cliproxy" as const,
79 label: "Hub",
80 checkedAt,
81 accounts: [
82 {
83 id: "account",
84 driver: ProviderDriverKind.make("codex"),
85 email: " PRIVATE@example.com ",
86 usageLimits: limits,
87 },
88 ],
89 },
90 ],
91 },
92 },
93 ],
94 ]);
95 expect(buildSubscriptionUsageSnapshot(input, deepLink).providers[0]?.detail).toBe(
96 "Subscription remaining",
97 );
98 input.get(EnvironmentId.make("env"))!.serverConfig.providers = [];
99 const snapshot = buildSubscriptionUsageSnapshot(input, deepLink);
100 expect(snapshot.providers[0]?.name).toBe("Codex");
101 expect(JSON.stringify(snapshot)).not.toContain("example.com");
102 });
103 it("bounds OS storage and puts the most constrained windows first", () => {
104 const windows = Array.from({ length: 20 }, (_, index) => ({
105 ...window,
106 id: `${index}`,
107 usedPercent: index * 5,
108 }));
109 const snapshot = buildSubscriptionUsageSnapshot(
110 presentations([provider({ usageLimits: { checkedAt, windows } })]),
111 deepLink,
112 );
113 expect(snapshot.providers[0]?.windows).toHaveLength(6);
114 expect(snapshot.providers[0]?.totalWindows).toBe(20);
115 expect(snapshot.providers[0]?.windows[0]?.remaining).toBe(5);
116 });
117 it("uses the freshest copy of an account across environments before pooling", () => {
118 const input = presentations();
119 input.set(EnvironmentId.make("other"), {
120 entry: { target: { label: "Other" } },
121 serverConfig: {
122 providers: [
123 provider({
124 usageLimits: {
125 checkedAt: new Date(now + 60_000).toISOString(),
126 windows: [{ ...window, usedPercent: 80 }],
127 },
128 }),
129 ],
130 },
131 });
132 const snapshot = buildSubscriptionUsageSnapshot(input, deepLink);
133 expect(snapshot.providers[0]?.detail).toBe("Subscription remaining");
134 expect(snapshot.providers[0]?.windows[0]?.remaining).toBe(20);
135 });
136});
137
138describe("subscription widget expiry", () => {
139 const maxAgeDeadline = now + 15 * 60_000;
140 function single(resetsAt: string) {
141 return buildSubscriptionUsageSnapshot(
142 presentations([provider({ usageLimits: { checkedAt, windows: [{ ...window, resetsAt }] } })]),
143 deepLink,
144 ).providers[0];
145 }
146
147 it.each(["2026-09-05T11:50:00.000Z", checkedAt])(
148 "keeps usage whose reset at %s already happened when observed",
149 (resetsAt) => {
150 expect(single(resetsAt)).toMatchObject({
151 detail: "Subscription remaining",
152 expiresAt: maxAgeDeadline,
153 windows: [{ remaining: 60, reset: expect.stringMatching(/^Reset /) }],
154 });
155 },
156 );
157
158 it.each([
159 { resetAccount: 1, expiresAt: maxAgeDeadline, label: /^Reset / },
160 { resetAccount: 0, expiresAt: now + 2 * 60_000, label: /^Next reset / },
161 ])(
162 "compares a pooled reset with its own account's observation (account $resetAccount)",
163 ({ resetAccount, expiresAt, label }) => {
164 // Account 0 was observed at 12:00, account 1 at 12:05; the pooled reset is at 12:02.
165 const snapshot = buildSubscriptionUsageSnapshot(
166 presentations(
167 [checkedAt, "2026-09-05T12:05:00.000Z"].map((accountCheckedAt, index) =>
168 provider({
169 instanceId: ProviderInstanceId.make(`codex-${index}`),
170 auth: { status: "authenticated", email: `account-${index}@example.com` },
171 usageLimits: {
172 checkedAt: accountCheckedAt,
173 windows: [
174 {
175 ...window,
176 resetsAt:
177 index === resetAccount
178 ? "2026-09-05T12:02:00.000Z"
179 : "2026-09-05T13:00:00.000Z",
180 },
181 ],
182 },
183 }),
184 ),
185 ),
186 deepLink,
187 );
188 expect(snapshot.providers[0]).toMatchObject({
189 detail: "2 accounts · pooled",
190 expiresAt,
191 windows: [{ remaining: 60, reset: expect.stringMatching(label) }],
192 });
193 },
194 );
195});
196
197describe("widget refresh probes", () => {
198 it("does not overlap a slow probe even after the refresh interval", async () => {
199 let finish!: () => void;
200 const probe = vi.fn(
201 () =>
202 new Promise<void>((resolve) => {
203 finish = resolve;
204 }),
205 );
206 const refresh = createWidgetRefresher(probe);
207 const first = refresh(["one", "one"], now);
208 await refresh(["one"], now + WIDGET_REFRESH_INTERVAL);
209 expect(probe).toHaveBeenCalledTimes(1);
210 finish();
211 await first;
212 });
213});