Files
paseo/packages/app/src/usage/format.test.ts
T

87 lines
3.6 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { i18n } from "@/i18n/i18next";
import {
formatAgo,
formatAmount,
formatPct,
formatProviderUsageLabel,
formatResetLabel,
formatRunsOutLabel,
} from "./format";
const NOW = Date.parse("2026-07-19T00:00:00.000Z");
describe("formatAmount", () => {
beforeEach(async () => {
await i18n.changeLanguage("en");
});
afterEach(async () => {
await i18n.changeLanguage("en");
});
it("groups thousands in the app's language", () => {
expect(formatAmount(12345, "credits", "en")).toBe("12,345");
expect(formatAmount(12345, "requests", "en")).toBe("12,345");
expect(formatAmount(12345, "credits", "fr").replace(/\s/g, " ")).toBe("12 345");
});
it("formats dollars as the language writes currency", () => {
expect(formatAmount(1234.5, "usd", "en")).toBe("$1,234.50");
expect(formatAmount(1234.5, "usd", "fr").replace(/\s/g, " ")).toBe("1 234,50 $US");
});
it("localizes usage timing without patching the global clock", async () => {
const twoHoursFromNow = new Date(NOW + 2 * 60 * 60 * 1000).toISOString();
const threeDaysAgo = new Date(NOW - 3 * 24 * 60 * 60 * 1000).toISOString();
expect(formatPct(7, "en")).toBe("7%");
expect(formatResetLabel(twoHoursFromNow, NOW)).toBe("resets 2h");
expect(formatRunsOutLabel(twoHoursFromNow, NOW)).toBe("runs out 2h");
await i18n.changeLanguage("ja");
expect(formatResetLabel(twoHoursFromNow, NOW)).toBe("2時間後にリセット");
expect(formatRunsOutLabel(twoHoursFromNow, NOW)).toBe("2時間後に上限に到達");
expect(formatAgo(threeDaysAgo, NOW)).toBe("3日前");
});
it("formats percentages with locale-specific spacing", () => {
expect(formatPct(42, "fr")).toBe("42\u00a0%");
});
it("formats relative-time counts with the active locale", async () => {
await i18n.changeLanguage("fr");
const days = 1_234;
const daysFromNow = new Date(NOW + days * 24 * 60 * 60 * 1000).toISOString();
const daysAgo = new Date(NOW - days * 24 * 60 * 60 * 1000).toISOString();
expect(formatResetLabel(daysFromNow, NOW)).toBe("se réinitialise dans 1\u202f234 j");
expect(formatRunsOutLabel(daysFromNow, NOW)).toBe("s’épuise dans 1\u202f234 j");
expect(formatAgo(daysAgo, NOW)).toBe("il y a 1\u202f234 j");
});
it("selects Arabic plural forms for relative durations", async () => {
await i18n.changeLanguage("ar");
const twoHoursFromNow = new Date(NOW + 2 * 60 * 60 * 1000).toISOString();
const threeHoursFromNow = new Date(NOW + 3 * 60 * 60 * 1000).toISOString();
const twoDaysAgo = new Date(NOW - 2 * 24 * 60 * 60 * 1000).toISOString();
expect(formatResetLabel(twoHoursFromNow, NOW)).toBe("تتم إعادة التعيين خلال ساعتين");
expect(formatRunsOutLabel(threeHoursFromNow, NOW)).toBe("ينفد خلال 3 ساعات");
expect(formatAgo(twoDaysAgo, NOW)).toBe("قبل يومين");
});
it("uses locale-aware compact notation for token balances", () => {
expect(formatAmount(1_234, "tokens", "en")).toBe("1.2K");
expect(formatAmount(1_234, "tokens", "ar")).toBe("1.2\u00a0ألف");
});
it("localizes known provider-usage labels and preserves provider-specific labels", async () => {
await i18n.changeLanguage("ko");
expect(formatProviderUsageLabel("session", "Session")).toBe("세션");
expect(formatProviderUsageLabel("five_hour", "Session")).toBe("세션");
expect(formatProviderUsageLabel("credits", "Credits")).toBe("크레딧");
expect(formatProviderUsageLabel("custom_limit", "Custom limit")).toBe("Custom limit");
});
});