1- import {
2- ProviderDriverKind ,
3- ProviderInstanceId ,
4- type ServerProvider ,
5- type ServerProviderUsageWindow ,
6- } from "@t3tools/contracts" ;
1+ import { ProviderInstanceId , type ServerProviderUsageWindow } from "@t3tools/contracts" ;
72import { describe , expect , it } from "vite-plus/test" ;
83
94import { formatTimeUntilReset , getComposerUsageView } from "./ComposerUsageIndicator.logic" ;
5+ import type { ProviderUsageAccount } from "./providerUsage/ProviderUsageAccounts" ;
106
11- function provider ( input : {
12- windows ? : ReadonlyArray < ServerProviderUsageWindow > ;
7+ function account ( input : {
8+ windows : ReadonlyArray < ServerProviderUsageWindow > ;
139 displayName ?: string ;
1410 accentColor ?: string ;
15- } ) : ServerProvider {
11+ checkedAt ?: string ;
12+ } ) : ProviderUsageAccount {
1613 return {
1714 instanceId : ProviderInstanceId . make ( "claudeAgent" ) ,
18- driver : ProviderDriverKind . make ( "claudeAgent" ) ,
19- ...( input . displayName ? { displayName : input . displayName } : { } ) ,
15+ displayName : input . displayName ?? "Claude" ,
2016 ...( input . accentColor ? { accentColor : input . accentColor } : { } ) ,
21- ...( input . windows
22- ? {
23- usageLimits : {
24- source : "claudeOAuth" ,
25- checkedAt : "2026-08-04T21:00:00.000Z" ,
26- windows : input . windows ,
27- } ,
28- }
29- : { } ) ,
30- enabled : true ,
31- installed : true ,
32- version : null ,
33- status : "ready" as const ,
34- auth : { status : "authenticated" as const } ,
35- checkedAt : "2026-08-04T21:00:00.000Z" ,
36- models : [ ] ,
37- slashCommands : [ ] ,
38- skills : [ ] ,
17+ usageLimits : {
18+ source : "claudeOAuth" ,
19+ checkedAt : input . checkedAt ?? "2026-08-06T11:59:00.000Z" ,
20+ windows : input . windows ,
21+ } ,
22+ isActive : true ,
3923 } ;
4024}
4125
@@ -66,7 +50,7 @@ const NOW = Date.parse("2026-08-06T12:00:00.000Z");
6650
6751describe ( "getComposerUsageView" , ( ) => {
6852 it ( "shows the session and account-wide weekly only" , ( ) => {
69- const view = getComposerUsageView ( provider ( { windows : CLAUDE_WINDOWS } ) , NOW ) ;
53+ const view = getComposerUsageView ( account ( { windows : CLAUDE_WINDOWS } ) , NOW ) ;
7054
7155 expect ( view ?. entries ) . toEqual ( [
7256 {
@@ -88,15 +72,15 @@ describe("getComposerUsageView", () => {
8872
8973 // The strip is a glance; the popover carries the model-scoped weeklies.
9074 it ( "leaves model-scoped weeklies out" , ( ) => {
91- const view = getComposerUsageView ( provider ( { windows : CLAUDE_WINDOWS } ) , NOW ) ;
75+ const view = getComposerUsageView ( account ( { windows : CLAUDE_WINDOWS } ) , NOW ) ;
9276
9377 expect ( view ?. entries . some ( ( entry ) => entry . detail === "Weekly (Fable)" ) ) . toBe ( false ) ;
9478 } ) ;
9579
9680 // Windows are matched on duration, so Codex's differently-named ones work.
9781 it ( "reads Codex's window labels" , ( ) => {
9882 const view = getComposerUsageView (
99- provider ( {
83+ account ( {
10084 windows : [
10185 { label : "Session" , usedPercent : 25 , windowDurationMins : 300 } ,
10286 { label : "Weekly" , usedPercent : 82 , windowDurationMins : 10_080 } ,
@@ -114,7 +98,7 @@ describe("getComposerUsageView", () => {
11498
11599 it ( "rounds a fractional percentage" , ( ) => {
116100 const view = getComposerUsageView (
117- provider ( { windows : [ { label : "Session" , usedPercent : 14.6 , windowDurationMins : 300 } ] } ) ,
101+ account ( { windows : [ { label : "Session" , usedPercent : 14.6 , windowDurationMins : 300 } ] } ) ,
118102 NOW ,
119103 ) ;
120104
@@ -123,7 +107,7 @@ describe("getComposerUsageView", () => {
123107
124108 it ( "carries the account name and accent for the tooltip and dot" , ( ) => {
125109 const view = getComposerUsageView (
126- provider ( { windows : CLAUDE_WINDOWS , displayName : "Claude Work" , accentColor : "#0088ff" } ) ,
110+ account ( { windows : CLAUDE_WINDOWS , displayName : "Claude Work" , accentColor : "#0088ff" } ) ,
127111 NOW ,
128112 ) ;
129113
@@ -133,22 +117,41 @@ describe("getComposerUsageView", () => {
133117
134118 it ( "renders one entry when only a session window is reported" , ( ) => {
135119 const view = getComposerUsageView (
136- provider ( { windows : [ { label : "Session" , usedPercent : 5 , windowDurationMins : 300 } ] } ) ,
120+ account ( { windows : [ { label : "Session" , usedPercent : 5 , windowDurationMins : 300 } ] } ) ,
137121 NOW ,
138122 ) ;
139123
140124 expect ( view ?. entries ) . toHaveLength ( 1 ) ;
141125 expect ( view ?. entries [ 0 ] ?. label ) . toBe ( "5h" ) ;
142126 } ) ;
143127
128+ // Dimming is the strip's whole way of admitting a number has fallen behind
129+ // the server's own poll, so the bound must track that poll.
130+ it ( "marks a reading stale only past the caller's bound" , ( ) => {
131+ const aged = account ( { windows : CLAUDE_WINDOWS , checkedAt : "2026-08-06T11:54:00.000Z" } ) ;
132+
133+ expect ( getComposerUsageView ( aged , NOW , 5 * 60_000 ) ?. stale ) . toBe ( true ) ;
134+ expect ( getComposerUsageView ( aged , NOW , 10 * 60_000 ) ?. stale ) . toBe ( false ) ;
135+ expect ( getComposerUsageView ( aged , NOW ) ?. age ) . toBe ( "6m" ) ;
136+ } ) ;
137+
138+ it ( "has no age for a reading under a minute old" , ( ) => {
139+ const view = getComposerUsageView (
140+ account ( { windows : CLAUDE_WINDOWS , checkedAt : "2026-08-06T11:59:30.000Z" } ) ,
141+ NOW ,
142+ ) ;
143+
144+ expect ( view ?. age ) . toBeUndefined ( ) ;
145+ expect ( view ?. stale ) . toBe ( false ) ;
146+ } ) ;
147+
144148 // Nothing to say beats a placeholder in a strip this dense.
145149 it . each ( [
146- [ "no provider" , null ] ,
147- [ "a provider with no usage" , provider ( { } ) ] ,
148- [ "a provider reporting zero windows" , provider ( { windows : [ ] } ) ] ,
150+ [ "no account" , null ] ,
151+ [ "an account reporting zero windows" , account ( { windows : [ ] } ) ] ,
149152 [
150153 "windows with no duration to classify" ,
151- provider ( { windows : [ { label : "Mystery" , usedPercent : 10 } ] } ) ,
154+ account ( { windows : [ { label : "Mystery" , usedPercent : 10 } ] } ) ,
152155 ] ,
153156 ] ) ( "returns null for %s" , ( _label , input ) => {
154157 expect ( getComposerUsageView ( input , NOW ) ) . toBeNull ( ) ;
0 commit comments