Files
UHD_Media_Tool/apps/web/app/lib/tokens.test.ts
T
rootandClaude Opus 5.5 fa344a7184 feat(web): token 数以 K 输入显示,已存凭证显示掩码占位(FIX-8)
- 新增 UnitInput 与 kind=tokens:上下文预算、单次 token 上限、自定义模型上下文窗口以 K 输入(允许小数),存储仍为原始 token 数;校验与提示用 K 表述;列表/详情 token 数统一 K/M 简写(formatTokens)
- 新增 SecretInput 与 kind=secret:已保存时显示「已设置 ••••••••」(有服务端掩码时带末 4 位),聚焦直接输入替换,留空保持,「清除」确认后保存生效;替换模型服务、TMDB、网页搜索、下载器、媒体服务器、浏览器服务、站点账号、Passkey、本机 Token 各处
- 统一只写凭证服务端语义:省略或空串 = 不变,null = 清除(contracts secretInput);下载器/媒体服务器新增清除;站点凭证同类更新可留空保持密码/Cookie/API Key/TOTP,TOTP 可 null 清除,不再误删 TOTP 与 UA
- contextBudget 最小值 4096→4000、contextWindow 1024→1000,便于按 K 填写
- 测试:换算与校验、SecretInput 渲染与状态、各接口留空不变/显式清除

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-30 00:10:46 +08:00

58 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from "vitest";
import { formatTokens, kToTokens, tokenInputError, tokenRangeText, tokensToK } from "./tokens.ts";
describe("token 以 K 为单位的换算", () => {
it("原始值 → 输入框 K 值:整千、小数、空", () => {
expect(tokensToK(128_000)).toBe("128");
expect(tokensToK(1_500)).toBe("1.5");
expect(tokensToK(4_096)).toBe("4.096");
expect(tokensToK(2_000_000)).toBe("2000");
expect(tokensToK(null)).toBe("");
expect(tokensToK(undefined)).toBe("");
});
it("K 值 → 原始值:允许小数与尾随 K,空串 undefined,非法 NaN", () => {
expect(kToTokens("128")).toBe(128_000);
expect(kToTokens(" 1.5 ")).toBe(1_500);
expect(kToTokens("200k")).toBe(200_000);
expect(kToTokens(".5")).toBe(500);
expect(kToTokens("0.0005")).toBe(1);
expect(kToTokens("")).toBeUndefined();
expect(kToTokens(" ")).toBeUndefined();
expect(kToTokens("abc")).toBeNaN();
expect(kToTokens("-1")).toBeNaN();
expect(kToTokens("1e3")).toBeNaN();
});
it("往返不丢精度", () => {
for (const n of [4_000, 4_096, 128_000, 131_072, 1_000_000, 2_000_000, 1]) expect(kToTokens(tokensToK(n))).toBe(n);
});
it("校验:范围、必填、非法输入,错误用 K 表述", () => {
const r = { min: 4_000, max: 2_000_000, required: true };
expect(tokenRangeText(r)).toBe("4K–2000K");
expect(tokenInputError("128", r)).toBeNull();
expect(tokenInputError("4", r)).toBeNull();
expect(tokenInputError("3.9", r)).toBe("填 4K–2000K");
expect(tokenInputError("2001", r)).toBe("填 4K–2000K");
expect(tokenInputError("", r)).toBe("填一个数,单位 K");
expect(tokenInputError("12x", r)).toMatch(/只填数字/);
// 可选:空串通过;0 不行
expect(tokenInputError("", { min: 1 })).toBeNull();
expect(tokenInputError("0", { min: 1 })).toBe("填 0.001K 以上");
expect(tokenInputError("0", {})).toBe("填大于 0 的数");
});
it("列表 / 详情显示:K / M 简写", () => {
expect(formatTokens(512)).toBe("512");
expect(formatTokens(1_500)).toBe("1.5K");
expect(formatTokens(12_345)).toBe("12.3K");
expect(formatTokens(128_000)).toBe("128K");
expect(formatTokens(200_000)).toBe("200K");
expect(formatTokens(999_960)).toBe("1M");
expect(formatTokens(1_000_000)).toBe("1M");
expect(formatTokens(1_048_576)).toBe("1.05M");
expect(formatTokens(undefined)).toBe("—");
});
});