Files
ttstd-infinite-canvas/web/test/banner-title.test.ts

102 lines
4.8 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, test } from "bun:test";
import {
BANNER_TITLE_FONT_FAMILIES,
bannerTitleCharCount,
bannerTitleContrastRatio,
bannerTitlePlainText,
bannerTitleRunStyle,
lowContrastBannerTitleColors,
normalizeBannerTitleHex,
normalizeBannerTitleRuns,
parseBannerTitleColor,
} from "@/lib/announcements/banner-title";
describe("通知标题样式分段清洗", () => {
test("合并相邻同样式分段,跳过空文本", () => {
const runs = normalizeBannerTitleRuns([
{ text: "限时", fontSize: 16, color: "#FF0000" },
{ text: "活动", fontSize: 16, color: "#ff0000" },
{ text: "", fontSize: 16 },
{ text: "上线", fontSize: 20 },
]);
expect(runs).toEqual([
{ text: "限时活动", fontSize: 16, color: "#FF0000" },
{ text: "上线", fontSize: 20 },
]);
});
test("丢弃白名单外的字号、字重、字体与颜色", () => {
expect(normalizeBannerTitleRuns([{ text: "标题", fontSize: 9 }])).toEqual([{ text: "标题" }]);
expect(normalizeBannerTitleRuns([{ text: "标题", fontSize: 21 }])).toEqual([{ text: "标题" }]);
expect(normalizeBannerTitleRuns([{ text: "标题", fontWeight: 6000 }])).toEqual([{ text: "标题" }]);
expect(normalizeBannerTitleRuns([{ text: "标题", fontFamily: "comic" as never }])).toEqual([{ text: "标题" }]);
expect(normalizeBannerTitleRuns([{ text: "标题", color: "red" }])).toEqual([{ text: "标题" }]);
expect(normalizeBannerTitleRuns([{ text: "标题", color: "#fff;background:url(x)" }])).toEqual([{ text: "标题" }]);
});
test("sans 视为默认字体,不写入分段", () => {
expect(normalizeBannerTitleRuns([{ text: "标题", fontFamily: "sans" }])).toEqual([{ text: "标题" }]);
expect(normalizeBannerTitleRuns([{ text: "标题", fontFamily: "mono" }])).toEqual([{ text: "标题", fontFamily: "mono" }]);
});
test("纯文本与字符数按码点统计", () => {
const runs = [{ text: "限时" }, { text: "活动🎉" }];
expect(bannerTitlePlainText(runs)).toBe("限时活动🎉");
expect(bannerTitleCharCount(runs)).toBe(5);
});
});
describe("通知标题样式输出", () => {
test("只输出已设置的维度", () => {
expect(bannerTitleRunStyle({ text: "标题" })).toEqual({});
expect(bannerTitleRunStyle({ text: "标题", fontSize: 20, fontWeight: 700, color: "#FF0000" })).toEqual({
fontSize: "20px",
fontWeight: 700,
color: "#FF0000",
});
});
test("字体档位输出对应字体栈", () => {
const serif = BANNER_TITLE_FONT_FAMILIES.find((item) => item.key === "serif");
expect(bannerTitleRunStyle({ text: "标题", fontFamily: "serif" }).fontFamily).toBe(serif?.css);
});
test("十六进制颜色归一化", () => {
expect(normalizeBannerTitleHex("#abc")).toBe("#AABBCC");
expect(normalizeBannerTitleHex("5f6ae4")).toBe("#5F6AE4");
expect(normalizeBannerTitleHex("#12345")).toBe("");
expect(parseBannerTitleColor("rgb(95, 106, 228)")).toEqual([95, 106, 228]);
expect(parseBannerTitleColor("not-a-color")).toBeNull();
});
});
describe("通知标题对比度检查", () => {
test("白字在通知条两种底色上的对比度", () => {
expect(bannerTitleContrastRatio("#FFFFFF", "#5C67E2")).toBeCloseTo(4.67, 2);
expect(bannerTitleContrastRatio("#FFFFFF", "#3F4590")).toBeCloseTo(8.52, 2);
expect(bannerTitleContrastRatio("not-a-color", "#3F4590")).toBeNull();
expect(bannerTitleContrastRatio("#FFFFFF", "")).toBeNull();
});
test("通知条底色 token 的白字对比度必须达到 AA(改 token 时同步更新此处)", () => {
// globals.css 的 --palette-banner-notice-500 / -700(「公告」类型);默认标题为白色 12px 正文,需 >= 4.5:1。
// 四种类型的完整覆盖见 test/banner-notice.test.ts。
expect(bannerTitleContrastRatio("#FFFFFF", "#5C67E2")).toBeGreaterThanOrEqual(4.5);
expect(bannerTitleContrastRatio("#FFFFFF", "#3F4590")).toBeGreaterThanOrEqual(4.5);
});
test("挑出对比度不足的颜色并去重,默认无色不参与检查", () => {
const runs = [
{ text: "低", color: "#808BF5" },
{ text: "也低", color: "#808BF5" },
{ text: "足够", color: "#FFFFFF" },
{ text: "没设颜色" },
];
expect(lowContrastBannerTitleColors(runs, "#5C67E2")).toEqual(["#808BF5"]);
expect(lowContrastBannerTitleColors(runs, "#3F4590")).toEqual(["#808BF5"]);
expect(lowContrastBannerTitleColors([{ text: "足够", color: "#FFFFFF" }], "#5C67E2")).toEqual([]);
expect(lowContrastBannerTitleColors(runs, "")).toEqual([]);
});
});