import assert from "node:assert/strict"; import test from "node:test"; import * as React from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { AccountSummaryPanel, AnimatedUsageChart, ChartShell, ModelShareChart, RadialMetric, RangeSwitch, RingMetrics, SourceGrid, StatsGrid, TokenActivityPanel, TokenMixPanel, TrayStatusStrip, UsageDetailPanel, UsageOverviewPanel } from "../../packages/ui/src/pages/tray/components/index.ts"; import { TrayApp } from "../../packages/ui/src/pages/tray/TrayApp.tsx"; import { TrayDetailApp } from "../../packages/ui/src/pages/tray/TrayDetailApp.tsx"; import { accountSnapshots, installBrowserGlobals, usageStats, usageTotals } from "./fixtures.ts"; installBrowserGlobals(); const componentVariants = { account: "bar", modelShare: "bars", rings: "rings", stats: "cards", tokenFlow: "line", tokenMix: "bars" } as const; test("UsageOverviewPanel renders every enabled overview tray module", () => { const activeStats = usageStats("30d"); const html = renderToStaticMarkup( ); assert.match(html, /openai \/ Primary Key/); assert.match(html, /30d Token Flow/); assert.match(html, /Activity/); assert.match(html, /Today tokens/); assert.match(html, /Token Mix/); assert.match(html, /Circular metrics/); assert.match(html, /Model Share/); assert.match(html, /Syncing usage\.\.\./); }); test("UsageDetailPanel renders configured detail widgets and empty state", () => { const activeStats = usageStats("7d"); const html = renderToStaticMarkup( undefined} /> ); const emptyHtml = renderToStaticMarkup( undefined} /> ); assert.match(html, /Usage Detail/); assert.match(html, /7d - OpenAI/); assert.match(html, /7d tokens/); assert.match(html, /Token Flow/); assert.match(html, /Token Mix/); assert.match(html, /Circular metrics/); assert.match(html, /Model Share/); assert.match(emptyHtml, /No tray modules enabled/); }); test("TrayStatusStrip renders open and quit actions", () => { const html = renderToStaticMarkup(); assert.match(html, /aria-label="Open CCR"/); assert.match(html, /title="Open CCR"/); assert.match(html, /12\.5K tokens/); assert.match(html, /CCR/); assert.match(html, /aria-label="Quit"/); }); test("SourceGrid renders provider tabs with the selected state", () => { const html = renderToStaticMarkup( undefined} /> ); assert.match(html, />All<\/button>/); assert.match(html, /border-teal-300\/35 bg-teal-300\/16 text-teal-50/); assert.match(html, />OpenAI<\/button>/); assert.match(html, />Anthropic<\/button>/); }); test("AccountSummaryPanel covers empty and metered account states", () => { const emptyHtml = renderToStaticMarkup(); const meteredHtml = renderToStaticMarkup( undefined} /> ); assert.match(emptyHtml, /No account data configured/); assert.match(meteredHtml, /openai \/ Primary Key/); assert.match(meteredHtml, /5h quota/); assert.match(meteredHtml, /42 requests/); assert.match(meteredHtml, /style="\s*width:42%"/); }); test("AccountSummaryPanel prioritizes Codex manual reset meter with expiration", () => { const resetAt = new Date(Date.now() + 72 * 60 * 60 * 1000).toISOString(); const resetEffectiveAt = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(); const html = renderToStaticMarkup( ); assert.match(html, /Primary quota/); assert.match(html, /Manual resets/); assert.match(html, /expires in/); assert.match(html, /2 resets/); assert.match(html, /width:/); assert.doesNotMatch(html, /Secondary quota/); }); test("RangeSwitch renders every usage range option", () => { const html = renderToStaticMarkup( undefined} />); assert.match(html, />Today<\/button>/); assert.match(html, />24h<\/button>/); assert.match(html, /bg-white\/14 text-slate-50/); assert.match(html, />7d<\/button>/); assert.match(html, />30d<\/button>/); }); test("ChartShell renders title, meta, and children", () => { const html = renderToStaticMarkup( chart body ); assert.match(html, /Token Flow/); assert.match(html, /gpt-4\.1/); assert.match(html, /chart body/); }); test("StatsGrid renders cards, compact, and pill variants", () => { const items = [ { label: "Tokens", value: "12K" }, { label: "Requests", value: "128" } ]; const cardsHtml = renderToStaticMarkup(); const compactHtml = renderToStaticMarkup(); const pillsHtml = renderToStaticMarkup(); assert.match(cardsHtml, /grid-cols-2/); assert.match(compactHtml, /py-0\.5/); assert.match(pillsHtml, /rounded-full/); assert.match(`${cardsHtml}${compactHtml}${pillsHtml}`, /Tokens/); assert.match(`${cardsHtml}${compactHtml}${pillsHtml}`, /12K/); }); test("AnimatedUsageChart renders line, area, bar, and sparkline output", () => { const series = usageStats().series; const lineHtml = renderToStaticMarkup(); const areaHtml = renderToStaticMarkup(); const barHtml = renderToStaticMarkup(); const sparkHtml = renderToStaticMarkup(); assert.match(lineHtml, /aria-label="Usage chart"/); assert.match(lineHtml, /line-chart-glow/); assert.match(areaHtml, /fill="rgba\(45,212,191,.18\)"/); assert.match(barHtml, / { const html = renderToStaticMarkup(); assert.match(html, /Activity/); assert.match(html, /Longest streak/); assert.match(html, /aria-label="Activity Tokens"/); assert.match(html, /Less/); assert.match(html, /More/); }); test("TokenMixPanel renders bars, stacked, and share chart variants", () => { const totals = usageTotals(); const barsHtml = renderToStaticMarkup(); const stackedHtml = renderToStaticMarkup(); const donutHtml = renderToStaticMarkup(); assert.match(barsHtml, /Token Mix/); assert.match(barsHtml, /Input/); assert.match(stackedHtml, /bg-blue-400/); assert.match(donutHtml, /aria-label="Share chart"/); }); test("RingMetrics and RadialMetric render accessible radial charts", () => { const ringsHtml = renderToStaticMarkup(); const radialHtml = renderToStaticMarkup( ); assert.match(ringsHtml, /Circular metrics/); assert.match(ringsHtml, /Success/); assert.match(ringsHtml, /Cache/); assert.match(radialHtml, /aria-label="Cache 24%"/); assert.match(radialHtml, /12K/); assert.match(radialHtml, /tokens/); }); test("ModelShareChart renders populated variants and empty state", () => { const rows = usageStats().models; const barsHtml = renderToStaticMarkup(); const listHtml = renderToStaticMarkup(); const donutHtml = renderToStaticMarkup(); const emptyHtml = renderToStaticMarkup(); assert.match(barsHtml, /Model Share/); assert.match(barsHtml, /gpt-4\.1/); assert.match(listHtml, /1\. gpt-4\.1/); assert.match(listHtml, /62%/); assert.match(donutHtml, /aria-label="Share chart"/); assert.match(emptyHtml, /No usage captured yet/); }); test("TrayApp and TrayDetailApp render their shell components without browser runtime", () => { const trayHtml = renderToStaticMarkup(); const detailHtml = renderToStaticMarkup(); assert.match(trayHtml, /Usage Overview/); assert.match(trayHtml, /Open CCR/); assert.match(detailHtml, /Usage Detail/); assert.match(detailHtml, /OpenAI/); });