102 lines
4.8 KiB
TypeScript
102 lines
4.8 KiB
TypeScript
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([]);
|
||
});
|
||
});
|