Files
paseo/packages/app/src/usage/model.test.ts
T
paseo-bot[bot]andMichael Wu 62dc5f6f57 fix(app): clarify and localize provider usage
Usage windows displayed consumed percentages without saying what they
meant, and their copy did not follow the app language. Translate the
usage surface while retaining the last successful values and timestamps
when refreshes fail. Preserve customized provider labels.

Co-authored-by: Michael Wu <michaelmwu@gmail.com>
2026-10-19 09:01:53 +02:00

406 lines
14 KiB
TypeScript

import { afterEach, describe, expect, it } from "vitest";
import { i18n } from "@/i18n/i18next";
import {
resolveUsageReport,
displayPercent,
resolveAgentUsageView,
replaceReport,
resolveUsageRefresh,
resolveUsageHostId,
resolveUsageModalHostId,
resolveUsageView,
settleReports,
upsertReport,
usageWindowRowLabel,
type UsageHost,
type UsageQueryState,
} from "./model";
import type { UsageReportEntry, UsageWindow } from "./types";
function entry(input: {
windows?: UsageWindow[];
planLabel?: string;
icon?: string;
sourceId?: string;
}): UsageReportEntry {
return {
id: `${input.sourceId ?? "fixture"}:account-1`,
account: {},
fetchedAt: "2026-01-01T00:00:00.000Z",
sourceId: input.sourceId ?? "fixture",
sourceLabel: "Fixture source",
...(input.icon ? { icon: input.icon } : {}),
report: {
status: "available",
...(input.planLabel ? { planLabel: input.planLabel } : {}),
windows: input.windows ?? [],
},
};
}
function ready(data: UsageReportEntry[]): UsageQueryState {
return { data, error: null, isFetching: false };
}
describe("resolveUsageView", () => {
it("asks for a host update when the host lacks usage sources", () => {
expect(
resolveUsageView({
hostLabel: "Laptop",
isConnected: true,
supportsUsage: false,
query: ready([entry({})]),
}),
).toEqual({ kind: "unavailable", message: "Update Laptop to see usage" });
});
it("asks for a connection before anything else", () => {
expect(
resolveUsageView({
hostLabel: "Laptop",
isConnected: false,
supportsUsage: false,
query: undefined,
}),
).toEqual({ kind: "unavailable", message: "Connect to Laptop to see usage" });
});
it("localizes unavailable host messages while retaining the host name", async () => {
await i18n.changeLanguage("ko");
expect(
resolveUsageView({
hostLabel: "Laptop",
isConnected: false,
supportsUsage: false,
query: undefined,
}),
).toEqual({ kind: "unavailable", message: "Laptop에 연결하여 제공업체 사용량을 확인하세요" });
});
it("moves from loading to ready to error", () => {
const base = { hostLabel: "Laptop", isConnected: true, supportsUsage: true };
expect(resolveUsageView({ ...base, query: undefined })).toEqual({ kind: "loading" });
expect(
resolveUsageView({ ...base, query: { data: [], error: null, isFetching: true } }),
).toEqual({ kind: "ready", reports: [], isRefreshing: true });
expect(
resolveUsageView({
...base,
query: { data: undefined, error: new Error("boom"), isFetching: false },
}),
).toEqual({ kind: "error", message: "boom" });
});
});
afterEach(async () => {
await i18n.changeLanguage("en");
});
const hosts: UsageHost[] = [
{ serverId: "offline", label: "Offline", isConnected: false, supportsUsage: true },
{ serverId: "old", label: "Old", isConnected: true, supportsUsage: false },
{ serverId: "a", label: "Alpha", isConnected: true, supportsUsage: true },
{ serverId: "b", label: "Beta", isConnected: true, supportsUsage: true },
];
describe("resolveUsageHostId", () => {
const choose = (pickedServerId: string | null, activeServerId: string | null) =>
resolveUsageHostId({ pickedServerId, activeServerId, hosts });
it("reads the picked host over the active workspace's host", () => {
expect(choose("a", "b")).toBe("a");
});
it("reads the active workspace's host when nothing usable is picked", () => {
expect(choose(null, "b")).toBe("b");
expect(choose("offline", "b")).toBe("b");
expect(choose("old", "b")).toBe("b");
});
it("falls back to the first connected host that reports usage", () => {
expect(choose(null, null)).toBe("a");
expect(choose(null, "offline")).toBe("a");
expect(choose(null, "old")).toBe("a");
});
it("has no host when none reports usage", () => {
expect(
resolveUsageHostId({
pickedServerId: "old",
activeServerId: "old",
hosts: hosts.slice(0, 2),
}),
).toBeNull();
});
});
describe("resolveUsageModalHostId", () => {
it("shows the picked host while it stays connected, even one that cannot report usage", () => {
expect(resolveUsageModalHostId({ pickedServerId: "old", activeServerId: "b", hosts })).toBe(
"old",
);
expect(resolveUsageModalHostId({ pickedServerId: "offline", activeServerId: "b", hosts })).toBe(
"b",
);
});
it("otherwise shows the host the sidebar row reads", () => {
for (const pickedServerId of [null, "a", "offline"]) {
for (const activeServerId of ["b", null, "old", "offline"]) {
const choice = { pickedServerId, activeServerId, hosts };
expect(resolveUsageModalHostId(choice)).toBe(resolveUsageHostId(choice));
}
}
});
it("shows the first connected host when none reports usage, so the modal says to update it", () => {
expect(
resolveUsageModalHostId({
pickedServerId: null,
activeServerId: null,
hosts: hosts.slice(0, 2),
}),
).toBe("old");
expect(
resolveUsageModalHostId({ pickedServerId: null, activeServerId: null, hosts: [] }),
).toBeNull();
});
});
describe("usageWindowRowLabel", () => {
it("names the window, its percent and its reset after what pinning it pins", () => {
expect(
usageWindowRowLabel({
pinLabel: "Pin Claude Session",
value: "31%",
trailing: "resets in 2h",
}),
).toBe("Pin Claude Session, 31% · resets in 2h");
expect(usageWindowRowLabel({ pinLabel: "Pin Codex Weekly", value: "—", trailing: null })).toBe(
"Pin Codex Weekly, —",
);
});
});
describe("displayPercent", () => {
const window = (input: Partial<UsageWindow>): UsageWindow => ({
id: "weekly",
label: "Weekly",
...input,
});
it("reads the share used or the share left", () => {
expect(displayPercent(window({ usedPct: 31 }), "used")).toBe(31);
expect(displayPercent(window({ usedPct: 31 }), "remaining")).toBe(69);
expect(displayPercent(window({ remainingPct: 40 }), "used")).toBe(60);
expect(displayPercent(window({ usedPct: 50, remainingPct: 45 }), "remaining")).toBe(45);
});
it("has no percent when the window reports none", () => {
expect(displayPercent(window({}), "remaining")).toBeNull();
});
});
describe("resolveUsageRefresh", () => {
it("is pending while a refresh runs, even after an earlier failure", () => {
expect(resolveUsageRefresh({ isPending: true, error: new Error("boom") })).toBe("pending");
});
it("is failed after a refresh errors", () => {
expect(resolveUsageRefresh({ isPending: false, error: new Error("boom") })).toBe("failed");
});
it("is idle before and after a successful refresh", () => {
expect(resolveUsageRefresh({ isPending: false, error: null })).toBe("idle");
});
});
describe("replaceReport", () => {
const alpha = entry({ sourceId: "alpha", planLabel: "Old" });
const beta = entry({ sourceId: "beta" });
it("swaps only the refreshed report, in place", () => {
const refreshed = entry({ sourceId: "alpha", planLabel: "New" });
expect(replaceReport([alpha, beta], alpha.id, refreshed)).toEqual([refreshed, beta]);
});
it("drops a report the daemon no longer knows", () => {
expect(replaceReport([alpha, beta], alpha.id, null)).toEqual([beta]);
});
});
describe("upsertReport", () => {
const alpha = entry({ sourceId: "alpha", planLabel: "Old" });
const beta = entry({ sourceId: "beta" });
it("starts a list from the first streamed report", () => {
expect(upsertReport(undefined, alpha)).toEqual([alpha]);
});
it("appends a report the list does not have yet", () => {
expect(upsertReport([alpha], beta)).toEqual([alpha, beta]);
});
it("replaces a report the list already has, in place", () => {
const streamed = entry({ sourceId: "alpha", planLabel: "New" });
expect(upsertReport([alpha, beta], streamed)).toEqual([streamed, beta]);
});
it("keeps a copy fetched after the streamed one, such as a Refresh that landed first", () => {
const refreshed = { ...alpha, planLabel: "Refreshed", fetchedAt: "2026-01-01T00:05:00.000Z" };
expect(upsertReport([refreshed, beta], alpha)).toEqual([refreshed, beta]);
});
});
describe("settleReports", () => {
const alpha = entry({ sourceId: "alpha", planLabel: "Old" });
const beta = entry({ sourceId: "beta" });
it("takes the finished list, dropping reports the host no longer has", () => {
const streamed = entry({ sourceId: "alpha", planLabel: "New" });
expect(settleReports([alpha, beta], [streamed])).toEqual([streamed]);
});
it("keeps a report refreshed while the list streamed over its older copy in the list", () => {
const refreshed = { ...alpha, planLabel: "Refreshed", fetchedAt: "2026-01-01T00:05:00.000Z" };
expect(settleReports([refreshed, beta], [alpha, beta])).toEqual([refreshed, beta]);
});
it("keeps the displayed order when providers finish a refresh in reverse order", () => {
const refreshed = entry({ sourceId: "alpha", planLabel: "New" });
const streamed = upsertReport(upsertReport([alpha, beta], beta), refreshed);
expect(settleReports(streamed, [beta, refreshed])).toEqual([refreshed, beta]);
});
it("drops missing reports and appends new ones without moving surviving reports", () => {
const gamma = entry({ sourceId: "gamma" });
const delta = entry({ sourceId: "delta" });
expect(settleReports([alpha, beta, gamma], [delta, gamma, alpha])).toEqual([
alpha,
gamma,
delta,
]);
});
it("takes the finished list as is when nothing was shown yet", () => {
expect(settleReports(undefined, [alpha, beta])).toEqual([alpha, beta]);
});
});
describe("resolveAgentUsageView", () => {
const report = entry({ sourceId: "claude" });
const idle: UsageQueryState = { data: undefined, error: null, isFetching: false };
it("shows nothing on a host that cannot report usage", () => {
expect(resolveAgentUsageView({ canReport: false, query: idle })).toEqual({ kind: "none" });
});
it("loads until the first report streams in", () => {
expect(
resolveAgentUsageView({ canReport: true, query: { ...idle, isFetching: true } }),
).toEqual({ kind: "loading" });
});
it("shows each report as it streams in, before the request finishes", () => {
expect(
resolveAgentUsageView({
canReport: true,
query: { data: [report], error: null, isFetching: true },
}),
).toEqual({ kind: "ready", reports: [report] });
});
it("shows nothing for an agent with no account to report", () => {
expect(resolveAgentUsageView({ canReport: true, query: { ...idle, data: [] } })).toEqual({
kind: "none",
});
});
it("says why a failed request has nothing to show", () => {
expect(
resolveAgentUsageView({
canReport: true,
query: { ...idle, error: new Error("Unknown agent") },
}),
).toEqual({ kind: "error", message: "Unable to load usage: Unknown agent" });
});
it("says the request failed instead of showing the reports from before it", () => {
expect(
resolveAgentUsageView({
canReport: true,
query: { data: [report], error: new Error("Unknown agent"), isFetching: false },
}),
).toEqual({ kind: "error", message: "Unable to load usage: Unknown agent" });
});
});
it("resolves retained usage and successful time without inventing old-daemon history", () => {
const success = entry({ windows: [{ id: "weekly", label: "Weekly", usedPct: 42 }] });
const failure: UsageReportEntry = {
...success,
fetchedAt: "2026-01-01T00:06:00.000Z",
report: { status: "error", error: "Rate limited" },
lastSuccessful: {
fetchedAt: success.fetchedAt,
report: success.report as Extract<UsageReportEntry["report"], { status: "available" }>,
},
};
expect(resolveUsageReport(failure)).toEqual({
windows: success.report.status === "available" ? success.report.windows : [],
balances: [],
details: [],
planLabel: null,
successfulAt: success.fetchedAt,
retained: true,
messages: ["Rate limited"],
});
expect(resolveUsageReport({ ...failure, lastSuccessful: undefined })).toEqual({
windows: [],
balances: [],
details: [],
planLabel: null,
successfulAt: null,
retained: false,
messages: ["Rate limited"],
});
expect(resolveUsageReport(success)).toEqual({
windows: success.report.status === "available" ? success.report.windows : [],
balances: [],
details: [],
planLabel: null,
successfulAt: success.fetchedAt,
retained: false,
messages: [],
});
});
it("orders failed polls by attempt time even when successful data is older", () => {
const success = entry({});
if (success.report.status !== "available") throw new Error("fixture must be available");
const failure: UsageReportEntry = {
...success,
fetchedAt: "2026-01-01T00:06:00.000Z",
report: { status: "error", error: "Rate limited" },
lastSuccessful: { fetchedAt: success.fetchedAt, report: success.report },
};
expect(upsertReport([failure], success)).toEqual([failure]);
expect(settleReports([failure], [success])).toEqual([failure]);
expect(upsertReport([success], failure)).toEqual([failure]);
});
it("available and retained usage show the same successful completion time", () => {
const success: UsageReportEntry = { ...entry({}), successfulAt: "2026-01-01T00:00:15.000Z" };
if (success.report.status !== "available") throw new Error("fixture must be available");
expect(resolveUsageReport(success).successfulAt).toBe("2026-01-01T00:00:15.000Z");
const failure: UsageReportEntry = {
...success,
successfulAt: undefined,
fetchedAt: "2026-01-01T00:06:00.000Z",
report: { status: "error", error: "Rate limited" },
lastSuccessful: { fetchedAt: success.successfulAt!, report: success.report },
};
expect(resolveUsageReport(failure).successfulAt).toBe(resolveUsageReport(success).successfulAt);
expect(upsertReport([failure], success)).toEqual([failure]);
});