|
1 | 1 | import { expect, test } from "bun:test"; |
| 2 | +import { Window } from "happy-dom"; |
| 3 | +import { act, createElement } from "react"; |
| 4 | +import { clearClientResourceStoresForTests } from "../src/client-resource"; |
| 5 | +import { LanguageProvider } from "../src/i18n/provider"; |
| 6 | +import Usage from "../src/pages/Usage"; |
2 | 7 |
|
3 | 8 | test("Usage renders every section in one scrollable column with a sticky strip", async () => { |
4 | 9 | const page = await Bun.file(new URL("../src/pages/Usage.tsx", import.meta.url)).text(); |
@@ -67,11 +72,73 @@ test("usage workspace i18n keys exist in every locale", async () => { |
67 | 72 | } |
68 | 73 | }); |
69 | 74 |
|
70 | | -test("Usage All becomes Available history and API-key lifetime totals are qualified when capped", async () => { |
71 | | - const usage = await Bun.file(new URL("../src/pages/Usage.tsx", import.meta.url)).text(); |
72 | | - const keys = await Bun.file(new URL("../src/components/apikeys-workspace/ApiKeysWorkspace.tsx", import.meta.url)).text(); |
73 | | - expect(usage).toContain('t("usage.range.available")'); |
74 | | - expect(usage).toContain('data?.historyTruncated'); |
75 | | - expect(keys).toContain('api.attribution.totalRequestsAvailable'); |
76 | | - expect(keys).toContain('api.attribution.sinceAvailable'); |
| 75 | +test("Usage renders Available history and a persistent qualification when history is capped", async () => { |
| 76 | + const globalKeys = ["document", "window", "navigator", "localStorage", "IS_REACT_ACT_ENVIRONMENT"] as const; |
| 77 | + const previous = Object.fromEntries(globalKeys.map(key => [key, Reflect.get(globalThis, key)])); |
| 78 | + const originalFetch = globalThis.fetch; |
| 79 | + const testWindow = new Window({ url: "http://localhost/" }); |
| 80 | + Object.defineProperties(globalThis, { |
| 81 | + document: { configurable: true, value: testWindow.document }, |
| 82 | + window: { configurable: true, value: testWindow }, |
| 83 | + navigator: { configurable: true, value: testWindow.navigator }, |
| 84 | + localStorage: { configurable: true, value: testWindow.localStorage }, |
| 85 | + }); |
| 86 | + (globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; |
| 87 | + clearClientResourceStoresForTests(); |
| 88 | + globalThis.fetch = (async () => Response.json({ |
| 89 | + range: "30d", |
| 90 | + surface: "all", |
| 91 | + since: null, |
| 92 | + generatedAt: Date.now(), |
| 93 | + summary: { |
| 94 | + requests: 0, |
| 95 | + measuredRequests: 0, |
| 96 | + reportedRequests: 0, |
| 97 | + unreportedRequests: 0, |
| 98 | + unsupportedRequests: 0, |
| 99 | + estimatedRequests: 0, |
| 100 | + inputTokens: 0, |
| 101 | + outputTokens: 0, |
| 102 | + cachedInputTokens: 0, |
| 103 | + reasoningOutputTokens: 0, |
| 104 | + totalTokens: 0, |
| 105 | + coverageRatio: 1, |
| 106 | + }, |
| 107 | + days: [], |
| 108 | + models: [], |
| 109 | + providers: [], |
| 110 | + historyTruncated: true, |
| 111 | + truncatedPrefixBytes: 1, |
| 112 | + entriesTruncated: false, |
| 113 | + entriesDropped: 0, |
| 114 | + })) as typeof fetch; |
| 115 | + |
| 116 | + const container = document.createElement("div"); |
| 117 | + document.body.append(container); |
| 118 | + const { createRoot } = await import("react-dom/client"); |
| 119 | + const root = createRoot(container); |
| 120 | + try { |
| 121 | + await act(async () => { |
| 122 | + root.render(createElement(LanguageProvider, null, createElement(Usage, { apiBase: "http://usage-qualification-test" }))); |
| 123 | + }); |
| 124 | + const deadline = Date.now() + 1_000; |
| 125 | + while (!(container.textContent ?? "").includes("Totals cover available history only")) { |
| 126 | + if (Date.now() >= deadline) throw new Error("Usage qualification did not render"); |
| 127 | + await act(async () => { |
| 128 | + await new Promise<void>(resolve => testWindow.setTimeout(resolve, 10)); |
| 129 | + }); |
| 130 | + } |
| 131 | + |
| 132 | + expect(container.querySelector('button[aria-label="Available history"]')).not.toBeNull(); |
| 133 | + expect(container.textContent).toContain("Totals cover available history only because older usage was not loaded."); |
| 134 | + } finally { |
| 135 | + await act(async () => { root.unmount(); }); |
| 136 | + container.remove(); |
| 137 | + globalThis.fetch = originalFetch; |
| 138 | + clearClientResourceStoresForTests(); |
| 139 | + testWindow.close(); |
| 140 | + for (const key of globalKeys) { |
| 141 | + Object.defineProperty(globalThis, key, { configurable: true, value: previous[key] }); |
| 142 | + } |
| 143 | + } |
77 | 144 | }); |
0 commit comments